Blame src/hooks/abrt_exception_handler_container.py

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