1#===----------------------------------------------------------------------===##
2#
3#                     The LLVM Compiler Infrastructure
4#
5# This file is dual licensed under the MIT and the University of Illinois Open
6# Source Licenses. See LICENSE.TXT for details.
7#
8#===----------------------------------------------------------------------===##
9
10import os
11import inspect
12
13
14def trace_function(function, log_calls, log_results, label=''):
15    def wrapper(*args, **kwargs):
16        kwarg_strs = ['{}={}'.format(k, v) for (k, v) in kwargs]
17        arg_str = ', '.join([str(a) for a in args] + kwarg_strs)
18        call_str = '{}({})'.format(function.func_name, arg_str)
19
20        # Perform the call itself, logging before, after, and anything thrown.
21        try:
22            if log_calls:
23                print('{}: Calling {}'.format(label, call_str))
24            res = function(*args, **kwargs)
25            if log_results:
26                print('{}: {} -> {}'.format(label, call_str, res))
27            return res
28        except Exception as ex:
29            if log_results:
30                print('{}: {} raised {}'.format(label, call_str, type(ex)))
31            raise ex
32
33    return wrapper
34
35
36def trace_object(obj, log_calls, log_results, label=''):
37    for name, member in inspect.getmembers(obj):
38        if inspect.ismethod(member):
39            # Skip meta-functions, decorate everything else
40            if not member.func_name.startswith('__'):
41                setattr(obj, name, trace_function(member, log_calls,
42                                                  log_results, label))
43    return obj
44