mdbq 3.9.5__py3-none-any.whl → 3.9.7__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 = '3.9.5'
1
+ VERSION = '3.9.7'
@@ -3,10 +3,12 @@ import logging.handlers
3
3
  import datetime
4
4
  import json
5
5
  import os
6
+ import sys
6
7
  import time
7
8
  import threading
8
9
  import queue
9
10
  from typing import Optional, Dict, Any, List, Callable, Union
11
+ import atexit
10
12
 
11
13
  try:
12
14
  import psutil
@@ -49,7 +51,7 @@ class MyLogger:
49
51
 
50
52
  def __init__(
51
53
  self,
52
- name: str = 'mlogger',
54
+ name: str = 'mylogger.log',
53
55
  logging_mode: str = 'console', # 'both', 'console', 'file', 'none'
54
56
  log_level: str = 'INFO', # 'DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'
55
57
  log_file: str = 'm_app.log',
@@ -63,7 +65,8 @@ class MyLogger:
63
65
  filters: Optional[List[Callable]] = None,
64
66
  enable_metrics: bool = False,
65
67
  metrics_interval: int = 300,
66
- message_limited: int = 1000
68
+ message_limited: int = 1000,
69
+ flush_interval: int = 5
67
70
  ):
68
71
  """
69
72
  初始化日志记录器
@@ -82,11 +85,15 @@ class MyLogger:
82
85
  :param enable_metrics: 是否启用系统指标采集
83
86
  :param metrics_interval: 指标采集间隔(秒)
84
87
  :param message_limited: 简化日志内容,避免过长
88
+ :param flush_interval: 定时刷新日志器间隔(秒)
85
89
  """
90
+ log_path = os.path.join(os.path.expanduser("~"), 'logfile')
86
91
  self.name = name
87
92
  self.logging_mode = logging_mode.lower()
88
93
  self.log_level = log_level.upper()
89
- self.log_file = log_file
94
+ self.log_file = os.path.join(log_path, log_file)
95
+ if not os.path.isdir(os.path.dirname(self.log_file)):
96
+ os.makedirs(os.path.dirname(self.log_file))
90
97
  self.log_format = log_format
91
98
  self.max_log_size = max_log_size
92
99
  self.backup_count = backup_count
@@ -98,6 +105,7 @@ class MyLogger:
98
105
  self.enable_metrics = enable_metrics and HAS_PSUTIL
99
106
  self.metrics_interval = metrics_interval
100
107
  self.message_limited = message_limited
108
+ self.flush_interval = flush_interval
101
109
 
102
110
  # 上下文相关
103
111
  self._context = threading.local()
@@ -112,6 +120,10 @@ class MyLogger:
112
120
  self._async_thread = None
113
121
  self._stop_event = threading.Event()
114
122
 
123
+ # 定时刷新相关
124
+ self._flush_thread = None
125
+ self._last_flush_time = 0
126
+
115
127
  # 创建日志记录器
116
128
  self.logger = logging.getLogger(name)
117
129
  self._init_logging()
@@ -119,6 +131,8 @@ class MyLogger:
119
131
  if self.enable_async:
120
132
  self._start_async_logging()
121
133
 
134
+ atexit.register(self.shutdown)
135
+
122
136
  def __enter__(self):
123
137
  """上下文管理器入口"""
124
138
  return self
@@ -205,11 +219,12 @@ class MyLogger:
205
219
  'timestamp': datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
206
220
  'level': record.levelname,
207
221
  'message': record.getMessage(),
208
- 'module': record.module,
222
+ # 'module': record.module,
209
223
  'function': record.funcName,
210
- 'line': record.lineno,
211
- 'thread': record.threadName,
212
- 'process': record.processName,
224
+ # 'line': record.lineno,
225
+ # 'thread': record.threadName,
226
+ # 'process': record.processName,
227
+ 'name': record.name,
213
228
  }
214
229
 
215
230
  # 添加额外字段
@@ -252,7 +267,8 @@ class MyLogger:
252
267
  filename=self.log_file,
253
268
  maxBytes=self.max_log_size * 1024 * 1024,
254
269
  backupCount=self.backup_count,
255
- encoding='utf-8'
270
+ encoding='utf-8',
271
+ delay=False
256
272
  )
257
273
  file_handler.setFormatter(formatter)
258
274
  self.logger.addHandler(file_handler)
@@ -429,13 +445,23 @@ class MyLogger:
429
445
  """关闭日志记录器,确保所有日志被刷新"""
430
446
  if self.enable_async:
431
447
  self._stop_event.set()
448
+ # 等待队列清空
449
+ while not self._log_queue.empty():
450
+ time.sleep(0.1)
432
451
  if self._async_thread and self._async_thread.is_alive():
433
- self._async_thread.join(timeout=5)
452
+ self._async_thread.join(timeout=2)
453
+ if self._flush_thread and self._flush_thread.is_alive():
454
+ self._flush_thread.join(timeout=2)
434
455
 
435
456
  # 确保所有handler被刷新
457
+ self._flush_handlers()
458
+
459
+ # 关闭所有handler
436
460
  for handler in self.logger.handlers:
437
- handler.flush()
438
- handler.close()
461
+ try:
462
+ handler.close()
463
+ except:
464
+ pass
439
465
 
440
466
  def debug(self, message: str, extra: Optional[Dict] = None):
441
467
  """记录调试信息"""
@@ -461,10 +487,43 @@ class MyLogger:
461
487
  """记录异常信息"""
462
488
  if not extra:
463
489
  extra = {}
464
- extra['异常'] = str(exc_info)
465
- extra['类型'] = exc_info.__class__.__name__
490
+ # # 获取异常发生的实际位置
491
+ # tb = exc_info.__traceback__
492
+ #
493
+ # if tb:
494
+ # extra.update({
495
+ # 'module': tb.tb_frame.f_globals.get('__name__', ''),
496
+ # 'function': tb.tb_frame.f_code.co_name,
497
+ # 'line': tb.tb_lineno,
498
+ # 'file': tb.tb_frame.f_code.co_filename
499
+ # })
500
+ # extra['异常'] = str(exc_info)
501
+ # extra['类型'] = exc_info.__class__.__name__
502
+ # self.log('error', message, extra)
503
+
504
+ # 获取完整的异常堆栈
505
+ tb = exc_info.__traceback__
506
+ while tb.tb_next:
507
+ tb = tb.tb_next # 获取最内层的堆栈帧
508
+
509
+ extra.update({
510
+ 'module': tb.tb_frame.f_globals.get('__name__', ''),
511
+ 'function': tb.tb_frame.f_code.co_name,
512
+ 'line': tb.tb_lineno,
513
+ 'file': tb.tb_frame.f_code.co_filename,
514
+ '异常': str(exc_info),
515
+ '类型': exc_info.__class__.__name__,
516
+ '堆栈': self._format_traceback(exc_info)
517
+ })
518
+
519
+ # 直接使用logger的error方法记录,保留原始调用栈
466
520
  self.log('error', message, extra)
467
521
 
522
+ def _format_traceback(self, exc_info):
523
+ """格式化异常堆栈"""
524
+ import traceback
525
+ return ''.join(traceback.format_exception(type(exc_info), exc_info, exc_info.__traceback__))
526
+
468
527
  def timeit(self, message: str = "Execution time"):
469
528
  """返回一个计时器上下文管理器"""
470
529
  return self._Timer(self, message)
@@ -485,6 +544,40 @@ class MyLogger:
485
544
  extra={'elapsed_seconds': elapsed})
486
545
  return False
487
546
 
547
+ def _start_flush_thread(self):
548
+ """启动定时刷新线程"""
549
+ self._stop_event.clear()
550
+ self._flush_thread = threading.Thread(
551
+ target=self._flush_worker,
552
+ name=f"{self.name}_flush_thread",
553
+ daemon=True
554
+ )
555
+ self._flush_thread.start()
556
+
557
+ def _flush_worker(self):
558
+ """定时刷新工作线程"""
559
+ while not self._stop_event.is_set():
560
+ try:
561
+ time.sleep(self.flush_interval)
562
+ self._flush_handlers()
563
+ except Exception as e:
564
+ try:
565
+ self.logger.error(f"刷新线程异常: {e}",
566
+ extra={'extra_data': {'flush_error': str(e)}})
567
+ except:
568
+ pass
569
+
570
+ def _flush_handlers(self):
571
+ """刷新所有handler"""
572
+ for handler in self.logger.handlers:
573
+ try:
574
+ handler.flush()
575
+ except Exception as e:
576
+ try:
577
+ self.logger.error(f"刷新handler失败: {e}",
578
+ extra={'extra_data': {'handler_flush_error': str(e)}})
579
+ except:
580
+ pass
488
581
 
489
582
  def main():
490
583
  # 创建日志记录器
@@ -493,34 +586,16 @@ def main():
493
586
  logging_mode='both',
494
587
  log_level='DEBUG',
495
588
  log_file='/Users/xigua/Downloads/my_app.log',
496
- log_format='simple',
497
- enable_async=True,
589
+ log_format='json',
590
+ max_log_size=50,
591
+ backup_count=5,
592
+ enable_async=True, # 是否启用异步日志
498
593
  sample_rate=1, # 采样50%的DEBUG/INFO日志
499
- sensitive_fields=['password', 'token'],
500
- enable_metrics=True
594
+ sensitive_fields=[], # 敏感字段列表
595
+ enable_metrics=False, # 是否启用性能指标
501
596
  )
502
597
 
503
- # 添加自定义过滤器
504
- def keyword_filter(level, message, extra):
505
- blocked_keywords = ['secret', 'password']
506
- return not any(keyword in message.lower() for keyword in blocked_keywords)
507
-
508
- logger.add_filter(keyword_filter)
509
-
510
- # 使用上下文管理器
511
- with logger.context(request_id='12345', user='admin'):
512
- logger.info("开始处理请求")
513
-
514
- # 使用计时器
515
- with logger.timeit("数据库查询"):
516
- time.sleep(0.1) # 模拟耗时操作
517
-
518
- logger.debug("调试信息", extra={'data': {'key': 'value'}})
519
-
520
- try:
521
- 1 / 0
522
- except Exception as e:
523
- logger.exception("发生错误", e)
598
+ logger.info('123')
524
599
 
525
600
  # 确保所有日志被刷新
526
601
  logger.shutdown()