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.
57
from bzrlib.lazy_import import lazy_import
58
lazy_import(globals(), """
59
from cStringIO import StringIO
68
lazy_import(globals(), """
60
from bzrlib.errors import BzrError, BzrNewError
61
from bzrlib.symbol_versioning import (deprecated_function,
77
65
_file_handler = None
78
66
_stderr_handler = None
82
70
_bzr_log_file = None
83
_bzr_log_filename = None
86
73
# configure convenient aliases for output routines
106
93
def mutter(fmt, *args):
107
94
if _trace_file is None:
109
if (getattr(_trace_file, 'closed', None) is not None) and _trace_file.closed:
96
if hasattr(_trace_file, 'closed') and _trace_file.closed:
112
if isinstance(fmt, unicode):
113
fmt = fmt.encode('utf8')
116
99
# It seems that if we do ascii % (unicode, ascii) we can
117
100
# get a unicode cannot encode ascii error, so make sure that "fmt"
118
101
# is a unicode string
121
if isinstance(arg, unicode):
122
arg = arg.encode('utf8')
123
real_args.append(arg)
124
out = fmt % tuple(real_args)
102
out = unicode(fmt) % args
128
_trace_file.write(out)
107
_trace_file.write(out)
108
except UnicodeError, e:
109
warning('UnicodeError: %s', e)
110
_trace_file.write(repr(out))
129
111
# TODO: jam 20051227 Consider flushing the trace file to help debugging
130
112
#_trace_file.flush()
133
def mutter_callsite(stacklevel, fmt, *args):
134
"""Perform a mutter of fmt and args, logging the call trace.
136
:param stacklevel: The number of frames to show. None will show all
138
:param fmt: The format string to pass to mutter.
139
:param args: A list of substitution variables.
142
traceback.print_stack(limit=stacklevel + 1, file=outf)
143
formatted_lines = outf.getvalue().splitlines()
144
formatted_stack = '\n'.join(formatted_lines[:-2])
145
mutter(fmt + "\nCalled from:\n%s", *(args + (formatted_stack,)))
148
116
def _rollover_trace_maybe(trace_fname):
152
120
if size <= 4 << 20:
154
122
old_fname = trace_fname + '.old'
155
osutils.rename(trace_fname, old_fname)
123
from osutils import rename
124
rename(trace_fname, old_fname)
160
def open_tracefile(tracefilename=None):
129
def open_tracefile(tracefilename='~/.bzr.log'):
161
130
# Messages are always written to here, so that we have some
162
131
# information if something goes wrong. In a future version this
163
132
# file will be removed on successful completion.
164
global _file_handler, _bzr_log_file, _bzr_log_filename
133
global _file_handler, _bzr_log_file
167
if tracefilename is None:
168
if sys.platform == 'win32':
169
from bzrlib import win32utils
170
home = win32utils.get_home_location()
172
home = os.path.expanduser('~')
173
_bzr_log_filename = os.path.join(home, '.bzr.log')
175
_bzr_log_filename = tracefilename
177
_bzr_log_filename = os.path.expanduser(_bzr_log_filename)
178
_rollover_trace_maybe(_bzr_log_filename)
136
trace_fname = os.path.join(os.path.expanduser(tracefilename))
137
_rollover_trace_maybe(trace_fname)
180
139
LINE_BUFFERED = 1
181
#tf = codecs.open(trace_fname, 'at', 'utf8', buffering=LINE_BUFFERED)
182
tf = open(_bzr_log_filename, 'at', LINE_BUFFERED)
140
tf = codecs.open(trace_fname, 'at', 'utf8', buffering=LINE_BUFFERED)
183
141
_bzr_log_file = tf
184
# tf.tell() on windows always return 0 until some writing done
187
tf.write("this is a debug log for diagnosing/reporting problems in bzr\n")
143
tf.write("\nthis is a debug log for diagnosing/reporting problems in bzr\n")
188
144
tf.write("you can delete or truncate this file, or include sections in\n")
189
tf.write("bug reports to bazaar@lists.canonical.com\n\n")
145
tf.write("bug reports to bazaar-ng@lists.canonical.com\n\n")
190
146
_file_handler = logging.StreamHandler(tf)
191
147
fmt = r'[%(process)5d] %(asctime)s.%(msecs)03d %(levelname)s: %(message)s'
192
148
datefmt = r'%a %H:%M:%S'
223
194
_bzr_logger.setLevel(logging.DEBUG)
226
def set_verbosity_level(level):
227
"""Set the verbosity level.
229
:param level: -ve for quiet, 0 for normal, +ve for verbose
231
global _verbosity_level
232
_verbosity_level = level
233
_update_logging_level(level < 0)
236
def get_verbosity_level():
237
"""Get the verbosity level.
239
See set_verbosity_level() for values.
241
return _verbosity_level
244
197
def be_quiet(quiet=True):
245
# Perhaps this could be deprecated now ...
247
set_verbosity_level(-1)
249
set_verbosity_level(0)
252
def _update_logging_level(quiet=True):
253
"""Hide INFO messages if quiet."""
198
global _stderr_handler, _stderr_quiet
200
_stderr_quiet = quiet
255
202
_stderr_handler.setLevel(logging.WARNING)
315
257
def report_exception(exc_info, err_file):
316
"""Report an exception to err_file (typically stderr) and to .bzr.log.
318
This will show either a full traceback or a short message as appropriate.
320
:return: The appropriate exit code for this error.
322
258
exc_type, exc_object, exc_tb = exc_info
323
259
# Log the full traceback to ~/.bzr.log
324
260
log_exception_quietly()
325
261
if (isinstance(exc_object, IOError)
326
262
and getattr(exc_object, 'errno', None) == errno.EPIPE):
327
err_file.write("bzr: broken pipe\n")
328
return errors.EXIT_ERROR
263
print >>err_file, "bzr: broken pipe"
329
264
elif isinstance(exc_object, KeyboardInterrupt):
330
err_file.write("bzr: interrupted\n")
331
return errors.EXIT_ERROR
332
elif not getattr(exc_object, 'internal_error', True):
265
print >>err_file, "bzr: interrupted"
266
elif getattr(exc_object, 'is_user_error', False):
333
267
report_user_error(exc_info, err_file)
334
return errors.EXIT_ERROR
335
268
elif isinstance(exc_object, (OSError, IOError)):
336
269
# Might be nice to catch all of these and show them as something more
337
270
# specific, but there are too many cases at the moment.
338
271
report_user_error(exc_info, err_file)
339
return errors.EXIT_ERROR
341
273
report_bug(exc_info, err_file)
342
return errors.EXIT_INTERNAL_ERROR
345
276
# TODO: Should these be specially encoding the output?
346
277
def report_user_error(exc_info, err_file):
347
"""Report to err_file an error that's not an internal error.
349
These don't get a traceback unless -Derror was given.
351
if 'error' in debug.debug_flags:
352
report_bug(exc_info, err_file)
354
err_file.write("bzr: ERROR: %s\n" % (exc_info[1],))
278
print >>err_file, "bzr: ERROR:", str(exc_info[1])
357
281
def report_bug(exc_info, err_file):
358
282
"""Report an exception that probably indicates a bug in bzr"""
360
284
exc_type, exc_object, exc_tb = exc_info
361
err_file.write("bzr: ERROR: %s.%s: %s\n" % (
362
exc_type.__module__, exc_type.__name__, exc_object))
285
print >>err_file, "bzr: ERROR: %s: %s" % (exc_type, exc_object)
364
287
traceback.print_exception(exc_type, exc_object, exc_tb, file=err_file)
366
err_file.write('bzr %s on python %s (%s)\n' % \
289
print >>err_file, 'bzr %s on python %s (%s)' % \
367
290
(bzrlib.__version__,
368
291
'.'.join(map(str, sys.version_info)),
370
err_file.write('arguments: %r\n' % sys.argv)
372
'encoding: %r, fsenc: %r, lang: %r\n' % (
373
osutils.get_user_encoding(), sys.getfilesystemencoding(),
374
os.environ.get('LANG')))
375
err_file.write("plugins:\n")
376
for name, a_plugin in sorted(plugin.plugins().items()):
377
err_file.write(" %-20s %s [%s]\n" %
378
(name, a_plugin.path(), a_plugin.__version__))
381
"** Please send this report to bazaar@lists.ubuntu.com\n"
382
" with a description of what you were doing when the\n"
293
print >>err_file, 'arguments: %r' % sys.argv
295
print >>err_file, "** please send this report to bazaar-ng@lists.ubuntu.com"