没有日志的话,服务挂了我根本就不知道是为啥。不只是服务器,日志对于桌面程序来说也很重要。当你的程序崩溃了,你可以让用户把日志文件发送给你,你就可以从中找到(崩溃的)原因。相信我,你永远无法预料到不同的 PC 环境会造成什么样稀奇古怪的问题。我有一次收到下面这样一份错误日志:
2011-08-22 17:52:54,828 - root - ERROR - [Errno 10104] getaddrinfo failed
Traceback (most recent call last):
File "<string>", line 124, in main
File "<string>", line 20, in __init__
File "h:\workspace\project\build\pyi.win32\mrdj\outPYZ1.pyz/wx._core", line 7978, in __init__
File "h:\workspace\project\build\pyi.win32\mrdj\outPYZ1.pyz/wx._core", line 7552, in _BootstrapApp
File "<string>", line 84, in OnInit
File "h:\workspace\project\build\pyi.win32\mrdj\outPYZ1.pyz/twisted.internet.wxreactor", line 175, in install
File "h:\workspace\project\build\pyi.win32\mrdj\outPYZ1.pyz/twisted.internet._threadedselect", line 106, in __init__
File "h:\workspace\project\build\pyi.win32\mrdj\outPYZ1.pyz/twisted.internet.base", line 488, in __init__
File "h:\workspace\project\build\pyi.win32\mrdj\outPYZ1.pyz/twisted.internet.posixbase", line 266, in installWaker
File "h:\workspace\project\build\pyi.win32\mrdj\outPYZ1.pyz/twisted.internet.posixbase", line 74, in __init__
File "h:\workspace\project\build\pyi.win32\mrdj\outPYZ1.pyz/socket", line 224, in meth
gaierror: [Errno 10104] getaddrinfo failed
importlogginglogger=logging.getLogger(__name__)logger.setLevel(logging.INFO)# create a file handlerhandler=logging.FileHandler('hello.log')handler.setLevel(logging.INFO)# create a logging formatformatter=logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')handler.setFormatter(formatter)# add the handlers to the loggerlogger.addHandler(handler)logger.info('Hello baby')
大部分情况下,你不想在日志文件中记录太多的细节。那么 debug 级别只应当在调试的时候被激活。我只在需要获取详细的调试信息时打开它,尤其是数据量很大,或是请求过于频繁,例如在调试 for 循环中算法的内部状态时。
1
2
3
4
5
defcomplex_algorithm(items):fori,iteminenumerate(items):# do some complex algorithm computationlogger.debug('%s iteration, item=%s',i,item)
我使用 info 级别来记录常规动作,例如处理请求或是服务器状态变更。
1
2
3
4
5
6
7
8
9
10
11
defhandle_request(request):logger.info('Handling request %s',request)# handle request hereresult='result'logger.info('Return result: %s',result)defstart_service():logger.info('Starting service at port %s ...',port)service.start()logger.info('Service is started')
在信息重要但不是错误的时候使用 warning,例如某个用户使用了错误密码登录,或是连接太慢。
1
2
3
4
5
defauthenticate(user_name,password,ip_address):ifuser_name!=USER_NAMEandpassword!=PASSWORD:logger.warn('Login attempt to %s from IP %s',user_name,ip_address)returnFalse# do authentication here
ERROR:__main__:Failed to open file
Traceback (most recent call last):
File "example.py", line 6, in <module>
open('/path/to/does/not/exist', 'rb')
IOError: [Errno 2] No such file or directory: '/path/to/does/not/exist'
importlogging# load my moduleimportmy_module# load the logging configurationlogging.config.fileConfig('logging.ini')my_module.foo()bar=my_module.Bar()bar.bar()
importloggingimportlogging.configlogger=logging.getLogger(__name__)# load config from file # logging.config.fileConfig('logging.ini', disable_existing_loggers=False)# or, for dictConfiglogging.config.dictConfig({'version':1,'disable_existing_loggers':False,# this fixes the problem'formatters':{'standard':{'format':'%(asctime)s [%(levelname)s] %(name)s: %(message)s'},},'handlers':{'default':{'level':'INFO','class':'logging.StreamHandler',},},'loggers':{'':{'handlers':['default'],'level':'INFO','propagate':True}}})logger.info('It works!')