Python命令行程序长时间运行后打log会弹异常如何解决

环境为 docker for win10,出异常的地方:

fn = self.logDir + "/%d-%s-%s.log" % (self.no, level, cate)
            file_object = open(fn, 'a')
            file_object.write(logLine)
            file_object.close()

异常为:

Traceback (most recent call last):
  File "/app/src/master.py", line 160, in <module>
  File "/app/src/master.py", line 155, in run
  File "/app/src/utils.py", line 133, in log
IOError: [Errno 5] Input/output error: '/app/var/log/0-warning-.log'

dockerfile 为:

FROM centos:6

RUN yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-6.noarch.rpm &&
yum -y install https://centos6.iuscommunity.org/ius-release.rpm &&
yum -y install htop \ iftop
git2u
vixie-cron
openssh-server
strace
python27
python27-pip &&
yum clean all

RUN ( echo “root”;sleep 1;echo “root” ) | passwd RUN git config --global credential.helper store

ENV IMAGE_VER 0.3 RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
&& echo ‘Asia/Shanghai’ > /etc/timezone

#不用 requirements.txt 而是分开安装在 docker 更快 #2.10.6 RUN pip2.7 install redis -i http://pypi.douban.com/simple/ --trusted-host=pypi.douban.com #2.18.4 RUN pip2.7 install requests -i http://pypi.douban.com/simple/ --trusted-host=pypi.douban.com #4.6.0 RUN pip2.7 install BS4 -i http://pypi.douban.com/simple/ --trusted-host=pypi.douban.com #0.1.7 RUN pip2.7 install pytesseract -i http://pypi.douban.com/simple/ --trusted-host=pypi.douban.com #3.5.0 RUN pip2.7 install ConfigParser -i http://pypi.douban.com/simple/ --trusted-host=pypi.douban.com #3.8.0 RUN pip2.7 install selenium -i http://pypi.douban.com/simple/ --trusted-host=pypi.douban.com

CMD service crond start && service sshd start && /bin/bash


Python命令行程序长时间运行后打log会弹异常如何解决

12 回复

实在搜不到解决方案,不知道啥原因导致的


我遇到过这个问题,通常是因为长时间运行的程序在输出日志时遇到了编码或缓冲区问题。

最常见的情况是Windows控制台的编码问题。试试这个解决方案:

import sys
import io

# 设置标准输出的编码为UTF-8
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='ignore')
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8', errors='ignore')

# 然后正常使用logging
import logging
logging.basicConfig(level=logging.INFO)

如果还不行,可能是日志处理器的问题。长时间运行的程序需要确保日志处理器正确关闭:

import logging
import atexit

# 创建logger
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

# 创建文件处理器
handler = logging.FileHandler('app.log', encoding='utf-8')
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)

# 注册退出时的清理函数
@atexit.register
def cleanup():
    for handler in logger.handlers:
        handler.close()
    logging.shutdown()

# 使用logger
logger.info("程序开始运行")

如果是控制台输出异常,可以改用更稳定的日志库,比如loguru:

from loguru import logger
import sys

# 配置loguru
logger.remove()  # 移除默认配置
logger.add(sys.stderr, format="{time} - {level} - {message}", level="INFO")
logger.add("app.log", rotation="500 MB", retention="10 days")  # 自动轮转日志文件

# 使用
logger.info("程序正常运行")

关键是要确保编码一致性和正确处理资源释放。

不止那个"/app/var/log/0-warning-.log"文件不能写,连别的文件也不能写:
<br>Exception IOError: (5, 'Input/output error', '/app/var/log/0-info-.log') in &lt;bound method Master.__del__ of &lt;__main__.Master object at 0x7f6f7aa9b8d0&gt;&gt; ignored<br>
我有点怀疑是因为我把 win 下的源码映射到 docker 容器的 /app 路径下,docker 容器是这么做的:
<br>docker create -it --name test -v C:/Users/path/to/test:/app -p 23333:22 --cap-add SYS_PTRACE test:0.1<br>

可是事后在 docker 容器里用 vim 也可以打开编辑那些 log 文件啊,比较迷

也没有别的程序以写或者读打开那些 log 文件

看看文件句柄数量是不是超过了当前进程的限制数量。

https://www.cyberciti.biz/faq/linux-increase-the-maximum-number-of-open-files/

- - - -

每写一行打开一次文件不是好的 practice。请用 logging 模块。

请用 logging 模块 +1

IOError: [Errno 5] Input/output error: '/app/var/log/0-warning-.log’

估计是 cate 参数为空导致的?感觉不是大问题。

lz 是不是在程序里开了多线程 /多进程啊 总觉得有点像是写冲突的样子……所以还是老老实实用 logging 吧……

这和 logging 模块无关啊,我只是觉得它太弱了我自己定制了一个,然后打开文件又写了点东西而已,那是个合法的文件名
lsof -n | grep 5950 -c 查出句柄一直是 59,没有泄漏啥的

总之先这样,多谢各位了:
<br> #<a target="_blank" href="https://www.v2ex.com/t/425463" rel="nofollow noopener">https://www.v2ex.com/t/425463</a><br> try:<br> fn = self.logDir + "/%d-%s-%s.log" % (<a target="_blank" href="http://self.no" rel="nofollow noopener">self.no</a>, level, cate)<br> file_object = open(fn, 'a')<br> file_object.write(logLine)<br> file_object.close()<br> fn = self.logDir + "/%d.log" % (<a target="_blank" href="http://self.no" rel="nofollow noopener">self.no</a>)<br> file_object = open(fn, 'a')<br> file_object.write(logLine)<br> file_object.close()<br> except Exception, e:<br> sys.stdout.write(e.message())<br>

出错的时候 pwd 打出来

文件绝对路径打 出来 os path exit 上层目录看看

win 里切换过盘符没 切换了盘符没换回来出错正常

回到顶部