114
# FIXME note always emits utf-8, regardless of the terminal encoding
113
116
# FIXME: clearing the ui and then going through the abstract logging
114
117
# framework is whack; we should probably have a logging Handler that
115
118
# deals with terminal output if needed.
283
286
start_time = osutils.format_local_date(_bzr_log_start_time,
284
287
timezone='local')
288
# create encoded wrapper around stderr
285
289
bzr_log_file = _open_bzr_log()
286
290
if bzr_log_file is not None:
287
291
bzr_log_file.write(start_time.encode('utf-8') + '\n')
290
294
r'%Y-%m-%d %H:%M:%S')
291
295
# after hooking output into bzr_log, we also need to attach a stderr
292
296
# handler, writing only at level info and with encoding
293
stderr_handler = EncodedStreamHandler(sys.stderr,
294
osutils.get_terminal_encoding(), 'replace', level=logging.INFO)
297
term_encoding = osutils.get_terminal_encoding()
298
writer_factory = codecs.getwriter(term_encoding)
299
encoded_stderr = writer_factory(sys.stderr, errors='replace')
300
stderr_handler = logging.StreamHandler(encoded_stderr)
301
stderr_handler.setLevel(logging.INFO)
295
302
logging.getLogger('bzr').addHandler(stderr_handler)
307
314
global _trace_file
308
315
# make a new handler
309
new_handler = EncodedStreamHandler(to_file, "utf-8", level=logging.DEBUG)
316
new_handler = logging.StreamHandler(to_file)
317
new_handler.setLevel(logging.DEBUG)
310
318
if log_format is None:
311
319
log_format = '%(levelname)8s %(message)s'
312
320
new_handler.setFormatter(logging.Formatter(log_format, date_format))
483
491
print_exception(exc_info, err_file)
484
492
return errors.EXIT_ERROR
485
493
exc_type, exc_object, exc_tb = exc_info
486
if isinstance(exc_object, KeyboardInterrupt):
494
if (isinstance(exc_object, IOError)
495
and getattr(exc_object, 'errno', None) == errno.EPIPE):
496
err_file.write("bzr: broken pipe\n")
497
return errors.EXIT_ERROR
498
elif isinstance(exc_object, KeyboardInterrupt):
487
499
err_file.write("bzr: interrupted\n")
488
500
return errors.EXIT_ERROR
489
501
elif isinstance(exc_object, MemoryError):
501
513
elif not getattr(exc_object, 'internal_error', True):
502
514
report_user_error(exc_info, err_file)
503
515
return errors.EXIT_ERROR
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
516
elif isinstance(exc_object, (OSError, IOError)) or (
517
# GZ 2010-05-20: Like (exc_type is pywintypes.error) but avoid import
518
exc_type.__name__ == "error" and exc_type.__module__ == "pywintypes"):
508
519
# Might be nice to catch all of these and show them as something more
509
520
# specific, but there are too many cases at the moment.
510
521
report_user_error(exc_info, err_file)
567
578
_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)
613
581
class Config(object):
614
582
"""Configuration of message tracing in bzrlib.