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统计日志ip访问数的方法
Jul 06 Python
详解Django框架中用户的登录和退出的实现
Jul 23 Python
python3处理含有中文的url方法
May 10 Python
python pandas 对series和dataframe的重置索引reindex方法
Jun 07 Python
python绘制多个子图的实例
Jul 07 Python
python 执行终端/控制台命令的例子
Jul 12 Python
解析python的局部变量和全局变量
Aug 15 Python
利用python实现.dcm格式图像转为.jpg格式
Jan 13 Python
Python基于BeautifulSoup爬取京东商品信息
Jun 01 Python
Tensorflow tensor 数学运算和逻辑运算方式
Jun 30 Python
基于python实现生成指定大小txt文档
Jul 20 Python
Python爬虫之Selenium实现键盘事件
Dec 04 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笔记之:文章中图片处理的使用
2013/04/26 PHP
xss防御之php利用httponly防xss攻击
2014/03/21 PHP
FastCGI 进程意外退出造成500错误
2015/07/26 PHP
PHP按指定键值对二维数组进行排序的方法
2015/12/22 PHP
PHP微信开发之微信消息自动回复下所遇到的坑
2016/05/09 PHP
Thinkphp3.2.3整合phpqrcode生成带logo的二维码
2016/07/21 PHP
基于JavaScript 声明全局变量的三种方式详解
2013/05/07 Javascript
捕获浏览器关闭、刷新事件不同情况下的处理方法
2013/06/02 Javascript
jquery的map与get方法详解
2013/11/04 Javascript
php读取sqlite数据库入门实例代码
2014/06/25 Javascript
JSON字符串和对象之间的转换详解
2015/05/26 Javascript
jQuery实现列表内容的动态载入特效
2015/08/08 Javascript
谈谈AngularJs中的隐藏和显示
2015/12/09 Javascript
js不间断滚动的简单实现
2016/06/03 Javascript
vue里面v-bind和Props 利用props绑定动态数据的方法
2018/08/27 Javascript
解决LayUI加上form.render()下拉框和单选以及复选框不出来的问题
2019/09/27 Javascript
Python编程实现使用线性回归预测数据
2017/12/07 Python
python中的for循环
2018/09/28 Python
pycharm执行python时,填写参数的方法
2018/10/29 Python
Python异常处理知识点总结
2019/02/18 Python
python读写配置文件操作示例
2019/07/03 Python
python装饰器原理与用法深入详解
2019/12/19 Python
python实现录音功能(可随时停止录音)
2020/10/26 Python
css3过渡_动力节点Java学院整理
2017/07/11 HTML / CSS
毕业生自荐书
2013/12/18 职场文书
工程质量承诺书范文
2014/03/27 职场文书
演讲稿的写法
2014/05/19 职场文书
食品委托检验协议书范本
2014/09/12 职场文书
协商一致解除劳动合同协议书
2014/09/14 职场文书
2014乡镇党委副书记对照检查材料思想汇报
2014/10/09 职场文书
2016春季小学开学寄语
2015/12/03 职场文书
教师学习十八届五中全会精神心得体会
2016/01/05 职场文书
司法廉洁教育心得体会
2016/01/20 职场文书
大学自主招生自荐信(2016精选篇)
2016/01/28 职场文书
初三数学教学反思
2016/02/17 职场文书
html css3不拉伸图片显示效果
2021/06/07 HTML / CSS