summaryrefslogtreecommitdiffstats
path: root/src/Hooks
diff options
context:
space:
mode:
authorJiri Moskovcak <jmoskovc@redhat.com>2009-06-02 17:06:39 +0200
committerJiri Moskovcak <jmoskovc@redhat.com>2009-06-02 17:06:39 +0200
commit8024b6ca0335cb59f737769f2e573435e32dd155 (patch)
treea7aa3da017f04b56191fa2d93fd22096e269eef0 /src/Hooks
parent8966e621a0809d2109133f180db6a23bb4335843 (diff)
downloadabrt-8024b6ca0335cb59f737769f2e573435e32dd155.tar.gz
abrt-8024b6ca0335cb59f737769f2e573435e32dd155.tar.xz
abrt-8024b6ca0335cb59f737769f2e573435e32dd155.zip
New hook for python apps
- minor fixes in python analyzer
Diffstat (limited to 'src/Hooks')
-rw-r--r--src/Hooks/Makefile.am13
-rw-r--r--src/Hooks/abrt_exception_handler.py.in333
-rw-r--r--src/Hooks/pyhook.conf1
-rw-r--r--src/Hooks/sitecustomize.py30
4 files changed, 377 insertions, 0 deletions
diff --git a/src/Hooks/Makefile.am b/src/Hooks/Makefile.am
index 88361c6b..2bb2e255 100644
--- a/src/Hooks/Makefile.am
+++ b/src/Hooks/Makefile.am
@@ -5,3 +5,16 @@ hookCCpp_SOURCES = CCpp.cpp
hookCCpp_LDADD = ../../lib/Utils/libABRTUtils.la
hookCCpp_CPPFLAGS = -I$(srcdir)/../../inc -I$(srcdir)/../../lib/Utils \
-DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\"
+
+python_PYTHON = sitecustomize.py abrt_exception_handler.py
+
+EXTRA_DIST = pyhook.conf
+
+# FIXME: remove hardcoded path
+pyhookconfdir = /etc/abrt
+dist_pyhookconf_DATA = pyhook.conf
+
+CLEANFILES := $(notdir $(wildcard *~)) $(notdir $(wildcard *\#)) $(notdir $(wildcard \.\#*)) $(notdir $(wildcard *.pyc))
+
+install-data-local:
+ sed s,@DEBUG_DUMP_DIR@,$(DEBUG_DUMPS_DIR),g abrt_exception_handler.py.in > abrt_exception_handler.py
diff --git a/src/Hooks/abrt_exception_handler.py.in b/src/Hooks/abrt_exception_handler.py.in
new file mode 100644
index 00000000..4283f3b6
--- /dev/null
+++ b/src/Hooks/abrt_exception_handler.py.in
@@ -0,0 +1,333 @@
+# -*- coding: utf-8 -*-
+## Copyright (C) 2001-2005 Red Hat, Inc.
+## Copyright (C) 2001-2005 Harald Hoyer <harald@redhat.com>
+## Copyright (C) 2009 Jiri Moskovcak <jmoskovc@redhat.com>
+
+## 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+"""
+Module for a userfriendly exception handling
+
+Example code:
+
+import sys
+
+from exception import action, error, exitcode, installExceptionHandler
+
+installExceptionHandler("test", "1.0", gui=0, debug=0)
+
+def exception_function():
+ action("Trying to divide by zero")
+
+ try:
+ local_var_1 = 1
+ local_var_2 = 0
+ # test exception raised to show the effect
+ local_var_3 = local_var_1 / local_var_2
+ except:
+ error("Does not seem to work!? :-)")
+ exitcode(15)
+ raise
+
+"""
+import sys
+import os
+import syslog
+# abrt lib for saving debugdumps
+import ABRTUtils
+
+from rhpl.translate import _
+
+
+__DUMPHASH = {}
+# FIXME: do length limits on obj dumps.
+def __dump_class(instance, fd, level=0):
+ "dumps all classes"
+ import types
+ # protect from loops
+ if not __DUMPHASH.has_key(instance):
+ __DUMPHASH[instance] = True
+ else:
+ fd.write("Already dumped\n")
+ return
+ if (instance.__class__.__dict__.has_key("__str__") or
+ instance.__class__.__dict__.has_key("__repr__")):
+ fd.write("%s\n" % (instance,))
+ return
+ fd.write("%s instance, containing members:\n" %
+ (instance.__class__.__name__))
+ pad = ' ' * ((level) * 2)
+ for key, value in instance.__dict__.items():
+ if type(value) == types.ListType:
+ fd.write("%s%s: [" % (pad, key))
+ first = 1
+ for item in value:
+ if not first:
+ fd.write(", ")
+ else:
+ first = 0
+ if type(item) == types.InstanceType:
+ __dump_class(item, fd, level + 1)
+ else:
+ fd.write("%s" % (item,))
+ fd.write("]\n")
+ elif type(value) == types.DictType:
+ fd.write("%s%s: {" % (pad, key))
+ first = 1
+ for k, v in value.items():
+ if not first:
+ fd.write(", ")
+ else:
+ first = 0
+ if type(k) == types.StringType:
+ fd.write("'%s': " % (k,))
+ else:
+ fd.write("%s: " % (k,))
+ if type(v) == types.InstanceType:
+ __dump_class(v, fd, level + 1)
+ else:
+ fd.write("%s" % (v,))
+ fd.write("}\n")
+ elif type(value) == types.InstanceType:
+ fd.write("%s%s: " % (pad, key))
+ __dump_class(value, fd, level + 1)
+ else:
+ fd.write("%s%s: %s\n" % (pad, key, value))
+
+def write_dump(pid, tb_uuid, tb):
+ import time
+ ttime = int(time.time())
+ # localstatedir
+ #dir_name = "/home/jmoskovc/.local/abrt/var/cache/abrt/pyhook-%s-%s" % (ttime , pid)
+ dir_name = "@DEBUG_DUMP_DIR@/pyhook-%s-%s" % (ttime , pid)
+ dd = ABRTUtils.CDebugDump()
+ try:
+ #os.mkdir(dir_name)
+ dd.Create(dir_name)
+ except Exception, e:
+ syslog.syslog("abrt: Cannot create dir %s" % dir_name)
+ return
+ # save executable
+ fexecutable = open("%s/executable" % dir_name, "w")
+ if sys.argv[0]:
+ fexecutable.write(os.path.abspath(sys.argv[0]))
+ else:
+ fexecutable.write("Exception raised from python shell")
+ fexecutable.close()
+ # save coredump
+ coredump = open("%s/backtrace" % dir_name, "w")
+ coredump.write(tb)
+ coredump.close()
+ # save uuid
+ uuid = open("%s/uuid" % dir_name, "w")
+ uuid.write(tb_uuid)
+ uuid.close()
+ # save cmdline
+ cmdline = open("%s/cmdline" % dir_name, "w")
+ cmdline.write(open("/proc/%s/cmdline" % pid).read().replace('\x00',' '))
+ cmdline.close()
+ # save uid
+ uid = open("%s/uid" % dir_name, "w")
+ uid.write(open("/proc/%s/loginuid" % pid).readlines()[0])
+ uid.close()
+ # save analyzer
+ analyzer = open("%s/analyzer" % dir_name, "w")
+ analyzer.write("Python")
+ analyzer.close()
+ dd.Close()
+
+def __dump_exception(out, text, tracebk):
+ 'write a traceback to "out"'
+
+ out.write(text)
+
+ trace = tracebk
+ while trace.tb_next:
+ trace = trace.tb_next
+ frame = trace.tb_frame
+ out.write ("\nLocal variables in innermost frame:\n")
+ try:
+ for (key, value) in frame.f_locals.items():
+ out.write ("%s: %s\n" % (key, value))
+ except:
+ pass
+
+
+def __exception_window(title, text, component_name):
+ pass
+
+__ACTION_STR = ""
+def action(what):
+ """Describe what you want to do actually.
+ what - string
+ """
+ global __ACTION_STR # pylint: disable-msg=W0603
+ __ACTION_STR = what
+
+__ERROR_STR = ""
+def error(what):
+ """Describe what went wrong with a userfriendly text.
+ what - string
+ """
+ global __ERROR_STR # pylint: disable-msg=W0603
+ __ERROR_STR = what
+
+__EXITCODE = 10
+def exitcode(num):
+ """The exitcode, with which the exception handling routine should call
+ sys.exit().
+ num - int(exitcode)
+ """
+ global __EXITCODE # pylint: disable-msg=W0603
+ __EXITCODE = int(num)
+
+#
+# handleMyException function
+#
+def handleMyException((etype, value, tb)):
+ """
+ The exception handling function.
+
+ progname - the name of the application
+ version - the version of the application
+ """
+
+ # restore original exception handler
+ sys.excepthook = sys.__excepthook__ # pylint: disable-msg=E1101
+
+ import os.path
+ import md5
+ import traceback
+
+ syslog.syslog("abrt: Pyhook: Detected unhandled exception in %s " % sys.argv[0])
+ elist = traceback.format_exception (etype, value, tb)
+ tblast = traceback.extract_tb(tb, limit=None)
+ if len(tblast):
+ tblast = tblast[len(tblast)-1]
+ extxt = traceback.format_exception_only(etype, value)
+ text = ""
+ text = text + "Summary: TB"
+ if tblast and len(tblast) > 3:
+ ll = []
+ ll.extend(tblast[:3])
+ ll[0] = os.path.basename(tblast[0])
+ tblast = ll
+
+ m = md5.new()
+ ntext = ""
+ for t in tblast:
+ ntext += str(t) + ":"
+ m.update(str(t))
+
+ tb_uuid = str(m.hexdigest())[:8]
+ text += tb_uuid + " " + ntext
+
+ text += extxt[0]
+ text += "\n"
+ text += "".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, value) in frame.f_locals.items():
+ text += "%s: %s\n" % (key, value)
+ except:
+ pass
+
+ # add coredump saving
+ print text
+ write_dump(os.getpid(), tb_uuid, text)
+ sys.exit(__EXITCODE)
+
+def installExceptionHandler(debug = 1):
+ """
+ Install the exception handling function.
+
+ progname - the name of the application
+ version - the version of the application
+ debug - show the full traceback (with "Save to file" in GUI)
+ """
+ # FIXME: only root can write ddump :(
+ if os.getuid() == 0:
+ sys.excepthook = lambda etype, value, tb: \
+ handleMyException((etype, value, tb))
+
+if __name__ == '__main__':
+ def _exception_function():
+ action("Trying to divide by zero")
+
+ try:
+ local_var_1 = 1
+ local_var_2 = 0
+ # test exception raised to show the effect
+ local_var_3 = local_var_1 / local_var_2 # pylint: disable-msg=W0612
+ except:
+ error("Does not seem to work!? :-)")
+ exitcode(15)
+ raise
+
+ def _usage():
+ print """%s [-dgh] [--debug] [--gui] [--help]
+ -d, --debug
+ Show the whole backtrace
+
+ -h, --help
+ Display this message""" % (sys.argv[0])
+
+ import getopt
+ __debug = 1
+
+ installExceptionHandler(__debug)
+
+ __debug = 0
+
+ class BadUsage(Exception):
+ "exception for a bad command line usage"
+
+ try:
+ __opts, __args = getopt.getopt(sys.argv[1:], "dgh",
+ [
+ "debug",
+ "help",
+ "gui",
+ ])
+
+ for __opt, __val in __opts:
+ if __opt == '-d' or __opt == '--debug':
+ __debug = 1
+ continue
+
+ if __opt == '-g' or __opt == '--gui':
+ __gui = 1
+ continue
+
+ if __opt == '-h' or __opt == '--help':
+ _usage()
+ sys.exit(0)
+
+ except (getopt.error, BadUsage):
+ _usage()
+ sys.exit(1)
+
+ installExceptionHandler(__debug)
+
+ _exception_function()
+ sys.exit(0)
+
+
+__author__ = "Harald Hoyer <harald@redhat.com>"
diff --git a/src/Hooks/pyhook.conf b/src/Hooks/pyhook.conf
new file mode 100644
index 00000000..731debbd
--- /dev/null
+++ b/src/Hooks/pyhook.conf
@@ -0,0 +1 @@
+enabled = yes
diff --git a/src/Hooks/sitecustomize.py b/src/Hooks/sitecustomize.py
new file mode 100644
index 00000000..5e7b5244
--- /dev/null
+++ b/src/Hooks/sitecustomize.py
@@ -0,0 +1,30 @@
+config = None
+conf = {}
+try:
+ config = open("/etc/abrt/pyhook.conf","r")
+except:
+ #silently ignore if file doesn't exist
+ pass
+
+try:
+ if config:
+ # we expect config in form
+ # key = value
+ # Enabled = yes
+ # this should strip
+ line = config.readline().lower().replace(' ','').strip('\n').split('=')
+ conf[line[0]] = line[1]
+except:
+ # ignore silently everything, because we don't want to bother user if this hook doesn't work
+ pass
+
+if conf.has_key("enabled"):
+ if conf["enabled"] == "yes":
+ try:
+ from abrt_exception_handler import *
+
+ installExceptionHandler(debug = 1)
+ except Exception, e:
+ # FIXME don't print anything, write it to some log file
+ print e
+ pass \ No newline at end of file