#:mode=python:
# -*- coding: utf-8 -*-
## Copyright (C) 2018 Red Hat, Inc.
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
"""
Module for the ABRT exception handling hook in container
"""
import sys
import os
from subprocess import Popen, PIPE
from time import strftime
def log(msg):
"""Log message to stderr"""
print(msg, file=sys.stderr)
def write_dump(tb_text, tb):
if sys.argv[0]:
if sys.argv[0][0] == "/":
executable = os.path.abspath(sys.argv[0])
elif sys.argv[0][0] == "-":
executable = "python3 {0} ...".format(sys.argv[0])
else:
executable = sys.argv[0]
else:
# We don't know the path.
# (BTW, we *can't* assume the script is in current directory.)
executable = sys.argv[0]
data = {
"type": "Python3",
"executable": executable,
"reason": tb_text.splitlines()[0],
"backtrace": tb_text,
"time": strftime("%s"),
"pid": os.getpid()
}
import json
try:
json_str = '{0}\n'.format(json.dumps(data))
p = Popen(['container-exception-logger'], stdin=PIPE)
p.communicate(input=json_str.encode())
except Exception as e:
print("ERROR: {}".format(e))
def handle_exception(etype, value, tb):
"""
The exception handling function.
progname - the name of the application
version - the version of the application
"""
try:
# Restore original exception handler
sys.excepthook = sys.__excepthook__ # pylint: disable-msg=E1101
import errno
# Ignore Ctrl-C
# SystemExit rhbz#636913 -> this exception is not an error
if etype in [KeyboardInterrupt, SystemExit]:
return sys.__excepthook__(etype, value, tb)
# Ignore EPIPE: it happens all the time
# Testcase: script.py | true, where script.py is:
## #!/usr/bin/python
## import os
## import time
## time.sleep(1)
## os.write(1, "Hello\n") # print "Hello" wouldn't be the same
#
if etype == IOError or etype == OSError:
if value.errno == errno.EPIPE:
return sys.__excepthook__(etype, value, tb)
import traceback
elist = traceback.format_exception(etype, value, tb)
if tb is not None and etype != IndentationError:
tblast = traceback.extract_tb(tb, limit=None)
if tblast:
tblast = tuple(tblast[-1])
extxt = traceback.format_exception_only(etype, value)
if tblast and len(tblast) > 3:
ll = []
ll.extend(tblast[:3])
ll[0] = os.path.basename(tblast[0])
tblast = ll
text = ""
for t in tblast:
text += "{0}:".format(t)
text += "{0}\n{1}".format(extxt[0], "".join(elist))
trace = tb
while trace.tb_next:
trace = trace.tb_next
frame = trace.tb_frame
text += ("\nLocal variables in innermost frame:\n")
try:
for (key, val) in frame.f_locals.items():
text += "{0}: {1}\n".format(key, repr(val))
except:
pass
else:
text = "{0}\n\n{1}".format(value, "".join(elist))
# Send data to the stderr of PID=1 process
write_dump(text, tb)
except Exception as e:
# Silently ignore any error in this hook,
# to not interfere with other scripts
pass
return sys.__excepthook__(etype, value, tb)
def install_handler():
"""
Install the exception handling function.
"""
sys.excepthook = lambda etype, value, tb: \
handle_exception(etype, value, tb)
# install the exception handler when the abrt_exception_handler
# module is imported
try:
install_handler()
except Exception as e:
pass
if __name__ == '__main__':
# test exception raised to show the effect
div0 = 1 / 0 # pylint: disable-msg=W0612
sys.exit(0)