~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/trace.py

  • Committer: Adeodato Simó
  • Date: 2007-07-17 13:47:45 UTC
  • mto: This revision was merged to the branch mainline in revision 2625.
  • Revision ID: dato@net.com.org.es-20070717134745-lex7ggja6p08kzts
Loose python2.4-specific shebangs; use generic python instead.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
 
1
# Copyright (C) 2005, 2006 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
50
50
# is quite expensive, even when the message is not printed by any handlers.
51
51
# We should perhaps change back to just simply doing it here.
52
52
 
53
 
import codecs
54
 
import logging
55
53
import os
56
54
import sys
57
55
import re
58
56
 
59
57
from bzrlib.lazy_import import lazy_import
60
58
lazy_import(globals(), """
61
 
from cStringIO import StringIO
62
59
import errno
63
 
import locale
64
 
import traceback
 
60
import logging
65
61
""")
66
62
 
67
63
import bzrlib
 
64
from bzrlib.symbol_versioning import (deprecated_function,
 
65
        zero_nine,
 
66
        )
68
67
 
69
68
lazy_import(globals(), """
70
 
from bzrlib import (
71
 
    debug,
72
 
    errors,
73
 
    osutils,
74
 
    plugin,
75
 
    )
 
69
from bzrlib import debug
76
70
""")
77
71
 
78
72
_file_handler = None
79
73
_stderr_handler = None
80
 
_verbosity_level = 0
 
74
_stderr_quiet = False
81
75
_trace_file = None
82
76
_trace_depth = 0
83
77
_bzr_log_file = None
88
82
 
89
83
_bzr_logger = logging.getLogger('bzr')
90
84
 
91
 
 
92
85
def note(*args, **kwargs):
93
86
    # FIXME note always emits utf-8, regardless of the terminal encoding
94
87
    import bzrlib.ui
132
125
    #_trace_file.flush()
133
126
 
134
127
 
135
 
def mutter_callsite(stacklevel, fmt, *args):
136
 
    """Perform a mutter of fmt and args, logging the call trace.
137
 
 
138
 
    :param stacklevel: The number of frames to show. None will show all
139
 
        frames.
140
 
    :param fmt: The format string to pass to mutter.
141
 
    :param args: A list of substitution variables.
142
 
    """
143
 
    outf = StringIO()
144
 
    traceback.print_stack(limit=stacklevel + 1, file=outf)
145
 
    formatted_lines = outf.getvalue().splitlines()
146
 
    formatted_stack = '\n'.join(formatted_lines[:-2])
147
 
    mutter(fmt + "\nCalled from:\n%s", *(args + (formatted_stack,)))
148
 
 
149
 
 
150
128
def _rollover_trace_maybe(trace_fname):
151
129
    import stat
152
130
    try:
154
132
        if size <= 4 << 20:
155
133
            return
156
134
        old_fname = trace_fname + '.old'
157
 
        osutils.rename(trace_fname, old_fname)
 
135
        from osutils import rename
 
136
        rename(trace_fname, old_fname)
158
137
    except OSError:
159
138
        return
160
139
 
173
152
        else:
174
153
            home = os.path.expanduser('~')
175
154
        _bzr_log_filename = os.path.join(home, '.bzr.log')
176
 
    else:
177
 
        _bzr_log_filename = tracefilename
178
155
 
179
156
    _bzr_log_filename = os.path.expanduser(_bzr_log_filename)
180
157
    _rollover_trace_maybe(_bzr_log_filename)
199
176
        warning("failed to open trace file: %s" % (e))
200
177
 
201
178
 
 
179
@deprecated_function(zero_nine)
 
180
def log_exception(msg=None):
 
181
    """Log the last exception to stderr and the trace file.
 
182
 
 
183
    The exception string representation is used as the error
 
184
    summary, unless msg is given.
 
185
 
 
186
    Please see log_exception_quietly() for the replacement API.
 
187
    """
 
188
    if msg:
 
189
        error(msg)
 
190
    log_exception_quietly()
 
191
 
 
192
 
202
193
def log_exception_quietly():
203
194
    """Log the last exception to the trace file only.
204
195
 
214
205
    """Configure default logging to stderr and .bzr.log"""
215
206
    # FIXME: if this is run twice, things get confused
216
207
    global _stderr_handler, _file_handler, _trace_file, _bzr_log_file
217
 
    # create encoded wrapper around stderr
218
 
    stderr = codecs.getwriter(osutils.get_terminal_encoding())(sys.stderr,
219
 
        errors='replace')
220
 
    _stderr_handler = logging.StreamHandler(stderr)
 
208
    _stderr_handler = logging.StreamHandler()
221
209
    logging.getLogger('').addHandler(_stderr_handler)
222
210
    _stderr_handler.setLevel(logging.INFO)
223
211
    if not _file_handler:
228
216
    _bzr_logger.setLevel(logging.DEBUG)
229
217
 
230
218
 
231
 
def set_verbosity_level(level):
232
 
    """Set the verbosity level.
233
 
 
234
 
    :param level: -ve for quiet, 0 for normal, +ve for verbose
235
 
    """
236
 
    global _verbosity_level
237
 
    _verbosity_level = level
238
 
    _update_logging_level(level < 0)
239
 
 
240
 
 
241
 
def get_verbosity_level():
242
 
    """Get the verbosity level.
243
 
 
244
 
    See set_verbosity_level() for values.
245
 
    """
246
 
    return _verbosity_level
247
 
 
248
 
 
249
219
def be_quiet(quiet=True):
250
 
    # Perhaps this could be deprecated now ...
251
 
    if quiet:
252
 
        set_verbosity_level(-1)
253
 
    else:
254
 
        set_verbosity_level(0)
255
 
 
256
 
 
257
 
def _update_logging_level(quiet=True):
258
 
    """Hide INFO messages if quiet."""
 
220
    global _stderr_handler, _stderr_quiet
 
221
    
 
222
    _stderr_quiet = quiet
259
223
    if quiet:
260
224
        _stderr_handler.setLevel(logging.WARNING)
261
225
    else:
263
227
 
264
228
 
265
229
def is_quiet():
266
 
    """Is the verbosity level negative?"""
267
 
    return _verbosity_level < 0
268
 
 
269
 
 
270
 
def is_verbose():
271
 
    """Is the verbosity level positive?"""
272
 
    return _verbosity_level > 0
 
230
    global _stderr_quiet
 
231
    return _stderr_quiet
273
232
 
274
233
 
275
234
def disable_default_logging():
318
277
 
319
278
 
320
279
def report_exception(exc_info, err_file):
321
 
    """Report an exception to err_file (typically stderr) and to .bzr.log.
322
 
 
323
 
    This will show either a full traceback or a short message as appropriate.
324
 
 
325
 
    :return: The appropriate exit code for this error.
326
 
    """
327
280
    exc_type, exc_object, exc_tb = exc_info
328
281
    # Log the full traceback to ~/.bzr.log
329
282
    log_exception_quietly()
330
283
    if (isinstance(exc_object, IOError)
331
284
        and getattr(exc_object, 'errno', None) == errno.EPIPE):
332
 
        err_file.write("bzr: broken pipe\n")
333
 
        return errors.EXIT_ERROR
 
285
        print >>err_file, "bzr: broken pipe"
334
286
    elif isinstance(exc_object, KeyboardInterrupt):
335
 
        err_file.write("bzr: interrupted\n")
336
 
        return errors.EXIT_ERROR
 
287
        print >>err_file, "bzr: interrupted"
337
288
    elif not getattr(exc_object, 'internal_error', True):
338
289
        report_user_error(exc_info, err_file)
339
 
        return errors.EXIT_ERROR
340
290
    elif isinstance(exc_object, (OSError, IOError)):
341
291
        # Might be nice to catch all of these and show them as something more
342
292
        # specific, but there are too many cases at the moment.
343
293
        report_user_error(exc_info, err_file)
344
 
        return errors.EXIT_ERROR
345
294
    else:
346
295
        report_bug(exc_info, err_file)
347
 
        return errors.EXIT_INTERNAL_ERROR
348
296
 
349
297
 
350
298
# TODO: Should these be specially encoding the output?
356
304
    if 'error' in debug.debug_flags:
357
305
        report_bug(exc_info, err_file)
358
306
        return
359
 
    err_file.write("bzr: ERROR: %s\n" % (exc_info[1],))
 
307
    print >>err_file, "bzr: ERROR:", str(exc_info[1])
360
308
 
361
309
 
362
310
def report_bug(exc_info, err_file):
363
311
    """Report an exception that probably indicates a bug in bzr"""
364
312
    import traceback
365
313
    exc_type, exc_object, exc_tb = exc_info
366
 
    err_file.write("bzr: ERROR: %s.%s: %s\n" % (
367
 
        exc_type.__module__, exc_type.__name__, exc_object))
368
 
    err_file.write('\n')
 
314
    print >>err_file, "bzr: ERROR: %s.%s: %s" % (
 
315
        exc_type.__module__, exc_type.__name__, exc_object)
 
316
    print >>err_file
369
317
    traceback.print_exception(exc_type, exc_object, exc_tb, file=err_file)
370
 
    err_file.write('\n')
371
 
    err_file.write('bzr %s on python %s (%s)\n' % \
 
318
    print >>err_file
 
319
    print >>err_file, 'bzr %s on python %s (%s)' % \
372
320
                       (bzrlib.__version__,
373
321
                        '.'.join(map(str, sys.version_info)),
374
 
                        sys.platform))
375
 
    err_file.write('arguments: %r\n' % sys.argv)
376
 
    err_file.write(
377
 
        'encoding: %r, fsenc: %r, lang: %r\n' % (
378
 
            osutils.get_user_encoding(), sys.getfilesystemencoding(),
379
 
            os.environ.get('LANG')))
380
 
    err_file.write("plugins:\n")
381
 
    for name, a_plugin in sorted(plugin.plugins().items()):
382
 
        err_file.write("  %-20s %s [%s]\n" %
383
 
            (name, a_plugin.path(), a_plugin.__version__))
384
 
    err_file.write(
385
 
        "\n"
386
 
        "** Please send this report to bazaar@lists.ubuntu.com\n"
387
 
        "   with a description of what you were doing when the\n"
388
 
        "   error occurred.\n"
389
 
        )
 
322
                        sys.platform)
 
323
    print >>err_file, 'arguments: %r' % sys.argv
 
324
    print >>err_file
 
325
    print >>err_file, "** please send this report to bazaar@lists.ubuntu.com"