~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/trace.py

[merge] trace improvements

 - shorter error messages on exceptions

 - shorter display of status and time in selftest output

 - send debug output direct to file to reduce cost of going
   through Python logging

 - always send exception tracebacks to trace file

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# This program is free software; you can redistribute it and/or modify
2
 
# it under the terms of the GNU General Public License as published by
3
 
# the Free Software Foundation; either version 2 of the License, or
4
 
# (at your option) any later version.
5
 
 
6
 
# This program is distributed in the hope that it will be useful,
7
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
8
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
9
 
# GNU General Public License for more details.
10
 
 
11
 
# You should have received a copy of the GNU General Public License
12
 
# along with this program; if not, write to the Free Software
13
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
14
 
 
 
1
# Copyright (C) 2005, Canonical Ltd
15
2
 
16
3
"""Messages and logging for bazaar-ng.
17
4
 
43
30
form.
44
31
"""
45
32
 
46
 
 
47
33
# TODO: in debug mode, stderr should get full tracebacks and also
48
34
# debug messages.  (Is this really needed?)
49
35
 
50
 
# TODO: When running the test suites, we should add an additional
51
 
# logger that sends messages into the test log file.
52
 
 
53
36
# FIXME: Unfortunately it turns out that python's logging module
54
37
# is quite expensive, even when the message is not printed by any handlers.
55
38
# We should perhaps change back to just simply doing it here.
66
49
_file_handler = None
67
50
_stderr_handler = None
68
51
_stderr_quiet = False
69
 
 
 
52
_trace_file = None
 
53
_bzr_log_file = None
70
54
 
71
55
class QuietFormatter(logging.Formatter):
72
56
    """Formatter that supresses the details of errors.
87
71
            s += '\n' + format_exception_short(record.exc_info)
88
72
        return s
89
73
        
90
 
 
91
 
 
92
 
 
93
 
################
94
74
# configure convenient aliases for output routines
95
75
 
96
76
_bzr_logger = logging.getLogger('bzr')
99
79
warning =   _bzr_logger.warning
100
80
log_error = _bzr_logger.error
101
81
error =     _bzr_logger.error
102
 
mutter =    _bzr_logger.debug
103
 
debug =     _bzr_logger.debug
 
82
 
 
83
 
 
84
def mutter(fmt, *args):
 
85
    if _trace_file is None:
 
86
        return
 
87
    if hasattr(_trace_file, 'closed') and _trace_file.closed:
 
88
        return
 
89
    if len(args) > 0:
 
90
        print >>_trace_file, fmt % args
 
91
    else:
 
92
        print >>_trace_file, fmt
 
93
debug = mutter
104
94
 
105
95
 
106
96
def _rollover_trace_maybe(trace_fname):
120
110
    # Messages are always written to here, so that we have some
121
111
    # information if something goes wrong.  In a future version this
122
112
    # file will be removed on successful completion.
123
 
    global _file_handler
 
113
    global _file_handler, _bzr_log_file
124
114
    import stat, codecs
125
115
 
126
116
    trace_fname = os.path.join(os.path.expanduser(tracefilename))
128
118
    try:
129
119
        LINE_BUFFERED = 1
130
120
        tf = codecs.open(trace_fname, 'at', 'utf8', buffering=LINE_BUFFERED)
131
 
 
132
 
        if os.fstat(tf.fileno())[stat.ST_SIZE] == 0:
 
121
        _bzr_log_file = tf
 
122
        if tf.tell() == 0:
133
123
            tf.write("\nthis is a debug log for diagnosing/reporting problems in bzr\n")
134
124
            tf.write("you can delete or truncate this file, or include sections in\n")
135
125
            tf.write("bug reports to bazaar-ng@lists.canonical.com\n\n")
136
 
        
137
126
        _file_handler = logging.StreamHandler(tf)
138
127
        fmt = r'[%(process)5d] %(asctime)s.%(msecs)03d %(levelname)s: %(message)s'
139
128
        datefmt = r'%a %H:%M:%S'
145
134
 
146
135
 
147
136
def log_startup(argv):
148
 
    debug('bzr %s invoked on python %s (%s)',
 
137
    debug('\n\nbzr %s invoked on python %s (%s)',
149
138
          bzrlib.__version__,
150
139
          '.'.join(map(str, sys.version_info)),
151
140
          sys.platform)
159
148
    The exception string representation is used as the error
160
149
    summary, unless msg is given.
161
150
    """
162
 
    exc_str = format_exception_short(sys.exc_info())
163
151
    if msg:
164
 
        _bzr_logger.exception(msg)
165
 
    _bzr_logger.error(exc_str)
 
152
        error(msg)
 
153
    else:
 
154
        exc_str = format_exception_short(sys.exc_info())
 
155
        error(exc_str)
 
156
    log_exception_quietly()
166
157
 
167
158
 
168
159
def log_exception_quietly():
178
169
 
179
170
def enable_default_logging():
180
171
    """Configure default logging to stderr and .bzr.log"""
181
 
    global _stderr_handler, _file_handler
182
 
 
 
172
    # FIXME: if this is run twice, things get confused
 
173
    global _stderr_handler, _file_handler, _trace_file, _bzr_log_file
183
174
    _stderr_handler = logging.StreamHandler()
184
175
    _stderr_handler.setFormatter(QuietFormatter())
185
176
    logging.getLogger('').addHandler(_stderr_handler)
186
 
 
187
 
    if os.environ.get('BZR_DEBUG'):
188
 
        level = logging.DEBUG
189
 
    else:
190
 
        level = logging.INFO
191
 
 
192
177
    _stderr_handler.setLevel(logging.INFO)
193
 
 
194
178
    if not _file_handler:
195
179
        open_tracefile()
196
 
 
 
180
    _trace_file = _bzr_log_file
197
181
    if _file_handler:
198
 
        _file_handler.setLevel(level)
 
182
        _file_handler.setLevel(logging.DEBUG)
 
183
    _bzr_logger.setLevel(logging.DEBUG) 
199
184
 
200
 
    _bzr_logger.setLevel(level) 
201
185
 
202
186
 
203
187
def be_quiet(quiet=True):
226
210
    l.removeHandler(_stderr_handler)
227
211
    if _file_handler:
228
212
        l.removeHandler(_file_handler)
 
213
    _trace_file = None
229
214
 
230
215
 
231
216
def enable_test_log(to_file):
232
217
    """Redirect logging to a temporary file for a test"""
233
218
    disable_default_logging()
234
 
    global _test_log_hdlr
 
219
    global _test_log_hdlr, _trace_file
235
220
    hdlr = logging.StreamHandler(to_file)
236
221
    hdlr.setLevel(logging.DEBUG)
237
222
    hdlr.setFormatter(logging.Formatter('%(levelname)8s  %(message)s'))
238
 
    logging.getLogger('').addHandler(hdlr)
239
 
    logging.getLogger('').setLevel(logging.DEBUG)
 
223
    _bzr_logger.addHandler(hdlr)
 
224
    _bzr_logger.setLevel(logging.DEBUG)
240
225
    _test_log_hdlr = hdlr
 
226
    _trace_file = to_file
241
227
 
242
228
 
243
229
def disable_test_log():
244
 
    logging.getLogger('').removeHandler(_test_log_hdlr)
 
230
    _bzr_logger.removeHandler(_test_log_hdlr)
 
231
    _trace_file = None
245
232
    enable_default_logging()
246
233
 
247
234