119
# FIXME note always emits utf-8, regardless of the terminal encoding
121
118
# FIXME: clearing the ui and then going through the abstract logging
122
119
# framework is whack; we should probably have a logging Handler that
123
120
# deals with terminal output if needed.
309
306
start_time = osutils.format_local_date(_bzr_log_start_time,
310
307
timezone='local')
311
# create encoded wrapper around stderr
312
308
bzr_log_file = _open_bzr_log()
313
309
if bzr_log_file is not None:
314
310
bzr_log_file.write(start_time.encode('utf-8') + '\n')
317
313
r'%Y-%m-%d %H:%M:%S')
318
314
# after hooking output into bzr_log, we also need to attach a stderr
319
315
# handler, writing only at level info and with encoding
320
term_encoding = osutils.get_terminal_encoding()
321
writer_factory = codecs.getwriter(term_encoding)
322
encoded_stderr = writer_factory(sys.stderr, errors='replace')
323
stderr_handler = logging.StreamHandler(encoded_stderr)
324
stderr_handler.setLevel(logging.INFO)
316
stderr_handler = EncodedStreamHandler(sys.stderr,
317
osutils.get_terminal_encoding(), 'replace', level=logging.INFO)
325
318
logging.getLogger('bzr').addHandler(stderr_handler)
337
330
global _trace_file
338
331
# make a new handler
339
new_handler = logging.StreamHandler(to_file)
340
new_handler.setLevel(logging.DEBUG)
332
new_handler = EncodedStreamHandler(to_file, "utf-8", level=logging.DEBUG)
341
333
if log_format is None:
342
334
log_format = '%(levelname)8s %(message)s'
343
335
new_handler.setFormatter(logging.Formatter(log_format, date_format))
597
589
_trace_file.flush()
592
class EncodedStreamHandler(logging.Handler):
593
"""Robustly write logging events to a stream using the specified encoding
595
Messages are expected to be formatted to unicode, but UTF-8 byte strings
596
are also accepted. An error during formatting or a str message in another
597
encoding will be quitely noted as an error in the Bazaar log file.
599
The stream is not closed so sys.stdout or sys.stderr may be passed.
602
def __init__(self, stream, encoding=None, errors='strict', level=0):
603
logging.Handler.__init__(self, level)
606
encoding = getattr(stream, "encoding", "ascii")
607
self.encoding = encoding
611
flush = getattr(self.stream, "flush", None)
612
if flush is not None:
615
def emit(self, record):
617
line = self.format(record)
618
if not isinstance(line, unicode):
619
line = line.decode("utf-8")
620
self.stream.write(line.encode(self.encoding, self.errors) + "\n")
622
log_exception_quietly()
623
# Try saving the details that would have been logged in some form
624
msg = args = "<Unformattable>"
626
msg = repr(record.msg).encode("ascii")
627
args = repr(record.args).encode("ascii")
630
# Using mutter() bypasses the logging module and writes directly
631
# to the file so there's no danger of getting into a loop here.
632
mutter("Logging record unformattable: %s %% %s", msg, args)
600
635
class Config(object):
601
636
"""Configuration of message tracing in bzrlib.