Skip to content

Instantly share code, notes, and snippets.

@nobody4t
Last active October 15, 2017 04:16
Show Gist options
  • Save nobody4t/f483edacc539a2128ad27a16d021d4bf to your computer and use it in GitHub Desktop.
Save nobody4t/f483edacc539a2128ad27a16d021d4bf to your computer and use it in GitHub Desktop.
Python logging

Python-logging

日志的重要性不言而喻,特别是在debug或者排除故障过程中起着不可忽略的作用。今天我们看一下python 的标准库--logging。 你可以这么用:

import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
  
logger.info("start reading database")
#some reading code
data = {'Alice':45, 'John': 33}
logger.debug('Data: %s', records)
logger.info('Updating the data...')
logger.info('Finish updating records')

这是最简单的应用。当然不会发挥它所有的威力。对于logging的应用无非有两个方面,配置和应用。 良好的配置设置能让应用事半功倍,那么这样说来重头戏还是配置了。接下来我们由浅入深的讲下logging 的配置。       这是最简单的应用。当然不会发挥它所有的威力。对于logging的应用无非有两个方面,配置和应用。

一般情况下我们会有两种应用,

  1. 直接打印log到终端,这样的的目的是很直观的确认我们的 系统正常运行,万一出现严重的错误,我们会一目了然,然后及时改正。如此省时省力。
  2. 对于比较复杂棘手的bug或者系统问题,我们无法直接找出故障原因,这时候需要我们有抽丝剥茧的耐心, 这时候详细的debug信息就显得非常重要,那么此时log的作用不言而喻了。

logging 的最简单的配置。如上示代码,最简单的应用莫过如此。直接镶嵌在代码中间,并直接log信息 打印到终端。对付简单的系统尚可。下面我们直接看下对于复杂系统的配置。

以代码为例:

   logger = logging.getLogger(name)     一般的logging是通过Logger实例来进行工作。而如果我们想要在应用中使用的话,我们可以直接调用getLogger 获得这种实例,直接把Logger 的接口暴露给了应用。而为了好的应用体验,每一个logger应该有个名字。这里 选择了**name** 这种命名方式被称作package/module,这样的好处是名字可以直接显示package和module的 层级关系。最上层一级被称为根级(root),它的名字自然是root了。

当然我们可以把log传送到不同的目的地,例如,终端,文件,甚至通过网络传送给远端,而这样的任务一般是教给handle, 默认情况下并没有目的地,但是我们可以通过addHandle 函数来添加不同的handle,来将不同的log传送到不同的目的地。 比如,你可能想要把一般的log放在本地,将错误信息及时通过邮件来通知,那么你就需要设置一个本地文件handle和远端的 邮件handle,你可能需要FileHandler和StreamHandler。

#log into the file
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO) #set the logger level

handle = logging.FileHandle("example.log")
handle.setLevel(logging.INFO) # set the handler log level

formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handel.setFormatter(formatter)

logger.addHandle(handle)

logger.info("Hello Baby.")

    运行代码则会产生如下结果: 2017-10-15 11:07:49,196 - main - INFO - Hello Baby.

默认情况下handle没有格式信息和时间戳。如果不指定的话,所有的信息将是默认值。

注意

  1. logger的level必须低于或者等于handler的level,那么handler对应的level信息才会被处理, 否则handler将不会处理相关信息。例如,logger 的level如果是WARNING的话,handler的level 是INFO的话,那么handler将不会收到任何INFO级别的log。如果handler没有设置log level的话, 那么handler自动使用logger的log level,此种行为称之为*effective level 上朔,root的 effective level默认为WARNING

  2. 关于时间格式,可以自行修改,并将参数datefmt传给basicConfig方法即可。

     import logging
     logging.basicConfig(format='%(asctime)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')
     logging.warning('is when this event was logged.')
    

利用配置文件设置:

目前可以通过三种方式来使用配置文件,一种是cofig file 格式如下:

[loggers]
keys=root,simpleExample

[handlers]
keys=consoleHandler

[formatters]
keys=simpleFormatter

[logger_root]
level=DEBUG
handlers=consoleHandler

[logger_simpleExample]
level=DEBUG
handlers=consoleHandler
qualname=simpleExample
propagate=0

[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=simpleFormatter
args=(sys.stdout,)

[formatter_simpleFormatter]
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
datefmt=

    通过loggin.config.fileConfig来完成配置, 这个函数有个小坑,使用必须注意 如果当前程序中config没有配置,那么在使用的时候他会自动清除之前所有的配置信息, 除非将disable_existing_loggers 默认值改为False。对于下面的这个函数同样 也有这么个默认设置,视情况设置即可。

第二种则可以通过json文件和YAMl文件的形式读取配置信息。这两种文件可读性高, 容易通过程序处理,所以备受青睐。而最终还是要归功于logging.config.dictConfig 这个函数可以读取字典类型的配置信息,你甚至可以直接在代码中将配置信息写成字典格式, 直接读取。 当然最可取的方法还是通过配置文件的形式。

最后需要注意的是,当log等级为error的时候你肯定希望打印完成的traceback,如此对 debug很有帮助,那么请设置 èxc_info=True即可。这种设置在捕获错误信息时候 特别有用例如:

try:                                                                                                                                                
    with open("./my.txt", "r") as f:                                                                                                                
    con = f.read()                                                                                                                                                                                                                                                                             
print con                                                                                                                                                                                                                                                                                     
except:                                                                                                                                             
    logger.error("Some errror just happens", exc_info=True) 

Then some useful message will be put out into your log for better debug:

**2017-10-15 12:00:02,621 -- main -- ERROR -- Some errror just happens Traceback (most recent call last): File "simple_logger.py", line 20, in <module> with open("./my.txt", "r") as f: IOError: [Errno 2] No such file or directory: './my.txt' print con **

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment