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正则匹配查询港澳通行证办理进度示例分享
Dec 27 Python
python抓取京东价格分析京东商品价格走势
Jan 09 Python
解决python3在anaconda下安装caffe失败的问题
Jun 15 Python
Python利用公共键如何对字典列表进行排序详解
May 19 Python
Python中Numpy包的安装与使用方法简明教程
Jul 03 Python
Django框架实现的普通登录案例【使用POST方法】
May 15 Python
python实现自动化上线脚本的示例
Jul 01 Python
Django框架表单操作实例分析
Nov 04 Python
TensorFlow实现打印每一层的输出
Jan 21 Python
python 绘制国旗的示例
Sep 27 Python
python 多进程和协程配合使用写入数据
Oct 30 Python
Flask中jinja2的继承实现方法及实例
Mar 03 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
深入for,while,foreach遍历时间比较的详解
2013/06/08 PHP
php中socket的用法详解
2014/10/24 PHP
PHP基于mssql扩展远程连接MSSQL的简单实现方法
2016/10/08 PHP
ppk谈JavaScript style属性
2008/10/10 Javascript
一个JS小玩意 几个属性相加不能超过一个特定值.
2009/09/29 Javascript
javascript删除一个html元素节点的方法
2014/12/20 Javascript
Underscore.js常用方法总结
2015/02/28 Javascript
JSON字符串和对象相互转换实例分析
2016/06/16 Javascript
javascript特殊文本输入框网页特效
2016/09/13 Javascript
jQuery监听文件上传实现进度条效果的方法
2016/10/16 Javascript
微信小程序 image组件binderror使用例子与js中的onerror区别
2017/02/15 Javascript
vue-cli 如何打包上线的方法示例
2018/05/08 Javascript
对angularJs中ng-style动态改变样式的实例讲解
2018/09/30 Javascript
vue移动端的左右滑动事件详解
2020/06/17 Javascript
[04:44]DOTA2 2017全国高校联赛视频回顾
2017/08/21 DOTA
[01:14]TI珍贵瞬间系列(六):冠军
2020/08/30 DOTA
python使用正则表达式分析网页中的图片并进行替换的方法
2015/03/26 Python
Python CSV模块使用实例
2015/04/09 Python
Pthon批量处理将pdb文件生成dssp文件
2015/06/21 Python
Python装饰器使用实例:验证参数合法性
2015/06/24 Python
Django objects的查询结果转化为json的三种方式的方法
2018/11/07 Python
Python操作MySQL数据库的两种方式实例分析【pymysql和pandas】
2019/03/18 Python
Python图像处理库PIL的ImageDraw模块介绍详解
2020/02/26 Python
pycharm的python_stubs问题
2020/04/08 Python
python 实现读取csv数据,分类求和 再写进 csv
2020/05/18 Python
keras打印loss对权重的导数方式
2020/06/10 Python
python实现excel公式格式化的示例代码
2020/12/23 Python
PyCharm2020.3.2安装超详细教程
2021/02/08 Python
Python解析m3u8拼接下载mp4视频文件的示例代码
2021/03/03 Python
Banana Republic欧盟:美国都市简约风格的代表品牌
2018/05/09 全球购物
美国牛仔品牌:True Religion
2018/11/16 全球购物
鸿星尔克广告词
2014/03/21 职场文书
初中班长竞选稿
2015/11/20 职场文书
2019公司借款合同范本2篇!
2019/07/24 职场文书
如何使用CocosCreator对象池
2021/04/14 Javascript
详解Oracle数据库中自带的所有表结构(sql代码)
2021/11/20 Oracle