Python 模块之logging

一 前言

Python 的logging 模块定义的函数和类为应用程序和库实现了一个灵活的事件日志系统。该模块提供多种日志级别并且支持多种记录日志的方式比如 终端,文件等等。在编写一个软件系统的时候 ,使用日志系统十分有必要 记录函数的执行过程和异常报错信息。本文算是一个学习笔记,对于跨文件引用的初学者有一定帮助。

二 入门

talk is cheap ,show me the code.

1 例子 logt.py

  1. #!/usr/bin/python
  2. # -*- coding:utf-8 -*-
  3. import logging
  4. logging.debug('this is a debug message')
  5. logging.info('this is a info message')
  6. logging.warn('this is a warn message')
  7. logging.error('this is a error message')
  8. logging.critical('this is a critical message')

运行该脚本

  1. root@rac4:~# >python logt.py
  2. WARNING:root:this is a warn message
  3. ERROR:root:this is a error message
  4. CRITICAL:root:this is a critical message

看到这个输出 ,有人可能会有疑问 为什么 logging.debug()和logging.info()没有输出内容? 恩,这个是个好问题,莫慌,且看下文分析。

2. logging 的日志级别

logging :提供了完整的日志体系,支持五种日志级别以便记录程序的执行过程。

DEBUG :详细信息,典型地调试问题的时候会使用。

INFO :证明事情按预期工作。

WARNING :表明发生了一些意外,或者不久的将来会发生问题(如‘磁盘满了’)。软件还是在正常工作。

ERROR :由于更严重的问题,软件已不能执行一些功能了。

CRITICAL :严重错误,表明软件已不能继续运行了。 以上五种日志级别从低到高分别是:DEBUG < INFO < WARNING < ERROR < CRITICAL 。默认的是WARNING,只有日志级别高于WARNING的日志信息才会输出,而输出有两种方式 一种输出控制台,也是默认的方式,另一种是记录到文件中,如日志文件。

3 logging的配置

python提供了多种配置方式控制日志的显示格式,内容,目的等。如上述例子中的日志输出“WARNING:root:this is awarn message”。

显式创建记录器Logger、处理器Handler和格式化器Formatter,并进行相关设置;

通过简单方式进行配置,使用basicConfig()函数直接进行配置;

通过配置文件进行配置,使用fileConfig()函数读取配置文件;

通过配置字典进行配置,使用dictConfig()函数读取配置信息;

本文使用basicConfig()方式作为例子。

basicConfig()支持下列关键字参数。

格式 描述

filename:创建一个FileHandler,使用指定的文件名,而不是使用StreamHandler。

filemode:如果指明了文件名,指明打开文件的模式(如果没有指明filemode,默认为'a',即append方式)。

format :handler使用指明的格式化字符串。详细的请参考 官方文档

datefmt:使用指明的日期/时间格式 比如 '%Y-%m-%d %H:%M:%S' 2017-11-21 23:10:00。

level 指定logger的日志级别。

stream 使用指明的流来初始化StreamHandler。该参数与'filename'不兼容,如果两个都有,'stream'将被忽略。

  1. #!/usr/bin/python
  2. # -*- coding:utf-8 -*-
  3. import logging
  4. logging.basicConfig(level=logging.DEBUG,
  5. format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
  6. datefmt='%Y%m%d %H:%M:%S',
  7. filename='myapp.log',
  8. filemode='w')
  9. logging.info('info message')
  10. logging.warn('warn message')
  11. logging.error('error message')
  12. logging.critical('critical message')

三 进阶介绍

logging模块提供四个组件logger,handler,filter,formatter

logger:记录器,为应用代码提供日志接口。logger最长用的操作有两类:配置和发送日志消息。可以通过logging.getLogger(name 获取logger对象,如果不指定name则返回root对象,如第一个例子。多次使用相同的name调用getLogger方法返回同一个logger对象。

调用方法:

logger = logging.getLogger(logger_name) #如果不指定 logger_name ,则默认创建一个root logger,见第一个例子。

logger.setLevel(logging.ERROR) #设置日志级别为ERROR,即只有日志级别大于等于ERROR的日志才会输出

logger.addHandler(handler_name) #为logger实例增加一个处理器

logger.removeHandler(handler_name) # 为logger实例删除一个处理器

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

详细信息请移步 官方文档

调用方法

StreamHandler

  1. ch = logging.StreamHandler(stream=None)

FileHandler

  1. fh = logging.FileHandler(filename, mode='a', encoding=None, delay=False)

返回FileHandler类的实例。指明的文件会被打开,并用作日志流。如果没有指明mode,使用'a'。如果encoding不为None,会用指定的编码来打开文件。如果delay为真,只到第一次调用emit()的时候才打开文件。默认情况下,文件会一直增长。 filter:提供一种优雅的方式决定一个日志记录是否发送到handler。 formatter:指定日志记录输出的具体格式。formatter的构造方法需要两个参数:消息的格式字符串和日期字符串,这两个参数都是可选的。 现在我们测试另外一个例子 logconfig.py ,该文件定义了一个init_log 函数,通过传入的参数显示的配置logging。函数里面创建一个logging 实例,分别将日志输出到文件和。当然有兴趣的朋友可以自己设置两个终端,将日志输入到文件的同时也打印到终端,不过线上的日志系统不推荐此类用法。

#!/usr/bin/env python
# coding:utf-8
import logging
import logging.handlers
import os
LOG_LEVELS = {'DEBUG': logging.DEBUG,
              'INFO': logging.INFO,
              'ERROR': logging.ERROR,
              'CRITICAL': logging.CRITICAL}
# 日志的输出的格式
LOGGING_FORMAT = "%(asctime)s [%(name)s] [%(levelname)s] [%(lineno)d] %(message)s"
STANDARD_DATE_FORMAT = '%Y-%m-%d %H:%M:%S'  # 时间格式 2016-06-14 10:10:00
DEFAULT_LOG_MAX_SIZE = 50 * 1024 * 1024     # 当达到50M就进行切分


def init_log(logger_name, level='DEBUG', logfile='',
             formatter=LOGGING_FORMAT, max_size=DEFAULT_LOG_MAX_SIZE):
    log_base = '/data/logs/'
    if not logfile:
        if not os.path.exists(log_base):
            os.mkdir(log_base)
        logfile = os.path.join(log_base, logger_name+'.log')

    logger = logging.getLogger(logger_name)      # 初始化一个logging 实例
    logger.setLevel(LOG_LEVELS[level])           # 设置日志的级别
    formatter = logging.Formatter(formatter)
    fh = logging.handlers.RotatingFileHandler(
        logfile, maxBytes=max_size, backupCount=3)
    # 定义日志输出到文件的handler ,也可以定义 fh=logging.FileHandler(logfile)
    fh.setLevel(logging.DEBUG)
    fh.setFormatter(formatter)
    # add the handlers to the logger
    logger.addHandler(fh)
    return logger


if __name__ == '__main__':
    LOGGER = init_log('youzan', 'INFO', '0614.log')
    LOGGER.info('info message')
    LOGGER.warn('warn message')
    LOGGER.error('error message')
    LOGGER.critical('critical message')

执行该脚本

(agent)➜ utils git:(master) python log_utils.py (agent)➜ utils git:(master) cat 0614.log 2017-11-21 23:32:40,314 [youzan] [INFO] [41] info message 2017-11-21 23:32:40,315 [youzan] [WARNING] [42] warn message 2017-11-21 23:32:40,315 [youzan] [ERROR] [43] error message 2017-11-21 23:32:40,316 [youzan] [CRITICAL] [44] critical message

四 拓展

其实这才是本章的重点,在构建一个整套的程序时,怎么全局配置logging 模块,并在不同的程序中调用呢?例子如下:

root@rac4:~/python# >tree . . ├── log2.py — 引用 logconfig中的logging 配置 ├── logconfig.py —配置logging 输出格式

特别注意,如果是跨文件访问定义的logconfig 配置 ,必须在 logconfig.py 所在的目录创建 __init__.py 空文件

log2.py

import sys
import os
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
from logconfig import init_log 
logger = init_log('logtest','INFO',logfile='666.log')
logger.info('this is a test %s'," yangyi@youzan.com")
logger.debug('debug message')
logger.warn('warn message')
logger.error('error message')
logger.critical('critical message')

(agent)➜ test git:(master) python log2.py

(agent)➜ test git:(master) cat 666.log

2017-11-21 23:38:27,760 [logtest] [INFO] [7] this is a test yangyi@youzan.com

2017-11-21 23:38:27,760 [logtest] [WARNING] [9] warn message

2017-11-21 23:38:27,760 [logtest] [ERROR] [10] error message

2017-11-21 23:38:27,760 [logtest] [CRITICAL] [11] critical message

五 参考文章

1 http://www.jianshu.com/p/feb86c06c4f4

2 http://python.usyiyi.cn/python_278/library/logging.html#

原文发表时间:2017-11-21

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Debian社区

Proxy-Go v3.8 发布,增加了日志文件功能

Proxy-Go v3.8 发布了。Proxy 是 golang 实现的高性能 http,https,websocket,tcp,udp,socks5 代理服务...

712
来自专栏向治洪

github pages + Hexo + 域名绑定搭建个人博客

环境 Windows 10(64 位) Git-2.7.4-64-bit  node-v4.4.7-x64 如果上述软件已经安装的,跳过,没有安装的下载安...

89610
来自专栏漫漫前端路

HTTP协议 - 从URI开始

URI, 既是统一资源标识符号,每个 Web 服务器都有一个 URI 标识符,它在世界范围内唯一标识并定位信息资源。

1524
来自专栏程序猿DD

Jenkins:配置信息变更历史

作者:sparkdev 出处:http://www.cnblogs.com/sparkdev/ 像 Jenkins 这样的系统,使用的过程就是配置文件变更的过程...

2415
来自专栏源哥的专栏

在struts中使用国际化(i18n)

在struts中使用国际化(i18n)     i18n可以满足对系统的国际化,它的原理就是将页面上的所有标志都放到一个消息资源文件中,不同的语言要提供不同的消...

732
来自专栏FreeBuf

闲聊Windows系统日志

最近遇到不少应急都提出一个需求,能不能溯源啊?这个事还真不好干,你把证据,犯案时间都确定的时候,要求翻看监控(日志)对应犯罪嫌疑人时,突然说监控(日志)没有记录...

9000
来自专栏绿巨人专栏

构建纯TypeScript应用

36712
来自专栏超然的博客

web攻击

  最常见和基本的攻击WEB网站的方法。攻击者在网页上发布包含攻击性代码的数据。当浏览者看到此网页时,特定的脚本就会以浏览者用户的身份和权限来执行。通过XSS可...

1251
来自专栏慎独

如何在Github上给别人的项目贡献代码

1354
来自专栏SDNLAB

“访问限制”&“代理访问”实验

前言: 第三届SDN创新大赛又悄悄临近了,第二届大赛时做的题目积压在电脑里实在可惜,因此简单整理,拿出来和大家分享,从代码到实验过程,比较详尽,可以供初学者参考...

38910

扫码关注云+社区

领取腾讯云代金券