【Free Style】华为云之Python实践(二)
使用 python 的标准日志模块
那么,怎么样记录日志才是正确的呢?其实非常简单,使用 python 的标准日志模块。多亏 python 社区将日志做成了一个标准模块。它非常简单易用且十分灵活。你可以像这样使用日志系统:
Python
1 2 3 4 5 6 7 8 9 10 11 12 13 | import logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__)
logger.info('Start reading database') # read database here
records = {'john': 55, 'tom': 66} logger.debug('Records: %s', records) logger.info('Updating records ...') # update records here
logger.info('Finish updating records') |
运行的时候就可看到:
Python
1 2 3 | INFO:__main__:Start reading database INFO:__main__:Updating records ... INFO:__main__:Finish updating records |
你可能会问这与使用 print 有什么不同呢。它有以下的优势:
你可以控制消息的级别,过滤掉那些并不重要的消息。
你可决定输出到什么地方,以及怎么输出。
有许多的重要性别级可供选择,debug、info、warning、error 以及 critical。通过赋予 logger 或者 handler 不同的级别,你就可以只输出错误消息到特定的记录文件中,或者在调试时只记录调试信息。让我们把 logger 的级别改成 DEBUG 再看一下输出结果:
Python
1 | logging.basicConfig(level=logging.DEBUG) |
输出变成了:
Python
1 2 3 4 | INFO:__main__:Start reading database DEBUG:__main__:Records: {'john': 55, 'tom': 66} INFO:__main__:Updating records ... INFO:__main__:Finish updating records |
正如看到的那样,我们把 logger 的等级改为 DEBUG 后,调试记录就出现在了输出当中。你也可以选择怎么处理这些消息。例如,你可以使用 FileHandler 把记录写进文件中:
Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | import logging
logger = logging.getLogger(__name__) logger.setLevel(logging.INFO)
# create a file handler
handler = logging.FileHandler('hello.log') handler.setLevel(logging.INFO)
# create a logging format
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') handler.setFormatter(formatter)
# add the handlers to the logger
logger.addHandler(handler)
logger.info('Hello baby') |
标准库模块中提供了许多的 handler ,你可以将记录发送到邮箱甚至发送到一个远程的服务器。你也可以实现自己的记录 handler 。这里将不具体讲述实现的细节,你可以参考官方文档:Basci Turial、Advanced Tutorial 与 Logging Cookbook。
以合适的等级输出日志记录
有了灵活的日志记录模块后,你可以按适当的等级将日志记录输出到任何地方然后配置它们。那么你可能会问,什么是合适的等级呢?在这儿我将分享一些我的经验。
大多数的情况下,你都不想阅读日志中的太多细节。因此,只有你在调试过程中才会使用 DEBUG 等级。我只使用 DEBUG 获取详细的调试信息,特别是当数据量很大或者频率很高的时候,比如算法内部每个循环的中间状态。
Python
1 2 3 4 5 | def complex_algorithm(items): for i, item in enumerate(items): # do some complex algorithm computation
logger.debug('%s iteration, item=%s', i, item) |
在处理请求或者服务器状态变化等日常事务中,我会使用 INFO 等级。
Python
1 2 3 4 5 6 7 8 9 10 11 | def handle_request(request): logger.info('Handling request %s', request) # handle request here
result = 'result' logger.info('Return result: %s', result)
def start_service(): logger.info('Starting service at port %s ...', port) service.start() logger.info('Service is started') |
当发生很重要的事件,但是并不是错误时,我会使用 WARNING 。比如,当用户登录密码错误时,或者连接变慢时。
Python
1 2 3 4 5 | def authenticate(user_name, password, ip_address): if user_name != USER_NAME and password != PASSWORD: logger.warn('Login attempt to %s from IP %s', user_name, ip_address) return False # do authentication here |
有错误发生时肯定会使用 ERROR 等级了。比如抛出异常,IO 操作失败或者连接问题等。
Python
1 2 3 4 5 6 | def get_user_by_id(user_id): user = db.read_user(user_id) if user is None: logger.error('Cannot find user with user_id=%s', user_id) return user return user |
我很少使用 CRITICAL 。当一些特别糟糕的事情发生时,你可以使用这个级别来记录。比方说,内存耗尽,磁盘满了或者核危机(希望永远别发生 :S)。
- 点赞
- 收藏
- 关注作者
评论(0)