一、模块定义:
Python的logging模块提供了通用的日志系统,可以方便第三方模块或者是应用使用。这个模块提供不同的日志级别,并可以采用不同的方式记录日志,比如文件,HTTP GET/POST,SMTP,Socket等,甚至可以自己实现具体的日志记录方式。
二、模块实现方式:
logging模块与log4j的机制是一样的,只是具体的实现细节不同。模块提供logger,handler,filter,formatter。
logger:提供日志接口,供应用代码使用。logger最长用的操作有两类:配置和发送日志消息。可以通过logging.getLogger(name)获取logger对象,如果不指定name则返回root对象,多次使用相同的name调用getLogger方法返回同一个logger对象。
handler:将日志记录(log record)发送到合适的目的地(destination),比如文件,socket等。一个logger对象可以通过addHandler方法添加多个handler,每个handler又可以定义不同日志级别,以实现日志分级过滤显示。
filter:提供一种优雅的方式决定一个日志记录是否发送到handler。
formatter:指定日志记录输出的具体格式。formatter的构造方法需要两个参数:消息的格式字符串和日期字符串,这两个参数都是可选的。
与log4j类似,logger,handler和日志消息的调用可以有具体的日志级别(level),只有在日志消息的级别大于logger和handler的级别。
#!/usr/bin/env python # -*- coding=utf-8 -*- import logging #创建一个logging的实例logger logger = logging.getLogger('Richard') #设定全局日志级别为DEBUG logger.setLevel(logging.INFO) #创建一个屏幕的handler,并且设定级别为DEBUG ch = logging.StreamHandler() ch.setLevel(logging.DEBUG) #创建一个日志文件的handler,并且设定级别为DEBUG fh = logging.FileHandler("access.log") fh.setLevel(logging.CRITICAL) #设置日志的格式 formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") #add formatter to ch and fh ch.setFormatter(formatter) fh.setFormatter(formatter) #add ch and fh to logger logger.addHandler(ch) logger.addHandler(fh) #'application' code logger.debug("debug message") logger.info("info message") logger.warn("warn message") logger.error("error message") logger.critical("crititcal message")
#输出结果
"D:Program Files (x86)python34python.exe" F:/Python/Alex/s12/Blog/log.py 2016-03-22 06:13:09,764 - Richard - INFO - info message 2016-03-22 06:13:09,764 - Richard - WARNING - warn message 2016-03-22 06:13:09,764 - Richard - ERROR - error message 2016-03-22 06:13:09,764 - Richard - CRITICAL - crititcal message access.log: 2016-03-22 06:13:09,764 - Richard - CRITICAL - crititcal message
在这里需要说明的一点是logger.setLevel(logging.INFO)和ch.setLevel(logging.DEBUG)的区别:
通过例子来看:
#设定全局日志级别为CRITICAL logger.setLevel(logging.CRITICAL) #创建一个屏幕的handler,并且设定级别为DEBUG ch = logging.StreamHandler() ch.setLevel(logging.DEBUG) #创建一个日志文件的handler,并且设定级别为INFO fh = logging.FileHandler("access.log") fh.setLevel(logging.INFO) 输出结果: "D:Program Files (x86)python34python.exe" F:/Python/Alex/s12/Blog/log.py 2016-03-22 06:20:10,712 - Richard - CRITICAL - crititcal message access.log: 2016-03-22 06:20:10,712 - Richard - CRITICAL - crititcal message
就是全局日志级别为CRITICAL的话,局部变量想设置成INFO或者DEBUG都会失效。
由此可以得出全局的比局部的级别要高,加入全局的设成DEBUG的话,局部可以设成WARNING,那么logging只会输出WARNG、ERROR、CRITICAL这三种类型。
备注:关于formatter的配置,采用的是%(<dict key>)s的形式,就是字典的关键字替换。提供的关键字包括:
Attribute name | Format | Description |
---|---|---|
args | You shouldn’t need to format this yourself. | The tuple of arguments merged into msg to produce message , or a dict whose values are used for the merge (when there is only one argument, and it is a dictionary). |
asctime | %(asctime)s |
Human-readable time when the LogRecord was created. By default this is of the form ‘2003-07-08 16:49:45,896’ (the numbers after the comma are millisecond portion of the time). |
created | %(created)f |
Time when the LogRecord was created (as returned by time.time() ). |
exc_info | You shouldn’t need to format this yourself. | Exception tuple (à la sys.exc_info ) or, if no exception has occurred, None. |
filename | %(filename)s |
Filename portion of pathname . |
funcName | %(funcName)s |
Name of function containing the logging call. |
levelname | %(levelname)s |
Text logging level for the message ('DEBUG' , 'INFO' , 'WARNING' , 'ERROR' ,'CRITICAL' ). |
levelno | %(levelno)s |
Numeric logging level for the message (DEBUG , INFO , WARNING , ERROR ,CRITICAL ). |
lineno | %(lineno)d |
Source line number where the logging call was issued (if available). |
module | %(module)s |
Module (name portion of filename ). |
msecs | %(msecs)d |
Millisecond portion of the time when the LogRecord was created. |
message | %(message)s |
The logged message, computed as msg % args . This is set whenFormatter.format() is invoked. |
msg | You shouldn’t need to format this yourself. | The format string passed in the original logging call. Merged with args to produce message , or an arbitrary object (see Using arbitrary objects as messages). |
name | %(name)s |
Name of the logger used to log the call. |
pathname | %(pathname)s |
Full pathname of the source file where the logging call was issued (if available). |
process | %(process)d |
Process ID (if available). |
processName | %(processName)s |
Process name (if available). |
relativeCreated | %(relativeCreated)d |
Time in milliseconds when the LogRecord was created, relative to the time the logging module was loaded. |
stack_info | You shouldn’t need to format this yourself. | Stack frame information (where available) from the bottom of the stack in the current thread, up to and including the stack frame of the logging call which resulted in the creation of this record. |
thread | %(thread)d |
Thread ID (if available). |
threadName | %(threadName)s |
Thread name (if available). |
logging官网地址:
https://docs.python.org/3.5/library/logging.html
本文内容转自:http://www.cnblogs.com/Richardzhu/p/5303887.html
三、实例:
""" logging配置 """ import os import logging.config # 定义三种日志输出格式 开始 standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' '[%(levelname)s][%(message)s]' #其中name为getlogger指定的名字 simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s' id_simple_format = '[%(levelname)s][%(asctime)s] %(message)s' # 定义日志输出格式 结束 logfile_dir = os.path.dirname(os.path.abspath(__file__)) # log文件的目录 logfile_name = 'all2.log' # log文件名 # 如果不存在定义的日志目录就创建一个 if not os.path.isdir(logfile_dir): os.mkdir(logfile_dir) # log文件的全路径 logfile_path = os.path.join(logfile_dir, logfile_name) # log配置字典 LOGGING_DIC = { 'version': 1, 'disable_existing_loggers': False, 'formatters': { 'standard': { 'format': standard_format }, 'simple': { 'format': simple_format }, 'id_simple': { 'format': id_simple_format }, }, 'filters': {}, 'handlers': { #打印到终端的日志 'console': { 'level': 'DEBUG', 'class': 'logging.StreamHandler', # 打印到屏幕 'formatter': 'simple' }, #打印到文件的日志,收集info及以上的日志 'default': { 'level': 'DEBUG', 'class': 'logging.handlers.RotatingFileHandler', # 保存到文件 'formatter': 'standard', 'filename': logfile_path, # 日志文件 'maxBytes': 1024*1024*5, # 日志大小 5M 'backupCount': 5, 'encoding': 'utf-8', # 日志文件的编码,再也不用担心中文log乱码了 }, 'boss': { 'level': 'DEBUG', 'class': 'logging.handlers.RotatingFileHandler', # 保存到文件 'formatter': 'standard', 'filename': 'boss.log', # 日志文件 'maxBytes': 1024 * 1024 * 5, # 日志大小 5M 'backupCount': 5, 'encoding': 'utf-8', # 日志文件的编码,再也不用担心中文log乱码了 }, }, 'loggers': { #logger1=logging.getLogger(__name__)拿到的logger配置 '': { 'handlers': ['default', 'console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕 'level': 'DEBUG', 'propagate': True, # 向上(更高level的logger)传递 }, #logger1=logging.getLogger('collect')拿到的logger配置 'collect': { 'handlers': ['boss',], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕 'level': 'DEBUG', 'propagate': True, # 向上(更高level的logger)传递 }, }, } def load_my_logging_cfg(): logging.config.dictConfig(LOGGING_DIC) # 导入上面定义的logging配置 logger = logging.getLogger(__name__) # 生成一个log实例 logger.info('It works!') # 记录该文件的运行状态 if __name__ == '__main__': load_my_logging_cfg()
四、logging日志级别详解
import logging ''' 日志级别: critical > error > warning > info > debug,notset 级别越高打印的日志越少,反之亦然,即 debug : 打印全部的日志(notset等同于debug) info : 打印info,warning,error,critical级别的日志 warning : 打印warning,error,critical级别的日志 error : 打印error,critical级别的日志 critical : 打印critical级别 ''' handler=logging.FileHandler("/tmp/TNLOG-error.log") def log(level): logger = logging.getLogger() #不能重复创建handler,否则会重复写入同样的记录? logger.addHandler(handler) logger.setLevel(level) logger.debug("debug") logger.info("info") logger.warning("warning") logger.error("error") logger.critical("critical ") if __name__ == "__main__": log(logging.NOTSET) log(logging.DEBUG) log(logging.INFO) log(logging.WARNING) log(logging.ERROR) log(logging.CRITICAL)
在程序开发阶段,显然我们需要大量的日志,因此日志级别应为debug,等系统逐渐稳定,我们需要记录的日志应该减少一些,这样可以提高程序执行效率(我觉得似乎不应该删除debug级别的日志语句,因为维护时会再度需要?虽然让代码变长,我认为好的系统应该有这样的语句在)这个时候,我们更关心用户在系统里的动作,用户做了什么,如果我们的程序是一个可以买东西的网站,我们需要记录一切与钱有关的信息,即用户对于核心数据的修改,我们必须记录在案,这个时候我们可以选择info和info以上级别的日志,最重要的信息,显然我们需要选择critical级别,具体怎么划分看系统的设计,我也没有太多经验就先不说了,不过异常部分(try-except)我建议还是使用error级别,即使系统正常运行以后也不能保证有未预料的错误产生,一旦选择低级别的日志很可能会漏记重要的系统异常的原因
四内容出自:http://www.cnblogs.com/kill-signal/archive/2012/08/15/2640971.html