0%

python | ConcurrentLogHandler

这里主要是针对

进行改造。

这套代码在 ubuntu 、 MacBook 上运行是正常的,但是,在 windows 中会出现

PermissionError: [WinError 32] 另一个程序正在使用此文件,进程无法访问

究其原因,是因为,logger 在将日志根据时间分片的时候,出现错误。


参考资料



ConcurrentLogHandler


这里暂时先直接放一个暂时性的代码,过几天我再来完善。

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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
import os
import sys
import traceback
import logging
import logging.handlers
from concurrent_log_handler import ConcurrentRotatingFileHandler


class ColoredFormatter(logging.Formatter):

def __init__(self, fmt=None, datefmt=None):
logging.Formatter.__init__(self, fmt, datefmt)

def format(self, record):
# Color escape string
COLOR_RED = '\033[1;31m'
COLOR_GREEN = '\033[1;32m'
COLOR_YELLOW = '\033[1;33m'
COLOR_BLUE = '\033[1;34m'
COLOR_PURPLE = '\033[1;35m'
COLOR_CYAN = '\033[1;36m'
COLOR_GRAY = '\033[1;37m'
COLOR_WHITE = '\033[1;38m'
COLOR_RESET = '\033[1;0m'
# Define log color
LOG_COLORS = {
'DEBUG': '%s',
'INFO': COLOR_GREEN + '%s' + COLOR_RESET,
'WARNING': COLOR_YELLOW + '%s' + COLOR_RESET,
'ERROR': COLOR_RED + '%s' + COLOR_RESET,
'CRITICAL': COLOR_RED + '%s' + COLOR_RESET,
'EXCEPTION': COLOR_RED + '%s' + COLOR_RESET,
}
level_name = record.levelname
msg = logging.Formatter.format(self, record)
return LOG_COLORS.get(level_name, '%s') % msg


class Log(object):
def __init__(self, loggername='', filename=None, mode='a',
cmdlevel='DEBUG',
filelevel='INFO',
cmdfmt='[%(asctime)s] %(filename)s line:%(lineno)d %(levelname)-8s%(message)s',
filefmt='[%(asctime)s] %(levelname)-8s%(message)s',
cmddatefmt='%H:%M:%S',
filedatefmt='%Y-%m-%d %H:%M:%S',
backup_count=0, limit=20480, when=None, colorful=False):
self.filename = filename
self.loggername = loggername
if self.filename is None:
self.filename = getattr(sys.modules['__main__'], '__file__', 'log.py')
self.filename = os.path.basename(self.filename.replace('.py', '.log'))
# self.filename = os.path.join('/tmp', self.filename)
if not os.path.exists(os.path.abspath(os.path.dirname(self.filename))):
os.makedirs(os.path.abspath(os.path.dirname(self.filename)))
self.mode = mode
self.cmdlevel = cmdlevel
self.filelevel = filelevel
if isinstance(self.cmdlevel, str):
self.cmdlevel = getattr(logging, self.cmdlevel.upper(), logging.DEBUG)
if isinstance(self.filelevel, str):
self.filelevel = getattr(logging, self.filelevel.upper(), logging.DEBUG)
self.filefmt = filefmt
self.cmdfmt = cmdfmt
self.filedatefmt = filedatefmt
self.cmddatefmt = cmddatefmt
self.backup_count = backup_count
self.limit = limit
self.when = when
self.colorful = colorful
self.logger = None
self.streamhandler = None
self.filehandler = None
if self.cmdlevel > 10:
self.filefmt = '[%(asctime)s] %(levelname)-8s%(message)s'
self.cmdfmt = '[%(asctime)s] %(levelname)-8s%(message)s'
self.cmddatefmt = '%Y-%m-%d %H:%M:%S'
self.set_logger(cmdlevel=self.cmdlevel)

def init_logger(self):
if self.logger is None:
self.logger = logging.getLogger(self.loggername)
else:
logging.shutdown()
self.logger.handlers = []
self.streamhandler = None
self.filehandler = None
self.logger.setLevel(logging.DEBUG)

def add_streamhandler(self):
self.streamhandler = logging.StreamHandler()
self.streamhandler.setLevel(self.cmdlevel)
if self.colorful:
formatter = ColoredFormatter(self.cmdfmt, self.cmddatefmt)
else:
formatter = logging.Formatter(self.cmdfmt, self.cmddatefmt, )
self.streamhandler.setFormatter(formatter)
self.logger.addHandler(self.streamhandler)

def add_filehandler(self):
# Choose the filehandler based on the passed arguments
if self.backup_count == 0: # Use FileHandler
self.filehandler = logging.FileHandler(self.filename, self.mode)
elif self.when is None: # Use RotatingFileHandler
self.filehandler = logging.handlers.RotatingFileHandler(self.filename,
self.mode, self.limit, self.backup_count)
else: # Use TimedRotatingFileHandler
# self.filehandler = logging.handlers.TimedRotatingFileHandler(self.filename,
# self.when, 1, self.backup_count)
self.filehandler = ConcurrentRotatingFileHandler('logs/log.log', "a", 100 * 1024, 30)
self.filehandler.setLevel(self.filelevel)
formatter = logging.Formatter(self.filefmt, self.filedatefmt, )
self.filehandler.setFormatter(formatter)
self.logger.addHandler(self.filehandler)

def set_logger(self, **kwargs):
keys = ['mode', 'cmdlevel', 'filelevel', 'filefmt', 'cmdfmt', \
'filedatefmt', 'cmddatefmt', 'backup_count', 'limit', \
'when', 'colorful']
for (key, value) in kwargs.items():
if not (key in keys):
return False
setattr(self, key, value)
if isinstance(self.cmdlevel, str):
self.cmdlevel = getattr(logging, self.cmdlevel.upper(), logging.DEBUG)
if isinstance(self.filelevel, str):
self.filelevel = getattr(logging, self.filelevel.upper(), logging.DEBUG)
if not "cmdfmt" in kwargs:
self.filefmt = '[%(asctime)s] %(filename)s line:%(lineno)d %(levelname)-8s%(message)s'
self.filedatefmt = '%Y-%m-%d %H:%M:%S'
self.cmdfmt = '[%(asctime)s] %(filename)s line:%(lineno)d %(levelname)-8s%(message)s'
self.cmddatefmt = '%H:%M:%S'
if self.cmdlevel > 10:
self.filefmt = '[%(asctime)s] %(levelname)-8s%(message)s'
self.cmdfmt = '[%(asctime)s] %(levelname)-8s%(message)s'
self.cmddatefmt = '%Y-%m-%d %H:%M:%S'
self.init_logger()
self.add_streamhandler()
self.add_filehandler()
# Import the common log functions for convenient
self.import_log_funcs()
return True

def addFileLog(self, log):
self.logger.addHandler(log.filehandler)
return self

def import_log_funcs(self):
log_funcs = ['debug', 'info', 'warning', 'error', 'critical',
'exception']
for func_name in log_funcs:
func = getattr(self.logger, func_name)
setattr(self, func_name, func)

def trace(self):
info = sys.exc_info()
for file, lineno, function, text in traceback.extract_tb(info[2]):
self.error('%s line:%s in %s:%s' % (file, lineno, function, text))
self.error('%s: %s' % info[:2])


logger = Log(cmdlevel='info', filename='logs/log.log', backup_count=4, when='M', colorful=True)
请我喝杯咖啡吧~