==========================
应用程序的logging的做法
==========================
1.
对于主模块, 采用logging.config.dictConfig(dict_LOG_CONFIG) 或
logging.config.fileConfig(ini_file) 初始化logger的配置
如果想让用户完全控制log的输出. , 推荐使用logging.config.dictConfig(); 如果是项目,
推荐使用logging.config.fileConfig().
2.
使用logging.getLogger(__name__)来获得logger实例, 使用getLogger(__name__)获得的logger,
输出的日志能体现出模块的命名空间. 主模块getLogger()应放在fileConfig()之后.
3.
对于非主模块,不应做logger的初始化配置, 也不应该在模块级上调用getLogger(),
而应该在function中或者class中来调用getLogger().
理由是: 最主要的原因是, log配置应该是主模块的特权. 还有一个理由是,
我们的主module往往是先import非主module, 然后再用logging.config.fileConfig()做初始化,
而fileConfig()缺省会disable已存在的所有logger, 也就是说非主模块级别的那些logger都被禁掉了, 也就无法再用来记日志.
4. 在主模块和非主模块推荐, 都应该使用logger.info()和logger.debug()来记日志,
不推荐使用logging.info()和logging.debug()这样的方法, 后者是用的是root logger, 所有模块都用root,
就无法区分日志是由哪个模块产生的了.
5. 推荐使用标准库的 TimedRotatingFileHandler 或者是 cloghandler.py 的
ConcurrentRotatingFileHandler.
而不是 RotatingFileHandler 和
FileHandler.
理由是 FileHandler, 单文件日志缺点比较多.
而 RotatingFileHandler的问题是, 在windows下当文件大小到达max时,
log有时候就记不进去了. 另外如果多个程序往同一个log文件写, RotatingFileHandler也会报错的, cloghandler.py没这个问题.
参考
http://pydoc.net/Python/cloud/2.3.9/cloud.util.cloghandler.cloghandler/
6.
长log的format, 我使用的是,
说明: 前面加上####, 这样log parser容易分开不同的log记录.
分隔符使用|而不是逗号, 因为时间串中会包含个逗号的.
formatter =
logging.Formatter(fmt=‘####%(asctime)s|pid=%(process)d|tid=%(thread)d|%(name)s|%(levelname)s|%(message)s‘)
短log的format, 我使用的是,
shortFormatter =
logging.Formatter(fmt=‘####%(asctime)s|%(name)s|%(levelname)s|%(message)s‘,
datefmt="%H:%M:%S")
7. 关于应用程序如何合并第3方类库的log输出, 比如合并SqlAlchemy的日志.
基本不用特别在意, 只要我们的程序设置了root logger, 应用程序和SqlAlchemy的日志自然会合并输出在root
logger的handler中.
==========================
类库的logging的做法
==========================
1.类库logging的使用,
其实和application的非主模块类似.
2.在类库的top level库中, 最好为logger加上NullHandler,
这样即使应用程序根本没做logging配置, 也不会出现未配置logging的警告信息.
==========================
几个有关的函数
==========================
rootLogger
= logging.getLogger() #getLogger()不带参数,
得到的即是rootLogger
logging.basicConfig(level=logging.DEBUG) #是一个很顺手的logging配置方案,
输出为stderr,
非常适合在demo和调试程序
==========================
选择合适的logging
level
==========================
这里误区也比较多, 很多程序员喜欢滥用error级别.
DEBUG :
开发人员debug用, 比如记录详尽的业务动作, 比如SQL
INFO : 记录一些关键的动作和数据.
WARN : 用于那些对业务功能已有影响, 但不太严重的情形
ERROR :
仅用于记录那些已影响业务功能的Error或Exception
FATAL : (同CRITICAL)仅用于影响到程序完全不能工作的情况,
比如非法退出
如果还不容易区分, 换另一个角度, WARNING和ERROR级别的问题, 都是需要及时处理.
==========================
dict
配置的写法
==========================
1. 具体 ini 配置文件如何写,
参考<python日志不完全指南> http://cjs.linuxapp.org/?p=116
2. dict
配置, 后面有个sample.
dict_LOG_CONFIG ={
#版本总是1
‘version‘: 1,
#
‘disable_existing_loggers‘:
False,
‘formatters‘:
{
‘standard‘:
{
‘format‘: ‘%(asctime)s [%(levelname)s] %(name)s:
%(message)s‘
},
},
‘handlers‘:
{
‘default‘:
{
‘level‘:‘INFO‘,
‘class‘:‘logging.StreamHandler‘,
},
},
‘loggers‘:
{
#加一个root
logger
‘‘:
{
‘handlers‘: [‘default‘],
‘level‘: ‘INFO‘,
‘propagate‘: True
},
#加其他logger
‘django.request‘: {
‘handlers‘:
[‘default‘],
‘level‘: ‘WARN‘,
‘propagate‘: False
},
}
}
==========================
ini
配置的写法
==========================
参考<python日志不完全指南> http://cjs.linuxapp.org/?p=116
# 定义logger模块,root是必需的,其它的是自定义。
[loggers]
keys=root, web.debug,
web.info, web.error
# 定义格式化输出
[formatters]
keys=simpleFormatter,
webSimpleFormatter
#
定义handler
[handlers]
keys=consoleHandler,rotateFileHandler,
webDebugRotateFileHandler, webInfoRotateFileHandler, webErrorRotateFileHandler,
webSMTPHandler
#--------------------------------------------------
#
实现上面定义的logger模块,必需是[logger_xxxx]这样的形式
#--------------------------------------------------
#
[logger_xxxx] logger_模块名称
# level
级别,级别有DEBUG、INFO、WARNING、ERROR、CRITICAL
# handlers 处理类,可以有多个,用逗号分开
#
qualname logger名称,应用程序通过 logging.getLogger获取。对于不能获取的名称,则记录到root模块。
#
propagate 是否继承父类的log信息,0:否 1:是
[logger_root]
level=DEBUG
handlers=consoleHandler,rotateFileHandler
[logger_web.debug]
level=DEBUG
handlers=consoleHandler,webDebugRotateFileHandler
qualname=web.debug
propagate=0
[logger_web.info]
level=INFO
handlers=consoleHandler,webInfoRotateFileHandler
qualname=web.info
propagate=0
[logger_web.error]
level=ERROR
handlers=consoleHandler,webErrorRotateFileHandler,webSMTPHandler
qualname=web.error
propagate=0
#--------------------------------------------------
#
日志格式
#--------------------------------------------------
#
%(asctime)s 年-月-日 时-分-秒,毫秒 2013-04-26
20:10:43,745
# %(filename)s 文件名,不含目录
#
%(pathname)s 目录名,完整路径
#
%(funcName)s 函数名
#
%(levelname)s 级别名
#
%(lineno)d 行号
#
%(module)s 模块名
#
%(message)s 消息体
#
%(name)s 日志模块名
#
%(process)d 进程id
#
%(processName)s 进程名
#
%(thread)d 线程id
#
%(threadName)s
线程名
[formatter_simpleFormatter]
format=%(asctime)s|%(name)s|%(threadName)s|%(levelname)s
> %(message)s
[formatter_webSimpleFormatter]
format=%(asctime)s
%(clientip)s %(levelname)s >
%(message)s
#--------------------------------------------------
#
handler
#--------------------------------------------------
#
[handler_xxxx]
# class handler类名
# level 日志级别
#
formatter,上面定义的formatter
# args handler初始化函数参数
[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=simpleFormatter
args=(sys.stdout,)
[handler_rotateFileHandler]
class=handlers.RotatingFileHandler
level=DEBUG
formatter=simpleFormatter
args=(‘access.log‘,‘a‘,2000000,9)
[handler_webDebugRotateFileHandler]
class=handlers.RotatingFileHandler
level=DEBUG
formatter=simpleFormatter
args=(‘debug.log‘,‘a‘,2000000,9)
[handler_webInfoRotateFileHandler]
class=handlers.RotatingFileHandler
level=INFO
formatter=webSimpleFormatter
args=(‘info.log‘,‘a‘,2000000,9)
[handler_webErrorRotateFileHandler]
class=handlers.RotatingFileHandler
level=ERROR
formatter=webSimpleFormatter
args=(‘error.log‘,‘a‘,2000000,9)
[handler_webSMTPHandler]
class=handlers.SMTPHandler
level=ERROR
formatter=webSimpleFormatter
args=(‘mailhost‘,
‘fromaddr‘, (‘toaddrs1‘,‘toaddrs2‘), ‘subject‘,
(‘username‘,‘password‘))
原文:http://www.cnblogs.com/harrychinese/p/logging_right_way.html