pytbox 0.1.6__py3-none-any.whl → 0.1.8__py3-none-any.whl

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/alert/ping.py CHANGED
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env python3
2
2
 
3
-
4
3
  from ..database.victoriametrics import VictoriaMetrics
5
4
  from ..lib.load_config import load_config
6
5
 
pytbox/base.py CHANGED
@@ -16,6 +16,7 @@ from pytbox.pyjira import PyJira
16
16
  from pytbox.mail.client import MailClient
17
17
  from pytbox.mail.alimail import AliMail
18
18
  from pytbox.alicloud.sls import AliCloudSls
19
+ from pytbox.utils.cronjob import cronjob_counter
19
20
 
20
21
 
21
22
  config = load_config_by_file(path='/workspaces/pytbox/tests/alert/config_dev.toml', oc_vault_id=os.environ.get('oc_vault_id'))
@@ -107,4 +108,8 @@ sls = AliCloudSls(
107
108
  access_key_secret=config['alicloud']['account1']['access_key_secret'],
108
109
  project=config['alicloud']['account1']['project'],
109
110
  logstore=config['alicloud']['account1']['logstore']
110
- )
111
+ )
112
+
113
+
114
+ def get_cronjob_counter(app_type='', app='', comment=None, schedule_interval=None, schedule_cron=None):
115
+ return cronjob_counter(vm=vm, log=get_logger('cronjob_counter'), app_type=app_type, app=app, comment=comment, schedule_interval=schedule_interval, schedule_cron=schedule_cron)
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env python3
2
2
 
3
+ import time
3
4
  import json
4
- from typing import Literal, Optional
5
+ from typing import Literal, Optional, Dict, List
5
6
  import requests
6
7
  from ..utils.response import ReturnResponse
7
8
  from ..utils.load_vm_devfile import load_dev_file
@@ -9,7 +10,7 @@ from ..utils.load_vm_devfile import load_dev_file
9
10
 
10
11
  class VictoriaMetrics:
11
12
 
12
- def __init__(self, url: str='', timeout: int=3) -> None:
13
+ def __init__(self, url: str='', timeout: int=3, env: str='prod') -> None:
13
14
  self.url = url
14
15
  self.timeout = timeout
15
16
  self.session = requests.Session()
@@ -17,7 +18,44 @@ class VictoriaMetrics:
17
18
  'Content-Type': 'application/json',
18
19
  'Accept': 'application/json'
19
20
  })
21
+ self.env = env
22
+
23
+ def insert(self, metric_name: str = '', labels: Dict[str, str] = None,
24
+ value: List[float] = None, timestamp: int = None) -> ReturnResponse:
25
+ """插入指标数据。
26
+
27
+ Args:
28
+ metric_name: 指标名称
29
+ labels: 标签字典
30
+ value: 值列表
31
+ timestamp: 时间戳(毫秒),默认为当前时间
32
+
33
+ Raises:
34
+ requests.RequestException: 当请求失败时抛出
35
+ """
36
+ if labels is None:
37
+ labels = {}
38
+ if value is None:
39
+ value = 1
40
+ if timestamp is None:
41
+ timestamp = int(time.time() * 1000)
42
+
43
+ url = f"{self.url}/api/v1/import"
44
+ data = {
45
+ "metric": {
46
+ "__name__": metric_name,
47
+ **labels
48
+ },
49
+ "values": [value],
50
+ "timestamps": [timestamp]
51
+ }
20
52
 
53
+ try:
54
+ response = requests.post(url, json=data, timeout=self.timeout)
55
+ return ReturnResponse(code=0, msg=f"数据插入成功,状态码: {response.status_code}, metric_name: {metric_name}, labels: {labels}, value: {value}, timestamp: {timestamp}")
56
+ except requests.RequestException as e:
57
+ return ReturnResponse(code=1, msg=f"数据插入失败: {e}")
58
+
21
59
  def query(self, query: str=None, output_format: Literal['json']=None) -> ReturnResponse:
22
60
  '''
23
61
  查询指标数据
@@ -208,9 +246,67 @@ class VictoriaMetrics:
208
246
  '''
209
247
  q = f"""avg_over_time(snmp_interface_ifOperStatus{{sysName="{sysname}", ifName="{if_name}"}}[{last_minute}m])"""
210
248
  r = self.query(query=q)
211
- status_code = r.data[0]['value'][1]
212
- if status_code == 1:
213
- status = 'up'
249
+ if r.code == 0:
250
+ status_code = int(r.data[0]['value'][1])
251
+ if status_code == 1:
252
+ status = 'up'
253
+ else:
254
+ status = 'down'
255
+ return ReturnResponse(code=0, msg=f"{sysname} {if_name} 最近 {last_minute} 分钟端口状态为 {status}", data=status)
214
256
  else:
215
- status = 'down'
216
- return ReturnResponse(code=0, msg=f"{sysname} {if_name} 最近 {last_minute} 分钟端口状态为 {status}", data=status)
257
+ return r
258
+
259
+ def insert_cronjob_run_status(self,
260
+ app_type: Literal['alert', 'meraki', 'other']='other',
261
+ app: str='',
262
+ status_code: Literal[0, 1]=1,
263
+ comment: str=None,
264
+ schedule_interval: str=None,
265
+ schedule_cron: str=None
266
+ ) -> ReturnResponse:
267
+ labels = {
268
+ "app": app,
269
+ "env": self.env,
270
+ }
271
+ if app_type:
272
+ labels['app_type'] = app_type
273
+ if comment:
274
+ labels['comment'] = comment
275
+
276
+ if schedule_interval:
277
+ labels['schedule_type'] = 'interval'
278
+ labels['schedule_interval'] = schedule_interval
279
+
280
+ if schedule_cron:
281
+ labels['schedule_type'] = 'cron'
282
+ labels['schedule_cron'] = schedule_cron
283
+
284
+ r = self.insert(metric_name="cronjob_run_status", labels=labels, value=status_code)
285
+ return r
286
+
287
+ def insert_cronjob_duration_seconds(self,
288
+ app_type: Literal['alert', 'meraki', 'other']='other',
289
+ app: str='',
290
+ duration_seconds: float=None,
291
+ comment: str=None,
292
+ schedule_interval: str=None,
293
+ schedule_cron: str=None
294
+ ) -> ReturnResponse:
295
+ labels = {
296
+ "app": app,
297
+ "env": self.env
298
+ }
299
+ if app_type:
300
+ labels['app_type'] = app_type
301
+ if comment:
302
+ labels['comment'] = comment
303
+
304
+ if schedule_interval:
305
+ labels['schedule_type'] = 'interval'
306
+ labels['schedule_interval'] = schedule_interval
307
+
308
+ if schedule_cron:
309
+ labels['schedule_type'] = 'cron'
310
+ labels['schedule_cron'] = schedule_cron
311
+ r = self.insert(metric_name="cronjob_run_duration_seconds", labels=labels, value=duration_seconds)
312
+ return r
@@ -0,0 +1,79 @@
1
+ #!/usr/bin/env python3
2
+
3
+ import time
4
+ from functools import wraps
5
+ from typing import Literal
6
+ from ..database.victoriametrics import VictoriaMetrics
7
+
8
+
9
+ def cronjob_counter(vm: VictoriaMetrics=None, log: str=None, app_type: Literal['']='', app='', comment=None, schedule_interval=None, schedule_cron=None):
10
+ """计算函数运行时间的装饰器,支持记录到 VictoriaMetrics
11
+
12
+ Args:
13
+ app_type: 应用类型 ('alert', 'meraki', 'other')
14
+ app: 应用名称
15
+ comment: 备注信息
16
+ schedule_interval: 定时任务间隔(如 '1m', '5m')
17
+ schedule_cron: cron 表达式(如 '0 */5 * * *')
18
+ """
19
+ def decorator(func):
20
+ @wraps(func)
21
+ def wrapper(*args, **kwargs):
22
+ start_time = time.time()
23
+
24
+ try:
25
+ result = func(*args, **kwargs)
26
+ end_time = time.time()
27
+ elapsed_time = end_time - start_time
28
+
29
+ # 记录任务成功完成状态
30
+ vm.insert_cronjob_run_status(
31
+ app_type=app_type,
32
+ app=app,
33
+ status_code=1, # 0 表示成功完成
34
+ comment=f"成功完成: {comment}" if comment else "任务成功完成",
35
+ schedule_interval=schedule_interval,
36
+ schedule_cron=schedule_cron
37
+ )
38
+
39
+ # 记录执行耗时
40
+ vm.insert_cronjob_duration_seconds(
41
+ app_type=app_type,
42
+ app=app,
43
+ duration_seconds=elapsed_time,
44
+ comment=comment,
45
+ schedule_interval=schedule_interval,
46
+ schedule_cron=schedule_cron
47
+ )
48
+ log.info(f"{app} 任务成功完成, 耗时 {elapsed_time:.2f} 秒")
49
+
50
+ return result
51
+
52
+ except Exception as e:
53
+ end_time = time.time()
54
+ elapsed_time = end_time - start_time
55
+
56
+ # 记录任务失败状态
57
+ error_comment = f"执行出错: {str(e)}" if not comment else f"{comment} (出错: {str(e)})"
58
+ vm.insert_cronjob_run_status(
59
+ app_type=app_type,
60
+ app=app,
61
+ status_code=0, # 1 表示失败
62
+ comment=error_comment,
63
+ schedule_interval=schedule_interval,
64
+ schedule_cron=schedule_cron
65
+ )
66
+
67
+ # 即使出错也记录耗时
68
+ vm.insert_cronjob_duration_seconds(
69
+ app_type=app_type,
70
+ app=app,
71
+ duration_seconds=elapsed_time,
72
+ comment=error_comment,
73
+ schedule_interval=schedule_interval,
74
+ schedule_cron=schedule_cron
75
+ )
76
+ log.error(f"任务失败: {error_comment}")
77
+ raise
78
+ return wrapper
79
+ return decorator
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pytbox
3
- Version: 0.1.6
3
+ Version: 0.1.8
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
@@ -1,4 +1,4 @@
1
- pytbox/base.py,sha256=7wUhNSX8sbZ5hlgWG7BhFYtNOhVB6b-k3ULNA0vPchU,3948
1
+ pytbox/base.py,sha256=uzrv0vlHVPOr2JjpUGd8R2Wr-iRf6SysnrAYOalKXYY,4283
2
2
  pytbox/cli.py,sha256=N775a0GK80IT2lQC2KRYtkZpIiu9UjavZmaxgNUgJhQ,160
3
3
  pytbox/dida365.py,sha256=pUMPB9AyLZpTTbaz2LbtzdEpyjvuGf4YlRrCvM5sbJo,10545
4
4
  pytbox/excel.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -7,7 +7,7 @@ pytbox/onepassword_sa.py,sha256=08iUcYud3aEHuQcUsem9bWNxdXKgaxFbMy9yvtr-DZQ,6995
7
7
  pytbox/pyjira.py,sha256=TMy34Rtu7OXRA8wpUuLsFeyIQfRNUn2ed2no00L8YSE,22470
8
8
  pytbox/vmware.py,sha256=WiH67_3-VCBjXJuh3UueOc31BdZDItiZhkeuPzoRhw4,3975
9
9
  pytbox/alert/alert_handler.py,sha256=FePPQS4LyGphSJ0QMv0_pLWaXxEqsRlcTKMfUjtsNfk,5048
10
- pytbox/alert/ping.py,sha256=g36X0U3U8ndZqfpVIcuoxJJ0X5gST3I_IwjTQC1roHA,779
10
+ pytbox/alert/ping.py,sha256=KEnnXdIRJHvR_rEHPWLBt0wz4cGwmA29Lenlak3Z_1Y,778
11
11
  pytbox/alicloud/sls.py,sha256=-r6rbCwDUQ4jwAgSVSNu7B2h1MNg20CrRIKnlXVeY9w,4159
12
12
  pytbox/categraf/build_config.py,sha256=9G85rLqkz3lchpH7ef0LbvckYHl0nRA6mHVLeUfs9Mw,6308
13
13
  pytbox/categraf/instances.toml,sha256=jcJyEaqhohUcECczWArxUK4t0-rdk4vmrX21kxZlSLA,1254
@@ -43,7 +43,7 @@ pytbox/cli/formatters/__init__.py,sha256=4o85w4j-A-O1oBLvuE9q8AFiJ2C9rvB3MIKsy5V
43
43
  pytbox/cli/formatters/output.py,sha256=h5WhZlQk1rjmxEj88Jy5ODLcv6L5zfGUhks_3AWIkKU,5455
44
44
  pytbox/common/__init__.py,sha256=3JWfgCQZKZuSH5NCE7OCzKwq82pkyop9l7sH5YSNyfU,122
45
45
  pytbox/database/mongo.py,sha256=CSpHC7iR-M0BaVxXz5j6iXjMKPgXJX_G7MrjCj5Gm8Q,3478
46
- pytbox/database/victoriametrics.py,sha256=0QXkrnqL0rV7dGaHmtZus-MdEW3uX9ZPm0D-sS4L1DU,7606
46
+ pytbox/database/victoriametrics.py,sha256=pKiAeZUTEXBegN8kGwkiGh1Pdm3i9DOnBhSG-la0mKk,11300
47
47
  pytbox/feishu/client.py,sha256=kwGLseGT_iQUFmSqpuS2_77WmxtHstD64nXvktuQ3B4,5865
48
48
  pytbox/feishu/endpoints.py,sha256=z3nPOZPC2JGDJlO7SusWBpRA33hZZ4Z-GBhI6F8L_u4,40240
49
49
  pytbox/feishu/errors.py,sha256=79qFAHZw7jDj3gnWAjI1-W4tB0q1_aSfdjee4xzXeuI,1179
@@ -55,16 +55,16 @@ pytbox/mail/alimail.py,sha256=njKA3PUbIaiKFaxKvUObmklmEEHg2YA-O5rpgsgT5_w,5147
55
55
  pytbox/mail/client.py,sha256=6HeKpChHGjTCYGBgQcfAhWlU_wh9wtO-bjP6TU38pGM,6120
56
56
  pytbox/mail/mail_detail.py,sha256=6u8DK-7WzYPSuX6TdicSCh2Os_9Ou6Rn9xc6WRvv85M,699
57
57
  pytbox/network/meraki.py,sha256=054E3C5KzAuXs9aPalvdAOUo6Hc5aOKZSWUaVbPquy4,6112
58
+ pytbox/utils/cronjob.py,sha256=b17CY1fmaFTdQojicXAXHliov_JZdmT7cZhtO4v5sCo,3080
58
59
  pytbox/utils/env.py,sha256=gD2-NyL3K3Vg1B1eGeD1hRtlSHPGgF8Oi9mchuQL6_o,646
59
60
  pytbox/utils/load_config.py,sha256=R4pGerBinbewsym41hQ8Z-I5I7gepuEKODjIrli4C08,5043
60
61
  pytbox/utils/load_vm_devfile.py,sha256=GVbB-FvGb0l586SDaraz__ZaXyDWd1WxcXVw5xGfXWw,1328
61
- pytbox/utils/ping_checker.py,sha256=Nqnn8clbgv-5l0PgxcTOldg8mkMKrFn4TvPL-rYUUGg,1
62
62
  pytbox/utils/response.py,sha256=kXjlwt0WVmLRam2eu1shzX2cQ7ux4cCQryaPGYwle5g,1247
63
63
  pytbox/utils/richutils.py,sha256=OT9_q2Q1bthzB0g1GlhZVvM4ZAepJRKL6a_Vsr6vEqo,487
64
64
  pytbox/utils/timeutils.py,sha256=uSKgwt20mVcgIGKLsH2tNum8v3rcpzgmBibPvyPQFgM,20433
65
65
  pytbox/win/ad.py,sha256=-3pWfL3dElz-XoO4j4M9lrgu3KJtlhrS9gCWJBpafAU,1147
66
- pytbox-0.1.6.dist-info/METADATA,sha256=mxB7SNMpc2yyjOXg9nVuF9DdryE6gDfe54RIoGN4jWI,6319
67
- pytbox-0.1.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
68
- pytbox-0.1.6.dist-info/entry_points.txt,sha256=YaTOJ2oPjOiv2SZwY0UC-UA9QS2phRH1oMvxGnxO0Js,43
69
- pytbox-0.1.6.dist-info/top_level.txt,sha256=YADgWue-Oe128ptN3J2hS3GB0Ncc5uZaSUM3e1rwswE,7
70
- pytbox-0.1.6.dist-info/RECORD,,
66
+ pytbox-0.1.8.dist-info/METADATA,sha256=iAknEyd73pj7U9J8ML0v1o9-q4AJvwD6OYSM4d91KAk,6319
67
+ pytbox-0.1.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
68
+ pytbox-0.1.8.dist-info/entry_points.txt,sha256=YaTOJ2oPjOiv2SZwY0UC-UA9QS2phRH1oMvxGnxO0Js,43
69
+ pytbox-0.1.8.dist-info/top_level.txt,sha256=YADgWue-Oe128ptN3J2hS3GB0Ncc5uZaSUM3e1rwswE,7
70
+ pytbox-0.1.8.dist-info/RECORD,,
@@ -1 +0,0 @@
1
-
File without changes