我一直在尝试编写一个程序来记录子进程的未捕获异常和语法错误.容易,对吧?只需将 stderr
管道传输到正确的位置.
I've been trying to write a program that logs uncaught exceptions and syntax errors for a subprocess. Easy, right? Just pipe stderr
to the right place.
然而,子进程是另一个 python 程序——我将其称为 test.py
——它需要像没有捕获其输出/错误一样运行.也就是说,运行记录器程序需要让用户看起来像正常运行 python test.py
.
However, the subprocess is another python program- I'll call it test.py
- that needs to run as if its output/errors are not being captured. That is, running the logger program needs to seem like the user has just run python test.py
as normal.
使问题更复杂的是 问题 raw_input
实际上被发送如果未使用 readline
,则转至 stderr
.不幸的是,我不能只import readline
,因为我无法控制正在使用我的错误记录器运行的文件.
Further complicating the issue is the problem that raw_input
actually gets sent to stderr
if readline
is not used. Unfortunately, I can't just import readline
, since I don't have control over the files that are being run using my error logger.
注意事项:
pexpect
或编辑 *customize.py
文件(因为该程序将由许多不同的用户运行).我真的觉得无论如何应该有一个标准库解决方案......pexpect
or edit the *customize.py
files (since the program will be run by a lot of different users). I really feel like there should be a stdlib solution anyway though...我尝试了以下方法,没有成功:
I've tried the following methods, without success:
tee
作为问题 如何在使用tee"时将标准错误写入文件使用管道?(未能产生 raw_input
提示);我在几个 SO 问题中发现的 tee
的 python 实现有类似的问题sys.excepthook
(未能使其适用于子进程)raw_input
提示.tee
as in the question How do I write stderr to a file while using "tee" with a pipe? (failed to produce raw_input
prompts); python implementations of tee
that I found in several SO questions had similar issuessys.excepthook
(failed to make it work for a subprocess)raw_input
prompts correctly.根据@nneonneo 在问题评论中的建议,我制作了这个似乎可以完成工作的程序.(请注意,目前,记录器文件的名称必须使用pylog"才能将错误正确打印给最终用户.)
Based on @nneonneo 's advice in the question comments, I made this program that seems to get the job done. (Note that currently, the name of the logger file has to by "pylog" for the errors to be printed correctly to the end user.)
#!/usr/bin/python
'''
This module logs python errors.
'''
import socket, os, sys, traceback
def sendError(err):
# log the error (in my actual implementation, this sends the error to a database)
with open('log','w') as f:
f.write(err)
def exceptHandler(etype, value, tb):
"""An additional wrapper around our custom exception handler, to prevent errors in
this program from being seen by end users."""
try:
subProgExceptHandler(etype, value, tb)
except:
sys.stderr.write('Sorry, but there seems to have been an error in pylog itself. Please run your program using regular python.
')
def subProgExceptHandler(etype, value, tb):
"""A custom exception handler that both prints error and traceback information in the standard
Python format, as well as logs it."""
import linecache
errorVerbatim = ''
# The following code mimics a traceback.print_exception(etype, value, tb) call.
if tb:
msg = "Traceback (most recent call last):
"
sys.stderr.write(msg)
errorVerbatim += msg
# The following code is a modified version of the trackeback.print_tb implementation from
# cypthon 2.7.3
while tb is not None:
f = tb.tb_frame
lineno = tb.tb_lineno
co = f.f_code
filename = co.co_filename
name = co.co_name
# Filter out exceptions from pylog itself (eg. execfile).
if not "pylog" in filename:
msg = ' File "%s", line %d, in %s
' % (filename, lineno, name)
sys.stderr.write(msg)
errorVerbatim += msg
linecache.checkcache(filename)
line = linecache.getline(filename, lineno, f.f_globals)
if line:
msg = ' ' + line.strip() + '
'
sys.stderr.write(msg)
errorVerbatim += msg
tb = tb.tb_next
lines = traceback.format_exception_only(etype, value)
for line in lines:
sys.stderr.write(line)
errorVerbatim += line
# Send the error data to our database handler via sendError.
sendError(errorVerbatim)
def main():
"""Executes the program specified by the user in its own sandbox, then sends
the error to our database for logging and analysis."""
# Get the user's (sub)program to run.
try:
subProgName = sys.argv[1]
subProgArgs = sys.argv[3:]
except:
print 'USAGE: ./pylog FILENAME.py *ARGS'
sys.exit()
# Catch exceptions by overriding the system excepthook.
sys.excepthook = exceptHandler
# Sandbox user code exeuction to its own global namespace to prevent malicious code injection.
execfile(subProgName, {'__builtins__': __builtins__, '__name__': '__main__', '__file__': subProgName, '__doc__': None, '__package__': None})
if __name__ == '__main__':
main()
这篇关于记录 python 子进程的语法错误和未捕获的异常并将它们打印到终端的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!