关于 python 写 log 的一个疑问

2016-11-08 10:47:45 +08:00
 kier
python 自带的 logging 模块虽然有 timerotate ,但是它是把当前 log 文件重命名,然后再开新文件,这样的话,就容易会出现多 process 冲突的问题!
所以楼主在上家公司时,是用的从 logging 模块扩展的模块,具体实现是每小时一个日志文件(文件名里包含时间信息),各个 process 都 append 方式打开写入,当前小时的 log 写完了,自动用 append 方式打开下一个日志文件,这样就不存在重命名的问题,也不会有多 process 冲突的问题。
最近做项目,还是想用这种方式,但是换了东家,原来的代码没找到,所以想网上找,结果一点相关的都没找到,难道就没人这么用的吗?那大家是如何处理写 log ,多 process 的问题呢?都用 sockethandler ,让一个单独的服务去同一写日志?
5154 次点击
所在节点    Python
19 条回复
iyaozhen
2016-11-08 11:00:34 +08:00
这就是两种打日志的风格了。
一种是 access.log
一种是 access.log.2016110810
看日志框架的类型了,一般都支持自己滚动日志。
不过一般第一种用的多, op 会自己配置日志切分程序,先 mv 重命名日志,然后再给写日志的进程发一个啥信号,然后程序会自动在原来的位置再起一个新文件打日志。
knightdf
2016-11-08 11:08:58 +08:00
python 自带的 TimedRotatingFileHandler 本来就在多进程下有 bug,会误删日志.得自己重写 doRollover 函数
doer233
2016-11-08 11:10:26 +08:00
python 新手请教个问题,生产项目的 log 代码直接写在生产代码里面吗?
lostarray
2016-11-08 12:48:36 +08:00
如果是在 Linux 下,可以考虑用 syslog 和 logrotate
onlyice
2016-11-08 12:50:14 +08:00
Python 的官方文档有提到这个问题: https://docs.python.org/3/howto/logging-cookbook.html#logging-to-a-single-file-from-multiple-processes

QueueHandler 可以解决这个问题。它是在 Python 3 中加入的; Python 2 中没有,但是也可以搜到类似代码。
yanchao7511461
2016-11-08 13:13:15 +08:00
借楼问个问题
一般 python 的 traceback 是出错定位的重要信息。但是一个程序里面 我又不想用 try... 能不能想办法把这个错误信息保存下来。看到具体哪行出错。 是不是除了 2 >&1 没办法了?
onlyice
2016-11-08 15:16:17 +08:00
@yanchao7511461 logging 里面的 logger.exception 函数
yanchao7511461
2016-11-08 19:32:10 +08:00
@onlyice 不太明白怎么用...我用 logger 一般都是 try 。。。。 excetion logger.error(" xxx error !!").都是通过 try 然后输出信息的... 所以一旦我的程序后台运行的,某一个我没想到的位置崩溃了。我就看不到 traceback 了.... 能给个例子 说一下 logger.exception 怎么用么
onlyice
2016-11-08 19:39:54 +08:00
@yanchao7511461 啊,我读题没读仔细。。

logger.exception 函数可以把 traceback 也打印下来。

但是对于未捕获的异常,你可以修改 sys.excepthook 来自定义行为: https://docs.python.org/2/library/sys.html#sys.excepthook

但是我不确定是不是好的实践。。感觉可以看看 Sentry 怎么做
kier
2016-11-08 20:47:46 +08:00
@knightdf 嗯,如果按照我帖子里描述的方法,多进程也是没有问题的,只是我在网上居然没有发现有哪怕一个人是用这种方式的,所以觉得很诧异!因为我的理解,对于中小型项目,这种方法的开发运维成本是最低的!
kier
2016-11-08 20:51:10 +08:00
@yanchao7511461 @onlyice 无法预知的 exception 没有必要自己去 try catch ,就让它落到 stderr 就 ok 了,而对于服务端程序这类需要常驻运行的,一般在最外层会捕获异常,并输出的
onlyice
2016-11-08 21:34:18 +08:00
@kier 嗯是的,只是 @yanchao7511461 的场景是他不想去 try catch ,所以可能 sys.excepthook 有作用
fengclient
2016-11-08 22:35:09 +08:00
同意上面说的 syslog/rsyslog ,可以很好解决多点写入的问题,这也是大型系统的标准操作吧。
knightdf
2016-11-08 23:40:57 +08:00
@kier 只要有新文件产生,append 必然也会有问题,因为问题就出在谁来产生这个新文件这.
ericls
2016-11-09 01:44:35 +08:00
用个 queue 来专门写日志
restran
2016-11-09 08:39:17 +08:00
kier
2016-11-09 10:25:20 +08:00
@knightdf 用 append 的方式 open 文件,应该没问题吧, open 应该是 atomic 操作吧
zjq426
2016-11-09 16:03:25 +08:00
@kier https://github.com/zhujiaqi/pycrabapi/tree/master/miscs/logger

我前前东家的项目里面刚好也有这个东西,在前前同事们的授意下我给他开源了
heqingpan
2016-11-09 20:13:13 +08:00
@kier
http://www.cnblogs.com/shizioo/p/python_logging_handler_custom.html
---
import logging
import os,os.path
import datetime

_filefmt=os.path.join("logs","%Y-%m-%d","%H.log")
class MyLoggerHandler(logging.Handler):
def __init__(self,filefmt=None):
self.filefmt=filefmt
if filefmt is None:
self.filefmt=_filefmt
logging.Handler.__init__(self)
def emit(self,record):
msg=self.format(record)
_filePath=datetime.datetime.now().strftime(self.filefmt)
_dir=os.path.dirname(_filePath)
try:
if os.path.exists(_dir) is False:
os.makedirs(_dir)
except Exception:
print "can not make dirs"
print "filepath is "+_filePath
pass
try:
_fobj=open(_filePath,'a')
_fobj.write(msg)
_fobj.write("\n")
_fobj.flush()
_fobj.close()
except Exception:
print "can not write to file"
print "filepath is "+_filePath

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/318922

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX