python日志模块

python的日志记录一般使用logging标准模块,比较强大,可以设置日志等级level,添加日志handler来扩展记录模式,比如streamhandlerfilehandlersmtphandler等等,基本不给第三方日志模块留活路。
比如打印到stdout的日志可以这么写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import logging

def init_log():
log = logging.getLogger(__name__)
log.setLevel(LOG_LEVEL)
console = logging.StreamHandler(sys.stdout)
console.setLevel(LOG_LEVEL)
fmt = "[%(levelname)s][%(asctime)s][%(process)d]" \
"logger=%(name)s|tag=%(funcName)s:%(filename)s:%(lineno)d|" \
"content=%(message)s"
datefmt = "%Y-%m-%d %H:%M:%S %z"
formatter = logging.Formatter(fmt=fmt, datefmt=datefmt)
console.setFormatter(formatter)
log.addHandler(console)
return log

然后就可以

1
2
3
4
log.debug('Message')

#log
[DEBUG][2016-11-25 16:23:23 +0000][22486]logger=app.common.init_log|tag=verify******:**********:24|content=Message

也可以使用logging的配置文件,如logging.conf

1
2
logging.config.fileConfig("logging.conf")  
logger = logging.getLogger('test')

目前更多使用字典做配置项的
嗯,陪老婆去逛街,回来继续
比如:

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
logger_dict_config = {
'version': 1,
'disable_existing_loggers': True,

'formatters': {
'console': {
'format': '[%(asctime)s][%(levelname)s] %(name)s '
'%(filename)s:%(funcName)s:%(lineno)d | %(message)s',
'datefmt': '%H:%M:%S',
},
},

'handlers': {
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'console',
'stream': 'ext://sys.stdout'
},
'error': {
'level': 'ERROR',
'class': 'logging.StreamHandler',
'formatter': 'console',
'stream': 'ext://sys.stderr'
}
},

'loggers': {
'app': {
'handlers': ['console'],
'level': 'DEBUG',
'propagate': False,
}
}
}

logging.config.dictConfig(get_logging_config(app.config))
_logger = logging.getLogger('app')

Flask日志

启动flask后,除了上述主动打印的服务日志或调试日志外,还会有:

1
127.0.0.1 - - [27/Nov/2016 14:15:13] "GET /login HTTP/1.1" 200 -

这个是由werkzeug模块控制的,在一定情况下需要定制或者重定向标准日志的时候可以

1
2
3
4
5
6
7
8
9
logger = logging.getLogger('werkzeug')
#仅ERROR级日志打印
logger.setLevel(logging.ERROR)
#关掉日志,仅仅打印服务日志
logger.disabled = True
#修改日志格式,和werkzeug日志在一块,上面关闭的话,也不会显示
from werkzeug._internal import _log
#_log('level','content')
_log('info','[Dirac]{real_ip} {remote_ip} {request_host} [{request_time}] "{request_method} {request_path}" {reqeust_staus_code} {response_time} {uuid}'.format(...)

上面的方法可以关掉werkzeug日志,只打印自己定义的服务日志,这样可以统一日志格式进行分析,但如果希望替换掉werkzug日志,则可以修改或者替换掉默认的请求handler的日志格式,例如

1
2
3
4
5
6
7
8
9
10
from werkzeug import serving
class LimitLogHandler(serving.WSGIRequestHandler):
def log(self, type, message, *args):
msg = (message % args)
_log(type, '%s - - (Lim) [%s] %s\n' % (self.address_string(),
self.log_date_time_string(),
"{} ... {}".format(msg[:50],msg[-40:])))
app = flask.Flask(__name__)
if __name__ == "__main__":
app.run(debug = True, request_handler = LimitLogHandler)

werkzeug真是个好东西,需要用好并好好读下源码
啥时候才能写出优雅高效的python代码啊?

过滤addFilter

增加过滤器,滤除不需要的log,上面修改werkzeug日志也可以滤出默认日志

1
2
3
4
5
6
class NoParsingFilter(logging.Filter):
#重写filter函数
def filter(self, record):
return not record.getMessage().startswith('[Dirac]')

logger.addFilter(NoParsingFilter())