跳过正文
  1. Teches/
  2. 程序语言/
  3. python/
  4. 自定模块/

脚本日志

·668 字·4 分钟
目录

print
#

纯print输出
#

通过sys.stdout/sys.stderr重定向输出至文件

</> python
 1import sys
 2class Tee:
 3    """同时重定向 stdout 和 stderr 到文件和终端"""
 4    def __init__(self, filename):
 5        self.file = open(filename, 'a')  # 追加模式
 6        self.stdout = sys.stdout
 7        self.stderr = sys.stderr
 8
 9    def write(self, message):
10        self.file.write(message)
11        self.stdout.write(message)  # 标准输出到终端
12        self.file.flush()          # 确保实时写入文件
13
14    def flush(self):
15        self.file.flush()
16
17# 脚本日志重定向
18sys.stdout = Tee(f"{__file__.split('.')[0]}.log")
19sys.stderr = Tee(f"{__file__.split('.')[0]}.log")

封装print,自定义输出
#

</> python
1from datetime import datetime
2class Logger:
3    def now(self):return datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")
4    def info(self, msg):print(self.now() + ' - INFO - ' + msg)
5    def warning(self, msg):print(self.now() + ' - WARN - ' + msg)
6    def error(self, msg):print(self.now() + ' - ERROR - ' + msg)
7
8logger = Logger()

logging
#

通用代码
#

</> python
 1import logging
 2import os
 3from datetime import datetime
 4
 5def setup_logger(name, log_level=logging.INFO, log_file_path=None):
 6    logger = logging.getLogger(name)
 7    logger.setLevel(log_level)
 8    formatter = logging.Formatter(
 9        '%(asctime)s - %(name)s - %(levelname)s - %(message)s',
10        datefmt='%Y-%m-%d %H:%M:%S'
11    )
12    console_handler = logging.StreamHandler()
13    console_handler.setFormatter(formatter)
14    logger.addHandler(console_handler)
15    
16    if log_file_path is None:
17        return logger
18
19    file_handler = logging.FileHandler(log_file_path)
20        
21    file_handler.setFormatter(formatter)
22    logger.addHandler(file_handler)
23    return logger

默认logger再封装
#

不设置formatter,自定义logging的info/debug/error方法
实现:

  1. info/debug日志分离
  2. 日志格式自定义
    1. 日期时间格式精确到.3f
    2. 增加marker功能
    3. 日志输出代码行准确指向前一个调用栈(调用封装日志模块的代码行)
  3. 自定义error日志上报、处理
  4. 日志锁(增加性能开销,低性能场景适用)
</> python
 1import logging
 2import os, inspect
 3from os.path import join
 4from datetime import datetime
 5def get_logger(log_root, infolog="info.log", debuglog="debug.log"):
 6    if not os.path.exists(log_root):os.makedirs(log_root)
 7    debuglogpath = join(log_root, debuglog)
 8    infologpath = join(log_root, infolog)
 9    list(map(lambda p:(os.remove(p) if os.path.exists(p) else None), [debuglogpath, infologpath]))
10    logger = logging.getLogger('my_logger')
11    logger.setLevel(logging.DEBUG)
12
13    # debug文件日志
14    debug_file_handler = logging.FileHandler(debuglogpath)
15    debug_file_handler.setLevel(logging.DEBUG)
16    logger.addHandler(debug_file_handler)
17
18    # info文件日志
19    info_file_handler = logging.FileHandler(infologpath)
20    info_file_handler.setLevel(logging.INFO)
21    logger.addHandler(info_file_handler)
22
23    # info终端日志
24    console_handler = logging.StreamHandler()
25    console_handler.setLevel(logging.INFO)
26    logger.addHandler(console_handler)
27
28    return logger
29
30class Logger:
31    def __init__(self):
32        self.logger = None
33        self.lock = threading.Lock()
34        self.marklength = 110
35        self.error_msg = []
36
37    def init_logger(self, infolog, debuglog, logroot):
38        self.logger = get_logger(logroot, infolog, debuglog)
39
40    def padding_size(self, msg):
41        return self.marklength - sum(map(lambda c:2 if ord(c) > 255 else 1, msg))
42
43    def now(self):
44        return datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
45
46    def debug(self, msg:str, frame=None):
47        frame = inspect.currentframe().f_back if not frame else frame
48        f = (frame.f_code.co_filename).split(os.sep)[-1].replace(".py", "")
49        l = frame.f_lineno
50        with self.lock:
51            self.logger.debug(self.now() + ' - DEBUG - ' + f'{f}-{l} - ' + str(msg))
52
53    def info(self, msg:str, frame=None, mark=None):
54        frame = inspect.currentframe().f_back if not frame else frame
55        f = (frame.f_code.co_filename).split(os.sep)[-1].replace(".py", "")
56        l = frame.f_lineno
57        markstr = ((self.padding_size(str(msg)) - len(f'{f}{l}')) * "-" + f"[{mark}]") if mark else ""
58        with self.lock:
59            self.logger.info(self.now() + ' - INFO - ' + f'{f}-{l} - ' + str(msg) + markstr)
60
61    def warning(self, msg:str, frame=None, mark=None):
62        frame = inspect.currentframe().f_back if not frame else frame
63        f = (frame.f_code.co_filename).split(os.sep)[-1].replace(".py", "")
64        l = frame.f_lineno
65        markstr = ((self.padding_size(str(msg)) - len(f'{f}{l}')) * "-" + f"[{mark}]") if mark else ""
66        with self.lock:
67            self.logger.warning(self.now() + ' - WARN - ' + f'{f}-{l} - ' + str(msg) + markstr)
68
69    def error(self, msg:str, frame=None, mark=None, report_msg=True):
70        frame = inspect.currentframe().f_back if not frame else frame
71        f = (frame.f_code.co_filename).split(os.sep)[-1].replace(".py", "")
72        l = frame.f_lineno
73        markstr = ((self.padding_size(str(msg)) - len(f'{f}{l}') - 1) * "-" + f"[{mark}]") if mark else ""
74        with self.lock:
75            self.logger.error(self.now() + ' - ERROR - ' + f'{f}-{l} - ' + str(msg) + markstr)
76            if report_msg:
77                self.error_msg.append(str(msg))

自定义logger类,实现logger实例解耦
#

使用自定义初始化函数init_logger,可以实现不同python文件使用不同logger实例

  1. 使用logging对象
</> python
1class Logger:
2    def init_logger(self, logger):
3        self.logger = logger
4
5logger.init_logger(get_logger(logroot, infolog, debuglog))
  1. 使用print封装
</> python
 1from datetime import datetime
 2class Wrapprint:
 3    def now(self):return datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")
 4    def info(self, msg):print(self.now() + ' - INFO - ' + msg)
 5    def warning(self, msg):print(self.now() + ' - WARN - ' + msg)
 6    def error(self, msg):print(self.now() + ' - ERROR - ' + msg)
 7
 8class Logger:
 9    def init_logger(self, logger):
10        self.logger = logger
11
12logger.init_logger(Wrapprint())

todo: 使用类继承实现logger多态
#