mdbq 4.0.81__py3-none-any.whl → 4.0.82__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.
mdbq/__version__.py CHANGED
@@ -1 +1 @@
1
- VERSION = '4.0.81'
1
+ VERSION = '4.0.82'
mdbq/route/monitor.py CHANGED
@@ -22,6 +22,7 @@ from typing import Dict, Any, Optional, List
22
22
  from urllib.parse import urlparse, parse_qs
23
23
  from dbutils.pooled_db import PooledDB
24
24
  from mdbq.myconf import myconf
25
+ from mdbq.log import mylogger
25
26
  from flask import request, g
26
27
  import re
27
28
  import ipaddress
@@ -33,6 +34,18 @@ host, port, username, password = parser.get_section_values(
33
34
  keys=['host', 'port', 'username', 'password'],
34
35
  )
35
36
 
37
+ logger = mylogger.MyLogger(
38
+ logging_mode='file',
39
+ log_level='info',
40
+ log_format='json',
41
+ max_log_size=50,
42
+ backup_count=5,
43
+ enable_async=False, # 是否启用异步日志
44
+ sample_rate=1, # 采样DEBUG/INFO日志
45
+ sensitive_fields=[], # 敏感字段过滤
46
+ enable_metrics=False, # 是否启用性能指标
47
+ )
48
+
36
49
 
37
50
  class RouteMonitor:
38
51
  """路由监控核心类"""
@@ -43,28 +56,59 @@ class RouteMonitor:
43
56
  self.pool = pool
44
57
  else:
45
58
  self.init_database_pool()
59
+
46
60
  self.init_database_tables()
61
+ logger.debug("✨ 路由监控系统初始化完成", {
62
+ "数据库表": "已创建/验证",
63
+ "系统状态": "就绪"
64
+ })
47
65
 
48
66
  def init_database_pool(self):
49
67
  """初始化数据库连接池"""
50
- self.pool = PooledDB(
51
- creator=pymysql,
52
- maxconnections=3, # 最大连接数
53
- mincached=1, # 初始化空闲连接数
54
- maxcached=3, # 空闲连接最大缓存数
55
- blocking=True,
56
- host=host,
57
- port=int(port),
58
- user=username,
59
- password=password,
60
- ping=1,
61
- charset='utf8mb4',
62
- cursorclass=pymysql.cursors.DictCursor
63
- )
68
+ try:
69
+ logger.debug("📊 初始化数据库连接池", {
70
+ "主机": host,
71
+ "端口": port,
72
+ "用户": username,
73
+ "最大连接数": 3
74
+ })
75
+
76
+ self.pool = PooledDB(
77
+ creator=pymysql,
78
+ maxconnections=3, # 最大连接数
79
+ mincached=1, # 初始化空闲连接数
80
+ maxcached=3, # 空闲连接最大缓存数
81
+ blocking=True,
82
+ host=host,
83
+ port=int(port),
84
+ user=username,
85
+ password=password,
86
+ ping=1,
87
+ charset='utf8mb4',
88
+ cursorclass=pymysql.cursors.DictCursor
89
+ )
90
+
91
+ logger.info("✅ 数据库连接池创建成功", {
92
+ "连接池状态": "已初始化",
93
+ "字符集": "utf8mb4"
94
+ })
95
+
96
+ except Exception as e:
97
+ logger.error("❌ 数据库连接池初始化失败", {
98
+ "错误信息": str(e),
99
+ "主机": host,
100
+ "端口": port
101
+ })
102
+ raise
64
103
 
65
104
  def init_database_tables(self):
66
105
  """初始化数据库表结构"""
67
106
  try:
107
+ logger.debug("🗄️ 开始创建/验证数据库表结构", {
108
+ "操作": "表结构初始化",
109
+ "预期表数": 4
110
+ })
111
+
68
112
  connection = self.pool.connection()
69
113
  try:
70
114
  with connection.cursor() as cursor:
@@ -121,6 +165,11 @@ class RouteMonitor:
121
165
  COMMENT='API请求详细日志表';
122
166
  """)
123
167
 
168
+ logger.debug("✅ api_request_logs 表创建/验证成功", {
169
+ "表名": "api_request_logs",
170
+ "用途": "API请求详细日志"
171
+ })
172
+
124
173
  # 创建访问统计汇总表
125
174
  cursor.execute("""
126
175
  CREATE TABLE IF NOT EXISTS `api_access_statistics` (
@@ -151,6 +200,11 @@ class RouteMonitor:
151
200
  COMMENT='API访问统计汇总表';
152
201
  """)
153
202
 
203
+ logger.debug("✅ api_access_statistics 表创建/验证成功", {
204
+ "表名": "api_access_statistics",
205
+ "用途": "API访问统计汇总"
206
+ })
207
+
154
208
  # 创建IP访问统计表
155
209
  cursor.execute("""
156
210
  CREATE TABLE IF NOT EXISTS `ip_access_statistics` (
@@ -179,6 +233,11 @@ class RouteMonitor:
179
233
  COMMENT='IP访问统计表';
180
234
  """)
181
235
 
236
+ logger.debug("✅ ip_access_statistics 表创建/验证成功", {
237
+ "表名": "ip_access_statistics",
238
+ "用途": "IP访问统计"
239
+ })
240
+
182
241
  # 创建系统性能统计表
183
242
  cursor.execute("""
184
243
  CREATE TABLE IF NOT EXISTS `system_performance_stats` (
@@ -198,10 +257,27 @@ class RouteMonitor:
198
257
  COMMENT='系统性能统计表';
199
258
  """)
200
259
 
260
+ logger.debug("✅ system_performance_stats 表创建/验证成功", {
261
+ "表名": "system_performance_stats",
262
+ "用途": "系统性能统计"
263
+ })
264
+
201
265
  connection.commit()
266
+ logger.info("🎯 所有数据库表结构初始化完成", {
267
+ "创建表数": 4,
268
+ "操作状态": "成功",
269
+ "数据库引擎": "InnoDB"
270
+ })
271
+
202
272
  finally:
203
273
  connection.close()
274
+
204
275
  except Exception as e:
276
+ logger.error("❌ 数据库表结构初始化失败", {
277
+ "错误信息": str(e),
278
+ "错误类型": type(e).__name__,
279
+ "影响": "监控系统可能无法正常工作"
280
+ })
205
281
  # 静默处理初始化错误,避免影响主应用
206
282
  pass
207
283
 
@@ -376,9 +452,24 @@ class RouteMonitor:
376
452
  # 设置请求ID到全局变量中,供后续使用
377
453
  g.request_id = request_id
378
454
 
455
+ logger.debug("📋 开始收集请求数据", {
456
+ "请求ID": request_id,
457
+ "请求方法": request.method,
458
+ "端点": request.endpoint or request.path,
459
+ "客户端IP": request.remote_addr
460
+ })
461
+
379
462
  # 获取真实IP
380
463
  real_ip, forwarded_ips = self.get_real_ip(request)
381
464
 
465
+ if real_ip != request.remote_addr:
466
+ logger.debug("🔍 检测到IP转发", {
467
+ "请求ID": request_id,
468
+ "原始IP": request.remote_addr,
469
+ "真实IP": real_ip,
470
+ "转发链长度": len(forwarded_ips) if forwarded_ips else 0
471
+ })
472
+
382
473
  # 获取请求头信息
383
474
  headers = dict(request.headers)
384
475
  sanitized_headers = self.sanitize_data(headers)
@@ -405,11 +496,25 @@ class RouteMonitor:
405
496
  request_body = body_data.decode('utf-8')
406
497
  except UnicodeDecodeError:
407
498
  request_body = f"[BINARY_DATA:{len(body_data)}_bytes]"
499
+ logger.debug("📁 检测到二进制数据", {
500
+ "请求ID": request_id,
501
+ "数据大小": len(body_data),
502
+ "处理方式": "标记为二进制"
503
+ })
408
504
 
409
505
  if request_body:
410
506
  request_size = len(str(request_body).encode('utf-8'))
411
- except Exception:
507
+ logger.debug("📊 请求体信息", {
508
+ "请求ID": request_id,
509
+ "数据类型": "JSON" if request.is_json else "表单" if request.form else "文本",
510
+ "大小": f"{request_size} bytes"
511
+ })
512
+ except Exception as e:
412
513
  request_body = "[ERROR_READING_BODY]"
514
+ logger.warning("⚠️ 读取请求体失败", {
515
+ "请求ID": request_id,
516
+ "错误": str(e)
517
+ })
413
518
 
414
519
  # 清理敏感数据
415
520
  sanitized_body = self.sanitize_data(request_body)
@@ -419,6 +524,20 @@ class RouteMonitor:
419
524
  user_agent = request.headers.get('User-Agent', '')
420
525
  device_info = self.extract_device_info(user_agent)
421
526
 
527
+ if device_info['is_bot']:
528
+ logger.debug("🤖 检测到机器人请求", {
529
+ "请求ID": request_id,
530
+ "用户代理": user_agent[:100] + "..." if len(user_agent) > 100 else user_agent,
531
+ "IP": real_ip
532
+ })
533
+
534
+ if device_info['is_mobile']:
535
+ logger.debug("📱 检测到移动设备请求", {
536
+ "请求ID": request_id,
537
+ "操作系统": device_info['os_name'],
538
+ "浏览器": device_info['browser_name']
539
+ })
540
+
422
541
  # URL解析
423
542
  parsed_url = urlparse(request.url)
424
543
 
@@ -457,6 +576,14 @@ class RouteMonitor:
457
576
  'os_version': device_info['os_version'],
458
577
  }
459
578
 
579
+ logger.debug("✅ 请求数据收集完成", {
580
+ "请求ID": request_id,
581
+ "数据字段数": len(request_data),
582
+ "请求大小": f"{request_size} bytes",
583
+ "设备类型": "移动" if device_info['is_mobile'] else "桌面",
584
+ "是否机器人": device_info['is_bot']
585
+ })
586
+
460
587
  return request_data
461
588
 
462
589
  def mask_token(self, token: str) -> str:
@@ -471,11 +598,20 @@ class RouteMonitor:
471
598
 
472
599
  def save_request_log(self, request_data: Dict[str, Any], response_data: Dict[str, Any] = None):
473
600
  """保存请求日志到数据库"""
601
+ request_id = request_data.get('request_id', 'unknown')
602
+
474
603
  try:
475
604
  # 合并响应数据
476
605
  if response_data:
477
606
  request_data.update(response_data)
478
607
 
608
+ logger.debug("💾 保存请求日志到数据库", {
609
+ "请求ID": request_id,
610
+ "端点": request_data.get('endpoint', ''),
611
+ "状态码": request_data.get('response_status', '未知'),
612
+ "处理时间": f"{request_data.get('process_time', 0)}ms"
613
+ })
614
+
479
615
  connection = self.pool.connection()
480
616
  try:
481
617
  with connection.cursor() as cursor:
@@ -490,16 +626,40 @@ class RouteMonitor:
490
626
 
491
627
  cursor.execute(sql, list(request_data.values()))
492
628
  connection.commit()
629
+
630
+ logger.debug("✅ 请求日志保存成功", {
631
+ "请求ID": request_id,
632
+ "写入状态": "成功",
633
+ "数据库表": "api_request_logs"
634
+ })
635
+
493
636
  finally:
494
637
  connection.close()
495
638
 
496
639
  except Exception as e:
640
+ logger.error("❌ 保存请求日志失败", {
641
+ "请求ID": request_id,
642
+ "错误信息": str(e),
643
+ "错误类型": type(e).__name__,
644
+ "影响": "日志丢失,但不影响主业务"
645
+ })
497
646
  # 静默处理错误,不影响主业务
498
647
  pass
499
648
 
500
649
  def update_statistics(self, request_data: Dict[str, Any]):
501
650
  """更新统计数据"""
651
+ request_id = request_data.get('request_id', 'unknown')
652
+ endpoint = request_data.get('endpoint', '')
653
+ status_code = request_data.get('response_status', 500)
654
+
502
655
  try:
656
+ logger.debug("📈 更新统计数据", {
657
+ "请求ID": request_id,
658
+ "端点": endpoint,
659
+ "状态码": status_code,
660
+ "统计类型": "API访问统计和IP统计"
661
+ })
662
+
503
663
  connection = self.pool.connection()
504
664
  try:
505
665
  with connection.cursor() as cursor:
@@ -552,10 +712,24 @@ class RouteMonitor:
552
712
  ))
553
713
 
554
714
  connection.commit()
715
+
716
+ logger.debug("✅ 统计数据更新成功", {
717
+ "请求ID": request_id,
718
+ "更新表": "api_access_statistics, ip_access_statistics",
719
+ "日期": str(date),
720
+ "小时": hour
721
+ })
722
+
555
723
  finally:
556
724
  connection.close()
557
725
 
558
726
  except Exception as e:
727
+ logger.error("❌ 更新统计数据失败", {
728
+ "请求ID": request_id,
729
+ "错误信息": str(e),
730
+ "错误类型": type(e).__name__,
731
+ "影响": "统计数据缺失,但不影响主业务"
732
+ })
559
733
  # 静默处理错误
560
734
  pass
561
735
 
@@ -569,6 +743,15 @@ class RouteMonitor:
569
743
 
570
744
  # 收集请求数据
571
745
  request_data = self.collect_request_data(request)
746
+ request_id = request_data.get('request_id', 'unknown')
747
+
748
+ logger.debug("🎯 开始监控请求", {
749
+ "请求ID": request_id,
750
+ "函数名": func.__name__,
751
+ "端点": request_data.get('endpoint', ''),
752
+ "方法": request_data.get('method', ''),
753
+ "来源IP": request_data.get('real_ip', request_data.get('client_ip'))
754
+ })
572
755
 
573
756
  try:
574
757
  # 执行原函数
@@ -578,12 +761,24 @@ class RouteMonitor:
578
761
  end_time = time.time()
579
762
  process_time = round((end_time - start_time) * 1000, 3)
580
763
 
764
+ response_status = getattr(response, 'status_code', 200) if hasattr(response, 'status_code') else 200
765
+ response_size = len(str(response.get_data() if hasattr(response, 'get_data') else ''))
766
+
581
767
  response_data = {
582
- 'response_status': getattr(response, 'status_code', 200) if hasattr(response, 'status_code') else 200,
768
+ 'response_status': response_status,
583
769
  'process_time': process_time,
584
- 'response_size': len(str(response.get_data() if hasattr(response, 'get_data') else ''))
770
+ 'response_size': response_size
585
771
  }
586
772
 
773
+ logger.debug("✅ 请求处理完成", {
774
+ "请求ID": request_id,
775
+ "函数名": func.__name__,
776
+ "状态码": response_status,
777
+ "处理时间": f"{process_time}ms",
778
+ "响应大小": f"{response_size} bytes",
779
+ "结果": "成功"
780
+ })
781
+
587
782
  # 保存日志
588
783
  self.save_request_log(request_data, response_data)
589
784
 
@@ -605,6 +800,15 @@ class RouteMonitor:
605
800
  'response_size': 0
606
801
  }
607
802
 
803
+ logger.error("❌ 请求处理异常", {
804
+ "请求ID": request_id,
805
+ "函数名": func.__name__,
806
+ "错误信息": str(e),
807
+ "错误类型": type(e).__name__,
808
+ "处理时间": f"{process_time}ms",
809
+ "结果": "异常"
810
+ })
811
+
608
812
  # 保存错误日志
609
813
  self.save_request_log(request_data, error_data)
610
814
 
@@ -620,12 +824,23 @@ class RouteMonitor:
620
824
  def get_statistics_summary(self, days: int = 7) -> Dict[str, Any]:
621
825
  """获取统计摘要"""
622
826
  try:
827
+ logger.debug("📊 开始获取统计摘要", {
828
+ "查询天数": days,
829
+ "操作": "统计数据查询"
830
+ })
831
+
623
832
  connection = self.pool.connection()
624
833
  try:
625
834
  with connection.cursor() as cursor:
626
835
  end_date = datetime.now().date()
627
836
  start_date = end_date - timedelta(days=days)
628
837
 
838
+ logger.debug("📅 统计查询时间范围", {
839
+ "开始日期": str(start_date),
840
+ "结束日期": str(end_date),
841
+ "查询天数": days
842
+ })
843
+
629
844
  # 总体统计
630
845
  cursor.execute("""
631
846
  SELECT
@@ -640,6 +855,14 @@ class RouteMonitor:
640
855
 
641
856
  summary = cursor.fetchone() or {}
642
857
 
858
+ logger.debug("📈 总体统计查询完成", {
859
+ "总请求数": summary.get('total_requests', 0),
860
+ "成功请求数": summary.get('success_requests', 0),
861
+ "错误请求数": summary.get('error_requests', 0),
862
+ "平均响应时间": f"{summary.get('avg_response_time', 0):.2f}ms",
863
+ "唯一端点数": summary.get('unique_endpoints', 0)
864
+ })
865
+
643
866
  # 热门端点
644
867
  cursor.execute("""
645
868
  SELECT endpoint, SUM(total_requests) as requests
@@ -652,6 +875,12 @@ class RouteMonitor:
652
875
 
653
876
  top_endpoints = cursor.fetchall()
654
877
 
878
+ logger.debug("🔥 热门端点查询完成", {
879
+ "查询结果数": len(top_endpoints),
880
+ "最热门端点": top_endpoints[0]['endpoint'] if top_endpoints else "无数据",
881
+ "最高请求数": top_endpoints[0]['requests'] if top_endpoints else 0
882
+ })
883
+
655
884
  # 活跃IP统计
656
885
  cursor.execute("""
657
886
  SELECT COUNT(DISTINCT ip_address) as unique_ips,
@@ -662,16 +891,36 @@ class RouteMonitor:
662
891
 
663
892
  ip_stats = cursor.fetchone() or {}
664
893
 
665
- return {
894
+ logger.debug("🌐 IP统计查询完成", {
895
+ "唯一IP数": ip_stats.get('unique_ips', 0),
896
+ "IP总请求数": ip_stats.get('total_ip_requests', 0)
897
+ })
898
+
899
+ result = {
666
900
  'period': f'{start_date} to {end_date}',
667
901
  'summary': summary,
668
902
  'top_endpoints': top_endpoints,
669
903
  'ip_statistics': ip_stats
670
904
  }
905
+
906
+ logger.debug("✅ 统计摘要获取成功", {
907
+ "查询天数": days,
908
+ "数据完整性": "完整",
909
+ "结果状态": "成功"
910
+ })
911
+
912
+ return result
913
+
671
914
  finally:
672
915
  connection.close()
673
916
 
674
917
  except Exception as e:
918
+ logger.error("❌ 获取统计摘要失败", {
919
+ "查询天数": days,
920
+ "错误信息": str(e),
921
+ "错误类型": type(e).__name__,
922
+ "影响": "统计摘要不可用"
923
+ })
675
924
  return {'error': str(e)}
676
925
 
677
926
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mdbq
3
- Version: 4.0.81
3
+ Version: 4.0.82
4
4
  Home-page: https://pypi.org/project/mdbq
5
5
  Author: xigua,
6
6
  Author-email: 2587125111@qq.com
@@ -1,5 +1,5 @@
1
1
  mdbq/__init__.py,sha256=Il5Q9ATdX8yXqVxtP_nYqUhExzxPC_qk_WXQ_4h0exg,16
2
- mdbq/__version__.py,sha256=YD3cYAm7S88cVN3ILcavwg3szxLssbqiRKGwLNBkYko,18
2
+ mdbq/__version__.py,sha256=EhiuwCH5w9iu_L2CjC33SiyfBk24L8BEGAIfGV49q3E,18
3
3
  mdbq/log/__init__.py,sha256=Mpbrav0s0ifLL7lVDAuePEi1hJKiSHhxcv1byBKDl5E,15
4
4
  mdbq/log/mylogger.py,sha256=DyBftCMNLe1pTTXsa830pUtDISJxpJHFIradYtE3lFA,26418
5
5
  mdbq/myconf/__init__.py,sha256=jso1oHcy6cJEfa7udS_9uO5X6kZLoPBF8l3wCYmr5dM,18
@@ -23,13 +23,12 @@ mdbq/redis/__init__.py,sha256=YtgBlVSMDphtpwYX248wGge1x-Ex_mMufz4-8W0XRmA,12
23
23
  mdbq/redis/getredis.py,sha256=vpBuNc22uj9Vr-_Dh25_wpwWM1e-072EAAIBdB_IpL0,23494
24
24
  mdbq/route/__init__.py,sha256=M0NZuQ7-112l8K2h1eayVvSmvQrufrOcD5AYKgIf_Is,1
25
25
  mdbq/route/analytics.py,sha256=iJ-LyE_LNICg4LB9XOd0L-N3Ucfl6BWUTVu9jUNAplg,28069
26
- mdbq/route/example.py,sha256=6AlhBXFWCJZlYoPy_LzFBLQ7C_kxx04P3NBWjSy9AJA,12662
27
- mdbq/route/monitor.py,sha256=AOPBQVtqOXkcSH53-cxI6OnLkoFB6Yr8sf2eJZOrjaQ,31531
26
+ mdbq/route/monitor.py,sha256=jO5QnlZeug7SIbwm4DS7dIhfoYu4iF2rVPcoLobg6u4,42194
28
27
  mdbq/route/routes.py,sha256=DHJg0eRNi7TKqhCHuu8ia3vdQ8cTKwrTm6mwDBtNboM,19111
29
28
  mdbq/selenium/__init__.py,sha256=AKzeEceqZyvqn2dEDoJSzDQnbuENkJSHAlbHAD0u0ZI,10
30
29
  mdbq/selenium/get_driver.py,sha256=1NTlVUE6QsyjTrVVVqTO2LOnYf578ccFWlWnvIXGtic,20903
31
30
  mdbq/spider/__init__.py,sha256=RBMFXGy_jd1HXZhngB2T2XTvJqki8P_Fr-pBcwijnew,18
32
- mdbq-4.0.81.dist-info/METADATA,sha256=Dlml8K1UGV80QH9aire0rWLhkZfKFlZmlvUTMCiwlEo,364
33
- mdbq-4.0.81.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
34
- mdbq-4.0.81.dist-info/top_level.txt,sha256=2FQ-uLnCSB-OwFiWntzmwosW3X2Xqsg0ewh1axsaylA,5
35
- mdbq-4.0.81.dist-info/RECORD,,
31
+ mdbq-4.0.82.dist-info/METADATA,sha256=jwoqL8TsKwNR_JEcxHOS1UMy4i0cVvHRJs-orjOdy6I,364
32
+ mdbq-4.0.82.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
33
+ mdbq-4.0.82.dist-info/top_level.txt,sha256=2FQ-uLnCSB-OwFiWntzmwosW3X2Xqsg0ewh1axsaylA,5
34
+ mdbq-4.0.82.dist-info/RECORD,,
mdbq/route/example.py DELETED
@@ -1,378 +0,0 @@
1
- """
2
- 路由监控系统集成示例
3
- 展示如何在现有的Flask应用中集成路由监控功能
4
-
5
- 重点:批量装饰器应用 - 无需手动为每个函数添加装饰器!
6
-
7
- 使用方法:
8
- 1. 导入监控模块
9
- 2. 定义需要监控的路由列表
10
- 3. 批量应用装饰器
11
- 4. 可选择性地添加全局监控
12
-
13
- """
14
-
15
- # ========================================
16
- # 方法1:批量装饰器应用(强烈推荐)
17
- # ========================================
18
-
19
- from monitor import monitor_request, get_request_id, get_statistics_summary
20
- from routes import register_routes
21
-
22
- # 在 dpflask.py 文件末尾添加以下代码:
23
-
24
- # 第一步:定义需要监控的路由函数名列表
25
- MONITORED_ROUTES = [
26
- # DeepSeek相关接口
27
- 'deepseek_request', # 主要接口
28
- 'deepseek_public_key', # 获取公钥接口
29
- 'deepseek_update', # 更新日志接口
30
- 'deepseek_feedback', # 客户端反馈接口
31
- 'deepseek_chat_history', # 加载历史记录接口
32
- 'deepseek_client_id_save_user_info', # 存储client id
33
- 'deepseek_client_id_auth_user_info', # 校检client id
34
-
35
- # 生意参谋相关接口
36
- 'sycm_access_control_info', # 访问控制信息
37
- 'sycm_load_userinfo', # 用户信息加载
38
- 'sycm_list_database', # 数据库列表
39
- 'sycm_list_tables', # 数据表列表
40
- 'sycm_view_table', # 查看表数据
41
- ]
42
-
43
- # 第二步:批量应用监控装饰器的函数
44
- def apply_monitor_to_routes(app_globals, route_names):
45
- """
46
- 为指定的路由函数批量添加监控装饰器
47
-
48
- 优势:
49
- - 无需手动修改每个函数
50
- - 统一管理监控配置
51
- - 避免遗漏或重复
52
- - 便于维护
53
- """
54
- applied_count = 0
55
- skipped_count = 0
56
-
57
- print("🚀 开始批量应用监控装饰器...")
58
-
59
- for route_name in route_names:
60
- if route_name in app_globals and callable(app_globals[route_name]):
61
- # 检查是否已经添加过监控装饰器
62
- if not hasattr(app_globals[route_name], '_is_monitored'):
63
- # 应用监控装饰器
64
- app_globals[route_name] = monitor_request(app_globals[route_name])
65
- app_globals[route_name]._is_monitored = True
66
- applied_count += 1
67
- print(f" ✅ 已为 {route_name} 添加监控")
68
- else:
69
- skipped_count += 1
70
- print(f" ⚠️ {route_name} 已经有监控装饰器,跳过")
71
- else:
72
- print(f" ❌ 未找到函数: {route_name}")
73
-
74
- print(f"📊 批量装饰器应用完成:")
75
- print(f" - 成功添加: {applied_count} 个")
76
- print(f" - 已存在跳过: {skipped_count} 个")
77
- print(f" - 总计处理: {len(route_names)} 个")
78
-
79
- # 第三步:执行批量应用(在 dpflask.py 文件最后添加)
80
- """
81
- # 批量应用监控装饰器
82
- apply_monitor_to_routes(globals(), MONITORED_ROUTES)
83
-
84
- # 注册管理界面路由
85
- register_routes(app)
86
-
87
- print("🎯 路由监控系统初始化完成!")
88
- """
89
-
90
- # ========================================
91
- # 方法2:按模式自动应用(更智能)
92
- # ========================================
93
-
94
- def auto_apply_monitor_by_pattern(app_globals, pattern_prefixes=None, exclude_patterns=None):
95
- """
96
- 根据函数名模式自动添加监控装饰器
97
-
98
- Args:
99
- pattern_prefixes: 匹配的函数名前缀,如 ['deepseek_', 'sycm_']
100
- exclude_patterns: 排除的模式,如 ['_test', '_internal']
101
- """
102
- if pattern_prefixes is None:
103
- pattern_prefixes = ['deepseek_', 'sycm_', 'api_']
104
-
105
- if exclude_patterns is None:
106
- exclude_patterns = ['_test', '_internal', '_helper', '_debug']
107
-
108
- applied_count = 0
109
-
110
- print("🔍 开始自动扫描并应用监控装饰器...")
111
-
112
- for name, obj in app_globals.items():
113
- # 检查是否为函数且符合命名模式
114
- if callable(obj) and any(name.startswith(prefix) for prefix in pattern_prefixes):
115
- # 检查是否需要排除
116
- if any(exclude in name for exclude in exclude_patterns):
117
- print(f" 🚫 跳过排除的函数: {name}")
118
- continue
119
-
120
- # 检查是否已经有监控装饰器
121
- if not hasattr(obj, '_is_monitored'):
122
- app_globals[name] = monitor_request(obj)
123
- app_globals[name]._is_monitored = True
124
- applied_count += 1
125
- print(f" ✅ 自动为 {name} 添加监控")
126
-
127
- print(f"🎯 自动扫描完成,为 {applied_count} 个路由添加了监控")
128
-
129
- # 使用自动模式的示例:
130
- """
131
- # 自动为所有以 deepseek_ 和 sycm_ 开头的函数添加监控
132
- auto_apply_monitor_by_pattern(globals(),
133
- pattern_prefixes=['deepseek_', 'sycm_'],
134
- exclude_patterns=['_test', '_internal', '_debug']
135
- )
136
- """
137
-
138
- # ========================================
139
- # 方法3:环境感知的监控配置(生产级)
140
- # ========================================
141
-
142
- import os
143
-
144
- class MonitorConfig:
145
- """监控配置管理类 - 根据环境应用不同的监控策略"""
146
-
147
- # 核心业务接口(所有环境都监控)
148
- CRITICAL_ROUTES = [
149
- 'deepseek_request',
150
- 'sycm_list_database',
151
- 'sycm_view_table',
152
- ]
153
-
154
- # 重要接口(生产和测试环境监控)
155
- IMPORTANT_ROUTES = [
156
- 'deepseek_public_key',
157
- 'deepseek_chat_history',
158
- 'sycm_load_userinfo',
159
- 'sycm_list_tables',
160
- ]
161
-
162
- # 辅助接口(仅生产环境监控)
163
- AUXILIARY_ROUTES = [
164
- 'deepseek_update',
165
- 'deepseek_feedback',
166
- 'sycm_access_control_info',
167
- 'deepseek_client_id_save_user_info',
168
- 'deepseek_client_id_auth_user_info',
169
- ]
170
-
171
- @classmethod
172
- def apply_monitoring(cls, app_globals, environment=None):
173
- """
174
- 根据环境应用相应的监控策略
175
-
176
- Args:
177
- environment: 'production', 'staging', 'development' 或 None(自动检测)
178
- """
179
- if environment is None:
180
- environment = os.getenv('FLASK_ENV', 'development')
181
-
182
- routes_to_monitor = []
183
-
184
- # 根据环境确定监控范围
185
- if environment == 'production':
186
- routes_to_monitor.extend(cls.CRITICAL_ROUTES)
187
- routes_to_monitor.extend(cls.IMPORTANT_ROUTES)
188
- routes_to_monitor.extend(cls.AUXILIARY_ROUTES)
189
- print("🔥 生产环境:启用完整监控")
190
-
191
- elif environment == 'staging':
192
- routes_to_monitor.extend(cls.CRITICAL_ROUTES)
193
- routes_to_monitor.extend(cls.IMPORTANT_ROUTES)
194
- print("🧪 测试环境:启用重要接口监控")
195
-
196
- else: # development
197
- routes_to_monitor.extend(cls.CRITICAL_ROUTES)
198
- print("🔧 开发环境:仅监控核心接口")
199
-
200
- # 应用监控
201
- apply_monitor_to_routes(app_globals, routes_to_monitor)
202
- print(f"📊 {environment} 环境监控配置已应用")
203
-
204
- # 环境感知监控的使用示例:
205
- """
206
- # 在 dpflask.py 文件末尾添加:
207
-
208
- # 根据环境自动应用监控配置
209
- MonitorConfig.apply_monitoring(globals())
210
-
211
- # 手动指定环境
212
- # MonitorConfig.apply_monitoring(globals(), 'production')
213
-
214
- # 注册管理界面
215
- register_routes(app)
216
- """
217
-
218
- # ========================================
219
- # 方法4:带条件的智能监控(高级用法)
220
- # ========================================
221
-
222
- def conditional_monitor_routes(app_globals, route_conditions):
223
- """
224
- 根据条件应用监控装饰器
225
-
226
- Args:
227
- route_conditions: 字典,格式为 {函数名: 条件函数}
228
- """
229
- applied_count = 0
230
-
231
- for route_name, condition_func in route_conditions.items():
232
- if route_name in app_globals and callable(app_globals[route_name]):
233
- if condition_func():
234
- if not hasattr(app_globals[route_name], '_is_monitored'):
235
- app_globals[route_name] = monitor_request(app_globals[route_name])
236
- app_globals[route_name]._is_monitored = True
237
- applied_count += 1
238
- print(f" ✅ 条件满足,为 {route_name} 添加监控")
239
- else:
240
- print(f" ⚠️ {route_name} 已有监控装饰器")
241
- else:
242
- print(f" 🚫 条件不满足,跳过 {route_name}")
243
-
244
- print(f"🎯 条件监控应用完成,处理了 {applied_count} 个路由")
245
-
246
- # 条件监控示例:
247
- """
248
- # 定义条件函数
249
- def is_production():
250
- return os.getenv('FLASK_ENV') == 'production'
251
-
252
- def is_debug_enabled():
253
- return os.getenv('DEBUG', '').lower() == 'true'
254
-
255
- # 定义条件监控规则
256
- CONDITIONAL_ROUTES = {
257
- 'deepseek_request': lambda: True, # 总是监控
258
- 'deepseek_update': is_production, # 仅生产环境监控
259
- 'sycm_view_table': is_production, # 仅生产环境监控
260
- 'debug_endpoint': is_debug_enabled, # 仅调试模式监控
261
- }
262
-
263
- # 应用条件监控
264
- conditional_monitor_routes(globals(), CONDITIONAL_ROUTES)
265
- """
266
-
267
- # ========================================
268
- # 完整的集成示例代码
269
- # ========================================
270
-
271
- COMPLETE_INTEGRATION_EXAMPLE = '''
272
- # ================================================
273
- # 在 dpflask.py 文件末尾添加以下完整代码
274
- # ================================================
275
-
276
- # 1. 导入监控模块
277
- from route.monitor import monitor_request, get_request_id, get_statistics_summary
278
- from route.routes import register_routes
279
- import os
280
-
281
- # 2. 批量装饰器应用函数
282
- def apply_monitor_to_routes(app_globals, route_names):
283
- """批量为路由函数添加监控装饰器"""
284
- applied_count = 0
285
- for route_name in route_names:
286
- if route_name in app_globals and callable(app_globals[route_name]):
287
- if not hasattr(app_globals[route_name], '_is_monitored'):
288
- app_globals[route_name] = monitor_request(app_globals[route_name])
289
- app_globals[route_name]._is_monitored = True
290
- applied_count += 1
291
- print(f"✅ 已为 {route_name} 添加监控")
292
- print(f"🎯 总计为 {applied_count} 个路由添加了监控")
293
-
294
- # 3. 定义需要监控的路由列表
295
- MONITORED_ROUTES = [
296
- 'deepseek_request',
297
- 'deepseek_public_key',
298
- 'deepseek_chat_history',
299
- 'sycm_list_database',
300
- 'sycm_view_table',
301
- # 根据需要添加更多路由
302
- ]
303
-
304
- # 4. 应用监控
305
- print("🚀 正在初始化路由监控系统...")
306
- apply_monitor_to_routes(globals(), MONITORED_ROUTES)
307
-
308
- # 5. 注册管理界面
309
- register_routes(app)
310
-
311
- # 6. 完成提示
312
- current_env = os.getenv('FLASK_ENV', 'development')
313
- print(f"✨ 路由监控系统初始化完成!")
314
- print(f"🔧 当前环境: {current_env}")
315
- print(f"📊 管理界面: http://localhost:5000/admin/monitor/dashboard")
316
-
317
- # 可选:添加一些简单的管理接口
318
- @app.route('/admin/monitor/stats', methods=['GET'])
319
- def get_monitor_stats():
320
- """获取监控统计信息"""
321
- try:
322
- days = request.args.get('days', 7, type=int)
323
- stats = get_statistics_summary(days)
324
- return jsonify({
325
- 'code': 0,
326
- 'status': 'success',
327
- 'data': stats
328
- })
329
- except Exception as e:
330
- return jsonify({
331
- 'code': 500,
332
- 'status': 'error',
333
- 'message': str(e)
334
- }), 500
335
- '''
336
-
337
- # ========================================
338
- # 总结说明
339
- # ========================================
340
-
341
- print("""
342
- 🎯 批量装饰器的核心优势:
343
-
344
- 1. ✅ 无需手动修改每个函数定义
345
- - 原始函数保持不变
346
- - 所有装饰器在一个地方统一管理
347
-
348
- 2. ✅ 灵活的监控策略
349
- - 可以根据环境启用不同的监控范围
350
- - 支持条件性监控
351
- - 便于测试和调试
352
-
353
- 3. ✅ 维护性强
354
- - 新增监控只需在列表中添加函数名
355
- - 移除监控只需从列表中删除
356
- - 避免在代码中到处添加装饰器
357
-
358
- 4. ✅ 性能优化
359
- - 避免重复装饰
360
- - 自动检测已有装饰器
361
- - 支持条件性启用
362
-
363
- 📋 推荐使用方式:
364
- - 开发阶段:使用方法1(明确的函数名列表)
365
- - 生产环境:使用方法3(环境感知配置)
366
- - 大型项目:结合多种方法,分模块管理
367
-
368
- 🔧 集成步骤:
369
- 1. 复制 COMPLETE_INTEGRATION_EXAMPLE 中的代码
370
- 2. 添加到 dpflask.py 文件末尾
371
- 3. 根据需要调整 MONITORED_ROUTES 列表
372
- 4. 重启应用即可生效
373
-
374
- 这样就实现了批量添加监控装饰器,无需手动修改每个函数!
375
- """)
376
-
377
- if __name__ == "__main__":
378
- print(COMPLETE_INTEGRATION_EXAMPLE)
File without changes