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

作者:小恩阿 时间:2021-03-07 04:31:01 

在一些微服务或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)

来源:https://blog.csdn.net/yyy72999/article/details/79610724

标签:Python,ogging,日志,配置
0
投稿

猜你喜欢

  • Oracle针对数据库某一行进行操作的时候,如何将这一行加行锁

    2009-03-06 10:37:00
  • SQLServer 游标简介与使用说明

    2009-07-02 13:53:00
  • Python如何调用JS文件中的函数

    2022-11-21 01:23:11
  • ie的javascript失效问题

    2009-09-21 12:49:00
  • 怎么样用xmlhttp读取远程xml的数据

    2008-10-11 13:52:00
  • 一文让你秒懂精通pip并快速体验深度学习应用【建议收藏】

    2022-07-08 22:27:56
  • Oracle8i和Microsoft SQL Server比较

    2010-07-26 13:05:00
  • Python Selenium自动化获取页面信息的方法

    2023-08-22 18:29:31
  • asp无限级分类加js收缩伸展功能代码

    2009-12-08 12:25:00
  • 一个不错的js软键盘代码而且移植方便

    2007-08-14 12:56:00
  • python编程控制Android手机操作技巧示例

    2021-12-01 07:59:05
  • Python实现的matplotlib动画演示之细胞自动机

    2022-05-23 15:49:09
  • 在ASP.NET 2.0中操作数据之三十九:在DataList的编辑界面里添加验证控件

    2023-07-06 02:02:48
  • Java+mysql本地图片上传数据库及下载示例

    2023-07-23 19:49:13
  • Python获取航线信息并且制作成图的讲解

    2023-08-28 18:18:56
  • Python趣味挑战之实现简易版音乐播放器

    2021-06-25 15:13:43
  • 文案是网站的性格

    2009-09-02 13:05:00
  • nlp自然语言处理学习CBOW模型类实现示例解析

    2023-08-08 00:26:03
  • div水平垂直居中方法(淘宝招聘css题目)

    2007-10-25 12:48:00
  • python自带缓存lru_cache用法及扩展的使用

    2022-06-16 08:48:15
  • asp之家 网络编程 m.aspxhome.com