sycommon-python-lib 0.1.56b6__py3-none-any.whl → 0.1.56b7__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.
@@ -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,9 @@ 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
- # 优先从请求头读取(兼容任意大小写)
13
+ # ========== 1. 请求阶段:获取/生成 TraceID ==========
15
14
  trace_id = request.headers.get(
16
15
  "x-traceId-header") or request.headers.get("x-traceid-header")
17
- # 无则生成雪花ID
18
16
  if not trace_id:
19
17
  trace_id = Snowflake.id
20
18
 
@@ -37,38 +35,30 @@ def setup_trace_id_handler(app):
37
35
 
38
36
  if is_json_content and request.method in ["POST", "PUT", "PATCH"]:
39
37
  try:
40
- # 兼容纯文本格式的 JSON(先读文本再解析)
38
+ # 兼容纯文本格式的 JSON
41
39
  if "text/plain" in content_type:
42
40
  raw_text = await request.text(encoding="utf-8")
43
41
  request_body = json.loads(raw_text)
44
42
  else:
45
- # application/json 直接解析
46
43
  request_body = await request.json()
47
- except Exception as e:
44
+ except Exception:
48
45
  try:
49
46
  request_body = await request.json()
50
47
  except Exception as e:
51
- # 精准捕获 JSON 解析错误(而非泛 Exception)
52
48
  request_body = {"error": f"JSON parse failed: {str(e)}"}
53
49
 
54
50
  elif "multipart/form-data" in content_type and request.method in ["POST", "PUT"]:
55
51
  try:
56
- # 从请求头中提取boundary
57
52
  boundary = None
58
53
  if "boundary=" in content_type:
59
54
  boundary = content_type.split("boundary=")[1].strip()
60
55
  boundary = boundary.encode('ascii')
61
56
 
62
57
  if boundary:
63
- # 读取原始请求体
64
58
  body = await request.body()
65
-
66
- # 尝试从原始请求体中提取文件名
67
59
  parts = body.split(boundary)
68
60
  for part in parts:
69
61
  part_str = part.decode('utf-8', errors='ignore')
70
-
71
- # 使用正则表达式查找文件名
72
62
  filename_match = re.search(
73
63
  r'filename="([^"]+)"', part_str)
74
64
  if filename_match:
@@ -82,31 +72,36 @@ def setup_trace_id_handler(app):
82
72
  request_body = {
83
73
  "error": f"Failed to process form data: {str(e)}"}
84
74
 
85
- # 构建请求日志(包含 traceId)
75
+ # 构建请求日志
86
76
  request_message = {
87
- "traceId": trace_id, # 请求日志中加入 traceId
77
+ "traceId": trace_id,
88
78
  "method": request.method,
89
79
  "url": str(request.url),
90
80
  "query_params": query_params,
91
81
  "request_body": request_body,
92
82
  "uploaded_files": files_info if files_info else None
93
83
  }
94
- request_message_str = json.dumps(request_message, ensure_ascii=False)
95
- SYLogger.info(request_message_str)
84
+ SYLogger.info(json.dumps(request_message, ensure_ascii=False))
85
+
86
+ # 标记位:默认认为会发生异常
87
+ # 这样如果中途代码报错跳转到 except,finally 就不会 reset,保留 trace_id 给 Exception Handler
88
+ had_exception = True
96
89
 
97
90
  try:
98
- # 处理请求
91
+ # ========== 2. 处理请求 ==========
99
92
  response = await call_next(request)
100
93
 
101
- # 获取响应Content-Type(统一小写)
102
- content_type = response.headers.get("content-type", "").lower()
94
+ # ========== 3. 响应处理阶段 ==========
95
+ # 注意:此阶段发生的任何异常都会被下方的 except 捕获
96
+ # 从而保证 trace_id 不被清除,能够透传
103
97
 
104
- # ========== 2. SSE 响应:仅设置 x-traceId-header,不修改其他头 ==========
105
- if "text/event-stream" in content_type:
98
+ response_content_type = response.headers.get(
99
+ "content-type", "").lower()
100
+
101
+ # 处理 SSE (Server-Sent Events)
102
+ if "text/event-stream" in response_content_type:
106
103
  try:
107
- # 强制写入 x-traceId-header 到响应头
108
104
  response.headers["x-traceId-header"] = trace_id
109
- # 确保前端能读取(仅补充暴露头,不覆盖原有值)
110
105
  expose_headers = response.headers.get(
111
106
  "access-control-expose-headers", "")
112
107
  if expose_headers:
@@ -115,29 +110,31 @@ def setup_trace_id_handler(app):
115
110
  "access-control-expose-headers"] = f"{expose_headers}, x-traceId-header"
116
111
  else:
117
112
  response.headers["access-control-expose-headers"] = "x-traceId-header"
118
- # SSE 必须移除 Content-Length(仅这一个额外操作)
113
+
114
+ # SSE 必须移除 Content-Length
119
115
  headers_lower = {
120
116
  k.lower(): k for k in response.headers.keys()}
121
117
  if "content-length" in headers_lower:
122
118
  del response.headers[headers_lower["content-length"]]
123
119
  except AttributeError:
124
- # 流式响应头只读:初始化时仅加入 traceId 和必要暴露头
120
+ # 流式响应头只读处理
125
121
  new_headers = dict(response.headers) if hasattr(
126
122
  response.headers, 'items') else {}
127
- new_headers["x-traceId-header"] = trace_id # 强制加入
128
- # 保留原有暴露头,补充 traceId
123
+ new_headers["x-traceId-header"] = trace_id
129
124
  if "access-control-expose-headers" in new_headers:
130
125
  if "x-traceId-header" not in new_headers["access-control-expose-headers"].lower():
131
126
  new_headers["access-control-expose-headers"] += ", x-traceId-header"
132
127
  else:
133
128
  new_headers["access-control-expose-headers"] = "x-traceId-header"
134
- # 移除 Content-Length
135
129
  new_headers.pop("content-length", None)
136
130
  response.init_headers(new_headers)
131
+
132
+ # SSE 不处理 Body,直接返回
133
+ had_exception = False
137
134
  return response
138
135
 
139
- # ========== 3. 非 SSE 响应:强制写入 x-traceId-header,保留 CORS ==========
140
- # 备份 CORS 头(防止丢失)
136
+ # 处理非 SSE 响应
137
+ # 备份 CORS
141
138
  cors_headers = {}
142
139
  cors_header_keys = [
143
140
  "access-control-allow-origin",
@@ -153,7 +150,7 @@ def setup_trace_id_handler(app):
153
150
  cors_headers[key] = response.headers[k]
154
151
  break
155
152
 
156
- # 合并 headers(非 SSE 场景)
153
+ # 合并 Headers
157
154
  merged_headers = merge_headers(
158
155
  source_headers=request.headers,
159
156
  target_headers=response.headers,
@@ -161,10 +158,11 @@ def setup_trace_id_handler(app):
161
158
  delete_keys={'content-length', 'accept', 'content-type'}
162
159
  )
163
160
 
164
- # 强制加入 x-traceId-header(优先级最高)
161
+ # 强制加入 x-traceId-header
165
162
  merged_headers["x-traceId-header"] = trace_id
166
- # 恢复 CORS 头 + 补充 traceId 到暴露头
167
163
  merged_headers.update(cors_headers)
164
+
165
+ # 更新暴露头
168
166
  expose_headers = merged_headers.get(
169
167
  "access-control-expose-headers", "")
170
168
  if expose_headers:
@@ -173,7 +171,7 @@ def setup_trace_id_handler(app):
173
171
  else:
174
172
  merged_headers["access-control-expose-headers"] = "x-traceId-header"
175
173
 
176
- # 更新响应头
174
+ # 应用 Headers
177
175
  if hasattr(response.headers, 'clear'):
178
176
  response.headers.clear()
179
177
  for k, v in merged_headers.items():
@@ -187,27 +185,26 @@ def setup_trace_id_handler(app):
187
185
  except (AttributeError, KeyError):
188
186
  pass
189
187
 
190
- # 处理普通响应体(JSON 加入 traceId)
188
+ # 处理响应体
191
189
  response_body = b""
192
190
  try:
193
191
  async for chunk in response.body_iterator:
194
192
  response_body += chunk
195
193
 
196
- # 获取 Content-Disposition(统一小写)
197
194
  content_disposition = response.headers.get(
198
195
  "content-disposition", "").lower()
199
196
 
200
- # JSON 响应体加入 traceId
201
- if "application/json" in content_type and not content_disposition.startswith("attachment"):
197
+ # JSON 响应体注入 traceId
198
+ if "application/json" in response_content_type and not content_disposition.startswith("attachment"):
202
199
  try:
203
200
  data = json.loads(response_body)
204
201
  new_body = response_body
205
- if data:
206
- data["traceId"] = trace_id # 响应体也加入
202
+ if isinstance(data, dict):
203
+ data["traceId"] = trace_id
207
204
  new_body = json.dumps(
208
205
  data, ensure_ascii=False).encode()
209
206
 
210
- # 重建响应,确保 header 包含 x-traceId-header
207
+ # 重建 Response 以更新 Body 和 Content-Length
211
208
  response = Response(
212
209
  content=new_body,
213
210
  status_code=response.status_code,
@@ -215,12 +212,12 @@ def setup_trace_id_handler(app):
215
212
  media_type=response.media_type
216
213
  )
217
214
  response.headers["content-length"] = str(len(new_body))
218
- response.headers["x-traceId-header"] = trace_id # 再次兜底
219
- # 恢复 CORS
215
+ response.headers["x-traceId-header"] = trace_id
216
+ # 恢复 CORS
220
217
  for k, v in cors_headers.items():
221
218
  response.headers[k] = v
222
219
  except json.JSONDecodeError:
223
- # 非 JSON 响应:仅更新长度,强制加入 traceId
220
+ # 非 JSON 或解析失败,仅更新长度
224
221
  response = Response(
225
222
  content=response_body,
226
223
  status_code=response.status_code,
@@ -229,11 +226,11 @@ def setup_trace_id_handler(app):
229
226
  )
230
227
  response.headers["content-length"] = str(
231
228
  len(response_body))
232
- response.headers["x-traceId-header"] = trace_id # 强制加入
229
+ response.headers["x-traceId-header"] = trace_id
233
230
  for k, v in cors_headers.items():
234
231
  response.headers[k] = v
235
232
  else:
236
- # 非 JSON 响应:强制加入 traceId
233
+ # 非 JSON 响应
237
234
  response = Response(
238
235
  content=response_body,
239
236
  status_code=response.status_code,
@@ -242,23 +239,21 @@ def setup_trace_id_handler(app):
242
239
  )
243
240
  response.headers["content-length"] = str(
244
241
  len(response_body))
245
- response.headers["x-traceId-header"] = trace_id # 强制加入
242
+ response.headers["x-traceId-header"] = trace_id
246
243
  for k, v in cors_headers.items():
247
244
  response.headers[k] = v
248
245
  except StopAsyncIteration:
249
246
  pass
250
247
 
251
- # 构建响应日志(包含 traceId)
248
+ # 构建响应日志
252
249
  response_message = {
253
- "traceId": trace_id, # 响应日志加入 traceId
250
+ "traceId": trace_id,
254
251
  "status_code": response.status_code,
255
252
  "response_body": response_body.decode('utf-8', errors='ignore'),
256
253
  }
257
- response_message_str = json.dumps(
258
- response_message, ensure_ascii=False)
259
- SYLogger.info(response_message_str)
254
+ SYLogger.info(json.dumps(response_message, ensure_ascii=False))
260
255
 
261
- # ========== 最终兜底:确保响应头必有 x-traceId-header ==========
256
+ # 兜底:确保 Header 必有 TraceId
262
257
  try:
263
258
  response.headers["x-traceId-header"] = trace_id
264
259
  except AttributeError:
@@ -268,22 +263,33 @@ def setup_trace_id_handler(app):
268
263
  if hasattr(response, "init_headers"):
269
264
  response.init_headers(new_headers)
270
265
 
266
+ # 如果执行到这里,说明一切正常,标记为无异常
267
+ had_exception = False
271
268
  return response
269
+
272
270
  except Exception as e:
273
- # 异常日志也加入 traceId
271
+ # ========== 4. 异常处理阶段 ==========
272
+ # 记录中间件层面的异常日志
274
273
  error_message = {
275
274
  "traceId": trace_id,
276
- "error": str(e),
275
+ "error": f"Middleware Error: {str(e)}",
277
276
  "query_params": query_params,
278
277
  "request_body": request_body,
279
278
  "uploaded_files": files_info if files_info else None
280
279
  }
281
- error_message_str = json.dumps(error_message, ensure_ascii=False)
282
- SYLogger.error(error_message_str)
280
+ # 使用 SYLogger.error,由于处于 except 块,会自动捕获堆栈
281
+ SYLogger.error(error_message)
282
+
283
+ # 关键:重新抛出异常,让 Global Exception Handler 接管
284
+ # 此时 had_exception 仍为 True,finally 不会 reset,trace_id 得以保留
283
285
  raise
286
+
284
287
  finally:
285
- # 清理上下文变量
286
- SYLogger.reset_trace_id(token)
287
- SYLogger.reset_headers(header_token)
288
+ # ========== 5. 清理阶段 ==========
289
+ # 只有在没有任何异常的情况下(had_exception=False),才手动清除上下文
290
+ if not had_exception:
291
+ SYLogger.reset_trace_id(token)
292
+ SYLogger.reset_headers(header_token)
293
+ # 如果 had_exception 为 True,这里什么都不做,保留 ContextVar 供 Exception Handler 读取
288
294
 
289
295
  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
 
@@ -799,7 +799,7 @@ class RabbitMQService:
799
799
  )
800
800
 
801
801
  # 构建消息头
802
- namespaceId = Config().config.get('Nacos', {}).get('namespaceId', '未知环境')
802
+ namespaceId = Config().config.get('Nacos', {}).get('namespaceId', '')
803
803
  tenant_id = "T000002" if namespaceId == "prod" or namespaceId == "wsuat1" else "T000003"
804
804
  mq_header = {
805
805
  "context": SsoUser(
File without changes
@@ -0,0 +1,34 @@
1
+ import sentry_sdk
2
+ from datetime import datetime
3
+ from sycommon.config.Config import Config
4
+ from sycommon.logging.kafka_log import SYLogger
5
+ from sentry_sdk.integrations.fastapi import FastApiIntegration
6
+ # from sentry_sdk.integrations.logging import LoggingIntegration
7
+
8
+
9
+ def sy_sentry_init():
10
+ config = Config().config
11
+ server_name = config.get('Name', '')
12
+ environment = config.get('Nacos', {}).get('namespaceId', '')
13
+ sentry_configs = config.get('SentryConfig', [])
14
+ target_config = next(
15
+ (item for item in sentry_configs if item.get('name') == server_name), None)
16
+ target_dsn = target_config.get('dsn')
17
+ target_enable = target_config.get('enable')
18
+ current_version = datetime.now().strftime("%Y-%m-%d %H:%M:%S-version")
19
+ if target_config and target_dsn and target_enable:
20
+ try:
21
+ sentry_sdk.init(
22
+ dsn=target_dsn,
23
+ traces_sample_rate=1.0,
24
+ server_name=server_name,
25
+ environment=environment,
26
+ release=current_version,
27
+ integrations=[
28
+ FastApiIntegration(),
29
+ # LoggingIntegration(level=logging.INFO,
30
+ # event_level=logging.ERROR)
31
+ ],
32
+ )
33
+ except Exception as e:
34
+ SYLogger.error(f"Sentry初始化失败: {str(e)}")
sycommon/services.py CHANGED
@@ -12,6 +12,7 @@ from sycommon.models.mqlistener_config import RabbitMQListenerConfig
12
12
  from sycommon.models.mqsend_config import RabbitMQSendConfig
13
13
  from sycommon.rabbitmq.rabbitmq_service import RabbitMQService
14
14
  from sycommon.tools.docs import custom_redoc_html, custom_swagger_ui_html
15
+ from sycommon.sentry.sy_sentry import sy_sentry_init
15
16
 
16
17
 
17
18
  class Services(metaclass=SingletonMeta):
@@ -87,6 +88,9 @@ class Services(metaclass=SingletonMeta):
87
88
  if logging_service:
88
89
  logging_service(config)
89
90
 
91
+ # 设置sentry
92
+ sy_sentry_init()
93
+
90
94
  # ========== 处理数据库服务 ==========
91
95
  # 清空之前的待执行列表(防止热重载时重复)
92
96
  cls._pending_async_db_setup = []