1
# Copyright (C) 2005-2010 Canonical Ltd
1
# Copyright (C) 2005-2011 Canonical Ltd
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
120
# FIXME note always emits utf-8, regardless of the terminal encoding
122
113
# FIXME: clearing the ui and then going through the abstract logging
123
114
# framework is whack; we should probably have a logging Handler that
124
115
# deals with terminal output if needed.
126
bzrlib.ui.ui_factory.clear_term()
116
ui.ui_factory.clear_term()
127
117
_bzr_logger.info(*args, **kwargs)
130
120
def warning(*args, **kwargs):
132
bzrlib.ui.ui_factory.clear_term()
121
ui.ui_factory.clear_term()
133
122
_bzr_logger.warning(*args, **kwargs)
136
@deprecated_function(deprecated_in((2, 1, 0)))
137
def info(*args, **kwargs):
138
"""Deprecated: use trace.note instead."""
139
note(*args, **kwargs)
142
@deprecated_function(deprecated_in((2, 1, 0)))
143
def log_error(*args, **kwargs):
144
"""Deprecated: use bzrlib.trace.show_error instead"""
145
_bzr_logger.error(*args, **kwargs)
148
@deprecated_function(deprecated_in((2, 1, 0)))
149
def error(*args, **kwargs):
150
"""Deprecated: use bzrlib.trace.show_error instead"""
151
_bzr_logger.error(*args, **kwargs)
154
125
def show_error(*args, **kwargs):
155
126
"""Show an error message to the user.
312
283
start_time = osutils.format_local_date(_bzr_log_start_time,
313
284
timezone='local')
314
# create encoded wrapper around stderr
315
285
bzr_log_file = _open_bzr_log()
316
286
if bzr_log_file is not None:
317
287
bzr_log_file.write(start_time.encode('utf-8') + '\n')
320
290
r'%Y-%m-%d %H:%M:%S')
321
291
# after hooking output into bzr_log, we also need to attach a stderr
322
292
# handler, writing only at level info and with encoding
323
term_encoding = osutils.get_terminal_encoding()
324
writer_factory = codecs.getwriter(term_encoding)
325
encoded_stderr = writer_factory(sys.stderr, errors='replace')
326
stderr_handler = logging.StreamHandler(encoded_stderr)
327
stderr_handler.setLevel(logging.INFO)
293
stderr_handler = EncodedStreamHandler(sys.stderr,
294
osutils.get_terminal_encoding(), 'replace', level=logging.INFO)
328
295
logging.getLogger('bzr').addHandler(stderr_handler)
335
302
:param to_file: A file-like object to which messages will be sent.
337
304
:returns: A memento that should be passed to _pop_log_file to restore the
338
previously active logging.
305
previously active logging.
340
307
global _trace_file
341
308
# make a new handler
342
new_handler = logging.StreamHandler(to_file)
343
new_handler.setLevel(logging.DEBUG)
309
new_handler = EncodedStreamHandler(to_file, "utf-8", level=logging.DEBUG)
344
310
if log_format is None:
345
311
log_format = '%(levelname)8s %(message)s'
346
312
new_handler.setFormatter(logging.Formatter(log_format, date_format))
438
def _dump_memory_usage(err_file):
441
fd, name = tempfile.mkstemp(prefix="bzr_memdump", suffix=".json")
442
dump_file = os.fdopen(fd, 'w')
443
from meliae import scanner
444
scanner.dump_gc_objects(dump_file)
445
err_file.write("Memory dumped to %s\n" % name)
447
err_file.write("Dumping memory requires meliae module.\n")
448
log_exception_quietly()
450
err_file.write("Exception while dumping memory.\n")
451
log_exception_quietly()
453
if dump_file is not None:
459
def _qualified_exception_name(eclass, unqualified_bzrlib_errors=False):
460
"""Give name of error class including module for non-builtin exceptions
462
If `unqualified_bzrlib_errors` is True, errors specific to bzrlib will
463
also omit the module prefix.
465
class_name = eclass.__name__
466
module_name = eclass.__module__
467
if module_name in ("exceptions", "__main__") or (
468
unqualified_bzrlib_errors and module_name == "bzrlib.errors"):
470
return "%s.%s" % (module_name, class_name)
473
473
def report_exception(exc_info, err_file):
474
474
"""Report an exception to err_file (typically stderr) and to .bzr.log.
483
483
print_exception(exc_info, err_file)
484
484
return errors.EXIT_ERROR
485
485
exc_type, exc_object, exc_tb = exc_info
486
if (isinstance(exc_object, IOError)
487
and getattr(exc_object, 'errno', None) == errno.EPIPE):
488
err_file.write("bzr: broken pipe\n")
489
return errors.EXIT_ERROR
490
elif isinstance(exc_object, KeyboardInterrupt):
486
if isinstance(exc_object, KeyboardInterrupt):
491
487
err_file.write("bzr: interrupted\n")
492
488
return errors.EXIT_ERROR
493
489
elif isinstance(exc_object, MemoryError):
494
490
err_file.write("bzr: out of memory\n")
491
if 'mem_dump' in debug.debug_flags:
492
_dump_memory_usage(err_file)
494
err_file.write("Use -Dmem_dump to dump memory to a file.\n")
495
495
return errors.EXIT_ERROR
496
496
elif isinstance(exc_object, ImportError) \
497
497
and str(exc_object).startswith("No module named "):
501
501
elif not getattr(exc_object, 'internal_error', True):
502
502
report_user_error(exc_info, err_file)
503
503
return errors.EXIT_ERROR
504
elif isinstance(exc_object, (OSError, IOError)) or (
505
# GZ 2010-05-20: Like (exc_type is pywintypes.error) but avoid import
506
exc_type.__name__ == "error" and exc_type.__module__ == "pywintypes"):
504
elif osutils.is_environment_error(exc_object):
505
if getattr(exc_object, 'errno', None) == errno.EPIPE:
506
err_file.write("bzr: broken pipe\n")
507
return errors.EXIT_ERROR
507
508
# Might be nice to catch all of these and show them as something more
508
509
# specific, but there are too many cases at the moment.
509
510
report_user_error(exc_info, err_file)
562
567
_trace_file.flush()
570
class EncodedStreamHandler(logging.Handler):
571
"""Robustly write logging events to a stream using the specified encoding
573
Messages are expected to be formatted to unicode, but UTF-8 byte strings
574
are also accepted. An error during formatting or a str message in another
575
encoding will be quitely noted as an error in the Bazaar log file.
577
The stream is not closed so sys.stdout or sys.stderr may be passed.
580
def __init__(self, stream, encoding=None, errors='strict', level=0):
581
logging.Handler.__init__(self, level)
584
encoding = getattr(stream, "encoding", "ascii")
585
self.encoding = encoding
589
flush = getattr(self.stream, "flush", None)
590
if flush is not None:
593
def emit(self, record):
595
line = self.format(record)
596
if not isinstance(line, unicode):
597
line = line.decode("utf-8")
598
self.stream.write(line.encode(self.encoding, self.errors) + "\n")
600
log_exception_quietly()
601
# Try saving the details that would have been logged in some form
602
msg = args = "<Unformattable>"
604
msg = repr(record.msg).encode("ascii")
605
args = repr(record.args).encode("ascii")
608
# Using mutter() bypasses the logging module and writes directly
609
# to the file so there's no danger of getting into a loop here.
610
mutter("Logging record unformattable: %s %% %s", msg, args)
565
613
class Config(object):
566
614
"""Configuration of message tracing in bzrlib.