pytbox 0.0.2__tar.gz → 0.0.3__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.

Files changed (38) hide show
  1. {pytbox-0.0.2 → pytbox-0.0.3}/PKG-INFO +1 -1
  2. {pytbox-0.0.2 → pytbox-0.0.3}/pyproject.toml +1 -1
  3. pytbox-0.0.3/src/pytbox/alert/alert_handler.py +119 -0
  4. pytbox-0.0.3/src/pytbox/alert/ping.py +25 -0
  5. {pytbox-0.0.2 → pytbox-0.0.3}/src/pytbox/alicloud/sls.py +0 -8
  6. pytbox-0.0.3/src/pytbox/base.py +41 -0
  7. pytbox-0.0.3/src/pytbox/database/mongo.py +58 -0
  8. pytbox-0.0.3/src/pytbox/database/victoriametrics.py +77 -0
  9. {pytbox-0.0.2 → pytbox-0.0.3}/src/pytbox/dida365.py +11 -17
  10. pytbox-0.0.3/src/pytbox/utils/load_config.py +86 -0
  11. pytbox-0.0.3/src/pytbox/utils/ping_checker.py +1 -0
  12. {pytbox-0.0.2 → pytbox-0.0.3}/src/pytbox/utils/response.py +1 -1
  13. {pytbox-0.0.2 → pytbox-0.0.3}/src/pytbox/utils/timeutils.py +14 -1
  14. {pytbox-0.0.2 → pytbox-0.0.3}/src/pytbox.egg-info/PKG-INFO +1 -1
  15. {pytbox-0.0.2 → pytbox-0.0.3}/src/pytbox.egg-info/SOURCES.txt +9 -3
  16. pytbox-0.0.2/src/pytbox/victoriametrics.py +0 -37
  17. {pytbox-0.0.2 → pytbox-0.0.3}/README.md +0 -0
  18. {pytbox-0.0.2 → pytbox-0.0.3}/setup.cfg +0 -0
  19. {pytbox-0.0.2 → pytbox-0.0.3}/src/pytbox/common/__init__.py +0 -0
  20. {pytbox-0.0.2 → pytbox-0.0.3}/src/pytbox/common/base.py +0 -0
  21. {pytbox-0.0.2 → pytbox-0.0.3}/src/pytbox/feishu/client.py +0 -0
  22. {pytbox-0.0.2 → pytbox-0.0.3}/src/pytbox/feishu/endpoints.py +0 -0
  23. {pytbox-0.0.2 → pytbox-0.0.3}/src/pytbox/feishu/errors.py +0 -0
  24. {pytbox-0.0.2 → pytbox-0.0.3}/src/pytbox/feishu/helpers.py +0 -0
  25. {pytbox-0.0.2 → pytbox-0.0.3}/src/pytbox/feishu/typing.py +0 -0
  26. {pytbox-0.0.2/src/pytbox → pytbox-0.0.3/src/pytbox/log}/logger.py +0 -0
  27. {pytbox-0.0.2/src/pytbox → pytbox-0.0.3/src/pytbox/log}/victorialog.py +0 -0
  28. {pytbox-0.0.2 → pytbox-0.0.3}/src/pytbox/onepassword_connect.py +0 -0
  29. {pytbox-0.0.2 → pytbox-0.0.3}/src/pytbox/onepassword_sa.py +0 -0
  30. {pytbox-0.0.2 → pytbox-0.0.3}/src/pytbox/utils/env.py +0 -0
  31. {pytbox-0.0.2 → pytbox-0.0.3}/src/pytbox.egg-info/dependency_links.txt +0 -0
  32. {pytbox-0.0.2 → pytbox-0.0.3}/src/pytbox.egg-info/requires.txt +0 -0
  33. {pytbox-0.0.2 → pytbox-0.0.3}/src/pytbox.egg-info/top_level.txt +0 -0
  34. {pytbox-0.0.2 → pytbox-0.0.3}/tests/test_feishu.py +0 -0
  35. {pytbox-0.0.2 → pytbox-0.0.3}/tests/test_logger.py +0 -0
  36. {pytbox-0.0.2 → pytbox-0.0.3}/tests/test_onepassword_connect.py +0 -0
  37. {pytbox-0.0.2 → pytbox-0.0.3}/tests/test_onepassword_sa.py +0 -0
  38. {pytbox-0.0.2 → pytbox-0.0.3}/tests/test_victoriametrics.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pytbox
3
- Version: 0.0.2
3
+ Version: 0.0.3
4
4
  Summary: A collection of Python integrations and utilities (Feishu, Dida365, VictoriaMetrics, ...)
5
5
  Author-email: mingming hou <houm01@foxmail.com>
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "pytbox"
7
- version = "0.0.2"
7
+ version = "0.0.3"
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 = { text = "MIT" }
@@ -0,0 +1,119 @@
1
+ #!/usr/bin/env python3
2
+
3
+
4
+ import uuid
5
+ from typing import Literal
6
+ from ..database.mongo import Mongo
7
+ from ..base import MongoClient
8
+ from ..feishu.client import Client as FeishuClient
9
+ from ..dida365 import Dida365
10
+ from ..utils.timeutils import TimeUtils
11
+
12
+
13
+ class AlertHandler:
14
+
15
+ def __init__(self,
16
+ config: dict=None,
17
+ mongo_client: Mongo=MongoClient(collection='alert'),
18
+ feishu_client: FeishuClient=None,
19
+ dida_client: Dida365=None
20
+ ):
21
+ self.config = config
22
+ self.mongo = mongo_client
23
+ self.feishu = feishu_client
24
+ self.dida = dida_client
25
+
26
+ def send_alert(self,
27
+ event_id: str=None,
28
+ event_type: Literal['trigger', 'resolved'] ='trigger',
29
+ event_time: str=None,
30
+ event_name: str=None,
31
+ event_content: str=None,
32
+ entity_name: str=None,
33
+ priority: Literal['critical', 'high', 'warning']='high',
34
+ resolved_expr: str=None,
35
+ suggestion: str='',
36
+ troubleshot: str='暂无',
37
+ mongo_id: str=None
38
+ ):
39
+
40
+ if not event_id:
41
+ event_id = str(uuid.uuid4())
42
+ if not event_time:
43
+ event_time = TimeUtils.get_now_time_mongo()
44
+
45
+ if self.mongo.check_alarm_exist(event_type=event_type, event_content=event_content):
46
+ if event_type == "trigger":
47
+ self.mongo.collection.insert_one(
48
+ {
49
+ 'event_id': event_id,
50
+ 'event_type': event_type,
51
+ 'event_name': event_name,
52
+ 'event_time': event_time,
53
+ 'event_content': event_content,
54
+ 'entity_name': entity_name,
55
+ 'priority': priority,
56
+ 'resolved_expr': resolved_expr,
57
+ 'suggestion': suggestion,
58
+ 'troubleshot': troubleshot,
59
+ }
60
+ )
61
+ elif event_type == "resolved":
62
+ filter_doc = {"_id": mongo_id}
63
+ update = {"$set": { "resolved_time": event_time}}
64
+ self.mongo.collection.update_one(filter_doc, update)
65
+ alarm_time = self.mongo.collection.find_one(filter_doc, {'event_time': 1})['event_time']
66
+
67
+ content = [
68
+ f'**事件名称**: {event_name}',
69
+ f'**告警时间**: {TimeUtils.convert_timeobj_to_str(timeobj=event_time, timezone_offset=0) if event_type == "trigger" else TimeUtils.convert_timeobj_to_str(timeobj=alarm_time, timezone_offset=8)}',
70
+ f'**事件内容**: {event_content}',
71
+ f'**告警实例**: {entity_name}',
72
+ f'**建议**: {suggestion}',
73
+ f'**故障排查**: {troubleshot}'
74
+ ]
75
+
76
+ if event_type == "resolved":
77
+ content.insert(2, f'**恢复时间**: {TimeUtils.convert_timeobj_to_str(event_time, timezone_offset=0)}')
78
+
79
+ if self.config['feishu']['enable_alert']:
80
+ self.feishu.extensions.send_message_notify(
81
+ color='red' if event_type == "trigger" else 'green',
82
+ title=event_content,
83
+ priority=priority,
84
+ sub_title="",
85
+ content='\n'.join(content)
86
+ )
87
+
88
+ if self.config['dida']['enable_alert']:
89
+ if event_type == "trigger":
90
+ res = self.dida.task_create(
91
+
92
+ project_id=self.config['dida']['alert_project_id'],
93
+ title=event_content,
94
+ content='\n'.join(content),
95
+ tags=['L-监控告警', priority]
96
+ )
97
+ dida_task_id = res.data.get("id")
98
+ self.mongo.collection.update_one(
99
+ {
100
+ "event_id": event_id
101
+ },
102
+ {
103
+ "$set": {
104
+ "dida_task_id": dida_task_id
105
+ }
106
+ }
107
+ )
108
+ else:
109
+ task_id = self.mongo.collection.find_one(filter_doc, {'dida_task_id': 1})['dida_task_id']
110
+ self.dida.task_update(
111
+ task_id=task_id,
112
+ project_id=self.config['dida']['alert_project_id'],
113
+ content=f'\n**恢复时间**: {TimeUtils.convert_timeobj_to_str(timeobj=event_time, timezone_offset=0)}'
114
+ )
115
+ self.dida.task_complete(task_id=task_id, project_id=self.config['dida']['alert_project_id'])
116
+
117
+
118
+ if self.config['wecom']['enable']:
119
+ pass
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env python3
2
+
3
+
4
+ from ..database.victoriametrics import VictoriaMetrics
5
+ from ..lib.load_config import load_config
6
+
7
+
8
+ def ping(config, target):
9
+ vm = VictoriaMetrics(url=config['victoriametrics']['url'])
10
+ ping_status = vm.query_ping_status(target=target, last_minutes=config['alert']['ping']['last_minutes'])
11
+ if ping_status == '不通':
12
+ insert_alert(
13
+ event_name=config['alert']['ping']['event_name'],
14
+ event_content=f"{target} {config['alert']['ping']['event_name']}",
15
+ entity_name=target,
16
+ priority=config['alert']['ping']['priority'],
17
+ resolved_query={
18
+ "target": target
19
+ }
20
+ )
21
+
22
+
23
+ if __name__ == "__main__":
24
+ config = load_config()
25
+ ping(config, "10.30.35.38")
@@ -20,14 +20,6 @@ class AliCloudSls:
20
20
  self.logstore = logstore
21
21
 
22
22
  def get_logs(self, project_name, logstore_name, query, from_time, to_time):
23
- # Project名称。
24
- # project_name = "sh-prod-network-devices-log"
25
- # Logstore名称
26
- # logstore_name = "sh-prod-network-devices-log"
27
- # 查询语句。
28
- # query = "*| select dev,id from " + logstore_name
29
- # query = "*"
30
- # 索引。
31
23
  logstore_index = {'line': {
32
24
  'token': [',', ' ', "'", '"', ';', '=', '(', ')', '[', ']', '{', '}', '?', '@', '&', '<', '>', '/', ':', '\n', '\t',
33
25
  '\r'], 'caseSensitive': False, 'chn': False}, 'keys': {'dev': {'type': 'text',
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env python3
2
+
3
+
4
+ from pytbox.database.mongo import Mongo
5
+ from pytbox.utils.load_config import load_config_by_file
6
+ from pytbox.database.victoriametrics import VictoriaMetrics
7
+ from pytbox.feishu.client import Client as FeishuClient
8
+ from pytbox.dida365 import Dida365
9
+
10
+
11
+ def MongoClient(collection, config_path='/workspaces/pytbox/tests/alert/config_dev.toml', oc_vault_id=None):
12
+ config = load_config_by_file(path=config_path, oc_vault_id=oc_vault_id)
13
+ return Mongo(
14
+ host=config['mongo']['host'],
15
+ port=config['mongo']['port'],
16
+ username=config['mongo']['username'],
17
+ password=config['mongo']['password'],
18
+ auto_source=config['mongo']['auto_source'],
19
+ db_name=config['mongo']['db_name'],
20
+ collection=collection
21
+ )
22
+
23
+ def vm_client(config_path='/workspaces/pytbox/tests/alert/config_dev.toml', oc_vault_id=None):
24
+ config = load_config_by_file(path=config_path, oc_vault_id=oc_vault_id)
25
+ return VictoriaMetrics(
26
+ url=config['victoriametrics']['url']
27
+ )
28
+
29
+ def feishu_client(config_path='/workspaces/pytbox/tests/alert/config_dev.toml', oc_vault_id=None):
30
+ config = load_config_by_file(path=config_path, oc_vault_id=oc_vault_id)
31
+ return FeishuClient(
32
+ app_id=config['feishu']['app_id'],
33
+ app_secret=config['feishu']['app_secret']
34
+ )
35
+
36
+ def dida_client(config_path='/workspaces/pytbox/tests/alert/config_dev.toml', oc_vault_id=None):
37
+ config = load_config_by_file(path=config_path, oc_vault_id=oc_vault_id)
38
+ return Dida365(
39
+ cookie=config['dida']['cookie'],
40
+ access_token=config['dida']['access_token']
41
+ )
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env python3
2
+
3
+ import pymongo
4
+
5
+
6
+ class Mongo:
7
+ '''
8
+ 当前主要使用的类
9
+ '''
10
+ def __init__(self, host, port, username, password, auto_source, db_name: str='automate', collection: str=None):
11
+ self.client = self._create_client(host, port, username, password, auto_source)
12
+ self.collection = self.client[db_name][collection]
13
+
14
+ def _create_client(self, host, port, username, password, auto_source):
15
+ '''
16
+ 创建客户端
17
+ '''
18
+ return pymongo.MongoClient(host=host,
19
+ port=port,
20
+ username=username,
21
+ password=password,
22
+ authSource=auto_source)
23
+
24
+
25
+ def check_alarm_exist(self, event_type, event_content) -> bool:
26
+ '''
27
+ _summary_
28
+
29
+ Args:
30
+ event_content (_type_): 告警内容
31
+
32
+ Returns:
33
+ bool: 如果为 True, 表示允许插入告警
34
+ '''
35
+ if event_type == 'trigger':
36
+ query = { "event_content": event_content }
37
+ fields = {"event_name": 1, "event_time": 1, "resolved_time": 1}
38
+ result = self.collection.find(query, fields).sort({ "_id": pymongo.DESCENDING }).limit(1)
39
+ if self.collection.count_documents(query) == 0:
40
+ return True
41
+ else:
42
+ for doc in result:
43
+ if 'resolved_time' in doc:
44
+ # 当前没有告警, 可以插入数据
45
+ return True
46
+ elif event_type == 'resolved':
47
+ return True
48
+
49
+ def query_alert_not_resolved(self, event_name: str=None):
50
+ query = {
51
+ "$or": [
52
+ {"resolved_time": { "$exists": False }}
53
+ ]
54
+ }
55
+ if event_name:
56
+ query['event_name'] = event_name
57
+ return self.collection.find(query)
58
+
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env python3
2
+
3
+ import requests
4
+ from ..utils.response import ReturnResponse
5
+
6
+
7
+ class VictoriaMetrics:
8
+
9
+ def __init__(self, url: str='', timeout: int=3) -> None:
10
+ self.url = url
11
+ self.timeout = timeout
12
+ self.session = requests.Session()
13
+ self.session.headers.update({
14
+ 'Content-Type': 'application/json',
15
+ 'Accept': 'application/json'
16
+ })
17
+
18
+ def query(self, query: str) -> ReturnResponse:
19
+ '''
20
+ 查询指标数据
21
+
22
+ Args:
23
+ query (str): 查询语句
24
+
25
+ Returns:
26
+ dict: 查询结果
27
+ '''
28
+ url = f"{self.url}/prometheus/api/v1/query"
29
+ r = requests.get(
30
+ url,
31
+ timeout=self.timeout,
32
+ params={"query": query}
33
+ )
34
+ if r.json().get("status") == "success":
35
+ if r.json()['data']['result']:
36
+ return ReturnResponse(code=0, msg=f"[{query}] 查询成功!", data=r.json()['data']['result'])
37
+ else:
38
+ return ReturnResponse(code=2, msg=f"[{query}] 没有查询到结果", data=r.json())
39
+ else:
40
+ return ReturnResponse(code=1, msg=f"[{query}] 查询失败: {r.json().get('error')}", data=r.json())
41
+
42
+ def check_ping_result(self, target: str, last_minute: int=10) -> ReturnResponse:
43
+ '''
44
+ 检查ping结果
45
+ '''
46
+ if target:
47
+ # 这里需要在字符串中保留 {},同时插入 target,可以用双大括号转义
48
+ query = f"ping_result_code{{target='{target}'}}"
49
+ else:
50
+ query = "ping_result_code"
51
+
52
+ if last_minute:
53
+ query = query + f"[{last_minute}m]"
54
+
55
+ r = self.query(query=query)
56
+ if r.code == 0:
57
+ values = r.data[0]['values']
58
+ if len(values) == 2 and values[1] == "0":
59
+ code = 0
60
+ msg = f"已检查 {target} 最近 {last_minute} 分钟是正常的!"
61
+ else:
62
+ if all(str(item[1]) == "1" for item in values):
63
+ code = 2
64
+ msg = f"已检查 {target} 最近 {last_minute} 分钟是异常的!"
65
+ else:
66
+ code = 0
67
+ msg = f"已检查 {target} 最近 {last_minute} 分钟是正常的!"
68
+ elif r.code == 2:
69
+ code = 2
70
+ msg = f"没有查询到 {target} 最近 {last_minute} 分钟的ping结果!"
71
+
72
+ try:
73
+ data = r.data[0]
74
+ except KeyError:
75
+ data = r.data
76
+
77
+ return ReturnResponse(code=code, msg=msg, data=data)
@@ -28,14 +28,8 @@ class Task:
28
28
  completed_time: str
29
29
  assignee: int
30
30
 
31
- @dataclass
32
- class DidaResponse:
33
- code: int
34
- message: str
35
- data: dict
36
-
37
31
 
38
- class ProcessDidaResponse:
32
+ class ProcessReturnResponse:
39
33
  @staticmethod
40
34
  def status(status):
41
35
  if status == 0:
@@ -89,7 +83,7 @@ class Dida365:
89
83
  }
90
84
  self.timeout = 10
91
85
 
92
- def request(self, api_url: str=None, method: str='GET', payload: dict={}):
86
+ def request(self, api_url: str=None, method: str='GET', payload: dict={}) -> ReturnResponse:
93
87
  """发送请求。
94
88
 
95
89
  Args:
@@ -108,14 +102,14 @@ class Dida365:
108
102
 
109
103
  if response.status_code == 200:
110
104
  if 'complete' in api_url:
111
- return DidaResponse(code=0, msg='success', data=None)
105
+ return ReturnResponse(code=0, msg='success', data=None)
112
106
  else:
113
107
  try:
114
- return DidaResponse(code=0, msg='success', data=response.json())
115
- except Exception as e:
116
- return DidaResponse(code=1, msg='warning', data=response)
108
+ return ReturnResponse(code=0, msg='success', data=response.json())
109
+ except Exception:
110
+ return ReturnResponse(code=1, msg='warning', data=response)
117
111
  else:
118
- return DidaResponse(code=1, msg='error', data=response.json())
112
+ return ReturnResponse(code=1, msg='error', data=response.json())
119
113
 
120
114
  def task_list(self, project_id: str, enhancement: bool=True):
121
115
  """获取任务列表。
@@ -142,8 +136,8 @@ class Dida365:
142
136
  desc=task.get('desc'),
143
137
  start_date=task.get('startDate'),
144
138
  due_date=task.get('dueDate'),
145
- priority=ProcessDidaResponse.priority(task.get('priority')),
146
- status=ProcessDidaResponse.status(task.get('status')),
139
+ priority=ProcessReturnResponse.priority(task.get('priority')),
140
+ status=ProcessReturnResponse.status(task.get('status')),
147
141
  tags=task.get('tags'),
148
142
  completed_time=task.get('completedTime'),
149
143
  assignee=task.get('assignee'))
@@ -157,8 +151,8 @@ class Dida365:
157
151
  desc=task.get('desc'),
158
152
  start_date=task.get('startDate'),
159
153
  due_date=task.get('dueDate'),
160
- priority=ProcessDidaResponse.priority(task.get('priority')),
161
- status=ProcessDidaResponse.status(task.get('status')),
154
+ priority=ProcessReturnResponse.priority(task.get('priority')),
155
+ status=ProcessReturnResponse.status(task.get('status')),
162
156
  tags=task.get('tags'),
163
157
  completed_time=task.get('completedTime'),
164
158
  assignee=task.get('assignee'))
@@ -0,0 +1,86 @@
1
+ #!/usr/bin/env python3
2
+
3
+
4
+ try:
5
+ import toml
6
+ except ImportError:
7
+ import tomllib as toml # Python 3.11+ fallback
8
+ from pytbox.onepassword_connect import OnePasswordConnect
9
+
10
+
11
+ def _replace_1password_values(data, oc):
12
+ """
13
+ 递归处理配置数据,替换 1password 和 password 开头的值
14
+
15
+ Args:
16
+ data: 配置数据(dict, list, str 等)
17
+ oc: OnePasswordConnect 实例
18
+
19
+ Returns:
20
+ 处理后的数据
21
+ """
22
+ if isinstance(data, dict):
23
+ result = {}
24
+ for k, v in data.items():
25
+ result[k] = _replace_1password_values(v, oc)
26
+ return result
27
+ elif isinstance(data, list):
28
+ return [_replace_1password_values(item, oc) for item in data]
29
+ elif isinstance(data, str):
30
+ # 处理 1password,item_id,field_name 格式
31
+ if data.startswith("1password,"):
32
+ parts = data.split(",")
33
+ if len(parts) >= 3:
34
+ item_id = parts[1]
35
+ field_name = parts[2]
36
+ # 通过 item_id 获取项目,然后从字段中提取对应值
37
+ item = oc.get_item(item_id)
38
+ for field in item.fields:
39
+ if field.label == field_name:
40
+ return field.value
41
+ return data # 如果找不到字段,返回原始值
42
+ # 处理 password,item_id,field_name 格式
43
+ elif data.startswith("password,"):
44
+ parts = data.split(",")
45
+ if len(parts) >= 3:
46
+ item_id = parts[1]
47
+ field_name = parts[2]
48
+ # 通过 item_id 获取项目,然后从字段中提取对应值
49
+ item = oc.get_item(item_id)
50
+ for field in item.fields:
51
+ if field.label == field_name:
52
+ return field.value
53
+ return data # 如果找不到字段,返回原始值
54
+ return data
55
+ else:
56
+ return data
57
+
58
+
59
+ def load_config_by_file(path: str='/workspaces/pytbox/src/pytbox/alert/config/config.toml', oc_vault_id: str=None) -> dict:
60
+ '''
61
+ 从文件加载配置,支持 1password 集成
62
+
63
+ Args:
64
+ path (str, optional): 配置文件路径. Defaults to '/workspaces/pytbox/src/pytbox/alert/config/config.toml'.
65
+ oc_vault_id (str, optional): OnePassword vault ID,如果提供则启用 1password 集成
66
+
67
+ Returns:
68
+ dict: 配置字典
69
+ '''
70
+ with open(path, 'r', encoding='utf-8') as f:
71
+ if path.endswith('.toml'):
72
+ config = toml.load(f)
73
+ else:
74
+ # 如果不是 toml 文件,假设是其他格式,这里可以扩展
75
+ import json
76
+ config = json.load(f)
77
+
78
+ if oc_vault_id:
79
+ oc = OnePasswordConnect(vault_id=oc_vault_id)
80
+ config = _replace_1password_values(config, oc)
81
+
82
+ return config
83
+
84
+
85
+ if __name__ == "__main__":
86
+ print(load_config_by_file(path='/workspaces/pytbox/tests/alert/config_dev.toml', oc_vault_id="hcls5uxuq5dmxorw6rfewefdsa"))
@@ -21,7 +21,7 @@ class ReturnResponse:
21
21
  8 - 服务不可用 (SERVICE_UNAVAILABLE)
22
22
  9 - 数据库错误 (DATABASE_ERROR)
23
23
  10 - 网络错误 (NETWORK_ERROR)
24
- message: 响应消息描述
24
+ msg: 响应消息描述
25
25
  data: 响应数据,可以是任意类型
26
26
  """
27
27
  code: int = 0
@@ -4,6 +4,7 @@
4
4
  import time
5
5
  import pytz
6
6
  import datetime
7
+ from typing import Literal
7
8
 
8
9
 
9
10
  class TimeUtils:
@@ -37,4 +38,16 @@ class TimeUtils:
37
38
 
38
39
  @staticmethod
39
40
  def get_utc_time():
40
- return datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3] + "Z"
41
+ return datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3] + "Z"
42
+
43
+ @staticmethod
44
+ def get_now_time_mongo():
45
+ return datetime.datetime.now(pytz.timezone('Asia/Shanghai'))
46
+
47
+ @staticmethod
48
+ def convert_timeobj_to_str(timeobj: str=None, timezone_offset: int=8, time_format: Literal['%Y-%m-%d %H:%M:%S', '%Y-%m-%dT%H:%M:%SZ']='%Y-%m-%d %H:%M:%S'):
49
+ time_obj_with_offset = timeobj + datetime.timedelta(hours=timezone_offset)
50
+ if time_format == '%Y-%m-%d %H:%M:%S':
51
+ return time_obj_with_offset.strftime("%Y-%m-%d %H:%M:%S")
52
+ elif time_format == '%Y-%m-%dT%H:%M:%SZ':
53
+ return time_obj_with_offset.strftime("%Y-%m-%dT%H:%M:%SZ")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pytbox
3
- Version: 0.0.2
3
+ Version: 0.0.3
4
4
  Summary: A collection of Python integrations and utilities (Feishu, Dida365, VictoriaMetrics, ...)
5
5
  Author-email: mingming hou <houm01@foxmail.com>
6
6
  License: MIT
@@ -1,25 +1,31 @@
1
1
  README.md
2
2
  pyproject.toml
3
+ src/pytbox/base.py
3
4
  src/pytbox/dida365.py
4
- src/pytbox/logger.py
5
5
  src/pytbox/onepassword_connect.py
6
6
  src/pytbox/onepassword_sa.py
7
- src/pytbox/victorialog.py
8
- src/pytbox/victoriametrics.py
9
7
  src/pytbox.egg-info/PKG-INFO
10
8
  src/pytbox.egg-info/SOURCES.txt
11
9
  src/pytbox.egg-info/dependency_links.txt
12
10
  src/pytbox.egg-info/requires.txt
13
11
  src/pytbox.egg-info/top_level.txt
12
+ src/pytbox/alert/alert_handler.py
13
+ src/pytbox/alert/ping.py
14
14
  src/pytbox/alicloud/sls.py
15
15
  src/pytbox/common/__init__.py
16
16
  src/pytbox/common/base.py
17
+ src/pytbox/database/mongo.py
18
+ src/pytbox/database/victoriametrics.py
17
19
  src/pytbox/feishu/client.py
18
20
  src/pytbox/feishu/endpoints.py
19
21
  src/pytbox/feishu/errors.py
20
22
  src/pytbox/feishu/helpers.py
21
23
  src/pytbox/feishu/typing.py
24
+ src/pytbox/log/logger.py
25
+ src/pytbox/log/victorialog.py
22
26
  src/pytbox/utils/env.py
27
+ src/pytbox/utils/load_config.py
28
+ src/pytbox/utils/ping_checker.py
23
29
  src/pytbox/utils/response.py
24
30
  src/pytbox/utils/timeutils.py
25
31
  tests/test_feishu.py
@@ -1,37 +0,0 @@
1
- #!/usr/bin/env python3
2
-
3
- import requests
4
- from .utils.response import ReturnResponse
5
-
6
-
7
- class VictoriaMetrics:
8
-
9
- def __init__(self, url: str='', timeout: int=3) -> None:
10
- self.url = url
11
- self.timeout = timeout
12
- self.session = requests.Session()
13
- self.session.headers.update({
14
- 'Content-Type': 'application/json',
15
- 'Accept': 'application/json'
16
- })
17
-
18
- def query(self, query: str) -> ReturnResponse:
19
- '''
20
- 查询指标数据
21
-
22
- Args:
23
- query (str): 查询语句
24
-
25
- Returns:
26
- dict: 查询结果
27
- '''
28
- url = f"{self.url}/prometheus/api/v1/query"
29
- r = requests.get(
30
- url,
31
- timeout=self.timeout,
32
- params={"query": query}
33
- )
34
- if r.json().get("status") == "success":
35
- return ReturnResponse(code=0, msg=f"[{query}] 查询成功!", data=r.json()['data']['result'])
36
- else:
37
- return ReturnResponse(code=1, msg=f"[{query}] 查询失败: {r.json().get('error')}", data=r.json())
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes