本章将介绍Python内建模块:日志模块,更多内容请从参考:Python学习指南

简单使用

最开始,我们用最短的代码体验一下logging的基本功能。

  1. import logging
  2. logger = logging.getLogger()
  3. logging.basicConfig()
  4. logger.setLevel('DEBUG')
  5. logger.debug('logsomething')
  6. #输出
  7. out>>DEBG:root:logsomething
  • 第一步,通过logging.getLogger函数,获取一个loger对象,但这个对象暂时是无法使用的。
  • 第二步,logging.basicConfig函数,进行一系列默认的配置,包括format、handler等。
  • 第三步,logger调用setLevel函数定义日志级别为DEBUG
  • 最后,调用debug函数,输出一条debug级别的message,显示在了标准输出上。

logging中的日志级别

logging在生成日志的时候,有一个日志级别的机制,默认有以下几个日志级别:

  1. CRITICAL = 50
  2. ERROR = 40
  3. WARNING = 30
  4. INFO 20
  5. DEBUG = 10
  6. NOTEST = 0

每一个logger对象,都有一个日志级别,它只会输出高于它level的日志。如果一个logger的level是INFO,那么调用logger.debug()是无法输出日志的,而logger.warning()能够输出。

一般来说,以上的6个日志级别完全满足我们日常使用了。

logging中的基础类

logging是python的一个基础模块,它在python中的源码位置如下:

  1. #主干代码
  2. /usr/lib/python2.7/logging/__init__.py
  3. #扩展的handler和config
  4. /usr/lib/pyhon2.7/logging/config.py
  5. /usr/lib/python2.7/loging/handlers.py

组成logging的主干的几个基础类都在__init__.py中:

第一个基础类LogRecord

一个LogRecord对象,对应了日志中的一行数据。通常包含:时间、日志级别、message信息、当前执行的模块、行号、函数名...这些信息都包含在一个LogRecord对象里。

LogRecord对象可以想象成一个大字典:

  1. class LogRecord(object):
  2. #代表一条日志的类
  3. def getMessage(self):
  4. #获取self.msg
  5. def markLogRecord(dict):
  6. #这个方法很重要,生成一个空的LogRecord,然后通过一个字典,直接更新LogReocrd中的成员变量
  7. rv = LogRecord(None, None, "", 0, "", (), None, None)
  8. rv.__dict__.update(dict)
  9. return rv

第二个基础类Formatter

Formatter对象是用来定义日志格式的,LogRecord保存了很多信息,但是打印日志的时候我们只需要其中几个,Formatter就提供了这样的功能,它依赖于python的一个功能:

  1. #通过字典的方式,输出格式化字符串
  2. print('%(name)s:%(num)d'%{'name':'my_name', 'num' : 100})
  3. out >>>my_name:100

如果说LogRecord是后面的那个字典,那么Formatter就是前面的那个格式字符串...的抽象

重要的代码如下:

  1. class Formatter(object):
  2. def __init__(self, fmt=None, datefmt = None):
  3. if fmt:
  4. self._fmt = fmt
  5. else:
  6. #默认的format
  7. self._fmt = "%(message)s"
  8. def format(self, record)
  9. #使用self._fmt进行格式化
  10. s = self._fmt %record.__dict__
  11. return s

第三个基础类Filter和Filterer

Filter类,功能很简单。Filter.filter()函数传入一个LogRecord对象,通过筛选返回1,否则返回0.从代码中可以看到,其实是对LogRecord.name的筛选。

Filterer类中有一个Filter对象的列表,它是一组Filter的抽象。

重要的代码如下:

  1. class Filter(object):
  2. def __init__(self, name=''):
  3. self.name = name
  4. self.nlen = len(name)
  5. def filter(self, record):
  6. #返回1表示record通过,0表示record不通过
  7. if self.nlen == 0:
  8. return 1
  9. elif self.name == record.name:
  10. return 1
  11. #record.name不是以filter开头
  12. elif record.name.find(self.name, 0, self.nlen) != 0:
  13. return 0
  14. #最后一位是否为
  15. return (record.name[self.nlen] == '.')
  16. class Filterer(object):
  17. #这个类其实是定义了一个self.filters = []的列表管理多个filter
  18. def addFilter(self, filter):
  19. def removefilter(self, filter):
  20. def filter(self, record):
  21. #使用列表中所有的filter进行筛选,任何一个失败都会返回0
  22. #例如:
  23. #filter.name = 'A', filter2.name='A.B', filter2.name = 'A, B, C'
  24. #此时record.name = 'A,B,C,D'这样的record才能通过所有filter的筛选

logging中的高级类

有了以上三个基础的类,就可以拼凑一些更重要的高级类了,高级类可以实现logging的重要功能。

Handler——抽象了log的输出过程

  • Handler类继承自Filterer。Handler类时log输出这个过程的抽象。
  • 同时Handler类具有一个成员变量self.level,在第二节讨论的日志级别的机制,就是在Handler中实现的。
  • Handler有一个emit(record)函数,这个函数负责输出log,必须在Handler的子类中实现。

重要代码如下:

  1. class Handler(Filterer):
  2. def __init__(self, level = NOTEST)
  3. #handler必须有level属性
  4. self.level = _checkLevel(level)
  5. def format(self, record):
  6. #使用self.formatter, formattercord
  7. def handler(self, record):
  8. #如果通过filter的筛选,则emit这条log
  9. rv = self.filter(record)
  10. self.emit(record)
  11. def emit(self, record):
  12. #等待子类去实现

接下来看两个简单的handler的子类,其中在logging源码中,有一个handler.py专门定义了很多复杂的handler,有的可以将log缓存在内存中,有的可以将log做rotation等。

StreamHandler

最简单的handler实现,将log写入一个流,默认的stream是sys.stderr

重要的代码如下:

  1. class StreamHandler(Handler):
  2. def __init__(self, stream = None):
  3. if stream is None:
  4. stream = sys.stderr
  5. self.stream = stream
  6. def emit(self, record):
  7. #将record的信息写入流
  8. #处理一些编码的异常
  9. fs = '%s\n' #每条日志都有换行
  10. stream = self.stream
  11. stream.write(fs%msg)

FileHandler

将log输出到文件的handler,继承StreamHandler

重要代码如下:

  1. class FileHandler(StreamHandler):
  2. def __init__(self, filename, mode='a')
  3. #append方式打开一个文件
  4. StreamHandler.__init__(self, self._open())
  5. def emit(self, record):
  6. #和streamhandler保持一致
  7. StreamHandler.emit(self, record)

Logger——一个独立的log管道

什么是logger?

+ logger类继承自Filterer,

+ logger对象有logger.level日志级别

+ logger对象控制多个handler:logger.handlers = []

+ logger对象之间存在福字关系

简单的来说,logger这个类,集中了我们以上所有的LogRecord、Filter类、Formatter类、handler类。首先,logger根据输入生成一个LogRecord读写,经过Filter和Formatter之后,再通过self.handlers列表中的所有handler,把log发送出去。一个logger中可能有多个handler,可以实现把一份log放到任意的位置。

  1. class Logger(Filterer):
  2. def __init__(self, name, level=NOTEST)
  3. #handler列表
  4. self.handlers = []
  5. self.level = _checklevel(level)
  6. def addHandler(self, hdlr):
  7. def removeHandler(self, hdlr):
  8. def _log(self, level, msg, args, exc_info=None, extra=None):
  9. #在_log函数中创建了一个LogRecord对象
  10. record = self.makeRecord(self.name, level, fn, lno, msg, args, exc_info, func, extra)
  11. #交给handle函数
  12. self.handle(record)
  13. def handle(self, reord):
  14. #进行filter,然后调用callHandlers
  15. if(not self.disabled) and self.filter(record):
  16. self.callHandlers(record)
  17. def callHandlers(self, record):
  18. #从当前logger到所有的父logger,递归的handl传入的record
  19. c = self
  20. while c:
  21. for hdlr in c.handlers:
  22. hdlr.handle(record) #进入handler的emit函数发送log
  23. ....
  24. c = c.parent

LoggerAdapter——对标准logger的一个扩展

LogRecord这个大字典中提供的成员变量已经很多,但是,如果在输出log时候仍然希望能够夹带一些自己想要看到的更多信息,例如产生这个log的时候,调用某些函数去获得其他信息,那么就可以把这些添加到Logger中,LoggerAdapter这个类就起到这个作用。

LoggerAdapter这个类很有意思,如果不做什么改动,那么LoggerAdapter类和Logger并没有什么区别。LoggerAdapter只是对Logger类进行了一下包装。

LoggerAdapter的用法其实是在它的成员函数process()的注释中已经说明了:

  1. def process(self, msg, kwargs):
  2. '''
  3. Normally,you'll only need to overwrite this one method in a LoggerAdapter subclass for your specific needs.
  4. '''

也就是说重写process函数,以下是一个例子:

  1. import logging
  2. import random
  3. L=logging.getLogger('name')
  4. #定义一个函数,生成0~1000的随机数
  5. def func():
  6. return random.randint(1,1000)
  7. class myLogger(logging.LoggerAdapter):
  8. #继承LoggerAdapter,重写process,生成随机数添加到msg前面
  9. def process(self,msg,kwargs):
  10. return '(%d),%s' % (self.extra['name'](),msg) ,kwargs
  11. #函数对象放入字典中传入
  12. LA=myLogger(L,{'name':func})
  13. #now,do some logging
  14. LA.debug('some_loging_messsage')
  15. out>>DEBUG:name:(167),some_loging_messsage

参考

python笔记_logging模块(一)

logging代码

python 日志封装

Python中的logging模块

Python自建logging模块的更多相关文章

  1. Python日志输出——logging模块

    Python日志输出——logging模块 标签: loggingpythonimportmodulelog4j 2012-03-06 00:18 31605人阅读 评论(8) 收藏 举报 分类: P ...

  2. Python实战之logging模块使用详解

    用Python写代码的时候,在想看的地方写个print xx 就能在控制台上显示打印信息,这样子就能知道它是什么了,但是当我需要看大量的地方或者在一个文件中查看的时候,这时候print就不大方便了,所 ...

  3. Python中的logging模块就这么用

    Python中的logging模块就这么用 1.日志日志一共分成5个等级,从低到高分别是:DEBUG INFO WARNING ERROR CRITICALDEBUG:详细的信息,通常只出现在诊断问题 ...

  4. python中日志logging模块的性能及多进程详解

    python中日志logging模块的性能及多进程详解 使用Python来写后台任务时,时常需要使用输出日志来记录程序运行的状态,并在发生错误时将错误的详细信息保存下来,以别调试和分析.Python的 ...

  5. Python入门之logging模块

    本章目录: 一.logging模块简介 二.logging模块的使用 三.通过JSON或者YMAL文件配置logging模块 ===================================== ...

  6. Python中的logging模块

    http://python.jobbole.com/86887/ 最近修改了项目里的logging相关功能,用到了python标准库里的logging模块,在此做一些记录.主要是从官方文档和stack ...

  7. python日志记录-logging模块

    1.logging模块日志级别 使用logging模块简单示例: >>>import logging >>>logging.debug("this's a ...

  8. Python自学笔记-logging模块详解

    简单将日志打印到屏幕: import logging logging.debug('debug message') logging.info('info message') logging.warni ...

  9. Day15 Python基础之logging模块(十三)

    参考源:http://www.cnblogs.com/yuanchenqi/articles/5732581.html logging模块 (****重点***) 一 (简单应用) import lo ...

随机推荐

  1. [SDOI2009]E&D

    题目描述 小E 与小W 进行一项名为“E&D”游戏. 游戏的规则如下: 桌子上有2n 堆石子,编号为1..2n.其中,为了方便起见,我们将第2k-1 堆与第2k 堆 (1 ≤ k ≤ n)视为 ...

  2. jQuery的get()post()getJson()方法

    jQuery get() 和 post() 方法用于通过 HTTP GET 或 POST 请求从服务器请求数据. HTTP 请求:GET vs. POST 两种在客户端和服务器端进行请求-响应的常用方 ...

  3. File API文件操作之FileReader

    近来研究点对点的文件传输,想到一种方案FileReader+WebRtc. 当我看到FileReader的时候,哎呀,不错的东西啊,仔细一看属于File API,或者叫做Web API. File A ...

  4. Windows下搭建Redis服务器

    Redis服务器是当下比较流行的缓存服务器,Redis通常被人拿来和Memcached进行对比.在我看来,应当是各具优势吧,虽然应用场景基本类似,但总会根据项目的不同来进行不通的选用. 我们今天主要讲 ...

  5. Ubuntu 安装Appium

    1.安装node apt-get install node.js 2.安装npm apt-get install npm 3.安装cnpm npm install -g cnpm 创建链接:ln -s ...

  6. python实现XSS过滤(BeautifulSoup和白名单处理)

    下面我做的莫名其妙的代码格式化是因为这个 --.-- 首先大致说一下XSS,就是在HTML里插入恶意的javascript代码,使得在该HTML加载时执行恶意代码,达到攻击的目的. 可能存在的地方呢, ...

  7. windows 连接Linux

    服务器:阿里云 ecs 从 Windows 环境远程登录 Linux 实例 远程登录软件的用法大同小异.本文档以 Putty 为例,介绍如何远程登录实例.Putty 操作简单.免费.免安装, 下载地址 ...

  8. .net的retrofit--WebApiClient库深入篇

    前言 本篇文章的内容是对上一篇.net的retrofit--WebApiClient库的深层次补充,你可能需要先阅读上一篇才能理解此篇文章.本文将详细地讲解WebApiClient的原理,结合实际项目 ...

  9. Java关于使用“final”修饰基本类型的注意事项

    今天无意发现这样一道题,可以先做做看: 正确答案是BCD. 至于原因有人给出了参考答案: 1.所有的byte,short,char型的值将被提升为int型: 2.如果有一个操作数是long型,计算结果 ...

  10. 七牛php-sdk使用-在线打包

    如果需要将空间中的多个文件,打包成一个压缩文件,该怎么做,不需要自己本地打包好再上传,七牛已经为我们提供了这项服务. 命令:mkzip/2/url/xx/alias/xxx; 不仅可以将文件打包,还可 ...