summaryrefslogtreecommitdiff
path: root/tracing.py
blob: 34528daf2085ce18a1bc610916d2712510194f22 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# Copyright (C) 2011  Lars Wirzenius <liw@liw.fi>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.


''':mod:`tracing` -- fast debug trace messages
==================================

This module provides fast debugging log messages that can be
turned on and off during runtime.

It is sometimes practical to add a lot of debugging log messages to a
program, but having them enabled all the time results in very large
log files. Also, logging that much takes quite a bit of time. Yet,
keeping the logging statements can be a good idea so that they can
be enabled if there is a problem that needs debugging, as long as
there is a way to disable them in normal production mode.

This module provides a way to achieve that. For example::

    # in the main program
    import tracing
    
    tracing.trace_add_pattern('foobar')
    tracing.trace_add_pattern('yeehaa')
    
    ...
    
    # in some other module
    tracing.trace('start procedure')
    tracing.trace('arg1=%s', arg1)
    tracing.trace('arg2=%s', arg2)
    
Only calls that happen in files whose names contain ``foobar`` or
``yeehaa`` will actually be logged. Pattern matching is based on
substring checking only, for speed, so there is no globbing or 
regular expression matching.

'''


import logging
import os
import traceback


trace_patterns = []
trace_cache = set()


def trace_add_pattern(pattern):
    '''Add a module name pattern.'''
    trace_patterns.append(pattern)
    
    
def trace_clear_patterns():
    '''Remove all module name patterns.
    
    After this, nothing will be traced. This is also the initial state.
    
    '''
    del trace_patterns[:]
    trace_cache.clear()


def trace(msg, *args):
    '''Log a trace message if the calling module's name matches a pattern.

    If any arguments are given, the message is formatted as if
    with ``msg % args``, otherwise the message is written out as is.
    
    '''

    if trace_patterns:
        frames = traceback.extract_stack(limit=2)
        filename, lineno, funcname, text = frames[0]
        log_it = filename in trace_cache
        if not log_it:
            for pattern in trace_patterns:
                if pattern in filename:
                    log_it = True
                    trace_cache.add(filename)
                    break
        if log_it:
            filename = os.path.basename(filename)
            if args:
                msg = msg % args
            logging.debug('%s:%s:%s: %s' % (filename, lineno, funcname, msg))