一、日志级别
CRITICAL = 50 #FATAL = CRITICAL ERROR = 40 WARNING = 30 #WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0 #不设置
二、默认级别为warning,默认打印到终端
1 import logging 2 3 logging.debug('调试debug') 4 logging.info('消息info') 5 logging.warning('警告warn') 6 logging.error('错误error') 7 logging.critical('严重critical') 8 9 ''' 10 WARNING:root:警告warn 11 ERROR:root:错误error 12 CRITICAL:root:严重critical 13 '''
三、为logging模块指定全局配置,针对所有logger有效,控制打印到文件中
1 可在logging.basicConfig()函数中通过具体参数来更改logging模块默认行为,可用参数有 2 filename:用指定的文件名创建FiledHandler(后边会具体讲解handler的概念),这样日志会被存储在指定的文件中。 3 filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。 4 format:指定handler使用的日志显示格式。 5 datefmt:指定日期时间格式。 6 level:设置rootlogger(后边会讲解具体概念)的日志级别 7 stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件,默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。 8 9 10 11 #格式 12 %(name)s:Logger的名字,并非用户名,详细查看 13 14 %(levelno)s:数字形式的日志级别 15 16 %(levelname)s:文本形式的日志级别 17 18 %(pathname)s:调用日志输出函数的模块的完整路径名,可能没有 19 20 %(filename)s:调用日志输出函数的模块的文件名 21 22 %(module)s:调用日志输出函数的模块名 23 24 %(funcName)s:调用日志输出函数的函数名 25 26 %(lineno)d:调用日志输出函数的语句所在的代码行 27 28 %(created)f:当前时间,用UNIX标准的表示时间的浮 点数表示 29 30 %(relativeCreated)d:输出日志信息时的,自Logger创建以 来的毫秒数 31 32 %(asctime)s:字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒 33 34 %(thread)d:线程ID。可能没有 35 36 %(threadName)s:线程名。可能没有 37 38 %(process)d:进程ID。可能没有 39 40 %(message)s:用户输出的消息 41 42 43 44 logging.basicConfig()
1 #======介绍 2 可在logging.basicConfig()函数中可通过具体参数来更改logging模块默认行为,可用参数有 3 filename:用指定的文件名创建FiledHandler(后边会具体讲解handler的概念),这样日志会被存储在指定的文件中。 4 filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。 5 format:指定handler使用的日志显示格式。 6 datefmt:指定日期时间格式。 7 level:设置rootlogger(后边会讲解具体概念)的日志级别 8 stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件,默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。 9 10 11 format参数中可能用到的格式化串: 12 %(name)s Logger的名字 13 %(levelno)s 数字形式的日志级别 14 %(levelname)s 文本形式的日志级别 15 %(pathname)s 调用日志输出函数的模块的完整路径名,可能没有 16 %(filename)s 调用日志输出函数的模块的文件名 17 %(module)s 调用日志输出函数的模块名 18 %(funcName)s 调用日志输出函数的函数名 19 %(lineno)d 调用日志输出函数的语句所在的代码行 20 %(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示 21 %(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数 22 %(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒 23 %(thread)d 线程ID。可能没有 24 %(threadName)s 线程名。可能没有 25 %(process)d 进程ID。可能没有 26 %(message)s用户输出的消息 27 28 29 30 31 #========使用 32 import logging 33 logging.basicConfig(filename='access.log', 34 format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', 35 datefmt='%Y-%m-%d %H:%M:%S %p', 36 level=10) 37 38 logging.debug('调试debug') 39 logging.info('消息info') 40 logging.warning('警告warn') 41 logging.error('错误error') 42 logging.critical('严重critical') 43 44 45 46 47 48 #========结果 49 access.log内容: 50 2018-04-18 10:32:17 AM - root - DEBUG -test: 调试debug 51 2018-04-18 10:32:17 AM - root - INFO -test: 消息info 52 2018-04-18 10:32:17 AM - root - WARNING -test: 警告warn 53 2018-04-18 10:32:17 AM - root - ERROR -test: 错误error 54 2018-04-18 10:32:17 AM - root - CRITICAL -test: 严重critical 55 56 part2: 可以为logging模块指定模块级的配置,即所有logger的配置
四、logging模块的Logger,Filter ,Handlerr, Formatter四个对象
#logger:产生日志的对象 #Filter:过滤日志的对象(基本不用) #Handler:接收日志然后控制打印到不同的地方,FileHandler用来打印到文件中,StreamHandler用来打印到终端 #Formatter对象:可以定制不同的日志格式对象,然后绑定给不同的Handler对象使用,以此来控制不同的Handler的日志格式
1 ''' 2 critical=50 3 error =40 4 warning =30 5 info = 20 6 debug =10 7 ''' 8 9 10 import logging 11 12 #1、logger对象:负责产生日志,然后交给Filter过滤,然后交给不同的Handler输出 13 logger=logging.getLogger(__file__) 14 15 #2、Filter对象:不常用,略 16 17 #3、Handler对象:接收logger传来的日志,然后控制输出 18 h1=logging.FileHandler('t1.log') #打印到文件 19 h2=logging.FileHandler('t2.log') #打印到文件 20 h3=logging.StreamHandler() #打印到终端 21 22 #4、Formatter对象:日志格式 23 formmater1=logging.Formatter('%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', 24 datefmt='%Y-%m-%d %H:%M:%S %p',) 25 26 formmater2=logging.Formatter('%(asctime)s : %(message)s', 27 datefmt='%Y-%m-%d %H:%M:%S %p',) 28 29 formmater3=logging.Formatter('%(name)s %(message)s',) 30 31 32 #5、为Handler对象绑定格式 33 h1.setFormatter(formmater1) 34 h2.setFormatter(formmater2) 35 h3.setFormatter(formmater3) 36 37 #6、将Handler添加给logger并设置日志级别 38 logger.addHandler(h1) 39 logger.addHandler(h2) 40 logger.addHandler(h3) 41 logger.setLevel(10) 42 43 #7、测试 44 logger.debug('debug') 45 logger.info('info') 46 logger.warning('warning') 47 logger.error('error') 48 logger.critical('critical')
五、Logger与Handler的级别
logger是第一级过滤,然后才能到handler,我们可以给logger和handler同时设置level,但是需要注意的是logger<handler(级别)
1 Logger is also the first to filter the message based on a level — if you set the logger to INFO, and all handlers to DEBUG, you still won't receive DEBUG messages on handlers — they'll be rejected by the logger itself. If you set logger to DEBUG, but all handlers to INFO, you won't receive any DEBUG messages either — because while the logger says "ok, process this", the handlers reject it (DEBUG < INFO). 2 3 4 5 #验证 6 import logging 7 8 9 form=logging.Formatter('%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', 10 datefmt='%Y-%m-%d %H:%M:%S %p',) 11 12 ch=logging.StreamHandler() 13 14 ch.setFormatter(form) 15 # ch.setLevel(10) 16 ch.setLevel(20) 17 18 l1=logging.getLogger('root') 19 # l1.setLevel(20) 20 l1.setLevel(10) 21 l1.addHandler(ch) 22 23 l1.debug('l1 debug') 24 25 重要,重要,重要!!!
六、Logger的继承(了解)【父类,子类,孙子类】
1 import logging 2 3 formatter=logging.Formatter('%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', 4 datefmt='%Y-%m-%d %H:%M:%S %p',) 5 6 ch=logging.StreamHandler() 7 ch.setFormatter(formatter) 8 9 10 logger1=logging.getLogger('root') 11 logger2=logging.getLogger('root.child1') 12 logger3=logging.getLogger('root.child1.child2') 13 14 15 logger1.addHandler(ch) 16 logger2.addHandler(ch) 17 logger3.addHandler(ch) 18 logger1.setLevel(10) 19 logger2.setLevel(10) 20 logger3.setLevel(10) 21 22 logger1.debug('log1 debug') 23 logger2.debug('log2 debug') 24 logger3.debug('log3 debug') 25 ''' 26 2018-04-18 10:22:05 AM - root - DEBUG -test: log1 debug 27 2018-04-18 10:22:05 AM - root.child1 - DEBUG -test: log2 debug 28 2018-04-18 10:22:05 AM - root.child1 - DEBUG -test: log2 debug 29 2018-04-18 10:22:05 AM- root.child1.child2 - DEBUG -test: log3 debug 30 2018-04-18 10:22:05 AM - root.child1.child2 - DEBUG -test: log3 debug 31 2018-04-18 10:22:05 AM - root.child1.child2 - DEBUG -test: log3 debug 32 '''
七、 应用(模板)
1 """ 2 logging配置 3 """ 4 5 import os 6 import logging.config 7 8 # 定义三种日志输出格式 开始 9 10 standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' 11 '[%(levelname)s][%(message)s]' #其中name为getlogger指定的名字 12 13 simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s' 14 15 id_simple_format = '[%(levelname)s][%(asctime)s] %(message)s' 16 17 # 定义日志输出格式 结束 18 19 logfile_dir = os.path.dirname(os.path.abspath(__file__)) # log文件的目录 20 21 logfile_name = 'all2.log' # log文件名 22 23 # 如果不存在定义的日志目录就创建一个 24 if not os.path.isdir(logfile_dir): 25 os.mkdir(logfile_dir) 26 27 # log文件的全路径 28 logfile_path = os.path.join(logfile_dir, logfile_name) 29 30 # log配置字典 31 LOGGING_DIC = { 32 'version': 1, 33 'disable_existing_loggers': False, 34 'formatters': { 35 'standard': { 36 'format': standard_format 37 }, 38 'simple': { 39 'format': simple_format 40 }, 41 }, 42 'filters': {}, 43 'handlers': { 44 #打印到终端的日志 45 'console': { 46 'level': 'DEBUG', 47 'class': 'logging.StreamHandler', # 打印到屏幕 48 'formatter': 'simple' 49 }, 50 #打印到文件的日志,收集info及以上的日志 51 'default': { 52 'level': 'DEBUG', 53 'class': 'logging.handlers.RotatingFileHandler', # 保存到文件 54 'formatter': 'standard', 55 'filename': logfile_path, # 日志文件 56 'maxBytes': 1024*1024*5, # 日志大小 5M 57 'backupCount': 5, 58 'encoding': 'utf-8', # 日志文件的编码,再也不用担心中文log乱码了 59 }, 60 }, 61 'loggers': { 62 #logging.getLogger(__name__)拿到的logger配置 63 '': { 64 'handlers': ['default', 'console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕 65 'level': 'DEBUG', 66 'propagate': True, # 向上(更高level的logger)传递 67 }, 68 }, 69 } 70 71 72 def load_my_logging_cfg(): 73 logging.config.dictConfig(LOGGING_DIC) # 导入上面定义的logging配置 74 logger = logging.getLogger(__name__) # 生成一个log实例 75 logger.info('It works!') # 记录该文件的运行状态 76 77 if __name__ == '__main__': 78 load_my_logging_cfg() 79 80 logging配置文件
1 """ 2 MyLogging Test 3 """ 4 5 import time 6 import logging 7 import my_logging # 导入自定义的logging配置 8 9 logger = logging.getLogger(__name__) # 生成logger实例 10 11 12 def demo(): 13 logger.debug("start range... time:{}".format(time.time())) 14 logger.info("中文测试开始。。。") 15 for i in range(10): 16 logger.debug("i:{}".format(i)) 17 time.sleep(0.2) 18 else: 19 logger.debug("over range... time:{}".format(time.time())) 20 logger.info("中文测试结束。。。") 21 22 if __name__ == "__main__": 23 my_logging.load_my_logging_cfg() # 在你程序文件的入口加载自定义logging配置 24 demo() 25 26 使用
1 注意注意注意: 2 3 4 #1、有了上述方式我们的好处是:所有与logging模块有关的配置都写到字典中就可以了,更加清晰,方便管理 5 6 7 #2、我们需要解决的问题是: 8 1、从字典加载配置:logging.config.dictConfig(settings.LOGGING_DIC) 9 10 2、拿到logger对象来产生日志 11 logger对象都是配置到字典的loggers 键对应的子字典中的 12 按照我们对logging模块的理解,要想获取某个东西都是通过名字,也就是key来获取的 13 于是我们要获取不同的logger对象就是 14 logger=logging.getLogger('loggers子字典的key名') 15 16 17 但问题是:如果我们想要不同logger名的logger对象都共用一段配置,那么肯定不能在loggers子字典中定义n个key 18 'loggers': { 19 'l1': { 20 'handlers': ['default', 'console'], # 21 'level': 'DEBUG', 22 'propagate': True, # 向上(更高level的logger)传递 23 }, 24 'l2: { 25 'handlers': ['default', 'console' ], 26 'level': 'DEBUG', 27 'propagate': False, # 向上(更高level的logger)传递 28 }, 29 'l3': { 30 'handlers': ['default', 'console'], # 31 'level': 'DEBUG', 32 'propagate': True, # 向上(更高level的logger)传递 33 }, 34 35 } 36 37 38 #我们的解决方式是,定义一个空的key 39 'loggers': { 40 '': { 41 'handlers': ['default', 'console'], 42 'level': 'DEBUG', 43 'propagate': True, 44 }, 45 46 } 47 48 这样我们再取logger对象时 49 logging.getLogger(__name__),不同的文件__name__不同,这保证了打印日志时标识信息不同,但是拿着该名字去loggers里找key名时却发现找不到,于是默认使用key=''的配置 50 51 !!!关于如何拿到logger对象的详细解释!!!
另外一个django的配置,瞄一眼就可以,跟上面的一样
1 #logging_config.py 2 LOGGING = { 3 'version': 1, 4 'disable_existing_loggers': False, 5 'formatters': { 6 'standard': { 7 'format': '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' 8 '[%(levelname)s][%(message)s]' 9 }, 10 'simple': { 11 'format': '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s' 12 }, 13 'collect': { 14 'format': '%(message)s' 15 } 16 }, 17 'filters': { 18 'require_debug_true': { 19 '()': 'django.utils.log.RequireDebugTrue', 20 }, 21 }, 22 'handlers': { 23 #打印到终端的日志 24 'console': { 25 'level': 'DEBUG', 26 'filters': ['require_debug_true'], 27 'class': 'logging.StreamHandler', 28 'formatter': 'simple' 29 }, 30 #打印到文件的日志,收集info及以上的日志 31 'default': { 32 'level': 'INFO', 33 'class': 'logging.handlers.RotatingFileHandler', # 保存到文件,自动切 34 'filename': os.path.join(BASE_LOG_DIR, "xxx_info.log"), # 日志文件 35 'maxBytes': 1024 * 1024 * 5, # 日志大小 5M 36 'backupCount': 3, 37 'formatter': 'standard', 38 'encoding': 'utf-8', 39 }, 40 #打印到文件的日志:收集错误及以上的日志 41 'error': { 42 'level': 'ERROR', 43 'class': 'logging.handlers.RotatingFileHandler', # 保存到文件,自动切 44 'filename': os.path.join(BASE_LOG_DIR, "xxx_err.log"), # 日志文件 45 'maxBytes': 1024 * 1024 * 5, # 日志大小 5M 46 'backupCount': 5, 47 'formatter': 'standard', 48 'encoding': 'utf-8', 49 }, 50 #打印到文件的日志 51 'collect': { 52 'level': 'INFO', 53 'class': 'logging.handlers.RotatingFileHandler', # 保存到文件,自动切 54 'filename': os.path.join(BASE_LOG_DIR, "xxx_collect.log"), 55 'maxBytes': 1024 * 1024 * 5, # 日志大小 5M 56 'backupCount': 5, 57 'formatter': 'collect', 58 'encoding': "utf-8" 59 } 60 }, 61 'loggers': { 62 #logging.getLogger(__name__)拿到的logger配置 63 '': { 64 'handlers': ['default', 'console', 'error'], 65 'level': 'DEBUG', 66 'propagate': True, 67 }, 68 #logging.getLogger('collect')拿到的logger配置 69 'collect': { 70 'handlers': ['console', 'collect'], 71 'level': 'INFO', 72 } 73 }, 74 } 75 76 77 # ----------- 78 # 用法:拿到俩个logger 79 80 logger = logging.getLogger(__name__) #线上正常的日志 81 collect_logger = logging.getLogger("collect") #领导说,需要为领导们单独定制领导们看的日志