asynchronous logging with Python

项目中通常会用Python logging模块做发报警邮件、发日志到logstash等功能,甚至可以发送到slack、telegram这类应用。可能是logging模块太好了,用来做这些notification都足够了。但如果有频繁的log请求或者比较高的响应要求,可能就会有很多时间花在这些网络日志的连接与断开上,因此想想大Python应该有异步日志之类的第三方模块吧。找了半天没有合适的可以满足我这类通用网络日志的模块,遂自己写了个。

主要用的是threading模块,当然如果觉得不合适可以用Celery。思路很简单,重载logging.Handler来写自己的日志处理。考虑到网络日志可能有如上各种应用,再加上如果需要使用Celery的话handler function需要可序列化,因此传个回调给handler实例,并在emit方法中调用。这个回调里做网络日志的各种操作,这样就可以做到足够的可定制化,话不多说,上代码。

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

from celery import shared_task

from asynclog import AsyncLogDispatcher

# 使用Celery
@shared_task
def write_task(msg):
# Write log in Network IO
print(msg)

celery_handler = AsyncLogDispatcher(write_task, use_thread=False, use_celery=True)
celery_handler.setLevel(logging.INFO)
logger.addHandler(celery_handler)

logger.info('Test Log')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 使用threading
def write_log(msg):
# Do write stuff, such as write log msg into network.
# ...
time.sleep(0.5)


logger = logging.getLogger()
logger.setLevel(logging.INFO)
handler = AsyncLogDispatcher(write_log)
handler.setLevel(logging.INFO)
logger.addHandler(handler)

logger.info('Test Log')
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
# 结合dictConfig
log_cfg = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'simple': {
'format': '%(asctime)s \n %(levelname)s \n %(message)s'
},
},
'handlers': {
'async_handler': {
'level': 'INFO',
'formatter': 'simple',
'class': 'asynclog.AsyncLogDispatcher',
'func': 'write_log',
}
},
'loggers': {
'asynclogger': {
'handlers': ['async_handler', ],
'level': 'DEBUG',
'propagate': False,
},
}
}

logging.config.dictConfig(log_cfg)
logger = logging.getLogger('asynclogger')
logger.info('Test asynclog')

考虑到重载的类实际只是用logging的方法来filter、format日志,真正处理的其实在回调中,所以类名也就不敢叫AsyncLogHandler, 就取名AsyncLogDispatcher

该模块已上传至pypi.org, pip install asynclog即可,代码托管在我的GitHub, 欢迎交流。