Re: Castrated traceback in sys.exc_info()

2010-03-25 Thread Andreas Löscher

 As you see, the traceback only starts from function c, which handles the 
 exception.
 It doesn't show main(), a() and b(), which might however be (and are, in 
 my case) critical to diagnose the severity of the problem (since many 
 different paths would lead to calling c()).

This results in the way the tb is created.

If an exception occours, and there is no one who handles it in the
current function, a traceback object is created. Because the the calling
function could have a try-except clause, the function returns with NULL
and an set exception. Now if there is no one to handle the exception, a
traceback object is created and linked with the existing one.

In your case does the traceback start from the function c, because no
exception occoured in main() etc. You catched it. If you want to
determine the calling path, you can take a look at the encapsuled frame
in the tb. 

Best


-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Castrated traceback in sys.exc_info()

2010-03-24 Thread Gabriel Genellina
En Tue, 23 Mar 2010 19:43:40 -0300, Vinay Sajip vinay_sa...@yahoo.co.uk  
escribió:

On Mar 23, 8:49 pm, Pascal Chambon chambon.pas...@wanadoo.fr wrote:


Should I open an issue for this evolution of exceptiuon handling, or
should we content ourselves of this hacking of frame stck ?


Possibly worth raising an issue (not logging-related), but perhaps
it's worth seeing if this has come up before creating the issue.


There is, from 2006: http://bugs.python.org/issue1553375
I'll add a patch+tests to this issue.

--
Gabriel Genellina

--
http://mail.python.org/mailman/listinfo/python-list


Re: Castrated traceback in sys.exc_info()

2010-03-23 Thread Gabriel Genellina
En Mon, 22 Mar 2010 15:20:39 -0300, Pascal Chambon  
chambon.pas...@wanadoo.fr escribió:


Allright, here is more concretely the problem :

ERROR:root:An error
Traceback (most recent call last):
  File C:/Users/Pakal/Desktop/aaa.py, line 7, in c
return d()
  File C:/Users/Pakal/Desktop/aaa.py, line 11, in d
def d(): raise ValueError
ValueError
 

As you see, the traceback only starts from function c, which handles the  
exception.
It doesn't show main(), a() and b(), which might however be (and are, in  
my case) critical to diagnose the severity of the problem (since many  
different paths would lead to calling c()).


So the question is : is that possible to enforce, by a way or another,  
the retrieval of the FULL traceback at exception raising point, instead  
of that incomplete one ?


Thanks for bringing this topic! I learned a lot trying to understand what  
happens.


The exception traceback (what sys.exc_info()[2] returns) is *not* a  
complete stack trace. The sys module documentation is wrong [1] when it  
says ...encapsulates the call stack at the point where the exception  
originally occurred.


The Language Reference is more clear [2]: Traceback objects represent a  
stack trace of an exception. A traceback object is created when an  
exception occurs. When the search for an exception handler unwinds the  
execution stack, at each unwound level a traceback object is inserted in  
front of the current traceback. When an exception handler is entered, the  
stack trace is made available to the program.


That is, a traceback holds only the *forward* part of the stack: the  
frames already exited when looking for an exception handler. Frames going  
from the program starting point up to the current execution point are  
*not* included.


Conceptually, it's like having two lists: stack and traceback. The  
complete stack trace is always stack+traceback. At each step (when  
unwinding the stack, looking for a frame able to handle the current  
exception) an item is popped from the top of the stack (last item) and  
inserted at the head of the traceback.


The traceback holds the forward path (from the current execution point,  
to the frame where the exception was actually raised). It's a linked list,  
its tb_next attribute holds a reference to the next item; None marks the  
last one.


The back path (going from the current execution point to its caller and  
all the way to the program entry point) is a linked list of frames; the  
f_back attribute points to the previous one, or None.


In order to show a complete stack trace, one should combine both. The  
traceback module contains several useful functions: extract_stack() +  
extract_tb() are a starting point. The simplest way I could find to make  
the logging module report a complete stack is to monkey patch  
logging.Formatter.formatException so it uses format_exception() and  
format_stack() combined (in fact it is simpler than the current  
implementation using a StringIO object):


code
import logging
import traceback

def formatException(self, ei):

Format and return the specified exception information as a string.

This implementation builds the complete stack trace, combining
traceback.format_exception and traceback.format_stack.

lines = traceback.format_exception(*ei)
if ei[2]:
lines[1:1] = traceback.format_stack(ei[2].tb_frame.f_back)
return ''.join(lines)

# monkey patch the logging module
logging.Formatter.formatException = formatException

def a(): return b()
def b(): return c()
def c():
try:
  return d()
except:
  logging.exception(An error)
  raise
def d(): raise ValueError

def main():
  a()

main()
/code

Output:

ERROR:root:An error
Traceback (most recent call last):
  File test_logging.py, line 32, in module
main()
  File test_logging.py, line 30, in main
a()
  File test_logging.py, line 19, in a
def a(): return b()
  File test_logging.py, line 20, in b
def b(): return c()
  File test_logging.py, line 23, in c
return d()
  File test_logging.py, line 27, in d
def d(): raise ValueError
ValueError

Traceback (most recent call last):
  File test_logging.py, line 32, in module
main()
  File test_logging.py, line 30, in main
a()
  File test_logging.py, line 19, in a
def a(): return b()
  File test_logging.py, line 20, in b
def b(): return c()
  File test_logging.py, line 23, in c
return d()
  File test_logging.py, line 27, in d
def d(): raise ValueError
ValueError

Note that both tracebacks are identical: the first comes from the patched  
logging module, the second is the standard Python one.


[1] http://docs.python.org/library/sys.html#sys.exc_info
[2]  
http://docs.python.org/reference/datamodel.html#the-standard-type-hierarchy


--
Gabriel Genellina

--
http://mail.python.org/mailman/listinfo/python-list


Re: Castrated traceback in sys.exc_info()

2010-03-23 Thread Vinay Sajip
On Mar 23, 6:12 am, Gabriel Genellina gagsl-...@yahoo.com.ar
wrote:
 En Mon, 22 Mar 2010 15:20:39 -0300, Pascal Chambon  
 chambon.pas...@wanadoo.fr escribi�:





  Allright, here is more concretely the problem :

  ERROR:root:An error
  Traceback (most recent call last):
    File C:/Users/Pakal/Desktop/aaa.py, line 7, in c
      return d()
    File C:/Users/Pakal/Desktop/aaa.py, line 11, in d
      def d(): raise ValueError
  ValueError

  As you see, the traceback only starts from function c, which handles the  
  exception.
  It doesn't show main(), a() and b(), which might however be (and are, in  
  my case) critical to diagnose the severity of the problem (since many  
  different paths would lead to calling c()).

  So the question is : is that possible to enforce, by a way or another,  
  the retrieval of the FULL traceback at exception raising point, instead  
  of that incomplete one ?

 Thanks for bringing this topic! I learned a lot trying to understand what  
 happens.

 The exception traceback (what sys.exc_info()[2] returns) is *not* a  
 complete stack trace. The sys module documentation is wrong [1] when it  
 says ...encapsulates the call stack at the point where the exception  
 originally occurred.

 The Language Reference is more clear [2]: Traceback objects represent a  
 stack trace of an exception. A traceback object is created when an  
 exception occurs. When the search for an exception handler unwinds the  
 execution stack, at each unwound level a traceback object is inserted in  
 front of the current traceback. When an exception handler is entered, the  
 stack trace is made available to the program.

 That is, a traceback holds only the *forward* part of the stack: the  
 frames already exited when looking for an exception handler. Frames going  
  from the program starting point up to the current execution point are  
 *not* included.

 Conceptually, it's like having two lists: stack and traceback. The  
 complete stack trace is always stack+traceback. At each step (when  
 unwinding the stack, looking for a frame able to handle the current  
 exception) an item is popped from the top of the stack (last item) and  
 inserted at the head of the traceback.

 The traceback holds the forward path (from the current execution point,  
 to the frame where the exception was actually raised). It's a linked list,  
 its tb_next attribute holds a reference to the next item; None marks the  
 last one.

 The back path (going from the current execution point to its caller and  
 all the way to the program entry point) is a linked list of frames; the  
 f_back attribute points to the previous one, or None.

 In order to show a complete stack trace, one should combine both. The  
 traceback module contains several useful functions: extract_stack() +  
 extract_tb() are a starting point. The simplest way I could find to make  
 theloggingmodule report a complete stack is to monkey patch  
 logging.Formatter.formatException so it uses format_exception() and  
 format_stack() combined (in fact it is simpler than the current  
 implementation using a StringIO object):

 code
 importlogging
 import traceback

 def formatException(self, ei):
      
      Format and return the specified exception information as a string.

      This implementation builds the complete stack trace, combining
      traceback.format_exception and traceback.format_stack.
      
      lines = traceback.format_exception(*ei)
      if ei[2]:
          lines[1:1] = traceback.format_stack(ei[2].tb_frame.f_back)
      return ''.join(lines)

 # monkey patch theloggingmodulelogging.Formatter.formatException = 
 formatException

 def a(): return b()
 def b(): return c()
 def c():
      try:
        return d()
      except:
        logging.exception(An error)
        raise
 def d(): raise ValueError

 def main():
    a()

 main()
 /code

 Output:

 ERROR:root:An error
 Traceback (most recent call last):
    File test_logging.py, line 32, in module
      main()
    File test_logging.py, line 30, in main
      a()
    File test_logging.py, line 19, in a
      def a(): return b()
    File test_logging.py, line 20, in b
      def b(): return c()
    File test_logging.py, line 23, in c
      return d()
    File test_logging.py, line 27, in d
      def d(): raise ValueError
 ValueError

 Traceback (most recent call last):
    File test_logging.py, line 32, in module
      main()
    File test_logging.py, line 30, in main
      a()
    File test_logging.py, line 19, in a
      def a(): return b()
    File test_logging.py, line 20, in b
      def b(): return c()
    File test_logging.py, line 23, in c
      return d()
    File test_logging.py, line 27, in d
      def d(): raise ValueError
 ValueError

 Note that both tracebacks are identical: the first comes from the patched  
 loggingmodule, the second is the standard Python one.

 [1]http://docs.python.org/library/sys.html#sys.exc_info
 [2]  

Re: Castrated traceback in sys.exc_info()

2010-03-23 Thread Pascal Chambon

Gabriel Genellina a écrit :


En Mon, 22 Mar 2010 15:20:39 -0300, Pascal Chambon 
chambon.pas...@wanadoo.fr escribió:


Allright, here is more concretely the problem :

ERROR:root:An error
Traceback (most recent call last):
  File C:/Users/Pakal/Desktop/aaa.py, line 7, in c
return d()
  File C:/Users/Pakal/Desktop/aaa.py, line 11, in d
def d(): raise ValueError
ValueError
 

As you see, the traceback only starts from function c, which handles 
the exception.
It doesn't show main(), a() and b(), which might however be (and are, 
in my case) critical to diagnose the severity of the problem (since 
many different paths would lead to calling c()).


So the question is : is that possible to enforce, by a way or 
another, the retrieval of the FULL traceback at exception raising 
point, instead of that incomplete one ?


Thanks for bringing this topic! I learned a lot trying to understand 
what happens.


The exception traceback (what sys.exc_info()[2] returns) is *not* a 
complete stack trace. The sys module documentation is wrong [1] when 
it says ...encapsulates the call stack at the point where the 
exception originally occurred.


The Language Reference is more clear [2]: Traceback objects represent 
a stack trace of an exception. A traceback object is created when an 
exception occurs. When the search for an exception handler unwinds the 
execution stack, at each unwound level a traceback object is inserted 
in front of the current traceback. When an exception handler is 
entered, the stack trace is made available to the program.


That is, a traceback holds only the *forward* part of the stack: the 
frames already exited when looking for an exception handler. Frames 
going from the program starting point up to the current execution 
point are *not* included.


Conceptually, it's like having two lists: stack and traceback. The 
complete stack trace is always stack+traceback. At each step (when 
unwinding the stack, looking for a frame able to handle the current 
exception) an item is popped from the top of the stack (last item) and 
inserted at the head of the traceback.


The traceback holds the forward path (from the current execution 
point, to the frame where the exception was actually raised). It's a 
linked list, its tb_next attribute holds a reference to the next item; 
None marks the last one.


The back path (going from the current execution point to its caller 
and all the way to the program entry point) is a linked list of 
frames; the f_back attribute points to the previous one, or None.


In order to show a complete stack trace, one should combine both. The 
traceback module contains several useful functions: extract_stack() + 
extract_tb() are a starting point. The simplest way I could find to 
make the logging module report a complete stack is to monkey patch 
logging.Formatter.formatException so it uses format_exception() and 
format_stack() combined (in fact it is simpler than the current 
implementation using a StringIO object):
Good point, there is clearly a distinction between stack trace and 
exception traceback that I didn't know (actually, it seems no one 
makes it in computer literature).



Good catch, Gabriel.

There should be no need to monkey-patch the logging module - it's
better if I include the change in the module itself. The only
remaining question is that of backward compatibility, but I can do
this for Python 2.7/3.2 only so that won't be an issue. It's probably
a good idea to log an issue on the bug tracker, though, so we have
some history for the change - do you want to do that, or shall I?

Regards,

Vinay Sajip
  
Well having it fixed in logging would be great, but that kind of 
information is good to have in other circumstances, so shouldn't we 
rather advocate the availability of this stack trace part in exc_info 
too ?
This way, people like me who consider frames as black magic wouldn't 
need to meet complex stuffs as 
traceback.format_stack(ei[2].tb_frame.f_back  :p


Should I open an issue for this evolution of exceptiuon handling, or 
should we content ourselves of this hacking of frame stck ?


Regards,
Pascal





--
http://mail.python.org/mailman/listinfo/python-list


Re: Castrated traceback in sys.exc_info()

2010-03-23 Thread Vinay Sajip
On Mar 23, 8:49 pm, Pascal Chambon chambon.pas...@wanadoo.fr wrote:

 Should I open an issue for this evolution of exceptiuon handling, or
 should we content ourselves of this hacking of frame stck ?


Possibly worth raising an issue (not logging-related), but perhaps
it's worth seeing if this has come up before creating the issue.

Regards,

Vinay Sajip
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Castrated traceback in sys.exc_info()

2010-03-22 Thread Pascal Chambon

Gabriel Genellina a écrit :


En Wed, 17 Mar 2010 09:42:06 -0300, Pascal Chambon 
chambon.pas...@gmail.com escribió:


traceback functions indeed allow the manipulation of exception 
tracebacks,

but the root problem is that anyway, since that traceback is incomplete,
your traceback.format_exc().splitlines() will only provide frames for
callee (downward) functions, not caller (upward) ones, starting from the
exception catching frame.


Either I don't understand what you mean, or I can't reproduce it:




Allright, here is more concretely the problem :

code
import logging

def a(): return b()
def b(): return c()
def c():
   try:
   return d()
   except:
   logging.exception(An error)
  
def d(): raise ValueError


def main():
   logging.basicConfig(level=logging.DEBUG)
   a()

main()
/code

OUTPUT:

ERROR:root:An error
Traceback (most recent call last):
 File C:/Users/Pakal/Desktop/aaa.py, line 7, in c
   return d()
 File C:/Users/Pakal/Desktop/aaa.py, line 11, in d
   def d(): raise ValueError
ValueError



As you see, the traceback only starts from function c, which handles the 
exception.
It doesn't show main(), a() and b(), which might however be (and are, in 
my case) critical to diagnose the severity of the problem (since many 
different paths would lead to calling c()).


So the question is : is that possible to enforce, by a way or another, 
the retrieval of the FULL traceback at exception raising point, instead 
of that incomplete one ?


Thank you for your help,
regards,

Pascal


--
http://mail.python.org/mailman/listinfo/python-list


Re: Castrated traceback in sys.exc_info()

2010-03-19 Thread Gabriel Genellina
En Wed, 17 Mar 2010 09:42:06 -0300, Pascal Chambon  
chambon.pas...@gmail.com escribió:


traceback functions indeed allow the manipulation of exception  
tracebacks,

but the root problem is that anyway, since that traceback is incomplete,
your traceback.format_exc().splitlines() will only provide frames for
callee (downward) functions, not caller (upward) ones, starting from the
exception catching frame.


Either I don't understand what you mean, or I can't reproduce it:

code
import logging

def a(): return b()
def b(): return c()
def c(): return d()
def d(): raise ValueError

def main():
  logging.basicConfig(level=logging.DEBUG)
  try: a()
  except: logging.exception(An error)

main()
/code

Output:

D:\temppython test_logging.py
ERROR:root:An error
Traceback (most recent call last):
  File test_logging.py, line 10, in main
try: a()
  File test_logging.py, line 3, in a
def a(): return b()
  File test_logging.py, line 4, in b
def b(): return c()
  File test_logging.py, line 5, in c
def c(): return d()
  File test_logging.py, line 6, in d
def d(): raise ValueError
ValueError

--
Gabriel Genellina

--
http://mail.python.org/mailman/listinfo/python-list


Castrated traceback in sys.exc_info()

2010-03-17 Thread Pakal
Hello

I've just realized recently that sys.exc_info() didn't return a full
traceback for exception concerned : it actually only contains the
frame below the point of exception catching.

That's very annoying to me, because I planned to log such tracebacks
with logging.critical(*, exc_info=True), and these partial
tracebacks, like the one below, are clearly unsufficient to determine
where the problem comes from. A whole traceback, from program entry
point to exception raising point, would be much better.

2010-03-17 09:28:59,184 - pims - CRITICAL - This is just a test to
ensure critical emails are properly sent
Traceback (most recent call last):
 HERE, lots of frames missing 
  File test_common.py, line 34, in test_email_sending
os.open(qsdsdqsdsdqsd, r)
TypeError: an integer is required

Is there any workaround for this ? I've thought about a custom logging
formatter, which would take both the exc_info traceback AND its own
full backtrace, and to connect them together on their relevant part,
but it's awkward and error prone... why can't we just have all the
precious traceback info under the hand there (an additional attribute
might have pointed the precise frame in which the exception was
caught).

Tanks for the attention,
Regards,
Pascal
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Castrated traceback in sys.exc_info()

2010-03-17 Thread Michael Ricordeau
Hi,

to log tracebacks, you can probably try traceback module.

I use it like this :

import traceback
 # your code

for line in traceback.format_exc().splitlines():
  log.trace(line)



Le Wed, 17 Mar 2010 03:42:44 -0700 (PDT),
Pakal chambon.pas...@gmail.com a écrit :

 Hello
 
 I've just realized recently that sys.exc_info() didn't return a full
 traceback for exception concerned : it actually only contains the
 frame below the point of exception catching.
 
 That's very annoying to me, because I planned to log such tracebacks
 with logging.critical(*, exc_info=True), and these partial
 tracebacks, like the one below, are clearly unsufficient to determine
 where the problem comes from. A whole traceback, from program entry
 point to exception raising point, would be much better.
 
 2010-03-17 09:28:59,184 - pims - CRITICAL - This is just a test to
 ensure critical emails are properly sent
 Traceback (most recent call last):
  HERE, lots of frames missing 
   File test_common.py, line 34, in test_email_sending
 os.open(qsdsdqsdsdqsd, r)
 TypeError: an integer is required
 
 Is there any workaround for this ? I've thought about a custom logging
 formatter, which would take both the exc_info traceback AND its own
 full backtrace, and to connect them together on their relevant part,
 but it's awkward and error prone... why can't we just have all the
 precious traceback info under the hand there (an additional attribute
 might have pointed the precise frame in which the exception was
 caught).
 
 Tanks for the attention,
 Regards,
 Pascal
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Castrated traceback in sys.exc_info()

2010-03-17 Thread Pascal Chambon
Hello,

traceback functions indeed allow the manipulation of exception tracebacks,
but the root problem is that anyway, since that traceback is incomplete,
your traceback.format_exc().splitlines() will only provide frames for
callee (downward) functions, not caller (upward) ones, starting from the
exception catching frame.

Regards,
Pascal



2010/3/17 Michael Ricordeau michael.ricord...@gmail.com

 Hi,

 to log tracebacks, you can probably try traceback module.

 I use it like this :

 import traceback
  # your code

 for line in traceback.format_exc().splitlines():
  log.trace(line)



 Le Wed, 17 Mar 2010 03:42:44 -0700 (PDT),
 Pakal chambon.pas...@gmail.com a écrit :

  Hello
 
  I've just realized recently that sys.exc_info() didn't return a full
  traceback for exception concerned : it actually only contains the
  frame below the point of exception catching.
 
  That's very annoying to me, because I planned to log such tracebacks
  with logging.critical(*, exc_info=True), and these partial
  tracebacks, like the one below, are clearly unsufficient to determine
  where the problem comes from. A whole traceback, from program entry
  point to exception raising point, would be much better.
 
  2010-03-17 09:28:59,184 - pims - CRITICAL - This is just a test to
  ensure critical emails are properly sent
  Traceback (most recent call last):
   HERE, lots of frames missing 
File test_common.py, line 34, in test_email_sending
  os.open(qsdsdqsdsdqsd, r)
  TypeError: an integer is required
 
  Is there any workaround for this ? I've thought about a custom logging
  formatter, which would take both the exc_info traceback AND its own
  full backtrace, and to connect them together on their relevant part,
  but it's awkward and error prone... why can't we just have all the
  precious traceback info under the hand there (an additional attribute
  might have pointed the precise frame in which the exception was
  caught).
 
  Tanks for the attention,
  Regards,
  Pascal

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Castrated traceback in sys.exc_info()

2010-03-17 Thread Vinay Sajip
On Mar 17, 10:42 am, Pakal chambon.pas...@gmail.com wrote:
 Hello

 I've just realized recently that sys.exc_info() didn't return a full
 traceback for exception concerned : it actually only contains the
 frame below the point of exception catching.

 That's very annoying to me, because I planned to log such tracebacks
 withlogging.critical(*, exc_info=True), and these partial
 tracebacks, like the one below, are clearly unsufficient to determine
 where the problem comes from. A whole traceback, from program entry
 point to exception raising point, would be much better.

 2010-03-17 09:28:59,184 - pims - CRITICAL - This is just a test to
 ensure critical emails are properly sent
 Traceback (most recent call last):
  HERE, lots of frames missing 
   File test_common.py, line 34, in test_email_sending
     os.open(qsdsdqsdsdqsd, r)
 TypeError: an integer is required

 Is there any workaround for this ? I've thought about a customlogging
 formatter, which would take both the exc_info traceback AND its own
 full backtrace, and to connect them together on their relevant part,
 but it's awkward and error prone... why can't we just have all the
 precious traceback info under the hand there (an additional attribute
 might have pointed the precise frame in which the exception was
 caught).

 Tanks for the attention,
 Regards,
 Pascal

Do you have a short script which demonstrates the problem? Some more
context is needed. For example, if you have multiple threads of
execution, the traceback will only go up to the top-level function in
the thread.

Regards,

Vinay Sajip
-- 
http://mail.python.org/mailman/listinfo/python-list