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 列表,数组,矩阵两两转换tolist()的实例
Apr 04 Python
Python中浅拷贝copy与深拷贝deepcopy的简单理解
Oct 26 Python
python向字符串中添加元素的实例方法
Jun 28 Python
python画图把时间作为横坐标的方法
Jul 07 Python
python版百度语音识别功能
Jul 09 Python
详解PyTorch手写数字识别(MNIST数据集)
Aug 16 Python
python 数据生成excel导出(xlwt,wlsxwrite)代码实例
Aug 23 Python
Python操作SQLite/MySQL/LMDB数据库的方法
Nov 07 Python
Python如何基于selenium实现自动登录博客园
Dec 16 Python
Django中密码的加密、验密、解密操作
Dec 19 Python
Python3.7实现验证码登录方式代码实例
Feb 14 Python
Python数据可视化常用4大绘图库原理详解
Oct 23 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 扩展Memcached命令用法实例总结
2020/06/04 PHP
js 加载时自动调整图片大小
2008/05/28 Javascript
javascript 清除输入框中的数据
2009/04/13 Javascript
jquery 单击li防止重复加载的实现代码
2010/12/24 Javascript
Javascript变量函数浅析
2011/09/02 Javascript
js里取容器大小、定位、距离等属性搜集整理
2013/08/19 Javascript
简单常用的幻灯片播放实现代码
2013/09/25 Javascript
基于jquery实现一张图片点击鼠标放大再点缩小
2013/09/29 Javascript
JS和Jquery获取和修改label的值的示例代码
2014/01/15 Javascript
file控件选择上传文件确定后触发的js事件是哪个
2014/03/17 Javascript
JQuery1.8 判断元素是否绑定事件的方法
2014/07/10 Javascript
jQuery中:submit选择器用法实例
2015/01/03 Javascript
JavaScript为事件句柄绑定监听函数实例详解
2015/12/15 Javascript
JS实现的多张图片轮流播放幻灯片效果
2016/07/22 Javascript
jQuery事件对象总结
2016/10/17 Javascript
angular 基于ng-messages的表单验证实例
2017/05/04 Javascript
js和jquery中获取非行间样式
2017/05/05 jQuery
JS实现留言板功能[楼层效果展示]
2017/12/27 Javascript
vue-cli构建项目下使用微信分享功能
2018/05/28 Javascript
基于vue中对鼠标划过事件的处理方式详解
2018/08/22 Javascript
详解vue中v-on事件监听指令的基本用法
2020/07/22 Javascript
Python文本相似性计算之编辑距离详解
2016/11/28 Python
微信跳一跳游戏python脚本
2020/04/01 Python
使用Python编写Prometheus监控的方法
2018/10/15 Python
opencv实现图片模糊和锐化操作
2018/11/19 Python
pyqt5 QlistView列表显示的实现示例
2020/03/24 Python
django正续或者倒序查库实例
2020/05/19 Python
Python3+selenium配置常见报错解决方案
2020/08/28 Python
canvas实现按住鼠标移动绘制出轨迹的示例代码
2018/02/05 HTML / CSS
three.js模拟实现太阳系行星体系功能
2019/09/03 HTML / CSS
开业庆典主持词
2014/03/21 职场文书
《山谷中的谜底》教学反思
2014/04/26 职场文书
英语复习计划
2015/01/19 职场文书
《蚂蚁和蝈蝈》教学反思
2016/02/22 职场文书
2019年健身俱乐部的创业计划书
2019/08/26 职场文书
Vue vee-validate插件的简单使用
2021/06/22 Vue.js