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.

Files changed (85) hide show
  1. {pytbox-0.1.4/src/pytbox.egg-info → pytbox-0.1.6}/PKG-INFO +1 -1
  2. {pytbox-0.1.4 → pytbox-0.1.6}/pyproject.toml +1 -1
  3. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/alicloud/sls.py +9 -6
  4. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/base.py +25 -1
  5. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/database/victoriametrics.py +71 -4
  6. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/log/logger.py +22 -6
  7. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/mail/alimail.py +55 -42
  8. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/utils/timeutils.py +5 -2
  9. {pytbox-0.1.4 → pytbox-0.1.6/src/pytbox.egg-info}/PKG-INFO +1 -1
  10. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox.egg-info/SOURCES.txt +1 -0
  11. pytbox-0.1.6/tests/test_load_jsonfile.py +14 -0
  12. pytbox-0.1.6/tests/test_logger.py +20 -0
  13. {pytbox-0.1.4 → pytbox-0.1.6}/tests/test_victoriametrics.py +6 -1
  14. pytbox-0.1.4/tests/test_logger.py +0 -15
  15. {pytbox-0.1.4 → pytbox-0.1.6}/MANIFEST.in +0 -0
  16. {pytbox-0.1.4 → pytbox-0.1.6}/README.md +0 -0
  17. {pytbox-0.1.4 → pytbox-0.1.6}/setup.cfg +0 -0
  18. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/alert/alert_handler.py +0 -0
  19. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/alert/ping.py +0 -0
  20. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/build_config.py +0 -0
  21. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/instances.toml +0 -0
  22. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/__init__.py +0 -0
  23. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.cpu/cpu.toml.j2 +0 -0
  24. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.disk/disk.toml.j2 +0 -0
  25. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.diskio/diskio.toml.j2 +0 -0
  26. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.dns_query/dns_query.toml.j2 +0 -0
  27. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.http_response/http_response.toml.j2 +0 -0
  28. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.mem/mem.toml.j2 +0 -0
  29. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.net/net.toml.j2 +0 -0
  30. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.net_response/net_response.toml.j2 +0 -0
  31. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.ping/ping.toml.j2 +0 -0
  32. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.prometheus/prometheus.toml.j2 +0 -0
  33. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.snmp/cisco_interface.toml.j2 +0 -0
  34. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.snmp/cisco_system.toml.j2 +0 -0
  35. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.snmp/h3c_interface.toml.j2 +0 -0
  36. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.snmp/h3c_system.toml.j2 +0 -0
  37. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.snmp/huawei_interface.toml.j2 +0 -0
  38. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.snmp/huawei_system.toml.j2 +0 -0
  39. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.snmp/ruijie_interface.toml.j2 +0 -0
  40. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.snmp/ruijie_system.toml.j2 +0 -0
  41. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/categraf/jinja2/input.vsphere/vsphere.toml.j2 +0 -0
  42. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/cli/__init__.py +0 -0
  43. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/cli/categraf/__init__.py +0 -0
  44. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/cli/categraf/commands.py +0 -0
  45. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/cli/commands/vm.py +0 -0
  46. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/cli/common/__init__.py +0 -0
  47. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/cli/common/options.py +0 -0
  48. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/cli/common/utils.py +0 -0
  49. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/cli/formatters/__init__.py +0 -0
  50. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/cli/formatters/output.py +0 -0
  51. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/cli/main.py +0 -0
  52. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/cli.py +0 -0
  53. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/common/__init__.py +0 -0
  54. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/database/mongo.py +0 -0
  55. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/dida365.py +0 -0
  56. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/excel.py +0 -0
  57. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/feishu/client.py +0 -0
  58. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/feishu/endpoints.py +0 -0
  59. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/feishu/errors.py +0 -0
  60. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/feishu/helpers.py +0 -0
  61. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/feishu/typing.py +0 -0
  62. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/log/victorialog.py +0 -0
  63. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/mail/client.py +0 -0
  64. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/mail/mail_detail.py +0 -0
  65. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/network/meraki.py +0 -0
  66. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/onepassword_connect.py +0 -0
  67. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/onepassword_sa.py +0 -0
  68. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/pyjira.py +0 -0
  69. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/utils/env.py +0 -0
  70. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/utils/load_config.py +0 -0
  71. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/utils/load_vm_devfile.py +0 -0
  72. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/utils/ping_checker.py +0 -0
  73. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/utils/response.py +0 -0
  74. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/utils/richutils.py +0 -0
  75. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/vmware.py +0 -0
  76. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox/win/ad.py +0 -0
  77. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox.egg-info/dependency_links.txt +0 -0
  78. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox.egg-info/entry_points.txt +0 -0
  79. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox.egg-info/requires.txt +0 -0
  80. {pytbox-0.1.4 → pytbox-0.1.6}/src/pytbox.egg-info/top_level.txt +0 -0
  81. {pytbox-0.1.4 → pytbox-0.1.6}/tests/test_base.py +0 -0
  82. {pytbox-0.1.4 → pytbox-0.1.6}/tests/test_feishu.py +0 -0
  83. {pytbox-0.1.4 → pytbox-0.1.6}/tests/test_onepassword_connect.py +0 -0
  84. {pytbox-0.1.4 → pytbox-0.1.6}/tests/test_onepassword_sa.py +0 -0
  85. {pytbox-0.1.4 → pytbox-0.1.6}/tests/test_vmware.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pytbox
3
- Version: 0.1.4
3
+ Version: 0.1.6
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-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "pytbox"
7
- version = "0.1.4"
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
- def __init__(self, access_key_id: str=None, access_key_secret: str=None, project: str, logstore: str):
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', check_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
- def __init__(self, email_address: str=None, client_id: str=None, client_secret: str=None):
12
-
13
- self.email_address = email_address
14
- self.client_id = auth['username']
15
- self.client_secret = auth['password']
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._get_access_token()}"
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=3)
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
- print(f"请求失败:{e}")
64
+ raise e
73
65
  except (KeyError, ValueError) as e:
74
66
  # 处理解析响应失败异常
75
- print(f"解析响应失败: {e}")
67
+ raise e
76
68
 
77
- def list_mail_folders(self):
78
- response = requests.get(
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 query_folder_id(self, folder_name: Literal['inbox']='inbox'):
85
- folders = self.list_mail_folders()
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 = requests.get(
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 list_mail(self, folder_name: str='inbox', size: int=100):
104
- folder_id = self.query_folder_id(folder_name=folder_name)
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 = requests.get(
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
- message.update(detail)
120
- yield message
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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pytbox
3
- Version: 0.1.4
3
+ Version: 0.1.6
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-Expression: MIT
@@ -74,6 +74,7 @@ src/pytbox/utils/timeutils.py
74
74
  src/pytbox/win/ad.py
75
75
  tests/test_base.py
76
76
  tests/test_feishu.py
77
+ tests/test_load_jsonfile.py
77
78
  tests/test_logger.py
78
79
  tests/test_onepassword_connect.py
79
80
  tests/test_onepassword_sa.py
@@ -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
File without changes
File without changes
File without changes
File without changes