Skip to content

Commit 1b7e93f

Browse files
committedOct 10, 2019
no message
1 parent 7ca2a90 commit 1b7e93f

File tree

2 files changed

+221
-0
lines changed

2 files changed

+221
-0
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
# -*- coding: utf-8 -*-
2+
# @Author : ydf
3+
# @Time : 2019/8/1 0001 17:54
4+
"""
5+
如果老项目没用使用Logmanager,可以打此猴子补丁,自动使项目中的任何日志变彩色和可跳转。
6+
7+
"""
8+
9+
import sys
10+
import os
11+
import logging
12+
13+
14+
class ColorHandler(logging.Handler):
15+
"""
16+
A handler class which writes logging records, appropriately formatted,
17+
to a stream. Note that this class does not close the stream, as
18+
sys.stdout or sys.stderr may be used.
19+
"""
20+
os_name = os.name
21+
terminator = '\n'
22+
bule = 96 if os_name == 'nt' else 36
23+
yellow = 93 if os_name == 'nt' else 33
24+
25+
def __init__(self, stream=None, ):
26+
"""
27+
Initialize the handler.
28+
29+
If stream is not specified, sys.stderr is used.
30+
"""
31+
logging.Handler.__init__(self)
32+
self.formatter = logging.Formatter(
33+
'%(asctime)s - %(name)s - "%(pathname)s:%(lineno)d" - %(funcName)s - %(levelname)s - %(message)s',
34+
"%Y-%m-%d %H:%M:%S")
35+
if stream is None:
36+
stream = sys.stdout # stderr无彩。
37+
self.stream = stream
38+
self._display_method = 7 if self.os_name == 'posix' else 0
39+
40+
def setFormatter(self, fmt):
41+
pass # 使私自设置日志模板失效。固定使用可跳转的模板。
42+
43+
def flush(self):
44+
"""
45+
Flushes the stream.
46+
"""
47+
self.acquire()
48+
try:
49+
if self.stream and hasattr(self.stream, "flush"):
50+
self.stream.flush()
51+
finally:
52+
self.release()
53+
54+
def emit0(self, record):
55+
"""
56+
前后彩色不分离的方式
57+
Emit a record.
58+
59+
If a formatter is specified, it is used to format the record.
60+
The record is then written to the stream with a trailing newline. If
61+
exception information is present, it is formatted using
62+
traceback.print_exception and appended to the stream. If the stream
63+
has an 'encoding' attribute, it is used to determine how to do the
64+
output to the stream.
65+
"""
66+
# noinspection PyBroadException
67+
try:
68+
msg = self.format(record)
69+
stream = self.stream
70+
if record.levelno == 10:
71+
# msg_color = ('\033[0;32m%s\033[0m' % msg) # 绿色
72+
msg_color = ('\033[%s;%sm%s\033[0m' % (self._display_method, 32, msg)) # 绿色
73+
elif record.levelno == 20:
74+
msg_color = ('\033[%s;%sm%s\033[0m' % (self._display_method, self.bule, msg)) # 青蓝色 36 96
75+
elif record.levelno == 30:
76+
msg_color = ('\033[%s;%sm%s\033[0m' % (self._display_method, self.yellow, msg))
77+
elif record.levelno == 40:
78+
msg_color = ('\033[%s;35m%s\033[0m' % (self._display_method, msg)) # 紫红色
79+
elif record.levelno == 50:
80+
msg_color = ('\033[%s;31m%s\033[0m' % (self._display_method, msg)) # 血红色
81+
else:
82+
msg_color = msg
83+
# print(msg_color,'***************')
84+
stream.write(msg_color)
85+
stream.write(self.terminator)
86+
self.flush()
87+
except Exception:
88+
self.handleError(record)
89+
90+
def emit(self, record):
91+
"""
92+
前后彩色分离的方式。
93+
Emit a record.
94+
95+
If a formatter is specified, it is used to format the record.
96+
The record is then written to the stream with a trailing newline. If
97+
exception information is present, it is formatted using
98+
traceback.print_exception and appended to the stream. If the stream
99+
has an 'encoding' attribute, it is used to determine how to do the
100+
output to the stream.
101+
"""
102+
# noinspection PyBroadException
103+
try:
104+
msg = self.format(record)
105+
stream = self.stream
106+
msg1, msg2 = self.__spilt_msg(record.levelno, msg)
107+
if record.levelno == 10:
108+
# msg_color = ('\033[0;32m%s\033[0m' % msg) # 绿色
109+
msg_color = f'\033[0;32m{msg1}\033[0m \033[7;32m{msg2}\033[0m' # 绿色
110+
elif record.levelno == 20:
111+
# msg_color = ('\033[%s;%sm%s\033[0m' % (self._display_method, self.bule, msg)) # 青蓝色 36 96
112+
msg_color = f'\033[0;{self.bule}m{msg1}\033[0m \033[7;{self.bule}m{msg2}\033[0m'
113+
elif record.levelno == 30:
114+
# msg_color = ('\033[%s;%sm%s\033[0m' % (self._display_method, self.yellow, msg))
115+
msg_color = f'\033[0;{self.yellow}m{msg1}\033[0m \033[7;{self.yellow}m{msg2}\033[0m'
116+
elif record.levelno == 40:
117+
# msg_color = ('\033[%s;35m%s\033[0m' % (self._display_method, msg)) # 紫红色
118+
msg_color = f'\033[0;35m{msg1}\033[0m \033[7;35m{msg2}\033[0m'
119+
elif record.levelno == 50:
120+
# msg_color = ('\033[%s;31m%s\033[0m' % (self._display_method, msg)) # 血红色
121+
msg_color = f'\033[0;31m{msg1}\033[0m \033[7;31m{msg2}\033[0m'
122+
else:
123+
msg_color = msg
124+
# print(msg_color,'***************')
125+
stream.write(msg_color)
126+
stream.write(self.terminator)
127+
self.flush()
128+
except Exception:
129+
self.handleError(record)
130+
131+
@staticmethod
132+
def __spilt_msg(log_level, msg: str):
133+
split_text = '- 级别 -'
134+
if log_level == 10:
135+
split_text = '- DEBUG -'
136+
elif log_level == 20:
137+
split_text = '- INFO -'
138+
elif log_level == 30:
139+
split_text = '- WARNING -'
140+
elif log_level == 40:
141+
split_text = '- ERROR -'
142+
elif log_level == 50:
143+
split_text = '- CRITICAL -'
144+
msg_split = msg.split(split_text, maxsplit=1)
145+
return msg_split[0] + split_text, msg_split[-1]
146+
147+
def __repr__(self):
148+
level = logging.getLevelName(self.level)
149+
name = getattr(self.stream, 'name', '')
150+
if name:
151+
name += ' '
152+
return '<%s %s(%s)>' % (self.__class__.__name__, name, level)
153+
154+
def patch_stream_handler_instead_of_color_handler():
155+
logging.StreamHandler = ColorHandler # REMIND 这一行就是打猴子补丁,可以尝试注释掉这一行对比。
156+
"""
157+
这里就是打猴子补丁,要在脚本最开始打猴子补丁,越早越好。
158+
否则原来脚本中使用from logging import StreamHandler变为不了彩色的handler。
159+
只有import logging,logging.StreamHandler的这种用法才会变彩。所以猴子补丁要趁早打。
160+
"""
161+
162+
if __name__ == '__main__':
163+
def my_func():
164+
"""
165+
模拟常规使用控制台StreamHandler日志的方式。自动变彩。
166+
:return:
167+
"""
168+
from logging import StreamHandler
169+
logger = logging.getLogger('abc')
170+
print(logger.handlers)
171+
print(StreamHandler().formatter)
172+
logger.addHandler(StreamHandler())
173+
logger.setLevel(10)
174+
print(logger.handlers)
175+
for _ in range(100):
176+
logger.debug('一个debug级别的日志' * 5)
177+
logger.info('一个info级别的日志' * 5)
178+
logger.warning('一个warning级别的日志' * 5)
179+
logger.error('一个error级别的日志' * 5)
180+
logger.critical('一个critical级别的日志' * 5)
181+
182+
patch_stream_handler_instead_of_color_handler() # 执行猴子补丁后,项目的任意控制台日志,自动变彩色和可跳转。
183+
my_func()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# -*- coding: utf-8 -*-
2+
# @Author : ydf
3+
# @Time : 2019/10/10 0010 10:18
4+
import json
5+
from datetime import datetime as _datetime
6+
from datetime import date as _date
7+
8+
class _CustomEncoder(json.JSONEncoder):
9+
"""自定义的json解析器,mongodb返回的字典中的时间格式是datatime,json直接解析出错"""
10+
11+
def default(self, obj):
12+
if isinstance(obj, _datetime):
13+
return obj.strftime('%Y-%m-%d %H:%M:%S')
14+
elif isinstance(obj, _date):
15+
return obj.strftime('%Y-%m-%d')
16+
else:
17+
return json.JSONEncoder.default(self, obj)
18+
19+
20+
# noinspection PyProtectedMember,PyPep8,PyRedundantParentheses
21+
def _dumps(obj, skipkeys=False, ensure_ascii=False, check_circular=True, allow_nan=True, cls=_CustomEncoder, indent=None, separators=None,
22+
default=None, sort_keys=False, **kw):
23+
if (not skipkeys and ensure_ascii and check_circular and allow_nan and cls is None and indent is None and separators is None and default is None and not sort_keys and not kw):
24+
return json._default_encoder.encode(obj)
25+
return cls(
26+
skipkeys=skipkeys, ensure_ascii=ensure_ascii,
27+
check_circular=check_circular, allow_nan=allow_nan, indent=indent,
28+
separators=separators, default=default, sort_keys=sort_keys, ).encode(obj)
29+
30+
31+
def monkey_patch_json():
32+
json.dumps = _dumps
33+
34+
35+
if __name__ == '__main__':
36+
dictx = {'a':1,'b':_datetime.now()}
37+
monkey_patch_json() # 不打猴子补丁时候,datetime是python自定义对象,不能被json序列化,程序会出错。
38+
print(json.dumps(dictx))

0 commit comments

Comments
 (0)
Please sign in to comment.