码迷,mamicode.com
首页 > 编程语言 > 详细

python logging - vasks

时间:2015-04-02 21:01:54      阅读:207      评论:0      收藏:0      [点我收藏+]

标签:

make sure your python version > Python 2.3

1 从一个小案例说起:

cat howto_logging.py

#coding=utf8
# file name:    howto_logging
# this file shows how to use logging
# made by vasks, email:vasks@qq.com
import logging

# 创建一个logger,级别:DEBUG
logger = logging.getLogger(‘Err_Logger‘)
logger.setLevel(logging.DEBUG)

# 创建一个handler,用于写入日志文件
fh = logging.FileHandler(‘err.log‘)
fh.setLevel(logging.DEBUG)

# 再创建一个handler,用于输出到控制台
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)

# 定义handler的输出格式
formatter = logging.Formatter(‘%(asctime)s - %(name)s - %(levelname)s - %(message)s - %(lineno)d‘)
fh.setFormatter(formatter)
ch.setFormatter(formatter)

# 给logger添加handler
logger.addHandler(fh)
logger.addHandler(ch)

# 记录日志 NOTSET < DEBUG < INFO < WARNING < ERROR < CRITICAL
logger.debug(‘just a debug‘)
logger.info(‘just a info‘)
logger.warning(‘waring,please check out‘)
logger.error(‘error,oh no‘)
logger.critical("critical,it doesn‘t work")  

终端输出执行结果:

2015-04-02 17:03:29,421 - Err_Logger - DEBUG - just a debug - 29
2015-04-02 17:03:29,423 - Err_Logger - INFO - just a info - 30
2015-04-02 17:03:29,423 - Err_Logger - WARNING - waring,please check out - 31
2015-04-02 17:03:29,423 - Err_Logger - ERROR - error,oh no - 32
2015-04-02 17:03:29,423 - Err_Logger - CRITICAL - critical,it doesn‘t work - 33
[Finished in 0.1s]

err.log的结果:

cat err.log
2015-04-02 17:03:29,421 - Err_Logger - DEBUG - just a debug - 29
2015-04-02 17:03:29,423 - Err_Logger - INFO - just a info - 30
2015-04-02 17:03:29,423 - Err_Logger - WARNING - waring,please check out - 31
2015-04-02 17:03:29,423 - Err_Logger - ERROR - error,oh no - 32
2015-04-02 17:03:29,423 - Err_Logger - CRITICAL - critical,it doesn‘t work - 33

2. logging 详解

2.1 logger:提供日志接口,供应用代码使用。logger最长用的操作有两类:配置和发送日志消息。

  • logging.getLogger(name):
    可以通过logging.getLogger(name)获取logger对象,如果不指定name则返回root对象,多次使用相同的name调用getLogger方法返回同一个logger对象。
  • Logger.setLevel(lvl):
    设置logger的level, level有以下几个级别:NOTSET < DEBUG < INFO < WARNING < ERROR < CRITICAL 如果把looger的级别设置为INFO, 那么小于INFO级别的日志都不输出, 大于等于INFO级别的日志都输出。小于的就不会输出。

2.2 handler:将日志记录发送到合适的目的地,比如文件,socket等。一个logger对象可以通过addHandler方法添加0到多个handler,每个handler又可以定义不同日志级别,以实现日志分级过滤显示。

我们这里设置了两个,一个输出到终端,一个输出到err.log文件。
handler主要有以下几种:
StreamHandler: 输出到控制台
FileHandler: 输出到文件
handler还可以设置自己的level以及输出格式。

2.3 filter:提供一种优雅的方式决定一个日志记录是否发送到handler。

2.4 formatter:指定日志记录输出的具体格式。formatter的构造方法需要两个参数:消息的格式字符串和日期字符串,这两个参数都是可选的。

更多的格式:

格式                       描述(代表什么)
%(name)s            Name of the logger (logging channel).
%(levelno)s         Numeric logging level for the message (DEBUG, INFO, WARNING, ERROR, CRITICAL).
%(levelname)s   Text logging level for the message (‘DEBUG‘, ‘INFO‘, ‘WARNING‘, ‘ERROR‘, ‘CRITICAL‘).
%(pathname)s    Full pathname of the source file where the logging call was issued (if available).
%(filename)s            Filename portion of pathname.
%(module)s          Module (name portion of filename).
%(funcName)s    Name of function containing the logging call.
%(lineno)d          Source line number where the logging call was issued (if available).
%(created)f         Time when the LogRecord was created (as returned by time.time()).
%(relativeCreated)d Time in milliseconds when the LogRecord was created, relative to the time the logging module was loaded.
%(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).
%(msecs)d           Millisecond portion of the time when the LogRecord was created.
%(thread)d          Thread ID (if available).
%(threadName)s  Thread name (if available).
%(process)d         Process ID (if available).
%(message)s         The logged message, computed as msg % args.

这里是中文的:

%(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”。逗号后面的是毫秒
%(thread)d           线程ID。可能没有
%(threadName)s        线程名。可能没有
%(process)d        进程ID。可能没有
%(message)s        用户输出的消息

2.5 logging.basicConfig()

2.5.1 logging.basicConfig([**kwargs])

  • 这个函数用来配置root logger, 为root logger创建一个Handler,
    设置默认的格式。

  • 这些函数: logging.debug()、logging.info()、logging.warning()、
    logging.error()、logging.critical() 如果调用的时候发现root logger没有任何
    handler, 会自动调用basicConfig添加一个handler

  • 如果root logger已有handler, 这个函数不做任何事情,使用basicConfig来配置root logger的输出格式和level。
    例子:

        import logging
        logging.basicConfig(format=‘%(levelname)s:%(message)s‘, 
                                                level=logging.DEBUG)
        logging.debug(‘This message should appear on the console‘)
    

关于root logger以及logger的父子关系

前面多次提到root logger, 实际上logger实例之间还有父子关系, root logger就是处于
最顶层的logger, 它是所有logger的祖先。如下图:
技术分享

root logger是默认的logger
如果不创建logger实例, 直接调用logging.debug()、logging.info()、logging.warning()、logging.error()、logging.critical()这些函数,那么使用的logger就是 root logger, 它可以自动创建,也是单实例的。

如何得到root logger
通过logging.getLogger()或者logging.getLogger(““)得到root logger实例。

默认的level
root logger默认的level是logging.WARNING

如何表示父子关系
logger的name的命名方式可以表示logger之间的父子关系. 比如:

    parent_logger = logging.getLogger(‘foo‘)
    child_logger = logging.getLogger(‘foo.bar‘)

什么是effective level
logger有一个概念,叫effective level。 如果一个logger没有显示地设置level,那么它就
用父亲的level。如果父亲也没有显示地设置level, 就用父亲的父亲的level,以此推….
最后到达root logger,一定设置过level。默认为logging.WARNING
child loggers得到消息后,既把消息分发给它的handler处理,也会传递给所有祖先logger处理,

来看一个例子

import logging

# 设置root logger
r = logging.getLogger()
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
formatter = logging.Formatter(‘%(asctime)s - %(levelname)s - %(message)s‘)
ch.setFormatter(formatter)
r.addHandler(ch)

# 创建一个logger作为父亲
p = logging.getLogger(‘foo‘)
p.setLevel(logging.DEBUG)
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
formatter = logging.Formatter(‘%(asctime)s - %(message)s‘)
ch.setFormatter(formatter)
p.addHandler(ch)

# 创建一个孩子logger
c = logging.getLogger(‘foo.bar‘)
c.debug(‘foo‘)  

输出如下:

2015-04-02 18:44:38,128 - foo
2015-04-02 18:44:38,128 - DEBUG - foo
[Finished in 0.2s]

可见, 孩子logger没有任何handler,所以对消息不做处理。但是它把消息转发给了它的父亲以及root logger。最后输出两条日志。

再看个例子:

    import logging

    # set up logging to file - see previous section for more details
    logging.basicConfig(level=logging.DEBUG,
                        format=‘%(asctime)s %(name)-12s %(levelname)-8s %(message)s‘,
                        datefmt=‘%m-%d %H:%M‘,
                        filename=‘mylogging.log‘,
                        filemode=‘w‘)
    # define a Handler which writes INFO messages or higher to the sys.stderr
    console = logging.StreamHandler()
    console.setLevel(logging.WARNING)
    # set a format which is simpler for console use
    formatter = logging.Formatter(‘%(name)-12s: %(levelname)-8s %(message)s‘)
    # tell the handler to use this format
    console.setFormatter(formatter)
    # add the handler to the root logger
    logging.getLogger(‘‘).addHandler(console)

    # Now, we can log to the root logger, or any other logger. First the root...
    logging.info(‘Jackdaws love my big sphinx of quartz.‘)

    # Now, define a couple of other loggers which might represent areas in your
    # application:

    logger1 = logging.getLogger(‘myapp.area1‘)
    logger2 = logging.getLogger(‘myapp.area2‘)

    logger1.debug(‘Quick zephyrs blow, vexing daft Jim.‘)
    logger1.info(‘How quickly daft jumping zebras vex.‘)
    logger2.warning(‘Jail zesty vixen who grabbed pay from quack.‘)
    logger2.error(‘The five boxing wizards jump quickly.‘)

终端输出:

    myapp.area2 : WARNING  Jail zesty vixen who grabbed pay from quack.
    myapp.area2 : ERROR    The five boxing wizards jump quickly.
    [Finished in 0.1s]

终端下 StreamHandler():
logging.info root自己info没有设置的级别warning大,不输出
logger1 的info和debug没有设置的级别:warning 大,所以不输出
logger2符合条件,输出
文本输出:

04-02 19:15 root                 INFO     Jackdaws love my big sphinx of quartz.
04-02 19:15 myapp.area1  DEBUG    Quick zephyrs blow, vexing daft Jim.
04-02 19:15 myapp.area1  INFO     How quickly daft jumping zebras vex.
04-02 19:15 myapp.area2  WARNING  Jail zesty vixen who grabbed pay from quack.
04-02 19:15 myapp.area2  ERROR    The five boxing wizards jump quickly.

basicConfig中设置的报警级别是debug,所以大家都输出了,输出到了文本。

2.5.1 详细说下basicConfig参数:

    filename: 指定日志文件名
    filemode: 和file函数意义相同,指定日志文件的打开模式,‘w‘或‘a‘
    format: 指定输出的格式和内容,format可以输出很多有用信息,如上例所示:
     %(levelno)s: 打印日志级别的数值
     %(levelname)s: 打印日志级别名称
     %(pathname)s: 打印当前执行程序的路径,其实就是sys.argv[0]
     %(filename)s: 打印当前执行程序名
     %(funcName)s: 打印日志的当前函数
     %(lineno)d: 打印日志的当前行号
     %(asctime)s: 打印日志的时间
     %(thread)d: 打印线程ID
     %(threadName)s: 打印线程名称
     %(process)d: 打印进程ID
     %(message)s: 打印日志信息
    datefmt: 指定时间格式,同time.strftime()
    level: 设置日志级别,默认为logging.WARNING
    stream: 指定将日志的输出流,可以指定输出到sys.stderr,sys.stdout或者文件,默认输出到sys.stderr,当stream和filename同时指定时,stream被忽略

本文引用这些博客:

  • http://www.cnblogs.com/captain_jack/archive/2011/01/21/1941453.html
  • http://bbs.chinaunix.net/thread-3590256-1-1.html
  • http://www.cnblogs.com/bjdxy/archive/2013/04/12/3016820.html

python logging - vasks

标签:

原文地址:http://my.oschina.net/VASKS/blog/395355

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!