Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trace Bug which happends only sometimes in CI

I have a strange bug in python code which only happens sometimes in CI.

We can't reproduce it.

Where is the test code:

response=self.admin_client.post(url, post)
self.assertEqual(200, response.status_code, response)

Sometimes we get a 302 which happens since the form gets saved.

My idea to debug this:

with some_magic_trace.trace() as trace:
    response=self.admin_client.post(url, post)
    self.assertEqual(200, response.status_code, trace)

The trace should contain the python lines (filename, line offset, line as string) executed by the interpreter.

How to implement some_magic_trace.trace()?

like image 706
guettli Avatar asked Jan 19 '16 09:01

guettli


2 Answers

The trace module gives you a very simple solution (different from what you are asking for, but simple enough to have a try.)

from trace import Trace

tracer = Trace()
response = tracer.runfunc(self.admin_client.post, url, post)
self.assertEqual(200, response.status_code, response)

A more complex solution that entails creating a context manager that saves the trace and prints it only on exceptions, requires the use of sys.settrace. Just a template for your own implementation could be:

class MyTracer():

    def __init__(self):
        self.trace = None

    def newscope(self, frame, event, arg):
        ## real work should be done here, just minimal example
        self.trace.append((frame, event, arg))
        return None

    def pprint(self):
        ## real pretty printing of trace info should be done here
        print(self.trace)

    def __enter__(self):
        self.trace = []
        sys.settrace(self.newscope)
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        sys.settrace(None)
        if exc_type is not None:
            self.pprint()
            ## print some info gathered from exc_type, exc_val, exc_tb

Then you can:

with MyTracer():
    response=self.admin_client.post(url, post)
    self.assertEqual(200, response.status_code, response)

The idea is that a MyTracer instance has a tracer method newscope that saves some useful info in self.trace. On an abnormal exit from the context the pprint method is called; on a normal exit the trace info is discarded.

Most of the work has to be done in the tracing method newscope. Some concrete examples of tracing functions can be found here.

like image 183
Stefano M Avatar answered Nov 04 '22 23:11

Stefano M


To use trace.Trace with the with context instead of Trace.runfunc you can use:

import trace

class ContextTrace(trace.Trace):
    def __enter__(self):
        if not self.donothing:
            sys.settrace(self.globaltrace)
        return self

    def __exit__(self,*others):
        if not self.donothing:
            sys.settrace(None)
like image 40
Tadhg McDonald-Jensen Avatar answered Nov 04 '22 23:11

Tadhg McDonald-Jensen