I have been working with plpython for several months and have
been hampered by the lack of a traceback being logged when a
plpython function raises an error. I have written a patch causes
the PLy_traceback function to fully log the traceback. The
output looks just like the traceback output provided by the
python interpreter.
Feedback appreciated.
Scott
--- plpython-1.70.c.orig2006-02-06 14:24:42.0 -0600
+++ plpython-1.70.c.patched 2006-02-06 15:34:05.0 -0600
@@ -2499,7 +2499,8 @@
*vob = NULL;
char *vstr,
*estr,
- *xstr = NULL;
+ *xstr = NULL,
+ *tbstr;
/*
* get the current exception
@@ -2523,6 +2524,82 @@
else
vstr = Unknown;
+ /* If there is a traceback object, we build a string containing
+ the traceback information. */
+ if (tb != NULL)
+ {
+ PyObject
+ *cur_tb, /* traceback (tb) item being handled */
+ *old_tb, /* holds tb so we can decrement reference to
it */
+ *hdr, /* First line of logged output */
+ *tmpl,/* PyString template for the logged tb item */
+ *ftr, /* Last line of logged output */
+ *tb_list, /* Each tb item create a PyString in this
list */
+ *ln, /* The line number of the item in the
traceback */
+ *frame, /* the tb_frame */
+ *code,/* the f_code this guy has filename and
method name*/
+ *fn, /* the filename of the item in the tb */
+ *nm, /* the function/method name of the item in
the tb */
+ *args,/* A tuple of the form (fn, ln, nm) */
+ *logline, /* The assembled string with the logged
message */
+ *os, /* points to the os module */
+ *sep, /* line separator */
+ *tb_log; /* PyString with the assembled log msg */
+
+ hdr = PyString_FromString(Traceback (most recent call last):);
+ tmpl = PyString_FromString( File \%s\, line %s, in %s);
+ ftr = PyString_FromString();
+
+ tb_list = PyList_New(0); /* create the list of strings */
+ PyList_Append(tb_list, hdr); /* Append the header to the list */
+
+ /* 1st tb is useless; throw it away */
+ cur_tb = PyObject_GetAttrString(tb, tb_next);
+ while (cur_tb != Py_None)
+ {
+
+ ln = PyObject_GetAttrString(cur_tb, tb_lineno);
+ frame = PyObject_GetAttrString(cur_tb, tb_frame);
+ code = PyObject_GetAttrString(frame, f_code);
+ fn = PyObject_GetAttrString(code, co_filename);
+ nm = PyObject_GetAttrString(code, co_name);
+
+ args = Py_BuildValue((OOO), fn, ln, nm); /* args
tuple */
+ logline = PyString_Format(tmpl, args); /* build logged
string */
+ PyList_Append(tb_list, logline); /* append string
to list */
+
+ /* decrement references on all our objects */
+ Py_DECREF(logline);
+ Py_DECREF(args);
+ Py_XDECREF(nm);
+ Py_XDECREF(fn);
+ Py_XDECREF(code);
+ Py_XDECREF(frame);
+ Py_XDECREF(ln);
+
+ old_tb = cur_tb;
+ /* get the next traceback item */
+ cur_tb = PyObject_GetAttrString(cur_tb, tb_next);
+ Py_DECREF(old_tb);/* we're done with old_tb so
decref it */
+ }
+ PyList_Append(tb_list, ftr); /* append the log msg footer */
+
+ os = PyImport_ImportModule(os);
+ sep = PyObject_GetAttrString(os, linesep); /* get os EOL char
*/
+ tb_log = _PyString_Join(sep, tb_list); /* create tb log
msgs */
+ tbstr = PyString_AsString(tb_log);
+
+ Py_DECREF(tb_log);
+ Py_DECREF(sep);
+ Py_DECREF(os);
+ Py_DECREF(tb_list);
+ Py_DECREF(ftr);
+ Py_DECREF(tmpl);
+ Py_DECREF(hdr);
+ }
+ else
+ tbstr = No Traceback;
+
/*
* I'm not sure what to do if eob is NULL here -- we can't call PLy_elog
* because that function calls us, so we could end up with infinite
@@ -2530,7 +2607,7 @@
* Assert() be more appropriate?
*/
estr = eob ? PyString_AsString(eob) :