笔记-python-module-logging.循环日志、多进程日志
笔记-python-module-logging.循环日志、多进程日志
1. logging循环日志
循环日志分为按大小切分和按时间切分,对应实现类如下。
1.1. RotatingFileHandler
常规文件回滚,需要指定文件名,encoding,maxBytes
如果maxbytes=0 或backupcount=0情况下不回滚,也就是只写到一个文件中。
新的日志永远写入filename.log,当它满的时候会将filename.log改名为filename.log.1或其它附加值;
def _set_file_handler(self, level=None):
file_name = os.path.join(LOG_PATH, '{}.log'.format(self.name))
file_handler =
RotatingFileHandler(file_name,
maxBytes=5000,
backupCount=5,
encoding='utf-8')
if not level:
file_handler.setLevel(self.level)
else:
file_handler.setLevel(level)
formatter = logging.Formatter('%(asctime)s
%(filename)s [line:%(lineno)d] %(levelname)s %(message)s')
file_handler.setFormatter(formatter)
self.file_handler
= file_handler
self.addHandler(file_handler)
1.2.
TimeRotatingFileHandler
def _set_time_rotating_handler(self, level=None):
file_name = os.path.join(LOG_PATH, '{}.log'.format(self.name))
time_handler =
logging.handlers.TimedRotatingFileHandler(file_name,
when='h',
interval=1,
backupCount=5)
if not level:
time_handler.setLevel(self.level)
else:
time_handler.setLevel(level)
formatter = logging.Formatter('%(asctime)s
%(filename)s [line:%(lineno)d] %(levelname)s %(message)s')
time_handler.setFormatter(formatter)
time_handler.suffix = "%Y-%m-%d_%H-%M-%S.log"
self.addHandler(time_handler)
需要注意的就是suffix的书写
1.3.
总结
有几个坑要注意:
- 尽量使用Logger(__name__),一般情况下是不需要日志传递的
- 使用getLogger返回的实际是一个日志树
- logger实例初始化的propagate属性是true,即向父辈传递消息。而且消息是直接传递给handler。
2.
multiprocessing and logging
logging 是线程安全的,handler 内部使用了
threading.RLock() 来保证同一时间只有一个线程能够输出。
但是,在使用 logging.FileHandler 时,多进程同时写一个日志文件是不支持的。
测试时发现多个进程写同一个文件是可以的,但部分文档说如果写长字符串时会出问题,测试写5000个字符的日志没问题,更长未确认。
在日志回滚时一定会出问题。
多进程写日志回滚的代码如下:
t
= self.rolloverAt - self.interval
if self.utc:
timeTuple = time.gmtime(t)
else:
timeTuple = time.localtime(t)
dfn = self.baseFilename + "." + time.strftime(self.suffix,
timeTuple)
if os.path.exists(dfn):
os.remove(dfn)
os.rename(self.baseFilename, dfn)
关键是在每个进程在过了rotate时间点之后写第一条日志时,都会执行这个doRollover,判断文件是否存在,如果存在则删除,改名,往新的.log中写入,等多个进程都做一遍后,前一周期的日志完全删除,本周期的日志也会有部分被删除。
术语一点的讲,就是在对文件操作时,没有对多进程进行一些约束。
解决办法:
- 解决文件重名问题:
既然问题是文件重名,那么就不让文件有重名,实际就是每个进程各写一个文件;有两种方法:
1)在文件名中加入pid,问题是老的pid不会被自动删除,无法自维护,不过可以通过定时任务检查并删除。
2)另一种方法是使用进程name做为logger名,在创建进程时给出不同的name,这样不会出现上面的问题;
不让文件重名的好处是可以单独追踪每个进程的日志,坏处是日志不集中。
建议使用这种方式,写日志有两种情况:
1-一般情况下每个进程是负责不同任务的,分开记录便于查找;
2-如果确实需要多个进程执行一样的任务,这时在查找日志记录时是比较麻烦的,不确定在哪个日志文件中,但考虑到工程效率,本方法也是可行的。
- 使用独立进程接收并写日志,logging提供了sockethandler;
- 改写logging的日志回滚类代码,不太喜欢,每次还得注意环境问题。
- 进程锁,效率问题,方法可行,但考虑各种因素,一般不会用。
2.1.
一些问题:windows下多进程异常
报错:The "freeze_support()"
line can be omitted if the program is not going to be
原因及解决方法:
应该是在其它的子进程
里又开了进程,
把创建进程部分放到 if __name__ == ‘__main__’下即可
例:
if __name__ == '__main__':
p = Process(target=func, name='my_process')
p.daemon = True
p.start()
p.join()
print('process
execute complete.')
3.
Logging.getLogger
getLogger是模块级的函数,实际是调用manager.getLogger()
def getLogger(name=None):
"""
Return a logger with the specified name, creating it if necessary.
If no name is specified, return the root logger.
"""
if name:
return Logger.manager.getLogger(name)
else:
return root
继续:manager.getLogger()
def
getLogger(self, name):
"""
Get a logger with the specified name (channel name), creating it
if it doesn't yet exist. This name is a dot-separated hierarchical
name, such as "a", "a.b", "a.b.c" or
similar.
If a PlaceHolder existed for the specified name [i.e. the logger
didn't exist but a child of it did], replace it with the created
logger and fix up the parent/child references which pointed to the
placeholder to now point to the logger.
"""
rv = None
if not isinstance(name, str):
raise TypeError('A logger name must be a string')
_acquireLock()
try:
if name in self.loggerDict:
rv = self.loggerDict[name]
if isinstance(rv, PlaceHolder):
ph = rv
rv = (self.loggerClass or
_loggerClass)(name)
rv.manager = self
self.loggerDict[name] = rv
self._fixupChildren(ph, rv)
self._fixupParents(rv)
else:
rv = (self.loggerClass or
_loggerClass)(name)
rv.manager = self
self.loggerDict[name] = rv
self._fixupParents(rv)
finally:
_releaseLock()
return rv
logging通过manager.loggerDict维护了一个logger列表,实现了相同名称返回同一个loogger。
如果logger名不存在,则创建一个新的:
rv = (self.loggerClass or
_loggerClass)(name)
基本等同于logger(name)
另外一点是logger的继承关系,是通过下面两个方法实现的
self._fixupChildren(ph, rv)
self._fixupParents(rv)
笔记-python-module-logging.循环日志、多进程日志的更多相关文章
- 转 使用Python的logging.config.fileConfig配置日志
Python的logging.config.fileConfig方式配置日志,通过解析conf配置文件实现.文件 logglogging.conf 配置如下: [loggers]keys=root,f ...
- 解决多个py模块调用同一个python的logging模块,打印日志冲突问题
前期对python中的logging模块进行了封装,这样自动化测试框架中的多个测试脚本(py)就可以使用同一个封装后的日志系统,这样各脚本中只需要引用一下即可,方面快捷.那么当我使用unittest框 ...
- Python入门之logging日志模块以及多进程日志
本篇文章主要对 python logging 的介绍加深理解.更主要是 讨论在多进程环境下如何使用logging 来输出日志, 如何安全地切分日志文件. 1. logging日志模块介绍 python ...
- python:利用logbook模块管理日志
日志管理作为软件项目的通用部分,无论是开发还是自动化测试过程中,都显得尤为重要. 最初是打算利用python的logging模块来管理日志的,后来看了些github及其他人的自动化框架设计,做了个比对 ...
- Python 中 logging 日志模块在多进程环境下的使用
因为我的个人网站 restran.net 已经启用,博客园的内容已经不再更新.请访问我的个人网站获取这篇文章的最新内容,Python 中 logging 日志模块在多进程环境下的使用 使用 Pytho ...
- Python中logging在多进程环境下打印日志
因为涉及到进程间互斥与通信问题,因此默认情况下Python中的logging无法在多进程环境下打印日志.但是查询了官方文档可以发现,推荐了一种利用logging.SocketHandler的方案来实现 ...
- python的日志模块:logging;django的日志系统;django日志输出时间修改
Django的log,主要是复用Python标准库中的logging模块,在settings.py中进行配置 源代码 1.__init__.py包含以下类: StreamHandler Formatt ...
- python 以单例模式封装logging相关api实现日志打印类
python 以单例模式封装logging相关api实现日志打印类 by:授客QQ:1033553122 测试环境: Python版本:Python 2.7 实现功能: 支持自由配置,如下lo ...
- 0x04 Python logger 支持多进程日志按大小分割
目录 支持多进程日志按大小分割 多进程日志大小分割handler配置实例 支持多进程日志按大小分割 由于python内置模块logging.handlers.RotatingFileHandler是不 ...
随机推荐
- JSON中不能加注释
今天犯了一个白痴级的错误,那就是向JSON数据文件中,很多行后面添加注释(Comment,//). 导致Node.js程序不能读取JSON文件,Server启动失败. Debug时间蛮久,经同事提醒才 ...
- 轻松解决 Eclipse Indigo 3.7 中文字体偏小,完美 Consolas 微软雅黑混合字体!(转)
在 Windows 7 下初始后化,发现界面变化不大,但中文字体却面目全非,小得根本看不见,而且也看起来很不爽.其实这是 Eclipse 的默认字体换了,以前的一直是 Courier New ,这次e ...
- python socket实现多个连接
socket实现多个连接 前戏很重要~~ 在实现多个连接之前,先实现下多次发送和接收数据. 如果要多次接收数据,那么在服务器端的接收和客户端的发送部分就必须使用循环. 以下代码在python3.5下运 ...
- Tomcat启动报Error listenerStart错误 | "beans" 必须匹配 DOCTYPE 根 "null" | java.lang.reflect.MalformedParameterizedTypeException
maven打包发布工程时,发布上去却报错FAIL - Deployed application at context path /ch but context failed to start 在服务器 ...
- Azure 3月新公布(二)
Azure 3月新发布:HDInsight 的 Apache Hadoop 以及 ExpressRoute 超高性能网关层正式发布,SQL Database Premium RS 层发布公共预览版 A ...
- Java项目性能瓶颈定位
文章目标 当Java项目出现性能瓶颈的时候,通常先是对资源消耗做分析,包括CPU,文件IO,网络IO,内存:之后再结合相应工具查找消耗主体的程序代码.本文主要介绍系统资源消耗的分析过程,以及常用的Ja ...
- TP5.1:数据库的增删改查操作(基于面向对象操作)
我们现实中对数据库的增删改查操作,都是使用模型类进行操作的(表名::),也就是面向对象操作,只有底层的代码用的是数据库操作(Db::table('表名')) 下面我将贴出模型类进行的增删改查操作,通过 ...
- java 通过接口在后台管理器中生成数据
需求:测试人员在后台批量添加数据很麻烦,特别是针对一款商品配置了英语,还需要手动添加法语.俄语.阿拉伯语,很麻烦,但是因为没有项目组配合,做个小工具批量生成数据就只有自己去研究了 第一步:通过抓包工具 ...
- 2018年第九届蓝桥杯【C++省赛B组】第三题 乘积尾零
如下的10行数据,每行有10个整数,请你求出它们的乘积的末尾有多少个零?5650 4542 3554 473 946 4114 3871 9073 90 43292758 7949 6113 5659 ...
- EF 连接 mysq l数据库 code first模式 的实践
准备工作: 1.下载vs2015 2.下载mysql2017 3.安装 开始: 1.创建 控制台文件 2.添加引用 Mysql.Data , Mysql.Data.Entity.EF6,Mysql.w ...