pytbox 0.1.4__tar.gz → 0.1.6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pytbox might be problematic. Click here for more details.
- {pytbox-0.1.4/src/pytbox.egg-info → pytbox-0.1.6}/PKG-INFO +1 -1
- {pytbox-0.1.4 → pytbox-0.1.6}/pyproject.toml +1 -1
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/alicloud/sls.py +9 -6
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/base.py +25 -1
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/database/victoriametrics.py +71 -4
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/log/logger.py +22 -6
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/mail/alimail.py +55 -42
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/utils/timeutils.py +5 -2
- {pytbox-0.1.4 → pytbox-0.1.6/src/pytbox.egg-info}/PKG-INFO +1 -1
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox.egg-info/SOURCES.txt +1 -0
- pytbox-0.1.6/tests/test_load_jsonfile.py +14 -0
- pytbox-0.1.6/tests/test_logger.py +20 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/tests/test_victoriametrics.py +6 -1
- pytbox-0.1.4/tests/test_logger.py +0 -15
- {pytbox-0.1.4 → pytbox-0.1.6}/MANIFEST.in +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/README.md +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/setup.cfg +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/alert/alert_handler.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/alert/ping.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/build_config.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/instances.toml +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/__init__.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.cpu/cpu.toml.j2 +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.disk/disk.toml.j2 +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.diskio/diskio.toml.j2 +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.dns_query/dns_query.toml.j2 +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.http_response/http_response.toml.j2 +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.mem/mem.toml.j2 +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.net/net.toml.j2 +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.net_response/net_response.toml.j2 +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.ping/ping.toml.j2 +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.prometheus/prometheus.toml.j2 +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.snmp/cisco_interface.toml.j2 +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.snmp/cisco_system.toml.j2 +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.snmp/h3c_interface.toml.j2 +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.snmp/h3c_system.toml.j2 +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.snmp/huawei_interface.toml.j2 +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.snmp/huawei_system.toml.j2 +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.snmp/ruijie_interface.toml.j2 +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.snmp/ruijie_system.toml.j2 +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.vsphere/vsphere.toml.j2 +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/cli/__init__.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/cli/categraf/__init__.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/cli/categraf/commands.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/cli/commands/vm.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/cli/common/__init__.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/cli/common/options.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/cli/common/utils.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/cli/formatters/__init__.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/cli/formatters/output.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/cli/main.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/cli.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/common/__init__.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/database/mongo.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/dida365.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/excel.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/feishu/client.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/feishu/endpoints.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/feishu/errors.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/feishu/helpers.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/feishu/typing.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/log/victorialog.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/mail/client.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/mail/mail_detail.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/network/meraki.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/onepassword_connect.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/onepassword_sa.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/pyjira.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/utils/env.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/utils/load_config.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/utils/load_vm_devfile.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/utils/ping_checker.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/utils/response.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/utils/richutils.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/vmware.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/win/ad.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox.egg-info/dependency_links.txt +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox.egg-info/entry_points.txt +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox.egg-info/requires.txt +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox.egg-info/top_level.txt +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/tests/test_base.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/tests/test_feishu.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/tests/test_onepassword_connect.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/tests/test_onepassword_sa.py +0 -0
- {pytbox-0.1.4 → pytbox-0.1.6}/tests/test_vmware.py +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "pytbox"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.6"
|
|
8
8
|
description = "A collection of Python integrations and utilities (Feishu, Dida365, VictoriaMetrics, ...)"
|
|
9
9
|
authors = [{ name = "mingming hou", email = "houm01@foxmail.com" }]
|
|
10
10
|
license = "MIT"
|
|
@@ -5,19 +5,21 @@ from typing import Literal
|
|
|
5
5
|
from aliyun.log import GetLogsRequest, LogItem, PutLogsRequest
|
|
6
6
|
from aliyun.log import LogClient as SlsLogClient
|
|
7
7
|
from aliyun.log.auth import AUTH_VERSION_4
|
|
8
|
-
from ..utils.env import check_env
|
|
9
8
|
|
|
10
9
|
|
|
11
10
|
|
|
12
11
|
class AliCloudSls:
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
'''
|
|
13
|
+
pip install -U aliyun-log-python-sdk
|
|
14
|
+
'''
|
|
15
|
+
def __init__(self, access_key_id: str=None, access_key_secret: str=None, project: str=None, logstore: str=None, env: str='prod'):
|
|
15
16
|
# 日志服务的服务接入点
|
|
16
17
|
self.endpoint = "cn-shanghai.log.aliyuncs.com"
|
|
17
18
|
# 创建 LogClient 实例,使用 V4 签名,根据实际情况填写 region,这里以杭州为例
|
|
18
19
|
self.client = SlsLogClient(self.endpoint, access_key_id, access_key_secret, auth_version=AUTH_VERSION_4, region='cn-shanghai')
|
|
19
20
|
self.project = project
|
|
20
21
|
self.logstore = logstore
|
|
22
|
+
self.env = env
|
|
21
23
|
|
|
22
24
|
def get_logs(self, project_name, logstore_name, query, from_time, to_time):
|
|
23
25
|
logstore_index = {'line': {
|
|
@@ -57,7 +59,7 @@ class AliCloudSls:
|
|
|
57
59
|
log_group = []
|
|
58
60
|
log_item = LogItem()
|
|
59
61
|
contents = [
|
|
60
|
-
('env',
|
|
62
|
+
('env', self.env),
|
|
61
63
|
('level', level),
|
|
62
64
|
('app', app),
|
|
63
65
|
('msg', msg),
|
|
@@ -69,8 +71,9 @@ class AliCloudSls:
|
|
|
69
71
|
log_item.set_contents(contents)
|
|
70
72
|
log_group.append(log_item)
|
|
71
73
|
request = PutLogsRequest(self.project, self.logstore, topic, "", log_group, compress=False)
|
|
72
|
-
self.client.put_logs(request)
|
|
73
|
-
|
|
74
|
+
r = self.client.put_logs(request)
|
|
75
|
+
return r
|
|
76
|
+
|
|
74
77
|
def put_logs_for_meraki(self, alert):
|
|
75
78
|
log_group = []
|
|
76
79
|
log_item = LogItem()
|
|
@@ -14,6 +14,9 @@ from pytbox.utils.env import get_env_by_os_environment
|
|
|
14
14
|
from pytbox.vmware import VMwareClient
|
|
15
15
|
from pytbox.pyjira import PyJira
|
|
16
16
|
from pytbox.mail.client import MailClient
|
|
17
|
+
from pytbox.mail.alimail import AliMail
|
|
18
|
+
from pytbox.alicloud.sls import AliCloudSls
|
|
19
|
+
|
|
17
20
|
|
|
18
21
|
config = load_config_by_file(path='/workspaces/pytbox/tests/alert/config_dev.toml', oc_vault_id=os.environ.get('oc_vault_id'))
|
|
19
22
|
|
|
@@ -52,6 +55,19 @@ def get_logger(app):
|
|
|
52
55
|
mongo=get_mongo('alert_program')
|
|
53
56
|
)
|
|
54
57
|
|
|
58
|
+
def get_logger_sls(app):
|
|
59
|
+
return AppLogger(
|
|
60
|
+
app_name=app,
|
|
61
|
+
enable_sls=True,
|
|
62
|
+
feishu=feishu,
|
|
63
|
+
dida=dida,
|
|
64
|
+
mongo=get_mongo('alert_program'),
|
|
65
|
+
sls_access_key_id=config['alicloud']['account1']['access_key_id'],
|
|
66
|
+
sls_access_key_secret=config['alicloud']['account1']['access_key_secret'],
|
|
67
|
+
sls_project=config['alicloud']['account1']['project'],
|
|
68
|
+
sls_logstore=config['alicloud']['account1']['logstore']
|
|
69
|
+
)
|
|
70
|
+
|
|
55
71
|
# ad_dev = ADClient(
|
|
56
72
|
# server=config['ad']['dev']['AD_SERVER'],
|
|
57
73
|
# base_dn=config['ad']['dev']['BASE_DN'],
|
|
@@ -83,4 +99,12 @@ pyjira = PyJira(
|
|
|
83
99
|
)
|
|
84
100
|
|
|
85
101
|
mail_163 = MailClient(mail_address=config['mail']['163']['mail_address'], password=config['mail']['163']['password'])
|
|
86
|
-
mail_qq = MailClient(mail_address=config['mail']['qq']['mail_address'], password=config['mail']['qq']['password'])
|
|
102
|
+
mail_qq = MailClient(mail_address=config['mail']['qq']['mail_address'], password=config['mail']['qq']['password'])
|
|
103
|
+
ali_mail = AliMail(mail_address=config['mail']['aliyun']['mail_address'], client_id=config['mail']['aliyun']['client_id'], client_secret=config['mail']['aliyun']['client_secret'])
|
|
104
|
+
|
|
105
|
+
sls = AliCloudSls(
|
|
106
|
+
access_key_id=config['alicloud']['account1']['access_key_id'],
|
|
107
|
+
access_key_secret=config['alicloud']['account1']['access_key_secret'],
|
|
108
|
+
project=config['alicloud']['account1']['project'],
|
|
109
|
+
logstore=config['alicloud']['account1']['logstore']
|
|
110
|
+
)
|
|
@@ -18,7 +18,7 @@ class VictoriaMetrics:
|
|
|
18
18
|
'Accept': 'application/json'
|
|
19
19
|
})
|
|
20
20
|
|
|
21
|
-
def query(self, query: str, output_format: Literal['json']=None) -> ReturnResponse:
|
|
21
|
+
def query(self, query: str=None, output_format: Literal['json']=None) -> ReturnResponse:
|
|
22
22
|
'''
|
|
23
23
|
查询指标数据
|
|
24
24
|
|
|
@@ -61,6 +61,52 @@ class VictoriaMetrics:
|
|
|
61
61
|
else:
|
|
62
62
|
return resp
|
|
63
63
|
|
|
64
|
+
def query_range(self, query):
|
|
65
|
+
'''
|
|
66
|
+
查询指标数据
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
query (str): 查询语句
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
dict: 查询结果
|
|
73
|
+
'''
|
|
74
|
+
url = f"{self.url}/prometheus/api/v1/query_range"
|
|
75
|
+
|
|
76
|
+
data = {
|
|
77
|
+
'query': query,
|
|
78
|
+
'start': '-1d',
|
|
79
|
+
'step': '1h'
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
r = requests.post(url, data=data, timeout=self.timeout)
|
|
83
|
+
res_json = r.json()
|
|
84
|
+
print(res_json)
|
|
85
|
+
# status = res_json.get("status")
|
|
86
|
+
# result = res_json.get("data", {}).get("result", [])
|
|
87
|
+
# is_json = output_format == 'json'
|
|
88
|
+
|
|
89
|
+
# if status == "success":
|
|
90
|
+
# if result:
|
|
91
|
+
# code = 0
|
|
92
|
+
# msg = f"[{query}] 查询成功!"
|
|
93
|
+
# data = result
|
|
94
|
+
# else:
|
|
95
|
+
# code = 2
|
|
96
|
+
# msg = f"[{query}] 没有查询到结果"
|
|
97
|
+
# data = res_json
|
|
98
|
+
# else:
|
|
99
|
+
# code = 1
|
|
100
|
+
# msg = f"[{query}] 查询失败: {res_json.get('error')}"
|
|
101
|
+
# data = res_json
|
|
102
|
+
|
|
103
|
+
# resp = ReturnResponse(code=code, msg=msg, data=data)
|
|
104
|
+
|
|
105
|
+
# if is_json:
|
|
106
|
+
# json_result = json.dumps(resp.__dict__, ensure_ascii=False)
|
|
107
|
+
# return json_result
|
|
108
|
+
# else:
|
|
109
|
+
# return resp
|
|
64
110
|
def get_labels(self, metric_name: str) -> ReturnResponse:
|
|
65
111
|
url = f"{self.url}/api/v1/series?match[]={metric_name}"
|
|
66
112
|
response = requests.get(url, timeout=self.timeout)
|
|
@@ -104,7 +150,6 @@ class VictoriaMetrics:
|
|
|
104
150
|
code = 0
|
|
105
151
|
msg = f"已检查 {target} 最近 {last_minute} 分钟是正常的!"
|
|
106
152
|
else:
|
|
107
|
-
|
|
108
153
|
if all(str(item[1]) == "1" for item in values):
|
|
109
154
|
code = 1
|
|
110
155
|
msg = f"已检查 {target} 最近 {last_minute} 分钟是异常的!"
|
|
@@ -114,7 +159,6 @@ class VictoriaMetrics:
|
|
|
114
159
|
elif r.code == 2:
|
|
115
160
|
code = 2
|
|
116
161
|
msg = f"没有查询到 {target} 最近 {last_minute} 分钟的ping结果!"
|
|
117
|
-
|
|
118
162
|
try:
|
|
119
163
|
data = r.data[0]
|
|
120
164
|
except KeyError:
|
|
@@ -146,4 +190,27 @@ class VictoriaMetrics:
|
|
|
146
190
|
query = f'(rate(snmp_interface_ifHCOutOctets{{sysName="{sysName}", ifName="{ifName}"}}[{last_minutes}m])) * 8 / 1000000'
|
|
147
191
|
r = self.query(query)
|
|
148
192
|
rate = r.data[0]['value'][1]
|
|
149
|
-
return int(float(rate))
|
|
193
|
+
return int(float(rate))
|
|
194
|
+
|
|
195
|
+
def check_snmp_port_status(self, sysname: str=None, if_name: str=None, last_minute: int=5) -> ReturnResponse:
|
|
196
|
+
'''
|
|
197
|
+
查询端口状态
|
|
198
|
+
status code 可参考 SNMP 文件 https://mibbrowser.online/mibdb_search.php?mib=IF-MIB
|
|
199
|
+
|
|
200
|
+
Args:
|
|
201
|
+
sysname (_type_): 设备名称
|
|
202
|
+
if_name (_type_): _description_
|
|
203
|
+
last_minute (_type_): _description_
|
|
204
|
+
|
|
205
|
+
Returns:
|
|
206
|
+
ReturnResponse:
|
|
207
|
+
code: 0, msg: , data: up,down
|
|
208
|
+
'''
|
|
209
|
+
q = f"""avg_over_time(snmp_interface_ifOperStatus{{sysName="{sysname}", ifName="{if_name}"}}[{last_minute}m])"""
|
|
210
|
+
r = self.query(query=q)
|
|
211
|
+
status_code = r.data[0]['value'][1]
|
|
212
|
+
if status_code == 1:
|
|
213
|
+
status = 'up'
|
|
214
|
+
else:
|
|
215
|
+
status = 'down'
|
|
216
|
+
return ReturnResponse(code=0, msg=f"{sysname} {if_name} 最近 {last_minute} 分钟端口状态为 {status}", data=status)
|
|
@@ -9,7 +9,7 @@ from ..database.mongo import Mongo
|
|
|
9
9
|
from ..feishu.client import Client as FeishuClient
|
|
10
10
|
from ..utils.timeutils import TimeUtils
|
|
11
11
|
from ..dida365 import Dida365
|
|
12
|
-
|
|
12
|
+
from ..alicloud.sls import AliCloudSls
|
|
13
13
|
|
|
14
14
|
logger.remove()
|
|
15
15
|
logger.add(sys.stdout, colorize=True, format="<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | <level>{level: <8}</level> | <level>{message}</level>")
|
|
@@ -31,7 +31,6 @@ class AppLogger:
|
|
|
31
31
|
feishu: FeishuClient=None,
|
|
32
32
|
dida: Dida365=None,
|
|
33
33
|
enable_sls: bool=False,
|
|
34
|
-
sls_url: str=None,
|
|
35
34
|
sls_access_key_id: str=None,
|
|
36
35
|
sls_access_key_secret: str=None,
|
|
37
36
|
sls_project: str=None,
|
|
@@ -49,10 +48,17 @@ class AppLogger:
|
|
|
49
48
|
self.stream = stream
|
|
50
49
|
self.victorialog = Victorialog(url=victorialog_url)
|
|
51
50
|
self.enable_victorialog = enable_victorialog
|
|
51
|
+
self.enable_sls = enable_sls
|
|
52
52
|
self.mongo = mongo
|
|
53
53
|
self.feishu = feishu
|
|
54
54
|
self.dida = dida
|
|
55
|
-
|
|
55
|
+
self.sls = AliCloudSls(
|
|
56
|
+
access_key_id=sls_access_key_id,
|
|
57
|
+
access_key_secret=sls_access_key_secret,
|
|
58
|
+
project=sls_project,
|
|
59
|
+
logstore=sls_logstore
|
|
60
|
+
)
|
|
61
|
+
|
|
56
62
|
def _get_caller_info(self) -> tuple[str, int, str]:
|
|
57
63
|
"""
|
|
58
64
|
获取调用者信息
|
|
@@ -78,6 +84,9 @@ class AppLogger:
|
|
|
78
84
|
logger.debug(f"[{caller_filename}:{caller_lineno}:{caller_function}] {message}")
|
|
79
85
|
if self.enable_victorialog:
|
|
80
86
|
self.victorialog.send_program_log(stream=self.stream, level="DEBUG", message=message, app_name=self.app_name, file_name=call_full_filename, line_number=caller_lineno, function_name=caller_function)
|
|
87
|
+
if self.enable_sls:
|
|
88
|
+
self.sls.put_logs(level="DEBUG", msg=message, app=self.app_name, caller_filename=caller_filename, caller_lineno=caller_lineno, caller_function=caller_function, call_full_filename=call_full_filename)
|
|
89
|
+
|
|
81
90
|
|
|
82
91
|
def info(self, message: str='', feishu_notify: bool=False):
|
|
83
92
|
"""记录信息级别日志"""
|
|
@@ -85,22 +94,28 @@ class AppLogger:
|
|
|
85
94
|
logger.info(f"[{caller_filename}:{caller_lineno}:{caller_function}] {message}")
|
|
86
95
|
if self.enable_victorialog:
|
|
87
96
|
r = self.victorialog.send_program_log(stream=self.stream, level="INFO", message=message, app_name=self.app_name, file_name=call_full_filename, line_number=caller_lineno, function_name=caller_function)
|
|
97
|
+
if self.enable_sls:
|
|
98
|
+
self.sls.put_logs(level="INFO", msg=message, app=self.app_name, caller_filename=caller_filename, caller_lineno=caller_lineno, caller_function=caller_function, call_full_filename=call_full_filename)
|
|
88
99
|
if feishu_notify:
|
|
89
100
|
self.feishu(message)
|
|
90
|
-
|
|
101
|
+
|
|
91
102
|
def warning(self, message: str):
|
|
92
103
|
"""记录警告级别日志"""
|
|
93
104
|
caller_filename, caller_lineno, caller_function, call_full_filename = self._get_caller_info()
|
|
94
105
|
logger.warning(f"[{caller_filename}:{caller_lineno}:{caller_function}] {message}")
|
|
95
106
|
if self.enable_victorialog:
|
|
96
107
|
self.victorialog.send_program_log(stream=self.stream, level="WARN", message=message, app_name=self.app_name, file_name=call_full_filename, line_number=caller_lineno, function_name=caller_function)
|
|
97
|
-
|
|
108
|
+
if self.enable_sls:
|
|
109
|
+
self.sls.put_logs(level="WARN", msg=message, app=self.app_name, caller_filename=caller_filename, caller_lineno=caller_lineno, caller_function=caller_function, call_full_filename=call_full_filename)
|
|
110
|
+
|
|
98
111
|
def error(self, message: str):
|
|
99
112
|
"""记录错误级别日志"""
|
|
100
113
|
caller_filename, caller_lineno, caller_function, call_full_filename = self._get_caller_info()
|
|
101
114
|
logger.error(f"[{caller_filename}:{caller_lineno}:{caller_function}] {message}")
|
|
102
115
|
if self.enable_victorialog:
|
|
103
116
|
self.victorialog.send_program_log(stream=self.stream, level="ERROR", message=message, app_name=self.app_name, file_name=call_full_filename, line_number=caller_lineno, function_name=caller_function)
|
|
117
|
+
if self.enable_sls:
|
|
118
|
+
self.sls.put_logs(level="ERROR", msg=message, app=self.app_name, caller_filename=caller_filename, caller_lineno=caller_lineno, caller_function=caller_function, call_full_filename=call_full_filename)
|
|
104
119
|
|
|
105
120
|
if self.feishu:
|
|
106
121
|
existing_message = self.mongo.collection.find_one({"message": message}, sort=[("time", -1)])
|
|
@@ -150,7 +165,8 @@ class AppLogger:
|
|
|
150
165
|
logger.critical(f"[{caller_filename}:{caller_lineno}:{caller_function}] {message}")
|
|
151
166
|
if self.enable_victorialog:
|
|
152
167
|
self.victorialog.send_program_log(stream=self.stream, level="CRITICAL", message=message, app_name=self.app_name, file_name=call_full_filename, line_number=caller_lineno, function_name=caller_function)
|
|
153
|
-
|
|
168
|
+
if self.enable_sls:
|
|
169
|
+
self.sls.put_logs(level="CRITICAL", msg=message, app=self.app_name, caller_filename=caller_filename, caller_lineno=caller_lineno, caller_function=caller_function, call_full_filename=call_full_filename)
|
|
154
170
|
|
|
155
171
|
# 使用示例
|
|
156
172
|
if __name__ == "__main__":
|
|
@@ -4,32 +4,29 @@ from typing import Literal
|
|
|
4
4
|
from datetime import datetime, timedelta
|
|
5
5
|
|
|
6
6
|
import requests
|
|
7
|
+
from ..utils.response import ReturnResponse
|
|
8
|
+
from .mail_detail import MailDetail
|
|
9
|
+
from ..utils.timeutils import TimeUtils
|
|
7
10
|
|
|
8
11
|
|
|
9
12
|
|
|
10
13
|
class AliMail:
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
self.
|
|
14
|
+
'''
|
|
15
|
+
_summary_
|
|
16
|
+
'''
|
|
17
|
+
def __init__(self, mail_address: str=None, client_id: str=None, client_secret: str=None, timeout: int=3):
|
|
18
|
+
self.email_address = mail_address
|
|
19
|
+
self.client_id = client_id
|
|
20
|
+
self.client_secret = client_secret
|
|
16
21
|
self.base_url = "https://alimail-cn.aliyuncs.com/v2"
|
|
22
|
+
self.timeout = timeout
|
|
17
23
|
self.headers = {
|
|
18
24
|
"Content-Type": "application/json",
|
|
19
|
-
"Authorization": f"bearer {self.
|
|
25
|
+
"Authorization": f"bearer {self._get_access_token_by_request()}"
|
|
20
26
|
}
|
|
27
|
+
self.session = requests.Session()
|
|
28
|
+
self.session.headers.update(self.headers)
|
|
21
29
|
|
|
22
|
-
def _get_access_token(self):
|
|
23
|
-
current_time = datetime.now()
|
|
24
|
-
# stored_token = mongo_alimail_token.find_one({"token_type": "bearer"})
|
|
25
|
-
if stored_token and stored_token.get('expiration_time'):
|
|
26
|
-
expiration_time = stored_token['expiration_time']
|
|
27
|
-
if current_time < expiration_time:
|
|
28
|
-
return stored_token['access_token']
|
|
29
|
-
else:
|
|
30
|
-
return self._get_access_token_by_request()
|
|
31
|
-
else:
|
|
32
|
-
return self._get_access_token_by_request()
|
|
33
30
|
|
|
34
31
|
def _get_access_token_by_request(self):
|
|
35
32
|
'''
|
|
@@ -52,7 +49,7 @@ class AliMail:
|
|
|
52
49
|
"client_secret": self.client_secret
|
|
53
50
|
}
|
|
54
51
|
try:
|
|
55
|
-
response = requests.post(interface_url, headers=headers, data=data, timeout=
|
|
52
|
+
response = requests.post(interface_url, headers=headers, data=data, timeout=self.timeout)
|
|
56
53
|
response_json = response.json()
|
|
57
54
|
current_time = datetime.now()
|
|
58
55
|
data = {
|
|
@@ -61,28 +58,23 @@ class AliMail:
|
|
|
61
58
|
'expires_in': response_json["expires_in"],
|
|
62
59
|
'expiration_time': current_time + timedelta(seconds=response_json["expires_in"])
|
|
63
60
|
}
|
|
64
|
-
mongo_alimail_token.update_one(
|
|
65
|
-
{"token_type": "bearer"},
|
|
66
|
-
{"$set": data},
|
|
67
|
-
upsert=True
|
|
68
|
-
)
|
|
69
61
|
return data.get("access_token")
|
|
70
62
|
except requests.RequestException as e:
|
|
71
63
|
# 处理请求失败异常
|
|
72
|
-
|
|
64
|
+
raise e
|
|
73
65
|
except (KeyError, ValueError) as e:
|
|
74
66
|
# 处理解析响应失败异常
|
|
75
|
-
|
|
67
|
+
raise e
|
|
76
68
|
|
|
77
|
-
def
|
|
78
|
-
response =
|
|
69
|
+
def get_mail_folders(self):
|
|
70
|
+
response = self.session.get(
|
|
79
71
|
url=f"{self.base_url}/users/{self.email_address}/mailFolders",
|
|
80
72
|
headers=self.headers
|
|
81
73
|
)
|
|
82
74
|
return response.json().get('folders')
|
|
83
75
|
|
|
84
|
-
def
|
|
85
|
-
folders = self.
|
|
76
|
+
def get_folder_id(self, folder_name: Literal['inbox']='inbox'):
|
|
77
|
+
folders = self.get_mail_folders()
|
|
86
78
|
for folder in folders:
|
|
87
79
|
if folder.get('displayName') == folder_name:
|
|
88
80
|
return folder.get('id')
|
|
@@ -92,7 +84,7 @@ class AliMail:
|
|
|
92
84
|
params = {
|
|
93
85
|
"$select": "body,toRecipients,internetMessageId,internetMessageHeaders"
|
|
94
86
|
}
|
|
95
|
-
response =
|
|
87
|
+
response = self.session.get(
|
|
96
88
|
url=f"{self.base_url}/users/{self.email_address}/messages/{mail_id}",
|
|
97
89
|
headers=self.headers,
|
|
98
90
|
params=params,
|
|
@@ -100,30 +92,51 @@ class AliMail:
|
|
|
100
92
|
)
|
|
101
93
|
return response.json().get('message')
|
|
102
94
|
|
|
103
|
-
def
|
|
104
|
-
folder_id = self.
|
|
95
|
+
def get_mail_list(self, folder_name: str='inbox', size: int=100):
|
|
96
|
+
folder_id = self.get_folder_id(folder_name=folder_name)
|
|
105
97
|
params = {
|
|
106
98
|
"size": size,
|
|
107
99
|
# "$select": "toRecipients"
|
|
108
100
|
}
|
|
109
|
-
response =
|
|
101
|
+
response = self.session.get(
|
|
110
102
|
url=f"{self.base_url}/users/{self.email_address}/mailFolders/{folder_id}/messages",
|
|
111
103
|
headers=self.headers,
|
|
112
104
|
params=params,
|
|
113
105
|
timeout=3
|
|
114
106
|
)
|
|
115
107
|
messages = response.json().get("messages")
|
|
108
|
+
sent_to_list = []
|
|
116
109
|
for message in messages:
|
|
117
110
|
mail_id = message.get("id")
|
|
118
111
|
detail = self.get_mail_detail(mail_id=mail_id)
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
112
|
+
|
|
113
|
+
for to_recipient in detail.get('toRecipients'):
|
|
114
|
+
sent_to_list.append(to_recipient.get('email'))
|
|
115
|
+
|
|
116
|
+
yield MailDetail(
|
|
117
|
+
uid=message.get('id'),
|
|
118
|
+
sent_from=message.get('from').get('email'),
|
|
119
|
+
sent_to=sent_to_list,
|
|
120
|
+
date=TimeUtils.convert_str_to_datetime(time_str=message.get('sentDateTime'), app='alimail'),
|
|
121
|
+
cc="",
|
|
122
|
+
subject=message.get('subject'),
|
|
123
|
+
body_plain=message.get('summary'),
|
|
124
|
+
body_html=""
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
def move(self, uid: str, destination_folder: str) -> ReturnResponse:
|
|
128
|
+
params = {
|
|
129
|
+
"ids": [uid],
|
|
130
|
+
"destinationFolderId": self.get_folder_id(destination_folder)
|
|
131
|
+
}
|
|
132
|
+
r = self.session.post(
|
|
133
|
+
url=f"{self.base_url}/users/{self.email_address}/messages/move",
|
|
134
|
+
params=params
|
|
135
|
+
)
|
|
136
|
+
if r.status_code == 200:
|
|
137
|
+
return ReturnResponse(code=0, msg=f'邮件移动到 {destination_folder} 成功', data=None)
|
|
138
|
+
else:
|
|
139
|
+
return ReturnResponse(code=1, msg=f'邮件移动到 {destination_folder} 失败', data=r.json())
|
|
122
140
|
|
|
123
141
|
if __name__ == '__main__':
|
|
124
|
-
ali_mail = AliMail()
|
|
125
|
-
# print(ali_mail.query_folder_id())
|
|
126
|
-
# for i in ali_mail.list_mail(size=1):
|
|
127
|
-
# print(i)
|
|
128
|
-
# print(ali_mail.access_token)
|
|
129
|
-
print(ali_mail.get_mail_detail(mail_id='DzzzzzzMeuY'))
|
|
142
|
+
ali_mail = AliMail()
|
|
@@ -287,7 +287,7 @@ class TimeUtils:
|
|
|
287
287
|
return int(time.time()) * 1000
|
|
288
288
|
|
|
289
289
|
@staticmethod
|
|
290
|
-
def convert_str_to_datetime(time_str: str, app: Literal['lg_alert_trigger', 'lg_alert_resolved', 'mongo']='lg_alert_trigger') -> datetime.datetime:
|
|
290
|
+
def convert_str_to_datetime(time_str: str, app: Literal['lg_alert_trigger', 'lg_alert_resolved', 'mongo', 'alimail']='lg_alert_trigger') -> datetime.datetime:
|
|
291
291
|
"""
|
|
292
292
|
将字符串转换为datetime对象
|
|
293
293
|
|
|
@@ -305,7 +305,10 @@ class TimeUtils:
|
|
|
305
305
|
elif app == 'mongo':
|
|
306
306
|
time_obj = datetime.datetime.fromisoformat(time_str.replace('Z', '+00:00'))
|
|
307
307
|
return time_obj # 已经包含时区信息,直接返回
|
|
308
|
-
|
|
308
|
+
elif app == 'alimail':
|
|
309
|
+
time_obj = datetime.datetime.strptime(time_str, "%Y-%m-%dT%H:%M:%SZ")
|
|
310
|
+
time_obj = time_obj + datetime.timedelta(hours=8)
|
|
311
|
+
# return time_obj
|
|
309
312
|
# 对于没有时区信息的时间对象,设置为Asia/Shanghai时区
|
|
310
313
|
time_with_tz = time_obj.replace(tzinfo=ZoneInfo("Asia/Shanghai"))
|
|
311
314
|
return time_with_tz
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
from pytbox.utils.load_config import load_config_by_file
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
config = load_config_by_file(
|
|
8
|
+
path='/workspaces/pytbox/tests/alert/config_dev.toml',
|
|
9
|
+
# oc_vault_id="hcls5uxuq5dmxorw6rfewefdsa"
|
|
10
|
+
jsonfile="test_load_config.json"
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
print(config['json_test'])
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
from pytbox.base import get_logger_sls, get_logger
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
log = get_logger('tests.test_logger')
|
|
7
|
+
log_sls = get_logger_sls(app="tests.test_logger")
|
|
8
|
+
|
|
9
|
+
def test_logger_info():
|
|
10
|
+
log.info('test_logger_info')
|
|
11
|
+
log.error('test error log2')
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_logger_sls():
|
|
15
|
+
log_sls.debug('test_logger_sls')
|
|
16
|
+
# log.error('test error log2')
|
|
17
|
+
|
|
18
|
+
if __name__ == "__main__":
|
|
19
|
+
# test_logger_info()
|
|
20
|
+
test_logger_sls()
|
|
@@ -16,7 +16,12 @@ def test_get_labels():
|
|
|
16
16
|
r = vm.get_labels('ping_average_response_ms')
|
|
17
17
|
print(r)
|
|
18
18
|
|
|
19
|
+
def test_check_snmp_port_status():
|
|
20
|
+
r = vm.check_snmp_port_status(sysname="shylf-prod-coresw-ce6820-182", if_name="10GE1/0/47", last_minute=10)
|
|
21
|
+
print(r)
|
|
22
|
+
|
|
19
23
|
if __name__ == "__main__":
|
|
20
24
|
# test_get_labels()
|
|
21
25
|
# test_query()
|
|
22
|
-
test_check_ping_result()
|
|
26
|
+
# test_check_ping_result()
|
|
27
|
+
test_check_snmp_port_status()
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
|
|
3
|
-
from pytbox.base import get_logger
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
log = get_logger('tests.test_logger')
|
|
8
|
-
|
|
9
|
-
def test_logger_info():
|
|
10
|
-
log.info('test_logger_info')
|
|
11
|
-
log.error('test error log2')
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
if __name__ == "__main__":
|
|
15
|
-
test_logger_info()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.http_response/http_response.toml.j2
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.net_response/net_response.toml.j2
RENAMED
|
File without changes
|
|
File without changes
|
{pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.prometheus/prometheus.toml.j2
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.snmp/huawei_interface.toml.j2
RENAMED
|
File without changes
|
|
File without changes
|
{pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.snmp/ruijie_interface.toml.j2
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|