plpython tracebacks - Mailing list pgsql-patches

From P. Scott DeVos
Subject plpython tracebacks
Date
Msg-id 43E7C831.3050207@countrysidetechnology.com
Whole thread Raw
Responses Re: plpython tracebacks
List pgsql-patches
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.orig    2006-02-06 14:24:42.000000000 -0600
+++ plpython-1.70.c.patched    2006-02-06 15:34:05.000000000 -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) : "Unknown Exception";
-    xstr = PLy_printf("%s: %s", estr, vstr);
+    xstr = PLy_printf("%s%s: %s", tbstr, estr, vstr);

      Py_DECREF(eob);
      Py_XDECREF(vob);

pgsql-patches by date:

Previous
From: Michael Meskes
Date:
Subject: Re: [INTERFACES] [BUGS] BUG #2171: Differences compiling plpgsql in ecpg and psql
Next
From: "Thomas F. O'Connell"
Date:
Subject: Re: pgbench: Support Multiple Simultaneous Runs (with Mean and Std. Dev.)