1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
|
import time
import sys
import os
import inspect
def get_caller_frame(parent_level=0):
frame = inspect.currentframe()
for _ in range(parent_level + 2):
frame = frame.f_back
return frame
# 日志控制器
class FishLogger:
def __init__(self,tag="FishLogger",path=None):
if path is None:
path=__file__
if tag is None:
tag=os.path.basename(path)
log_path=f"{os.path.dirname(path)}/log/{os.path.basename(path)}.log"
if not os.path.exists(os.path.dirname(log_path)):
os.makedirs(os.path.dirname(log_path),exist_ok=True)
self.tag = tag
self.terminal = sys.stdout
self.log_fd = open(log_path, "a+", encoding='utf-8')
# 输出执行的时间
# run_time = time.strftime('run_time: %Y-%m-%d %H:%M:%S', time.localtime(time.time()))
divider_msg="###################################################"
self.warning(divider_msg)
self.debug(f"path: {path}")
self.debug(f"log_path: {log_path}")
self.debug(f"tag: {tag}")
def debug(self, msg):
self.record("DEBUG", msg)
def info(self, msg):
self.record("INFO", msg)
def warning(self, msg):
self.record("WARN", msg)
def error(self, msg):
self.record("ERROR", msg)
def msg_wrapper(self, level, msg,caller_level=2):
timestamp = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
level_padded = level.ljust(5) # 使用 ljust 方法填充字符串,使得长度为 5
caller_frame = get_caller_frame(caller_level)
file_name = caller_frame.f_code.co_filename
line_number = caller_frame.f_lineno
func_name = caller_frame.f_code.co_name
base_name = os.path.basename(file_name)
new_msg=f"[{timestamp}] [{level_padded}] [{self.tag}] {base_name}:{line_number} {func_name}() - {msg}"
return new_msg
# 日志级别到颜色的映射字典
level_colors = {
'DEBUG': 'blue',
'INFO': 'green',
'WARN': 'yellow',
'ERROR': 'red'
}
# 添加 ANSI 转义码来着色日志消息
def colorize(self, msg, color):
colors = {
'red': '\033[91m',
'green': '\033[92m',
'yellow': '\033[93m',
'blue': '\033[94m',
'magenta': '\033[95m',
'cyan': '\033[96m',
'white': '\033[97m',
'reset': '\033[0m'
}
return f"{colors[color]}{msg}{colors['reset']}"
def print(self,msg):
if self.terminal is not None:
self.terminal.write(msg + "\n")
self.terminal.flush()
def write(self,msg):
self.log_fd.write(msg + "\n")
self.log_fd.flush()
def record(self,level,msg,caller_level=2):
msg=self.msg_wrapper(level,msg,caller_level)
color = self.level_colors.get(level, 'white')
self.print(self.colorize(msg, color))
self.write(msg)
def test():
print(__file__)
logger=FishLogger()
logger.debug("debug")
logger.info("info")
logger.warning("warning")
logger.error("error")
logger.print("print") # 只输出到控制台
logger.write("write") # 只输出到文件
logger.record("record","record",caller_level=1) #同时输出到控制台和文件
if __name__ == "__main__":
test()
|