[SATYR PATCH 2/5] Short text representation for python stacktraces

Martin Milata mmilata at redhat.com
Fri May 24 15:55:20 UTC 2013


Signed-off-by: Martin Milata <mmilata at redhat.com>
---
 lib/python_frame.c            | 23 +++++++++++++++++++++++
 lib/python_frame.h            |  8 ++++++++
 lib/python_stacktrace.c       | 22 ++++++++++++++++++++++
 lib/python_stacktrace.h       |  8 ++++++++
 python/py_python_stacktrace.c | 29 ++++++++++++++++++++++++++++-
 python/py_python_stacktrace.h |  1 +
 tests/python/python.py        | 10 ++++++++++
 7 files changed, 100 insertions(+), 1 deletion(-)

diff --git a/lib/python_frame.c b/lib/python_frame.c
index 24a07c2..59f3e88 100644
--- a/lib/python_frame.c
+++ b/lib/python_frame.c
@@ -302,3 +302,26 @@ sr_python_frame_to_json(struct sr_python_frame *frame)
     sr_strbuf_append_char(strbuf, '}');
     return sr_strbuf_free_nobuf(strbuf);
 }
+
+void
+sr_python_frame_append_to_str(struct sr_python_frame *frame,
+                              struct sr_strbuf *dest)
+{
+    sr_strbuf_append_strf(dest, "%s%s%s",
+                          (frame->special_function ? "<" : ""),
+                          (frame->function_name ? frame->function_name : "??"),
+                          (frame->special_function ? ">" : ""));
+
+    if (frame->file_name)
+    {
+        sr_strbuf_append_strf(dest, " in %s%s%s",
+                              (frame->special_file ? "<" : ""),
+                              frame->file_name,
+                              (frame->special_file ? ">" : ""));
+
+        if (frame->file_line)
+        {
+            sr_strbuf_append_strf(dest, ":%d", frame->file_line);
+        }
+    }
+}
diff --git a/lib/python_frame.h b/lib/python_frame.h
index 0466f85..fc9be79 100644
--- a/lib/python_frame.h
+++ b/lib/python_frame.h
@@ -34,6 +34,7 @@ extern "C" {
 #include <stdint.h>
 
 struct sr_location;
+struct sr_strbuf;
 
 struct sr_python_frame
 {
@@ -170,6 +171,13 @@ sr_python_frame_parse(const char **input,
 char *
 sr_python_frame_to_json(struct sr_python_frame *frame);
 
+/**
+ * Appends textual representation of the frame to the string buffer dest.
+ */
+void
+sr_python_frame_append_to_str(struct sr_python_frame *frame,
+                              struct sr_strbuf *dest);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/python_stacktrace.c b/lib/python_stacktrace.c
index 9e0ecba..c46c57a 100644
--- a/lib/python_stacktrace.c
+++ b/lib/python_stacktrace.c
@@ -214,3 +214,25 @@ sr_python_stacktrace_get_reason(struct sr_python_stacktrace *stacktrace)
 
     return sr_asprintf("%s in %s:%"PRIu32, exc, file, line);
 }
+
+char *
+sr_python_stacktrace_to_short_text(struct sr_python_stacktrace *stacktrace,
+                                   int max_frames)
+{
+    struct sr_strbuf *strbuf = sr_strbuf_new();
+    struct sr_python_frame *frame;
+    int i = 0;
+
+    for (frame = stacktrace->frames; frame; frame = frame->next)
+    {
+        i++;
+        sr_strbuf_append_strf(strbuf, "#%d ", i);
+        sr_python_frame_append_to_str(frame, strbuf);
+        sr_strbuf_append_char(strbuf, '\n');
+
+        if (max_frames && i >= max_frames)
+            break;
+    }
+
+    return sr_strbuf_free_nobuf(strbuf);
+}
diff --git a/lib/python_stacktrace.h b/lib/python_stacktrace.h
index 4c5eb88..55021d3 100644
--- a/lib/python_stacktrace.h
+++ b/lib/python_stacktrace.h
@@ -115,6 +115,14 @@ sr_python_stacktrace_get_reason(struct sr_python_stacktrace *stacktrace);
 char *
 sr_python_stacktrace_to_json(struct sr_python_stacktrace *stacktrace);
 
+/**
+ * Returns brief textual representation of the stacktrace, or NULL in case of
+ * failure. Caller has to free it using free().
+ */
+char *
+sr_python_stacktrace_to_short_text(struct sr_python_stacktrace *stacktrace,
+                                   int max_frames);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/python/py_python_stacktrace.c b/python/py_python_stacktrace.c
index fdc3b7f..832f4e6 100644
--- a/python/py_python_stacktrace.c
+++ b/python/py_python_stacktrace.c
@@ -18,6 +18,10 @@
                   "Clones the PythonStacktrace object. All new structures are independent " \
                   "on the original object."
 
+#define f_to_short_text "Usage: stacktrace.to_short_text([max_frames])\n" \
+                        "Returns short text representation of the stacktrace. If max_frames is\n" \
+                        "specified, the result includes only that much topmost frames.\n"
+
 #define f_normalize_doc "Usage: stacktrace.normalize()\n" \
                         "Normalizes the stacktrace."
 
@@ -30,7 +34,8 @@ static PyMethodDef
 python_stacktrace_methods[] =
 {
     /* methods */
-    { "dup", sr_py_python_stacktrace_dup, METH_NOARGS, f_dup_doc },
+    { "dup",           sr_py_python_stacktrace_dup,           METH_NOARGS,  f_dup_doc },
+    { "to_short_text", sr_py_python_stacktrace_to_short_text, METH_VARARGS, f_to_short_text },
 //    { "normalize", sr_py_python_stacktrace_normalize, METH_NOARGS, f_normalize_doc },
     { NULL },
 };
@@ -285,6 +290,28 @@ sr_py_python_stacktrace_dup(PyObject *self, PyObject *args)
     return (PyObject*)bo;
 }
 
+PyObject *
+sr_py_python_stacktrace_to_short_text(PyObject *self, PyObject *args)
+{
+    int max_frames = 0;
+    if (!PyArg_ParseTuple(args, "|i", &max_frames))
+        return NULL;
+
+    struct sr_py_python_stacktrace *this = (struct sr_py_python_stacktrace*)self;
+    if (python_stacktrace_prepare_linked_list(this) < 0)
+        return NULL;
+
+    char *text =
+        sr_python_stacktrace_to_short_text(this->stacktrace, max_frames);
+    if (!text)
+        return NULL;
+
+    PyObject *result = PyString_FromString(text);
+
+    free(text);
+    return result;
+}
+
 /*
  * No python normalization implemented yet
  *
diff --git a/python/py_python_stacktrace.h b/python/py_python_stacktrace.h
index e8e1d31..8075344 100644
--- a/python/py_python_stacktrace.h
+++ b/python/py_python_stacktrace.h
@@ -55,6 +55,7 @@ PyObject *sr_py_python_stacktrace_str(PyObject *self);
 /* methods */
 PyObject *sr_py_python_stacktrace_dup(PyObject *self, PyObject *args);
 PyObject *sr_py_python_stacktrace_normalize(PyObject *self, PyObject *args);
+PyObject *sr_py_python_stacktrace_to_short_text(PyObject *self, PyObject *args);
 
 
 #ifdef __cplusplus
diff --git a/tests/python/python.py b/tests/python/python.py
index 0f989dc..1209617 100755
--- a/tests/python/python.py
+++ b/tests/python/python.py
@@ -12,6 +12,13 @@ except ImportError:
 
 path = '../python_stacktraces/python-01'
 frames_expected = 11
+expected_short_text = '''#1 _getPackage in /usr/share/PackageKit/helpers/yum/yumBackend.py:2534
+#2 updateProgress in /usr/share/PackageKit/helpers/yum/yumBackend.py:2593
+#3 _do_start in /usr/share/PackageKit/helpers/yum/yumBackend.py:2551
+#4 start in /usr/lib/python2.6/site-packages/urlgrabber/progress.py:129
+#5 downloadPkgs in /usr/lib/yum-plugins/presto.py:419
+#6 predownload_hook in /usr/lib/yum-plugins/presto.py:577
+'''
 
 if not os.path.isfile(path):
     path = '../' + path
@@ -83,6 +90,9 @@ class TestPythonStacktrace(BindingsTestCase):
         self.assertTrue(f.special_file)
         self.assertTrue(f.special_function)
 
+    def test_to_short_text(self):
+        self.assertEqual(self.trace.to_short_text(6), expected_short_text)
+
 class TestPythonFrame(BindingsTestCase):
     def setUp(self):
         self.frame = satyr.PythonStacktrace(contents).frames[-1]
-- 
1.7.11.7



More information about the Crash-catcher mailing list