如何解决捕获模块中抛出的错误
我使用 gevent 的 WSGIServer 的 serve_forever()
方法和我自己的证书。
像这样:
http_server = WSGIServer(arguments)
http_server.serve_forever()
显然,由于证书不被识别,它会抛出一个错误:
Traceback (most recent call last):
File "src/gevent/greenlet.py",line 854,in gevent._gevent_cgreenlet.Greenlet.run
File "/usr/local/lib/python3.7/dist-packages/gevent/baseserver.py",line 34,in _handle_and_close_when_done
return handle(*args_tuple)
File "/usr/local/lib/python3.7/dist-packages/gevent/server.py",line 233,in wrap_socket_and_handle
with _closing_socket(self.wrap_socket(client_socket,**self.ssl_args)) as ssl_socket:
File "/usr/local/lib/python3.7/dist-packages/gevent/_ssl3.py",line 802,in wrap_socket
ciphers=ciphers)
File "/usr/local/lib/python3.7/dist-packages/gevent/_ssl3.py",line 312,in __init__
raise x
File "/usr/local/lib/python3.7/dist-packages/gevent/_ssl3.py",line 308,in __init__
self.do_handshake()
File "/usr/local/lib/python3.7/dist-packages/gevent/_ssl3.py",line 667,in do_handshake
self._sslobj.do_handshake()
ssl.SSLError: [SSL: SSLV3_ALERT_CERTIFICATE_UNKNOWN] sslv3 alert certificate unknown (_ssl.c:1091)
2021-02-25T07:44:54Z <Greenlet at 0x7f5d8ffe5b90: _handle_and_close_when_done(<bound method StreamServer.wrap_socket_and_handle,<bound method StreamServer.do_close of <WSGIServer,(<gevent._socket3.socket [closed] at 0x7f5d9b91a1d)> failed with SSLError
我尝试将文件对象传递给 error_log
参数:
file_with_errors = open("path/to/file","+w")
http_server = WSGIServer(arguments,error_log=file_with_errors)
http_server.serve_forever()
我试着简单地捕捉错误:
http_server = WSGIServer(arguments)
try:
http_server.serve_forever()
except:
do_something()
但这些都不起作用,这告诉我错误被抛出并记录在 gevent 模块中的某处。
为了确认这一点,我尝试了:
import io
def func():
http_server = WSGIServer(arguments)
http_server.serve_forever()
try:
_orig_stderr = sys.stderr
_new_stderr = io.StringIO()
sys.stderr = _new_stderr
func()
except:
file_with_errors = open("path/to/file","+w")
_new_stderr.seek(0)
output = _new_stderr.read()
file_with_errors.write(output)
sys.stderr = _orig_stderr
file_with_errors.close()
并发送了一个 KeyboardInterrupt,它起作用了。错误已记录在文件中。
有什么方法可以让我捕获并重定向错误回溯?
解决方法
试试这个:
import logging
import traceback
from wsgiref.simple_server import WSGIServer
logging.basicConfig(filename='test.log',level=logging.DEBUG)
logger = logging.getLogger()
try:
http_server = WSGIServer(arguments)
http_server.serve_forever()
except:
logger.error(traceback.format_exc())
,
这对我有用,它将通过 gevent 控制台发送的任何内容打印到文本文件中。
import logging,sys
from logging import handlers
level = logging.getLevelName('INFO')
log = logging.getLogger('')
log.setLevel(level)
format = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
fh = handlers.RotatingFileHandler('logs/streamlog.txt',maxBytes=(1048576 * 5),backupCount=3)
fh.setFormatter(format)
log.addHandler(fh)
ch = logging.StreamHandler(sys.stdout)
ch.setFormatter(format)
log.addHandler(ch)
,
import logging,backupCount=3)
fh.setFormatter(format)
log.addHandler(fh)
ch = logging.StreamHandler(sys.stdout)
ch.setFormatter(format)
log.addHandler(ch)
,
根据 gevent uwsgi 文档,error_log 是一个类似文件的对象,具有 write、writelines 和 flush 方法,错误日志将写入其中而不是文件名
log – 如果给定,一个对象具有写入方法的请求 (访问)日志将被写入。如果没有给出,默认为 sys.stderr。 您可以通过 None 来禁用请求日志记录。您可以使用包装器, 围绕例如日志记录,以支持未实现写入的对象 方法。 (如果你传递一个 Logger 实例,或者一般来说 提供日志方法但不提供写入方法,这样的包装器将 自动创建,并将在 INFO 级别登录。)
error_log – 如果给定,则是一个类似文件的对象,带有写、写行和 将写入错误日志的刷新方法。如果不给, 默认为 sys.stderr。您可以通过 None 来禁用错误日志记录 (不建议)。您可以使用包装器,例如记录日志,来 支持没有实现正确方法的对象。这 参数将成为 WSGI 中 wsgi.errors 的值 环境(如果尚未设置)。 (与日志一样,Logger 的包装器 实例等将自动创建并记录到 错误级别。)
你可以试试这个:
logger = logging.getLogger()
file_handler = logging.FileHandler("path/to/file.log")
logger.addHandler(file_handler)
logger.setLevel(logging.INFO)
http_server = WSGIServer(arguments,error_log=logger)
http_server.serve_forever()
另一种解决方案
Gevent 将所有日志写入 stderr,您可以将写入 stderr 的所有内容重定向到您的日志文件,并且由于 sys.stderr 只不过是一个文件对象,因此您无法确定 Gevent 是否没有在 sys.stderr 上使用其他方法。代码中其他地方的 stderr。所以你只需要覆盖 sys.stderr.write 保持一切完好,这样 sys.stderr 的任何其他使用都不会破坏 Gevent 和你的应用程序。
class RedirectStderr(file):
def __init__(self,*args,**kwargs):
self._cfg = kwargs.pop('cfg')
self._log_file = open(self._cfg['access_log_path'],'a')
super(RedirectStderr,self).__init__(*args,**kwargs)
def write(self,msg):
# Just in-case you want to write to both stderr and another log file
super(RedirectStderr,self).write(msg)
# Write to another access log file
self._log_file.write(msg)
self._log_file.flush()
# Or use Python's logging facility to log the standard way you log
# across your project
log.info(msg)
def close(self):
super(RedirectStderr,self).close()
self._log_file.close()
import sys
sys.stderr = RedirectStderr('path/to/file','w',cfg=cfg)
您可以在此link
中了解更多信息版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。