sycommon-python-lib 0.1.56b5__py3-none-any.whl → 0.1.57b1__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.
Files changed (38) hide show
  1. sycommon/config/Config.py +24 -3
  2. sycommon/config/LangfuseConfig.py +15 -0
  3. sycommon/config/SentryConfig.py +13 -0
  4. sycommon/llm/embedding.py +78 -23
  5. sycommon/llm/get_llm.py +9 -218
  6. sycommon/llm/struct_token.py +192 -0
  7. sycommon/llm/sy_langfuse.py +103 -0
  8. sycommon/llm/usage_token.py +117 -0
  9. sycommon/logging/kafka_log.py +187 -433
  10. sycommon/middleware/exception.py +10 -16
  11. sycommon/middleware/timeout.py +2 -1
  12. sycommon/middleware/traceid.py +81 -76
  13. sycommon/notice/uvicorn_monitor.py +32 -27
  14. sycommon/rabbitmq/rabbitmq_client.py +228 -243
  15. sycommon/rabbitmq/rabbitmq_pool.py +201 -123
  16. sycommon/rabbitmq/rabbitmq_service.py +25 -843
  17. sycommon/rabbitmq/rabbitmq_service_client_manager.py +211 -0
  18. sycommon/rabbitmq/rabbitmq_service_connection_monitor.py +73 -0
  19. sycommon/rabbitmq/rabbitmq_service_consumer_manager.py +285 -0
  20. sycommon/rabbitmq/rabbitmq_service_core.py +117 -0
  21. sycommon/rabbitmq/rabbitmq_service_producer_manager.py +238 -0
  22. sycommon/sentry/__init__.py +0 -0
  23. sycommon/sentry/sy_sentry.py +35 -0
  24. sycommon/services.py +122 -96
  25. sycommon/synacos/nacos_client_base.py +119 -0
  26. sycommon/synacos/nacos_config_manager.py +107 -0
  27. sycommon/synacos/nacos_heartbeat_manager.py +144 -0
  28. sycommon/synacos/nacos_service.py +63 -783
  29. sycommon/synacos/nacos_service_discovery.py +157 -0
  30. sycommon/synacos/nacos_service_registration.py +270 -0
  31. sycommon/tools/env.py +62 -0
  32. sycommon/tools/merge_headers.py +20 -0
  33. sycommon/tools/snowflake.py +101 -153
  34. {sycommon_python_lib-0.1.56b5.dist-info → sycommon_python_lib-0.1.57b1.dist-info}/METADATA +10 -8
  35. {sycommon_python_lib-0.1.56b5.dist-info → sycommon_python_lib-0.1.57b1.dist-info}/RECORD +38 -20
  36. {sycommon_python_lib-0.1.56b5.dist-info → sycommon_python_lib-0.1.57b1.dist-info}/WHEEL +0 -0
  37. {sycommon_python_lib-0.1.56b5.dist-info → sycommon_python_lib-0.1.57b1.dist-info}/entry_points.txt +0 -0
  38. {sycommon_python_lib-0.1.56b5.dist-info → sycommon_python_lib-0.1.57b1.dist-info}/top_level.txt +0 -0
@@ -1,7 +1,7 @@
1
1
  from fastapi import Request, HTTPException
2
2
  from fastapi.responses import JSONResponse
3
3
  from pydantic import ValidationError
4
- import traceback
4
+ from sycommon.logging.kafka_log import SYLogger
5
5
 
6
6
 
7
7
  def setup_exception_handler(app, config: dict):
@@ -15,7 +15,7 @@ def setup_exception_handler(app, config: dict):
15
15
  int_MaxBytes = int(MaxBytes) / 1024 / 1024
16
16
  return JSONResponse(
17
17
  content={
18
- 'code': 413, 'error': f'File size exceeds the allowed limit of {int_MaxBytes}MB.'},
18
+ 'code': 413, 'error': f'File size exceeds the allowed limit of {int_MaxBytes}MB.', 'traceId': SYLogger.get_trace_id()},
19
19
  status_code=413
20
20
  )
21
21
 
@@ -27,7 +27,8 @@ def setup_exception_handler(app, config: dict):
27
27
  content={
28
28
  "code": exc.status_code,
29
29
  "message": exc.detail,
30
- "path": str(request.url.path)
30
+ "path": str(request.url.path),
31
+ "traceId": SYLogger.get_trace_id()
31
32
  }
32
33
  )
33
34
 
@@ -39,7 +40,8 @@ def setup_exception_handler(app, config: dict):
39
40
  content={
40
41
  "code": 400,
41
42
  "message": "参数验证失败",
42
- "details": exc.errors()
43
+ "details": exc.errors(),
44
+ "traceId": SYLogger.get_trace_id()
43
45
  }
44
46
  )
45
47
 
@@ -55,30 +57,22 @@ def setup_exception_handler(app, config: dict):
55
57
  status_code=exc.code,
56
58
  content={
57
59
  "code": exc.code,
58
- "message": exc.message
60
+ "message": exc.message,
61
+ "traceId": SYLogger.get_trace_id()
59
62
  }
60
63
  )
61
64
 
62
65
  # 5. 全局异常处理器(捕获所有未处理的异常)
63
66
  @app.exception_handler(Exception)
64
67
  async def global_exception_handler(request: Request, exc: Exception):
65
- # 记录详细错误信息
66
- error_msg = f"请求路径: {request.url}\n"
67
- error_msg += f"错误类型: {type(exc).__name__}\n"
68
- error_msg += f"错误信息: {str(exc)}\n"
69
- error_msg += f"堆栈信息: {traceback.format_exc()}"
70
-
71
- # 使用你的日志服务记录错误
72
- from sycommon.logging.kafka_log import SYLogger
73
- SYLogger.error(error_msg)
74
-
75
68
  # 返回统一格式的错误响应(生产环境可选择不返回详细信息)
76
69
  return JSONResponse(
77
70
  status_code=500,
78
71
  content={
79
72
  "code": 500,
80
73
  "message": "服务器内部错误,请稍后重试",
81
- "detail": str(exc) if config.get('DEBUG', False) else "Internal Server Error"
74
+ "detail": str(exc) if config.get('DEBUG', False) else "Internal Server Error",
75
+ "traceId": SYLogger.get_trace_id()
82
76
  }
83
77
  )
84
78
 
@@ -2,6 +2,7 @@
2
2
  import time
3
3
  from fastapi import Request
4
4
  from fastapi.responses import JSONResponse
5
+ from sycommon.logging.kafka_log import SYLogger
5
6
 
6
7
 
7
8
  def setup_request_timeout_middleware(app, config: dict):
@@ -14,6 +15,6 @@ def setup_request_timeout_middleware(app, config: dict):
14
15
  response = await call_next(request)
15
16
  duration = time.time() - request.state.start_time
16
17
  if duration > REQUEST_TIMEOUT:
17
- return JSONResponse(content={'code': 1, 'error': 'Request timed out'}, status_code=504)
18
+ return JSONResponse(content={'code': 1, 'error': 'Request timed out', 'traceId': SYLogger.get_trace_id()}, status_code=504)
18
19
  return response
19
20
  return app
@@ -10,11 +10,8 @@ from sycommon.tools.snowflake import Snowflake
10
10
  def setup_trace_id_handler(app):
11
11
  @app.middleware("http")
12
12
  async def trace_id_and_log_middleware(request: Request, call_next):
13
- # ========== 1. 请求阶段:确保获取/生成 x-traceId-header ==========
14
- # 优先从请求头读取(兼容任意大小写)
15
- trace_id = request.headers.get(
16
- "x-traceId-header") or request.headers.get("x-traceid-header")
17
- # 无则生成雪花ID
13
+ # ========== 1. 请求阶段:获取/生成 TraceID ==========
14
+ trace_id = request.headers.get("x-traceid-header")
18
15
  if not trace_id:
19
16
  trace_id = Snowflake.id
20
17
 
@@ -37,38 +34,30 @@ def setup_trace_id_handler(app):
37
34
 
38
35
  if is_json_content and request.method in ["POST", "PUT", "PATCH"]:
39
36
  try:
40
- # 兼容纯文本格式的 JSON(先读文本再解析)
37
+ # 兼容纯文本格式的 JSON
41
38
  if "text/plain" in content_type:
42
39
  raw_text = await request.text(encoding="utf-8")
43
40
  request_body = json.loads(raw_text)
44
41
  else:
45
- # application/json 直接解析
46
42
  request_body = await request.json()
47
- except Exception as e:
43
+ except Exception:
48
44
  try:
49
45
  request_body = await request.json()
50
46
  except Exception as e:
51
- # 精准捕获 JSON 解析错误(而非泛 Exception)
52
47
  request_body = {"error": f"JSON parse failed: {str(e)}"}
53
48
 
54
49
  elif "multipart/form-data" in content_type and request.method in ["POST", "PUT"]:
55
50
  try:
56
- # 从请求头中提取boundary
57
51
  boundary = None
58
52
  if "boundary=" in content_type:
59
53
  boundary = content_type.split("boundary=")[1].strip()
60
54
  boundary = boundary.encode('ascii')
61
55
 
62
56
  if boundary:
63
- # 读取原始请求体
64
57
  body = await request.body()
65
-
66
- # 尝试从原始请求体中提取文件名
67
58
  parts = body.split(boundary)
68
59
  for part in parts:
69
60
  part_str = part.decode('utf-8', errors='ignore')
70
-
71
- # 使用正则表达式查找文件名
72
61
  filename_match = re.search(
73
62
  r'filename="([^"]+)"', part_str)
74
63
  if filename_match:
@@ -82,62 +71,69 @@ def setup_trace_id_handler(app):
82
71
  request_body = {
83
72
  "error": f"Failed to process form data: {str(e)}"}
84
73
 
85
- # 构建请求日志(包含 traceId)
74
+ # 构建请求日志
86
75
  request_message = {
87
- "traceId": trace_id, # 请求日志中加入 traceId
76
+ "traceId": trace_id,
88
77
  "method": request.method,
89
78
  "url": str(request.url),
90
79
  "query_params": query_params,
91
80
  "request_body": request_body,
92
81
  "uploaded_files": files_info if files_info else None
93
82
  }
94
- request_message_str = json.dumps(request_message, ensure_ascii=False)
95
- SYLogger.info(request_message_str)
83
+ SYLogger.info(json.dumps(request_message, ensure_ascii=False))
84
+
85
+ # 标记位:默认认为会发生异常
86
+ # 这样如果中途代码报错跳转到 except,finally 就不会 reset,保留 trace_id 给 Exception Handler
87
+ had_exception = True
96
88
 
97
89
  try:
98
- # 处理请求
90
+ # ========== 2. 处理请求 ==========
99
91
  response = await call_next(request)
100
92
 
101
- # 获取响应Content-Type(统一小写)
102
- content_type = response.headers.get("content-type", "").lower()
93
+ # ========== 3. 响应处理阶段 ==========
94
+ # 注意:此阶段发生的任何异常都会被下方的 except 捕获
95
+ # 从而保证 trace_id 不被清除,能够透传
96
+
97
+ response_content_type = response.headers.get(
98
+ "content-type", "").lower()
103
99
 
104
- # ========== 2. SSE 响应:仅设置 x-traceId-header,不修改其他头 ==========
105
- if "text/event-stream" in content_type:
100
+ # 处理 SSE (Server-Sent Events)
101
+ if "text/event-stream" in response_content_type:
106
102
  try:
107
- # 强制写入 x-traceId-header 到响应头
108
- response.headers["x-traceId-header"] = trace_id
109
- # 确保前端能读取(仅补充暴露头,不覆盖原有值)
103
+ response.headers["x-traceid-header"] = trace_id
110
104
  expose_headers = response.headers.get(
111
105
  "access-control-expose-headers", "")
112
106
  if expose_headers:
113
- if "x-traceId-header" not in expose_headers.lower():
107
+ if "x-traceid-header" not in expose_headers.lower():
114
108
  response.headers[
115
- "access-control-expose-headers"] = f"{expose_headers}, x-traceId-header"
109
+ "access-control-expose-headers"] = f"{expose_headers}, x-traceid-header"
116
110
  else:
117
- response.headers["access-control-expose-headers"] = "x-traceId-header"
118
- # SSE 必须移除 Content-Length(仅这一个额外操作)
111
+ response.headers["access-control-expose-headers"] = "x-traceid-header"
112
+
113
+ # SSE 必须移除 Content-Length
119
114
  headers_lower = {
120
115
  k.lower(): k for k in response.headers.keys()}
121
116
  if "content-length" in headers_lower:
122
117
  del response.headers[headers_lower["content-length"]]
123
118
  except AttributeError:
124
- # 流式响应头只读:初始化时仅加入 traceId 和必要暴露头
119
+ # 流式响应头只读处理
125
120
  new_headers = dict(response.headers) if hasattr(
126
121
  response.headers, 'items') else {}
127
- new_headers["x-traceId-header"] = trace_id # 强制加入
128
- # 保留原有暴露头,补充 traceId
122
+ new_headers["x-traceid-header"] = trace_id
129
123
  if "access-control-expose-headers" in new_headers:
130
- if "x-traceId-header" not in new_headers["access-control-expose-headers"].lower():
131
- new_headers["access-control-expose-headers"] += ", x-traceId-header"
124
+ if "x-traceid-header" not in new_headers["access-control-expose-headers"].lower():
125
+ new_headers["access-control-expose-headers"] += ", x-traceid-header"
132
126
  else:
133
- new_headers["access-control-expose-headers"] = "x-traceId-header"
134
- # 移除 Content-Length
127
+ new_headers["access-control-expose-headers"] = "x-traceid-header"
135
128
  new_headers.pop("content-length", None)
136
129
  response.init_headers(new_headers)
130
+
131
+ # SSE 不处理 Body,直接返回
132
+ had_exception = False
137
133
  return response
138
134
 
139
- # ========== 3. 非 SSE 响应:强制写入 x-traceId-header,保留 CORS ==========
140
- # 备份 CORS 头(防止丢失)
135
+ # 处理非 SSE 响应
136
+ # 备份 CORS
141
137
  cors_headers = {}
142
138
  cors_header_keys = [
143
139
  "access-control-allow-origin",
@@ -153,7 +149,7 @@ def setup_trace_id_handler(app):
153
149
  cors_headers[key] = response.headers[k]
154
150
  break
155
151
 
156
- # 合并 headers(非 SSE 场景)
152
+ # 合并 Headers
157
153
  merged_headers = merge_headers(
158
154
  source_headers=request.headers,
159
155
  target_headers=response.headers,
@@ -161,19 +157,20 @@ def setup_trace_id_handler(app):
161
157
  delete_keys={'content-length', 'accept', 'content-type'}
162
158
  )
163
159
 
164
- # 强制加入 x-traceId-header(优先级最高)
165
- merged_headers["x-traceId-header"] = trace_id
166
- # 恢复 CORS 头 + 补充 traceId 到暴露头
160
+ # 强制加入 x-traceid-header
161
+ merged_headers["x-traceid-header"] = trace_id
167
162
  merged_headers.update(cors_headers)
163
+
164
+ # 更新暴露头
168
165
  expose_headers = merged_headers.get(
169
166
  "access-control-expose-headers", "")
170
167
  if expose_headers:
171
- if "x-traceId-header" not in expose_headers.lower():
172
- merged_headers["access-control-expose-headers"] = f"{expose_headers}, x-traceId-header"
168
+ if "x-traceid-header" not in expose_headers.lower():
169
+ merged_headers["access-control-expose-headers"] = f"{expose_headers}, x-traceid-header"
173
170
  else:
174
- merged_headers["access-control-expose-headers"] = "x-traceId-header"
171
+ merged_headers["access-control-expose-headers"] = "x-traceid-header"
175
172
 
176
- # 更新响应头
173
+ # 应用 Headers
177
174
  if hasattr(response.headers, 'clear'):
178
175
  response.headers.clear()
179
176
  for k, v in merged_headers.items():
@@ -187,27 +184,26 @@ def setup_trace_id_handler(app):
187
184
  except (AttributeError, KeyError):
188
185
  pass
189
186
 
190
- # 处理普通响应体(JSON 加入 traceId)
187
+ # 处理响应体
191
188
  response_body = b""
192
189
  try:
193
190
  async for chunk in response.body_iterator:
194
191
  response_body += chunk
195
192
 
196
- # 获取 Content-Disposition(统一小写)
197
193
  content_disposition = response.headers.get(
198
194
  "content-disposition", "").lower()
199
195
 
200
- # JSON 响应体加入 traceId
201
- if "application/json" in content_type and not content_disposition.startswith("attachment"):
196
+ # JSON 响应体注入 traceId
197
+ if "application/json" in response_content_type and not content_disposition.startswith("attachment"):
202
198
  try:
203
199
  data = json.loads(response_body)
204
200
  new_body = response_body
205
- if data:
206
- data["traceId"] = trace_id # 响应体也加入
201
+ if isinstance(data, dict):
202
+ data["traceId"] = trace_id
207
203
  new_body = json.dumps(
208
204
  data, ensure_ascii=False).encode()
209
205
 
210
- # 重建响应,确保 header 包含 x-traceId-header
206
+ # 重建 Response 以更新 Body 和 Content-Length
211
207
  response = Response(
212
208
  content=new_body,
213
209
  status_code=response.status_code,
@@ -215,12 +211,12 @@ def setup_trace_id_handler(app):
215
211
  media_type=response.media_type
216
212
  )
217
213
  response.headers["content-length"] = str(len(new_body))
218
- response.headers["x-traceId-header"] = trace_id # 再次兜底
219
- # 恢复 CORS
214
+ response.headers["x-traceid-header"] = trace_id
215
+ # 恢复 CORS
220
216
  for k, v in cors_headers.items():
221
217
  response.headers[k] = v
222
218
  except json.JSONDecodeError:
223
- # 非 JSON 响应:仅更新长度,强制加入 traceId
219
+ # 非 JSON 或解析失败,仅更新长度
224
220
  response = Response(
225
221
  content=response_body,
226
222
  status_code=response.status_code,
@@ -229,11 +225,11 @@ def setup_trace_id_handler(app):
229
225
  )
230
226
  response.headers["content-length"] = str(
231
227
  len(response_body))
232
- response.headers["x-traceId-header"] = trace_id # 强制加入
228
+ response.headers["x-traceid-header"] = trace_id
233
229
  for k, v in cors_headers.items():
234
230
  response.headers[k] = v
235
231
  else:
236
- # 非 JSON 响应:强制加入 traceId
232
+ # 非 JSON 响应
237
233
  response = Response(
238
234
  content=response_body,
239
235
  status_code=response.status_code,
@@ -242,48 +238,57 @@ def setup_trace_id_handler(app):
242
238
  )
243
239
  response.headers["content-length"] = str(
244
240
  len(response_body))
245
- response.headers["x-traceId-header"] = trace_id # 强制加入
241
+ response.headers["x-traceid-header"] = trace_id
246
242
  for k, v in cors_headers.items():
247
243
  response.headers[k] = v
248
244
  except StopAsyncIteration:
249
245
  pass
250
246
 
251
- # 构建响应日志(包含 traceId)
247
+ # 构建响应日志
252
248
  response_message = {
253
- "traceId": trace_id, # 响应日志加入 traceId
249
+ "traceId": trace_id,
254
250
  "status_code": response.status_code,
255
251
  "response_body": response_body.decode('utf-8', errors='ignore'),
256
252
  }
257
- response_message_str = json.dumps(
258
- response_message, ensure_ascii=False)
259
- SYLogger.info(response_message_str)
253
+ SYLogger.info(json.dumps(response_message, ensure_ascii=False))
260
254
 
261
- # ========== 最终兜底:确保响应头必有 x-traceId-header ==========
255
+ # 兜底:确保 Header 必有 TraceId
262
256
  try:
263
- response.headers["x-traceId-header"] = trace_id
257
+ response.headers["x-traceid-header"] = trace_id
264
258
  except AttributeError:
265
259
  new_headers = dict(response.headers) if hasattr(
266
260
  response.headers, 'items') else {}
267
- new_headers["x-traceId-header"] = trace_id
261
+ new_headers["x-traceid-header"] = trace_id
268
262
  if hasattr(response, "init_headers"):
269
263
  response.init_headers(new_headers)
270
264
 
265
+ # 如果执行到这里,说明一切正常,标记为无异常
266
+ had_exception = False
271
267
  return response
268
+
272
269
  except Exception as e:
273
- # 异常日志也加入 traceId
270
+ # ========== 4. 异常处理阶段 ==========
271
+ # 记录中间件层面的异常日志
274
272
  error_message = {
275
273
  "traceId": trace_id,
276
- "error": str(e),
274
+ "error": f"Middleware Error: {str(e)}",
277
275
  "query_params": query_params,
278
276
  "request_body": request_body,
279
277
  "uploaded_files": files_info if files_info else None
280
278
  }
281
- error_message_str = json.dumps(error_message, ensure_ascii=False)
282
- SYLogger.error(error_message_str)
279
+ # 使用 SYLogger.error,由于处于 except 块,会自动捕获堆栈
280
+ SYLogger.error(error_message)
281
+
282
+ # 关键:重新抛出异常,让 Global Exception Handler 接管
283
+ # 此时 had_exception 仍为 True,finally 不会 reset,trace_id 得以保留
283
284
  raise
285
+
284
286
  finally:
285
- # 清理上下文变量
286
- SYLogger.reset_trace_id(token)
287
- SYLogger.reset_headers(header_token)
287
+ # ========== 5. 清理阶段 ==========
288
+ # 只有在没有任何异常的情况下(had_exception=False),才手动清除上下文
289
+ if not had_exception:
290
+ SYLogger.reset_trace_id(token)
291
+ SYLogger.reset_headers(header_token)
292
+ # 如果 had_exception 为 True,这里什么都不做,保留 ContextVar 供 Exception Handler 读取
288
293
 
289
294
  return app
@@ -7,11 +7,12 @@ import json
7
7
  from typing import Optional
8
8
  from urllib.parse import urlparse, parse_qs, urlencode, urlunparse
9
9
  from sycommon.config.Config import Config
10
+ from sycommon.logging.kafka_log import SYLogger
10
11
 
11
12
 
12
13
  async def send_wechat_markdown_msg(
13
14
  content: str,
14
- webhook: str = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=b9992872-ea66-494f-8683-f43411b7713a"
15
+ webhook: str = None
15
16
  ) -> Optional[dict]:
16
17
  """
17
18
  异步发送企业微信Markdown格式的WebHook消息
@@ -50,13 +51,14 @@ async def send_wechat_markdown_msg(
50
51
  response_text) if response_text else {}
51
52
 
52
53
  if status == 200 and response_data.get("errcode") == 0:
53
- print(f"消息发送成功: {response_data}")
54
+ SYLogger.info(f"消息发送成功: {response_data}")
54
55
  return response_data
55
56
  else:
56
- print(f"消息发送失败 - 状态码: {status}, 响应: {response_data}")
57
+ SYLogger.info(
58
+ f"消息发送失败 - 状态码: {status}, 响应: {response_data}")
57
59
  return None
58
60
  except Exception as e:
59
- print(f"错误:未知异常 - {str(e)}")
61
+ SYLogger.info(f"错误:未知异常 - {str(e)}")
60
62
  return None
61
63
 
62
64
 
@@ -71,10 +73,12 @@ async def send_webhook(error_info: dict = None, webhook: str = None):
71
73
  try:
72
74
  service_name = Config().config.get('Name', "未知服务")
73
75
  env = Config().config.get('Nacos', {}).get('namespaceId', '未知环境')
76
+ webHook = Config().config.get('llm', {}).get('WebHook', '未知环境')
74
77
  except Exception as e:
75
78
  service_name = "未知服务"
76
79
  env = "未知环境"
77
- print(f"读取配置失败: {str(e)}")
80
+ webHook = None
81
+ SYLogger.info(f"读取配置失败: {str(e)}")
78
82
 
79
83
  start_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
80
84
 
@@ -92,13 +96,14 @@ async def send_webhook(error_info: dict = None, webhook: str = None):
92
96
  > 错误信息: <font color="danger">{error_msg}</font>
93
97
  > 错误堆栈: {stack_trace}"""
94
98
 
95
- # 发送消息(优先使用传入的webhook,否则用默认值)
96
- default_webhook = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=b9992872-ea66-494f-8683-f43411b7713a"
97
- result = await send_wechat_markdown_msg(
98
- content=markdown_content,
99
- webhook=webhook if webhook else default_webhook
100
- )
101
- print(f"通知发送结果: {result}")
99
+ if webhook or webHook:
100
+ result = await send_wechat_markdown_msg(
101
+ content=markdown_content,
102
+ webhook=webhook or webHook
103
+ )
104
+ SYLogger.info(f"通知发送结果: {result}")
105
+ else:
106
+ SYLogger.info("未设置企业微信WebHook")
102
107
 
103
108
 
104
109
  def run(*args, webhook: str = None, **kwargs):
@@ -133,7 +138,7 @@ def run(*args, webhook: str = None, **kwargs):
133
138
  masked_query = urlencode(query, doseq=True)
134
139
  masked_webhook = urlunparse(
135
140
  (parsed.scheme, parsed.netloc, parsed.path, parsed.params, masked_query, parsed.fragment))
136
- print(f"自定义企业微信WebHook: {masked_webhook}")
141
+ SYLogger.info(f"自定义企业微信WebHook: {masked_webhook}")
137
142
 
138
143
  # 初始化错误信息
139
144
  error_info = None
@@ -146,10 +151,10 @@ def run(*args, webhook: str = None, **kwargs):
146
151
  except KeyboardInterrupt:
147
152
  # 处理用户手动中断(不算启动失败)
148
153
  elapsed = (datetime.now() - start_time).total_seconds()
149
- print(f"\n{'='*50}")
150
- print(f"ℹ️ 应用被用户手动中断")
151
- print(f"启动耗时: {elapsed:.2f} 秒")
152
- print(f"{'='*50}\n")
154
+ SYLogger.info(f"\n{'='*50}")
155
+ SYLogger.info(f"ℹ️ 应用被用户手动中断")
156
+ SYLogger.info(f"启动耗时: {elapsed:.2f} 秒")
157
+ SYLogger.info(f"{'='*50}\n")
153
158
  sys.exit(0)
154
159
 
155
160
  except Exception as e:
@@ -167,16 +172,16 @@ def run(*args, webhook: str = None, **kwargs):
167
172
  }
168
173
 
169
174
  # 打印错误信息
170
- print(f"\n{'='*50}")
171
- print(f"🚨 应用启动失败!")
172
- print(f"失败时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
173
- print(f"错误类型: {type(e).__name__}")
174
- print(f"错误信息: {str(e)}")
175
- print(f"\n📝 错误堆栈(关键):")
176
- print(f"-"*50)
175
+ SYLogger.info(f"\n{'='*50}")
176
+ SYLogger.info(f"🚨 应用启动失败!")
177
+ SYLogger.info(f"失败时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
178
+ SYLogger.info(f"错误类型: {type(e).__name__}")
179
+ SYLogger.info(f"错误信息: {str(e)}")
180
+ SYLogger.info(f"\n📝 错误堆栈(关键):")
181
+ SYLogger.info(f"-"*50)
177
182
  traceback.print_exc(file=sys.stdout)
178
- print(f"\n⏱️ 启动耗时: {elapsed:.2f} 秒")
179
- print(f"{'='*50}\n")
183
+ SYLogger.info(f"\n⏱️ 启动耗时: {elapsed:.2f} 秒")
184
+ SYLogger.info(f"{'='*50}\n")
180
185
 
181
186
  finally:
182
187
  # 运行异步通知函数,传递自定义的webhook参数
@@ -186,7 +191,7 @@ def run(*args, webhook: str = None, **kwargs):
186
191
  webhook=webhook
187
192
  ))
188
193
  except Exception as e:
189
- print(f"错误:异步通知失败 - {str(e)}")
194
+ SYLogger.info(f"错误:异步通知失败 - {str(e)}")
190
195
  # 启动失败时退出程序
191
196
  sys.exit(1)
192
197