Signed-off-by: Martin Milata <mmilata(a)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