Python logging日志模块 配置文件方式


Posted in Python onJuly 12, 2020

在一些微服务或web服务中我们难免需要日志功能,用来记录一些用户的登录记录,操作记录,以及一些程序的崩溃定位,执行访问定位等等;

Python内置 非常强大的日志模块 ==> logging 今天给大家分享一下以配置文件形式进行配置log日志 ;

Centos6.7

Python3.6

logging0.5.1.2

logging模块有三个比较重要的功能组件:

1、loggers 配置文件可定义一些输出日志的appname

2、handler 过滤器,比如设置日志的分隔大小,输出位置,日志文件创建等

3、formatters 指定日志输出的格式

1: 创建一个文件,以.conf结尾 或以.ini结尾(PS: 其他的结尾没试过,你可以试试)

vim log.conf

2: 定义日志输出的APP名,指定过滤器这里用loggers功能

[loggers]        #固定写法
keys=root,error,info  #创建三个app名,root是父类,必需存在的

[logger_root]      #创建完的app名我们要定义一些规则,严格要求格式为"logger_appname"
level=DEBUG       #设置日志级别
qualname=root      #这里在"root"appname下可以不填,所有没获取get的情况下默认app名都是root
handlers=debugs     #设置指定过滤器,多个以逗号分隔,这个名字待会儿 我们会以固定格式"handler_(value)"创建

[logger_error]
level=ERROR
qualname=error     #除了root appname以外,定义的app名必须要设置这个属性,用于定义打印输出时候的app名
handlers=errors

[logger_info]
level=INFO
qualname=INFO
handlers=infos

3: 定义日志过滤器这里用handler功能

[handlers]         #固定格式
keys=infos,errors,debugs  #定义过滤器名称,下面定义以handler_keysname格式定义,上面引用名称必须和keys一致

[handler_infos]       
class=FileHandler      #指定过滤器组件,详情请看官网,这个是以文件方式创建
level=INFO         #设置级别
formatter=form01      #定义日志打印格式,下面会创建formatters,格式也是严格要求formatter_keysname 创建
args=('info.log','a')    #创建文件名字,以什么方式打开

[handler_errors] 
class=FileHandler
level=DEBUG
formatter=form02
args=('info1.log','a')

[handler_debugs] 
class=FileHandler
level=DEBUG
formatter=form02
args=('info1.log','a')

3: 定义日志输出格式,这里我们介绍最后一个组件formatters

[formatters]      #固定格式
keys=form01,form02   #定义名称,下面会引用格式同上

[formatter_form01]
format=%(asctime)s %(filename)s %(levelname)s %(message)s #年-月-日 时-分-秒,毫秒,文件名,级别名,消息信息
datefmt=%Y-%m-%d %H:%M:%S  #日期输出格式

[formatter_form02]
format=%(asctime)s %(filename)s %(levelname)s %(message)s
datefmt=%Y-%m-%d %H:%M:%S

4: 具体程序引用

#!/usr/bin/env python
import logging 
import logging.config 
logging.config.fileConfig('log.conf')

logs = logging.getLogger('error')
logs.error('errorsssss')

补充知识:python按照日志等级将日志输出至不同的日志文件

将日志按照等级分别保存在不同的文件中,并在控制台同步输出。

import os
import sys
import logging
from logs.multiprocessloghandler import MultiprocessHandler

def loggerDefine(platform, log_name):
  base_dir = "F:\PythonProject\\xiao_new_resources\logs"

  info_dir_path = base_dir + "\\info\\{}".format(platform)
  error_dir_path = base_dir + "\\error\\{}".format(platform)

  # 判断响应的文件是否存在
  if not os.path.exists(info_dir_path):
    os.makedirs(info_dir_path)
  info_dir = os.path.join(info_dir_path, log_name)

  if not os.path.exists(error_dir_path):
    os.makedirs(error_dir_path)
  error_dir = os.path.join(error_dir_path, log_name)

  # 返回一个logger对象,如果没有指定名字将返回root logger
  log = logging.getLogger('test')

  # 定义日志输出格式
  formattler = '%(asctime)s|%(processName)s|%(threadName)s|%(levelname)s|%(filename)s:%(lineno)d|%(funcName)s|%(message)s'
  fmt = logging.Formatter(formattler)

  # 设置日志控制台输出
  stream_handler = logging.StreamHandler(sys.stdout)
  stream_handler.setLevel(logging.INFO)

  # 设置控制台文件输出
  log_handler_info = MultiprocessHandler(info_dir)
  log_handler_err = MultiprocessHandler(error_dir)

  # 设置日志输出格式:
  stream_handler.setFormatter(fmt)
  log_handler_info.setFormatter(fmt)
  log_handler_err.setFormatter(fmt)

  # 设置过滤条件
  info_filter = logging.Filter()
  info_filter.filter = lambda record: record.levelno < logging.WARNING # 设置过滤等级
  err_filter = logging.Filter()
  err_filter.filter = lambda record: record.levelno >= logging.WARNING

  # 对文件输出日志添加过滤条件
  log_handler_info.addFilter(info_filter)
  log_handler_err.addFilter(err_filter)

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

  log.setLevel("INFO")
  return log

if __name__ == '__main__':
  logg = loggerDefine("youtube", "youtube.log")
  logg.info("info")
  logg.warning("warning")
  logg.error("error")

multiprocessloghandler源码:

import datetime
import logging
import os
import re

try:
  import codecs
except ImportError:
  codecs = None

class MultiprocessHandler(logging.FileHandler):
  """支持多进程的TimedRotatingFileHandler"""

  def __init__(self, filename, when='D', backupCount=7, encoding="utf-8", delay=False):
    """
    filename 日志文件名,when 时间间隔的单位,backupCount 保留文件个数
    delay 是否开启 OutSteam缓存
    True 表示开启缓存,OutStream输出到缓存,待缓存区满后,刷新缓存区,并输出缓存数据到文件。
    False表示不缓存,OutStrea直接输出到文件
    """
    self.prefix = filename
    self.backupCount = backupCount
    self.when = when.upper()
    # 正则匹配 年-月-日
    # 正则写到这里就对了
    self.extMath = r"\d{4}-\d{2}-\d{2}"

    # S 每秒建立一个新文件
    # M 每分钟建立一个新文件
    # H 每天建立一个新文件
    # D 每天建立一个新文件
    self.when_dict = {
      'S': "%Y-%m-%d-%H-%M-%S",
      'M': "%Y-%m-%d-%H-%M",
      'H': "%Y-%m-%d-%H",
      'D': "%Y-%m-%d"
    }
    # 日志文件日期后缀
    self.suffix = self.when_dict.get(when)
    # 源码中self.extMath写在这里
    # 这个正则匹配不应该写到这里,不然非D模式下 会造成 self.extMath属性不存在的问题
    # 不管是什么模式都是按照这个正则来搜索日志文件的。
    # if self.when == 'D':
    #  正则匹配 年-月-日
    #  self.extMath = r"^\d{4}-\d{2}-\d{2}"
    if not self.suffix:
      raise ValueError(u"指定的日期间隔单位无效: %s" % self.when)
    # 拼接文件路径 格式化字符串
    self.filefmt = os.path.join(os.getcwd(), "%s.%s" % (self.prefix, self.suffix))
    a = "%s.%s" % (self.prefix, self.suffix)
    # 使用当前时间,格式化文件格式化字符串
    self.filePath = datetime.datetime.now().strftime(self.filefmt)
    # 获得文件夹路径
    _dir = os.path.dirname(self.filefmt)
    try:
      # 如果日志文件夹不存在,则创建文件夹
      if not os.path.exists(_dir):
        os.makedirs(_dir)
    except Exception:
      print("创建文件夹失败")
      print("文件夹路径:" + self.filePath)
      pass
    if codecs is None:
      encoding = None
      # 调用FileHandler
    logging.FileHandler.__init__(self, self.filePath, 'a+', encoding, delay)

  def shouldChangeFileToWrite(self):
    """更改日志写入目的写入文件
    return True 表示已更改,False 表示未更改"""
    # 以当前时间获得新日志文件路径
    _filePath = datetime.datetime.now().strftime(self.filefmt)
    # 新日志文件日期 不等于 旧日志文件日期,则表示 已经到了日志切分的时候
    #  更换日志写入目的为新日志文件。
    # 例如 按 天 (D)来切分日志
    #  当前新日志日期等于旧日志日期,则表示在同一天内,还不到日志切分的时候
    #  当前新日志日期不等于旧日志日期,则表示不在
    # 同一天内,进行日志切分,将日志内容写入新日志内。
    if _filePath != self.filePath:
      self.filePath = _filePath
      return True
    return False

  def doChangeFile(self):
    """输出信息到日志文件,并删除多于保留个数的所有日志文件"""
    # 日志文件的绝对路径
    self.baseFilename = os.path.abspath(self.filePath)
    # stream == OutStream
    # stream is not None 表示 OutStream中还有未输出完的缓存数据
    if self.stream:
      # self.stream.flush()
      self.stream.close()
      self.stream = None
    # delay 为False 表示 不OutStream不缓存数据 直接输出
    #  所有,只需要关闭OutStream即可
    if not self.delay:
      # self.stream.close()
      self.stream = self._open()

    # 删除多于保留个数的所有日志文件
    if self.backupCount > 0:
      for s in self.getFilesToDelete():
        # print s
        os.remove(s)

  def getFilesToDelete(self):
    """获得过期需要删除的日志文件"""
    # 分离出日志文件夹绝对路径
    # split返回一个元组(absFilePath,fileName)
    # 例如:split('I:\ScripPython\char4\mybook\util\logs\mylog.2017-03-19)
    # 返回(I:\ScripPython\char4\mybook\util\logs, mylog.2017-03-19)
    # _ 表示占位符,没什么实际意义,
    dirName, _ = os.path.split(self.baseFilename)
    fileNames = os.listdir(dirName)
    result = []
    # self.prefix 为日志文件名 列如:mylog.2017-03-19 中的 mylog
    # 加上 点号 . 方便获取点号后面的日期
    prefix = self.prefix
    prefix = _.rsplit(".", 1)[0] + "."
    plen = len(prefix)
    for fileName in fileNames:
      if fileName[:plen] == prefix:
        # 日期后缀 mylog.2017-03-19 中的 2017-03-19
        suffix = fileName[plen:]
        # 匹配符合规则的日志文件,添加到result列表中
        if re.compile(self.extMath).match(suffix):
          result.append(os.path.join(dirName, fileName))
    result.sort()

    # 返回 待删除的日志文件
    #  多于 保留文件个数 backupCount的所有前面的日志文件。
    if len(result) < self.backupCount:
      result = []
    else:
      result = result[:len(result) - self.backupCount]
    return result

  def emit(self, record):
    """发送一个日志记录
    覆盖FileHandler中的emit方法,logging会自动调用此方法"""
    try:
      if self.shouldChangeFileToWrite():
        self.doChangeFile()
      logging.FileHandler.emit(self, record)
    except (KeyboardInterrupt, SystemExit):
      raise
    except:
      self.handleError(record)

以上这篇Python logging日志模块 配置文件方式就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
在Python中使用Neo4j数据库的教程
Apr 16 Python
对于Python中RawString的理解介绍
Jul 07 Python
基于Python 的进程管理工具supervisor使用指南
Sep 18 Python
使用Python+Splinter自动刷新抢12306火车票
Jan 03 Python
Python基于递归算法求最小公倍数和最大公约数示例
Jul 27 Python
使用Python实现将多表分批次从数据库导出到Excel
May 15 Python
浅谈keras.callbacks设置模型保存策略
Jun 18 Python
基于CentOS搭建Python Django环境过程解析
Aug 24 Python
基于Python爬取51cto博客页面信息过程解析
Aug 25 Python
手把手教你从PyCharm安装到激活(最新激活码),亲测有效可激活至2089年
Nov 25 Python
Python绘画好看的星空图
Mar 17 Python
基于Python实现流星雨效果的绘制
Mar 18 Python
django rest framework 过滤时间操作
Jul 12 #Python
使用python脚本自动生成K8S-YAML的方法示例
Jul 12 #Python
python读取excel进行遍历/xlrd模块操作
Jul 12 #Python
django rest framework 自定义返回方式
Jul 12 #Python
Django+RestFramework API接口及接口文档并返回json数据操作
Jul 12 #Python
Python3交互式shell ipython3安装及使用详解
Jul 11 #Python
Python QTimer实现多线程及QSS应用过程解析
Jul 11 #Python
You might like
一个PHP+MSSQL分页的例子
2006/10/09 PHP
PHP正则提取不包含指定网址的图片地址的例子
2014/04/21 PHP
深入讲解PHP的Yii框架中的属性(Property)
2016/03/18 PHP
Yii 2.0自带的验证码使用经验分享
2017/06/19 PHP
PHP基于phpqrcode类生成二维码的方法详解
2018/03/14 PHP
js实现双向链表互联网机顶盒实战应用实现
2011/10/28 Javascript
JavaScript获得指定对象大小的方法
2015/07/01 Javascript
jQuery插件开发汇总
2016/05/15 Javascript
ES6入门教程之let和const命令详解
2017/05/17 Javascript
解决Nodejs全局安装模块后找不到命令的问题
2018/05/15 NodeJs
axios使用拦截器统一处理所有的http请求的方法
2018/11/02 Javascript
ionic4+angular7+cordova上传图片功能的实例代码
2019/06/19 Javascript
解决layer.msg 不居中 ifram中的问题
2019/09/05 Javascript
Taro小程序自定义顶部导航栏功能的实现
2020/12/17 Javascript
Python获取DLL和EXE文件版本号的方法
2015/03/10 Python
PyMongo安装使用笔记
2015/04/27 Python
Python守护进程和脚本单例运行详解
2017/01/06 Python
教你用Python创建微信聊天机器人
2020/03/31 Python
Sanic框架路由用法实例分析
2018/07/16 Python
Python中is和==的区别详解
2018/11/15 Python
Python API自动化框架总结
2019/11/12 Python
python 解决mysql where in 对列表(list,,array)问题
2020/06/06 Python
python 监控logcat关键字功能
2020/09/04 Python
python利用递归方法实现求集合的幂集
2020/09/07 Python
全方位了解CSS3的Regions扩展
2015/08/07 HTML / CSS
伦敦一家非常流行的时尚精品店:Oxygen Boutique
2017/01/15 全球购物
阿迪达斯英国官方网站:adidas英国
2019/08/13 全球购物
捷克建筑材料网上商店:DEK.cz
2021/03/06 全球购物
软件测试工程师面试问题精选
2016/10/28 面试题
医院实习介绍信
2014/01/12 职场文书
教师考察材料范文
2014/06/03 职场文书
2014年全国爱牙日宣传活动方案
2014/09/21 职场文书
民主生活会对照检查材料
2014/09/22 职场文书
四风之害观后感
2015/06/09 职场文书
初中毕业生感言
2015/07/31 职场文书
三好学生竞选稿范文
2019/08/21 职场文书