python 日志logging模块学习

logging模块介绍:

logging是python内置的标准库模块,模块提供不同的日志级别,并可以采用不同的方式记录日志,比如:文件,HTTP GET/POST,SMTP,Socket等,甚至可以实现自己的日记记录方式。
  模块提供logger,handler,filter,formatter
logger
  提供提供日志接口,供应用代码使用。
  logger最常用的操作有两类:配置和发送消息。
  通过logger = logging.getLogger(name)获取logger对象,如果不指定name则返回root对象。多次使用相同的name调用getLogger返回同一个logger对象。
  logging模块保证在同一个python解释器内多次使用相同的name调用getLogger返回同一个logger对象,即使在多个模块的情况下。
handler
  日志处理器。负责日志的具体怎么处理-----将日志发送到合适的目的地。比如:文件,Socket等。
  一个logger对象可以通过addHandler方法添加0到多个handler。每个handler可以定义不同的日志级别,以实现日志分级过滤显示。
filter
  日志过滤器:提供一种优雅的方式决定一个日志记录是否发送到handler
formattler:
  定义日志记录输出格式化方式。
发送消息
  使用logger.info(message),或debug(message)等,发送不同级别的日志消息
  只有发送的消息级别大于或等于设定的日志级别,才会进行日志记录,否则忽略。
配置方式
  python代码配置,配置文件。

logging的简单使用:
将日志消息同时发送到控制台与日志文件内。

coding=utf-8
import logging
import sys

#定义日志输出格式
formattler = '%(levelname)s - %(name)s - %(asctime)s - %(message)s'
fmt = logging.Formatter(formattler)

#获得logger,默认获得root logger对象
#设置logger级别 debug
#root logger默认的级别是warning级别。
#不设置的话 只能发送 >= warning级别的日志
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)

#设置handleer日志处理器,日志具体怎么处理都在日志处理器里面定义
#SteamHandler 流处理器,输出到控制台,输出方式为stdout
#   StreamHandler默认输出到sys.stderr
#设置handler所处理的日志级别。
#   只能处理 >= 所设置handler级别的日志
#设置日志输出格式
stream_handler = logging.StreamHandler(sys.stdout)
stream_handler.setLevel(logging.DEBUG)
stream_handler.setFormatter(fmt)

#FileHandler 文件处理器,定义日志输出到mylog.log文件内
#   文件打开方式默认为 a
file_handler = logging.FileHandler('mylog.log')
file_handler.setLevel(logging.DEBUG)
file_handler.setFormatter(fmt)

#对logger增加handler日志处理器
logger.addHandler(stream_handler)
logger.addHandler(file_handler)

#发送debug级别日志消息
logger.debug('日志测试')
image.png

mylog.log文件内同样出现日志消息。


image.png

logging 的日志级别:
  logging 提供了完整的日志体系,支持五种日志级别以便记录程序的执行过程。
  DEBUG     详细信息,典型地调试问题的时候会使用。
  INFO      证明事情按预期工作。
  WARNING   表明发生了一些意外,或者不久的将来会发生问题(如‘磁盘满了’)。软件还是在正常工作。
  ERROR     由于更严重的问题,软件已不能执行一些功能了。
  CRITICAL    严重错误,表明软件已不能继续运行了。
以上五种日志级别从低到高分别是:DEBUG < INFO < WARNING < ERROR < CRITICAL 。默认的是WARNING,只有日志级别高于WARNING的日志信息才会输出

logging handler 日志处理器:
一些常用的日志处理器handler

  1. logging.StreamHandler
      使用这个Handler可以向类似与sys.stdout或者sys.stderr的流输出信息,也就是输出到控制台。它的构造函数是:StreamHandler([strm])其中strm参数默认是sys.stderr

  2. logging.FileHandler
      和StreamHandler类似,用于向一个文件输出日志信息。不过FileHandler会帮你打开这个文件。它的构造函数是:FileHandler(filename[,mode])
      filename是文件名,必须指定一个文件名。
      mode是文件的打开方式。参见Python内置函数open()的用法。默认是’a',即添加到文件末尾。

  3. logging.handlers.RotatingFileHandler
      这个Handler类似于上面的FileHandler,但是它可以管理文件大小。当文件达到一定大小之后,它会自动将当前日志文件改名,然后创建 一个新的同名日志文件继续输出。比如日志文件是chat.log。当chat.log达到指定的大小之后,RotatingFileHandler自动把 文件改名为chat.log.1。不过,如果chat.log.1已经存在,会先把chat.log.1重命名为chat.log.2。。。最后重新创建 chat.log,继续输出日志信息。它的构造函数是:
      RotatingFileHandler( filename[, mode[, maxBytes[, backupCount]]])
       其中filename和mode两个参数和FileHandler一样。
       maxBytes用于指定日志文件的最大文件大小。如果maxBytes为0,意味着日志文件可以无限大,这时上面描述的重命名过程就不会发生。
       backupCount用于指定保留的备份文件的个数。比如,如果指定为2,当上面描述的重命名过程发生时,原有的chat.log.2并不会被更名,而是被删除。

  4. logging.handlers.TimedRotatingFileHandler
       这个Handler和RotatingFileHandler类似,不过,它没有通过判断文件大小来决定何时重新创建日志文件,而是间隔一定时间就 自动创建新的日志文件。重命名的过程与RotatingFileHandler类似,不过新的文件不是附加数字,而是当前时间。它的构造函数是:
       TimedRotatingFileHandler( filename [,when [,interval [,backupCount]]])
        其中filename参数和backupCount参数和RotatingFileHandler具有相同的意义。
        interval是时间间隔,意思就是间隔多久创建新日志一次。
        when参数是一个字符串。表示时间间隔的单位,不区分大小写。它有以下取值:
         S 秒
         M 分
         H 小时
         D 天
         W 每星期(interval==0时代表星期一)
         midnight 每天凌晨
      比如:when=‘M’,interval=1 就表示一分钟创建新日志一次。

  5. logging.handlers.SocketHandler

  6. logging.handlers.DatagramHandler
       以上两个Handler类似,都是将日志信息发送到网络。不同的是前者使用TCP协议,后者使用UDP协议。它们的构造函数是:
          Handler(host, port)
       其中host是主机名,port是端口名

我们来试一下TimedRotatingFileHandler日志处理器

以一分钟创建一次日志文件。
代码如下:

#coding=utf-8
import sys
import time
import logging
import logging.handlers


#定义日志输出格式
formattler = '%(levelname)s - %(name)s - %(asctime)s - %(message)s'
fmt = logging.Formatter(formattler)

#获得logger,默认获得root logger对象
#设置logger级别 debug
#root logger默认的级别是warning级别。
#不设置的话 只能发送 >= warning级别的日志
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)

#设置handleer日志处理器,日志具体怎么处理都在日志处理器里面定义
#SteamHandler 流处理器,输出到控制台,输出方式为stdout
#   StreamHandler默认输出到sys.stderr
#设置handler所处理的日志级别。
#   只能处理 >= 所设置handler级别的日志
#设置日志输出格式
stream_handler = logging.StreamHandler(sys.stdout)
stream_handler.setLevel(logging.DEBUG)
stream_handler.setFormatter(fmt)

#FileHandler 文件处理器,定义日志输出到mylog.log文件内
#   文件打开方式默认为 a
time_handler = logging.handlers.TimedRotatingFileHandler('mylog.log',when='M',interval=1)
time_handler.setLevel(logging.DEBUG)
time_handler.setFormatter(fmt)

#对logger增加handler日志处理器
logger.addHandler(stream_handler)
logger.addHandler(time_handler)

for i in range(10):
    #发送debug级别日志消息
    #15秒发送一次日志消息
    logger.debug('日志测试'+str(i))
    time.sleep(15)

看一下运行结果:15秒发送一次日志消息。

image.png

看一下日志文件:的确是一分钟新建一个日志文件。
image.png

要注意 第一个日志文件是 mylog.log.2017-03-09_15-32。
最后一个日志文件才是 mylog.log

image.png

image.png

logging Formatters 日志消息格式化。

Formatters 跟python中的字符串格式化是一个意思,定义了最终log信息的顺序,结构和内容
  logging.Formatter(fmt,datefmt)
    fmt参数为格式化字符串
    datefmt为时间格式化,默认的时间格式为%Y-%m-%d %H:%M:%S
常用格式为:
%(name)s        Logger的名字
%(levelno)s       数字形式的日志级别
%(levelname)s     文本形式的日志级别
%(pathname)s      调用日志输出函数的模块的完整路径名,可能没有
%(filename)s      调用日志输出的模块的文件名
%(module)s       调用日志输出函数的模块名
%(funcName)s     调用日志输出函数的函数名
%(lineno)d       调用日志输出函数的语句所在的代码行
%(created)f      当前时间,用UNIX标准的表示时间的浮 点数表示
%(relativeCreated)d   输出日志信息时的,自Logger创建以 来的毫秒数
%(asctime)s       字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒。datefmt就是设置这个的。
%(thread)d       线程ID。可能没有
%(threadName)s    线程名。可能没有
%(process)d      进程ID。可能没有
%(message)s      用户输出的消息。就是logger.info(message)发送的日志消息。
例如:
 '%(levelname)s - %(name)s - %(asctime)s - %(message)s'
表示 输出格式为:
 日志级别名称 - logger名字 - 当前时间 - 日志消息
结果:
 DEBUG - root - 2017-03-09 15:34:27,963 - 日志测试8

logging 配置:
  logging配置有两种方式:python代码内配置,配置文件。
  python代码内配置就是上面那样。
  下面说一下配置文件:
logging配置文件 是 conf格式的文本文件:

#logging.conf
#logging配置文件

#定义logger模块,root是父类,必须存在,其他的自定义
#logging。getLogger(name) 相当于向loggging模块注册了一种日志打印
#如果name为loggers里面keys的值,则调用对应的配置,如果name没有则调用默认(root)的配置
#name 中用点 . 表示继承关系
#可以有多个,以逗号隔开
[loggers]
keys=root,filelog


#实现logger对应的配置信息
#            必须是 logger_name格式  name为loggers中key的值
#level       日志级别,级别有 DEBUG,INFO,WARNING,ERROR,CRITICAL
#handlers    日志处理器,可以有多个 以逗号隔开
#qualname    logger的名称,通过logging.getLogger(name)获取,这里的name便是qualname
#            如果获取的logger 名称不存在,则调用默认(root)logger
#propagate   是否继承符类的配置信息,0:否 1:是
[logger_root]
level=DEBUG
handlers=consoleHandler
qualname=root

#在这里 如果propagate=1,则表示继承父类(root)的配置信息。
#也就是说 既输出到控制台(继承父类的配置)又输出到日志文件
#propagate = 0 表示仅使用自身的配置,仅输出到日志文件 
[logger_filelog]
level=DEBUG
handlers=fileHandler
qualname=filelog
propagate=0

#定义handlers
[handlers]
keys=consoleHandler,fileHandler


#handlers的具体配置实现
#必须是 handler_name格式  name为handlers中key的值
#class为logging包里面的handler处理器
#formatter 日志输入格式
#args handler相关参数
[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=simpleFormatter
args=(sys.stdout,)     

[handler_fileHandler]
class=FileHandler
level=DEBUG
formatter=simpleFormatter
args=('error.log','a')


#定义日志输出格式
[formatters]
keys=simpleFormatter

#日志输出格式化实现
#datefmt 日期格式 对应asctime
#----------------------------
#日志格式
#----------------------------
# %(asctime)s      年-月-日 时-分-秒,毫秒
# %(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=%(levelname)s - %(name)s - %(asctime)s - %(module)s.%(funcName)s - %(message)s
datefmt=%Y-%m-%d %H:%M:%S

这里有个几个地方需要讲解一下:
  logger实现 也就是 logger_name里面的 qualanme 除了root logger以外其他的logger必须都存在,并设置值。
  当logging.getLogger(name)时候 如果配置文件中并没有name,那么则默认获取root的配置。
  propagate 表示是否继承父logger 也就是 root logger的配置。
   如果 propagate = 1 表示继承root logger的配置。
   比如:把 logger_filelog里面的 propagate 设置为 1,则使用filelog的时候 即输出到日志文件,又输出到控制台。
   设置为 0 则仅输出到日志文件。
  propagate默认为 1

下面来使用一下配置文件来配置logging。

logging使用 logging.config.fileConfig(confname)加载日志配置文件。
  加载完后 就可以 使用 logging.getLogger(name)来使用logger了。

#coding=utf-8
import logging.config

#加载配置文件
logging.config.fileConfig('logging.conf')

#获取根 root logger 输出到控制台
root_logger = logging.getLogger()
root_logger.debug('输出到控制台')

#获取名称为 filelog的 logger 输出日志消息到日志文件
logger = logging.getLogger('filelog')
logger.debug('输出到日志文件')

#获取配置文件中不存在的logger,如果不存在,则默认使用root logger的配置
name_logger = logging.getLogger('test')
name_logger.debug('使用 配置文件中logger名称不存在的 logger')

结果如下:


image.png

image.png

可以看到 使用 配置文件中不存在的logger,则默认使用的是root logger的配置。
filelog logger 仅输出到了 日志文件中,并没有在控制台输出。
  因为 filelog logger 中 propagate = 0 表示不继承 root logger 的配置。
设置为 propagate = 1 则 即输出日志文件,又输出到控制台(root logger的配置是输出到控制台)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,390评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,821评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,632评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,170评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,033评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,098评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,511评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,204评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,479评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,572评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,341评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,893评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,171评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,486评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,676评论 2 335

推荐阅读更多精彩内容