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采集腾讯新闻实例
Jul 10 Python
利用Python实现图书超期提醒
Aug 02 Python
Python字典创建 遍历 添加等实用基础操作技巧
Sep 13 Python
python3爬虫怎样构建请求header
Dec 23 Python
Django框架HttpResponse对象用法实例分析
Nov 01 Python
pytorch 批次遍历数据集打印数据的例子
Dec 30 Python
解决python replace函数替换无效问题
Jan 18 Python
多个python文件调用logging模块报错误
Feb 12 Python
python pyqtgraph 保存图片到本地的实例
Mar 14 Python
Python基于gevent实现高并发代码实例
May 15 Python
PyQt实现计数器的方法示例
Jan 18 Python
pytorch中的numel函数用法说明
May 13 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 上一篇,下一篇文章实现代码与原理说明
2010/05/09 PHP
php读取二进制流(C语言结构体struct数据文件)的深入解析
2013/06/13 PHP
PHP中iconv函数知识汇总
2015/07/02 PHP
php投票系统之增加与删除投票(管理员篇)
2016/07/01 PHP
如何在Laravel之外使用illuminate组件详解
2020/09/20 PHP
JavaScript 继承详解(一)
2009/07/13 Javascript
js null undefined 空区别说明
2010/06/13 Javascript
九种js弹出对话框的方法总结
2013/03/12 Javascript
直接拿来用的15个jQuery代码片段
2015/09/23 Javascript
JavaScript判断浏览器和hack滚动条的写法
2017/07/23 Javascript
使用JQ完成表格隔行换色的简单实例
2017/08/25 Javascript
从表单校验看JavaScript策略模式的使用详解
2020/10/17 Javascript
vue+swiper实现左右滑动的测试题功能
2020/10/30 Javascript
vue+openlayers绘制省市边界线
2020/12/24 Vue.js
python中去空格函数的用法
2014/08/21 Python
python中zip和unzip数据的方法
2015/05/27 Python
Python的re模块正则表达式操作
2016/05/25 Python
基于Python log 的正确打开方式
2018/04/28 Python
python: 判断tuple、list、dict是否为空的方法
2018/10/22 Python
Python3最长回文子串算法示例
2019/03/04 Python
python GUI库图形界面开发之PyQt5不规则窗口实现与显示GIF动画的详细方法与实例
2020/03/09 Python
详解Django自定义图片和文件上传路径(upload_to)的2种方式
2020/12/01 Python
英国袜子店:Sock Shop
2017/01/11 全球购物
企业演讲稿范文
2013/12/28 职场文书
单位成立周年感言
2014/01/26 职场文书
秦兵马俑教学反思
2014/02/07 职场文书
春节联欢晚会主持词
2014/03/24 职场文书
幼儿教师师德承诺书
2014/05/23 职场文书
普通党员个人对照检查材料
2014/09/18 职场文书
国家税务局领导班子对照检查材料思想汇报
2014/10/04 职场文书
2014年教师教学工作总结
2014/11/08 职场文书
婚礼答谢礼品
2015/01/20 职场文书
司机岗位职责
2015/02/04 职场文书
物业客服专员岗位职责
2015/04/07 职场文书
践行三严三实心得体会(2016推荐篇)
2016/01/06 职场文书
利用 SQL Server 过滤索引提高查询语句的性能分析
2021/07/15 SQL Server