Trace given trace_obj (usuall a Message instance) recursively.
        :param trace_obj:
        :return: a string with properly formatted tracing information

def trace(self, trace_obj):
        """
        Trace given trace_obj (usuall a Message instance) recursively.
        :param trace_obj:
        :return: a string with properly formatted tracing information
        """
        tracer = self
        tracer.writeln(u'%s = ' % trace_obj.__class__.__name__)
        tracer.incr('{')
        for attr_name in trace_obj.__tracing_attrs__:
            attr = getattr(trace_obj, attr_name)
            if isinstance(attr, tuple) and hasattr(attr, '_fields'):
                # probably a namedtuple instance
                tracer.writeln(u'%s = ' % (attr_name,))
                tracer.incr('[')
                for k, v in attr._asdict().items():
                    # _asdict() creates an OrderedDict, so elements are still in order
                    tracer.writeln(u'%s = %s' % (k, v))
                tracer.decr(']')
            elif isinstance(attr, (list, tuple)):
                if attr:
                    tracer.writeln(u'%s = ' % (attr_name,))
                    tracer.incr('[')
                    for elem in attr:
                        if hasattr(elem, '__tracing_attrs__'):
                            self.trace(elem)
                        else:
                            # some other plain list element, just print it as it is:
                            tracer.writeln(u'%s' % repr(elem))
                    tracer.decr(']')
                else:
                    tracer.writeln(u'%s = []' % (attr_name,))
            else:
                # a plain attribute object, just print it as it is
                tracer.writeln(u'%s = %s' % (attr_name, repr(attr)))
        tracer.decr('}')
        return self.getvalue()