您的位置:首页技术文章
文章详情页

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

【字号: 日期:2022-07-17 18:18:21浏览:3作者:猪猪

在一些微服务或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名都是roothandlers=debugs #设置指定过滤器,多个以逗号分隔,这个名字待会儿 我们会以固定格式'handler_(value)'创建[logger_error]level=ERRORqualname=error #除了root appname以外,定义的app名必须要设置这个属性,用于定义打印输出时候的app名handlers=errors[logger_info]level=INFOqualname=INFOhandlers=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=FileHandlerlevel=DEBUGformatter=form02args=(’info1.log’,’a’)[handler_debugs] class=FileHandlerlevel=DEBUGformatter=form02args=(’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)sdatefmt=%Y-%m-%d %H:%M:%S

4: 具体程序引用

#!/usr/bin/env pythonimport logging import logging.config logging.config.fileConfig(’log.conf’)logs = logging.getLogger(’error’)logs.error(’errorsssss’)

补充知识:python按照日志等级将日志输出至不同的日志文件

将日志按照等级分别保存在不同的文件中,并在控制台同步输出。

import osimport sysimport loggingfrom logs.multiprocessloghandler import MultiprocessHandlerdef loggerDefine(platform, log_name): base_dir = 'F:PythonProjectxiao_new_resourceslogs' 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 logif __name__ == ’__main__’: logg = loggerDefine('youtube', 'youtube.log') logg.info('info') logg.warning('warning') logg.error('error')

multiprocessloghandler源码:

import datetimeimport loggingimport osimport retry: import codecsexcept ImportError: codecs = Noneclass 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 sos.remove(s) def getFilesToDelete(self): '''获得过期需要删除的日志文件''' # 分离出日志文件夹绝对路径 # split返回一个元组(absFilePath,fileName) # 例如:split(’I:ScripPythonchar4mybookutillogsmylog.2017-03-19) # 返回(I:ScripPythonchar4mybookutillogs, 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-19suffix = 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 编程
相关文章: