mirror of
https://github.com/gotoeasy/glogcenter.git
synced 2025-09-26 19:51:16 +08:00
添加python客户端支持
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -27,3 +27,7 @@
|
||||
|
||||
/glc/www/web/src/pkgs/*/
|
||||
/glc/www/web/src/pkgs/index-pkgs.js
|
||||
|
||||
/glc-python-client/build/
|
||||
/glc-python-client/dist/
|
||||
/glc-python-client/glogcenter.egg-info/
|
||||
|
21
glc-python-client/LICENSE
Normal file
21
glc-python-client/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 gotoeasy.top
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
1
glc-python-client/MANIFEST.in
Normal file
1
glc-python-client/MANIFEST.in
Normal file
@@ -0,0 +1 @@
|
||||
include README.md LICENSE
|
1
glc-python-client/README.md
Normal file
1
glc-python-client/README.md
Normal file
@@ -0,0 +1 @@
|
||||
日志中心的 python 客户端
|
3
glc-python-client/glogcenter/__init__.py
Normal file
3
glc-python-client/glogcenter/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from .glc import debug, info, warn, error, GlcData
|
||||
|
||||
__all__ = ['debug', 'info', 'warn', 'error', 'GlcData']
|
8
glc-python-client/glogcenter/__version__.py
Normal file
8
glc-python-client/glogcenter/__version__.py
Normal file
@@ -0,0 +1,8 @@
|
||||
# 8b d8 Yb dP 88""Yb db dP""b8 88 dP db dP""b8 888888
|
||||
# 88b d88 YbdP 88__dP dPYb dP `" 88odP dPYb dP `" 88__
|
||||
# 88YbdP88 8P 88""" dP__Yb Yb 88"Yb dP__Yb Yb "88 88""
|
||||
# 88 YY 88 dP 88 dP""""Yb YboodP 88 Yb dP""""Yb YboodP 888888
|
||||
|
||||
VERSION = (5, 2, 0)
|
||||
|
||||
__version__ = '.'.join(map(str, VERSION))
|
149
glc-python-client/glogcenter/glc.py
Normal file
149
glc-python-client/glogcenter/glc.py
Normal file
@@ -0,0 +1,149 @@
|
||||
import os
|
||||
import json
|
||||
import datetime
|
||||
import requests
|
||||
import platform
|
||||
import socket
|
||||
import netifaces
|
||||
from decimal import Decimal
|
||||
import random
|
||||
import sys
|
||||
|
||||
|
||||
cached_ip = None
|
||||
server_name = None
|
||||
|
||||
def get_server_name():
|
||||
global server_name
|
||||
if server_name is None:
|
||||
server_name = platform.node()
|
||||
return server_name
|
||||
|
||||
def get_intranet_ip():
|
||||
global cached_ip
|
||||
|
||||
if cached_ip is None:
|
||||
interfaces = netifaces.interfaces()
|
||||
ip_addresses = []
|
||||
|
||||
for interface in interfaces:
|
||||
addresses = netifaces.ifaddresses(interface).get(socket.AF_INET)
|
||||
if addresses:
|
||||
for address in addresses:
|
||||
ip = address['addr']
|
||||
if ip.startswith('192.') or ip.startswith('172.') or ip.startswith('10.'):
|
||||
ip_addresses.append(ip)
|
||||
|
||||
# 对IP地址列表按照特定优先级排序(192优先)
|
||||
sorted_ips = sorted(ip_addresses, key=lambda x: (x.startswith('192.'), x.startswith('172.'), x.startswith('10.')))
|
||||
if sorted_ips:
|
||||
cached_ip = sorted_ips[0]
|
||||
else:
|
||||
cached_ip = '127.0.0.1'
|
||||
|
||||
return cached_ip
|
||||
|
||||
def hash_string(input_str = ''):
|
||||
rs = 53653
|
||||
i = len(input_str) if input_str is not None else 0
|
||||
while i > 0:
|
||||
rs = (rs * 33) ^ ord(input_str[i - 1])
|
||||
i -= 1
|
||||
return str(Decimal(rs & 0xFFFFFFFF).to_eng_string())
|
||||
|
||||
# yyyy-MM-dd HH:mm:ss.SSS
|
||||
def get_current_time():
|
||||
current_time = datetime.datetime.now()
|
||||
return current_time.strftime('%Y-%m-%d %H:%M:%S.') + str(1000 + current_time.microsecond % 1000)[-3:]
|
||||
|
||||
class GlcData:
|
||||
def __init__(self, logLevel = ''):
|
||||
self.text = ''
|
||||
self.date = get_current_time()
|
||||
self.system = os.getenv('GLC_SYSTEM')
|
||||
self.serverName = get_server_name()
|
||||
self.serverIp = get_intranet_ip()
|
||||
self.clientIp = ''
|
||||
self.traceId = os.getenv('GLC_TRACE_ID')
|
||||
self.user = ''
|
||||
|
||||
|
||||
def post_glc_data(glc_data, logLevel):
|
||||
if not glc_data:
|
||||
return
|
||||
|
||||
url = os.getenv('GLC_API_URL')
|
||||
if url is None:
|
||||
# 不发日志中心就打印日志,否则不打印
|
||||
print(get_current_time(), logLevel, glc_data.text)
|
||||
return
|
||||
|
||||
data = {
|
||||
'text': glc_data.text,
|
||||
'date': glc_data.date,
|
||||
'system': glc_data.system,
|
||||
'servername': glc_data.serverName,
|
||||
'serverip': glc_data.serverIp,
|
||||
'clientip': glc_data.clientIp,
|
||||
'traceid': glc_data.traceId,
|
||||
'loglevel': logLevel,
|
||||
'user': glc_data.user
|
||||
}
|
||||
json_data = json.dumps(data)
|
||||
|
||||
headers = {'Content-Type': 'application/json', 'X-GLC-AUTH': 'glogcenter'}
|
||||
if os.getenv('GLC_API_KEY') is not None:
|
||||
headers['X-GLC-AUTH'] = os.getenv('GLC_API_KEY')
|
||||
|
||||
requests.post(url, data=json_data, headers=headers)
|
||||
|
||||
|
||||
def argsToGlcData(*args):
|
||||
text = ''
|
||||
glc_data = None
|
||||
|
||||
# 将非空且非GlcData实例的参数转换为字符串并拼接
|
||||
for arg in args:
|
||||
if arg is not None and not isinstance(arg, GlcData):
|
||||
text += ' ' + str(arg)
|
||||
text = text.strip()
|
||||
|
||||
# 无内容时返回空
|
||||
if text == '':
|
||||
return None
|
||||
|
||||
# 处理GlcData实例参数
|
||||
glc_args = [arg for arg in args if isinstance(arg, GlcData)]
|
||||
|
||||
if glc_args:
|
||||
# 如果有GlcData实例参数,取出最后一个作为glc_data
|
||||
glc_data = glc_args[-1]
|
||||
else:
|
||||
# 如果没有GlcData实例参数,新建一个GlcdData实例
|
||||
glc_data = GlcData()
|
||||
|
||||
# 将第一步得到的text赋值给glc_data的text属性
|
||||
glc_data.text = text
|
||||
|
||||
# 相应字段为空时设定默认值
|
||||
if glc_data.system == '':
|
||||
glc_data.system = 'default'
|
||||
if glc_data.traceId == '':
|
||||
glc_data.traceId = hash_string(str(random.randint(10000, sys.maxsize)))
|
||||
|
||||
return glc_data
|
||||
|
||||
|
||||
def debug(*args):
|
||||
post_glc_data(argsToGlcData(*args), 'DEBUG')
|
||||
|
||||
def info(*args):
|
||||
post_glc_data(argsToGlcData(*args), 'INFO')
|
||||
|
||||
def warn(*args):
|
||||
post_glc_data(argsToGlcData(*args), 'WARN')
|
||||
|
||||
def error(*args):
|
||||
post_glc_data(argsToGlcData(*args), 'ERROR')
|
||||
|
||||
|
131
glc-python-client/setup.py
Normal file
131
glc-python-client/setup.py
Normal file
@@ -0,0 +1,131 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Note: To use the 'upload' functionality of this file, you must:
|
||||
# $ pipenv install twine --dev
|
||||
|
||||
import io
|
||||
import os
|
||||
import sys
|
||||
from shutil import rmtree
|
||||
|
||||
from setuptools import find_packages, setup, Command
|
||||
|
||||
# Package meta-data.
|
||||
NAME = 'glogcenter'
|
||||
DESCRIPTION = 'glogcenter 的 python 版客户端'
|
||||
URL = 'https://github.com/gotoeasy/glogcenter'
|
||||
EMAIL = 'gotoeasy@163.com'
|
||||
AUTHOR = 'gotoeasy'
|
||||
REQUIRES_PYTHON = '>=3.6.0'
|
||||
VERSION = '0.1.8'
|
||||
|
||||
# What packages are required for this module to be executed?
|
||||
REQUIRED = [
|
||||
'requests', 'netifaces'
|
||||
]
|
||||
|
||||
# What packages are optional?
|
||||
EXTRAS = {
|
||||
# 'fancy feature': ['django'],
|
||||
}
|
||||
|
||||
# The rest you shouldn't have to touch too much :)
|
||||
# ------------------------------------------------
|
||||
# Except, perhaps the License and Trove Classifiers!
|
||||
# If you do change the License, remember to change the Trove Classifier for that!
|
||||
|
||||
here = os.path.abspath(os.path.dirname(__file__))
|
||||
|
||||
# Import the README and use it as the long-description.
|
||||
# Note: this will only work if 'README.md' is present in your MANIFEST.in file!
|
||||
try:
|
||||
with io.open(os.path.join(here, 'README.md'), encoding='utf-8') as f:
|
||||
long_description = '\n' + f.read()
|
||||
except FileNotFoundError:
|
||||
long_description = DESCRIPTION
|
||||
|
||||
# Load the package's __version__.py module as a dictionary.
|
||||
about = {}
|
||||
if not VERSION:
|
||||
project_slug = NAME.lower().replace("-", "_").replace(" ", "_")
|
||||
with open(os.path.join(here, project_slug, '__version__.py')) as f:
|
||||
exec(f.read(), about)
|
||||
else:
|
||||
about['__version__'] = VERSION
|
||||
|
||||
|
||||
class UploadCommand(Command):
|
||||
"""Support setup.py upload."""
|
||||
|
||||
description = 'Build and publish the package.'
|
||||
user_options = []
|
||||
|
||||
@staticmethod
|
||||
def status(s):
|
||||
"""Prints things in bold."""
|
||||
print('\033[1m{0}\033[0m'.format(s))
|
||||
|
||||
def initialize_options(self):
|
||||
pass
|
||||
|
||||
def finalize_options(self):
|
||||
pass
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
self.status('Removing previous builds…')
|
||||
rmtree(os.path.join(here, 'dist'))
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
self.status('Building Source and Wheel (universal) distribution…')
|
||||
os.system('{0} setup.py sdist bdist_wheel --universal'.format(sys.executable))
|
||||
|
||||
self.status('Uploading the package to PyPI via Twine…')
|
||||
os.system('twine upload dist/*')
|
||||
|
||||
self.status('Pushing git tags…')
|
||||
os.system('git tag v{0}'.format(about['__version__']))
|
||||
os.system('git push --tags')
|
||||
|
||||
sys.exit()
|
||||
|
||||
|
||||
# Where the magic happens:
|
||||
setup(
|
||||
name=NAME,
|
||||
version=about['__version__'],
|
||||
description=DESCRIPTION,
|
||||
long_description=long_description,
|
||||
long_description_content_type='text/markdown',
|
||||
author=AUTHOR,
|
||||
author_email=EMAIL,
|
||||
python_requires=REQUIRES_PYTHON,
|
||||
url=URL,
|
||||
packages=find_packages(exclude=["tests", "*.tests", "*.tests.*", "tests.*"]),
|
||||
# If your package is a single module, use this instead of 'packages':
|
||||
# py_modules=['mypackage'],
|
||||
|
||||
# entry_points={
|
||||
# 'console_scripts': ['mycli=mymodule:cli'],
|
||||
# },
|
||||
install_requires=REQUIRED,
|
||||
extras_require=EXTRAS,
|
||||
include_package_data=True,
|
||||
license='MIT',
|
||||
classifiers=[
|
||||
# Trove classifiers
|
||||
# Full list: https://pypi.python.org/pypi?%3Aaction=list_classifiers
|
||||
'License :: OSI Approved :: MIT License',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: Implementation :: CPython',
|
||||
'Programming Language :: Python :: Implementation :: PyPy'
|
||||
],
|
||||
# $ setup.py publish support.
|
||||
cmdclass={
|
||||
'upload': UploadCommand,
|
||||
},
|
||||
)
|
Reference in New Issue
Block a user