114
# FIXME note always emits utf-8, regardless of the terminal encoding
116
113
# FIXME: clearing the ui and then going through the abstract logging
117
114
# framework is whack; we should probably have a logging Handler that
118
115
# deals with terminal output if needed.
286
283
start_time = osutils.format_local_date(_bzr_log_start_time,
287
284
timezone='local')
288
# create encoded wrapper around stderr
289
285
bzr_log_file = _open_bzr_log()
290
286
if bzr_log_file is not None:
291
287
bzr_log_file.write(start_time.encode('utf-8') + '\n')
294
290
r'%Y-%m-%d %H:%M:%S')
295
291
# after hooking output into bzr_log, we also need to attach a stderr
296
292
# handler, writing only at level info and with encoding
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)
293
stderr_handler = EncodedStreamHandler(sys.stderr,
294
osutils.get_terminal_encoding(), 'replace', level=logging.INFO)
302
295
logging.getLogger('bzr').addHandler(stderr_handler)
314
307
global _trace_file
315
308
# make a new handler
316
new_handler = logging.StreamHandler(to_file)
317
new_handler.setLevel(logging.DEBUG)
309
new_handler = EncodedStreamHandler(to_file, "utf-8", level=logging.DEBUG)
318
310
if log_format is None:
319
311
log_format = '%(levelname)8s %(message)s'
320
312
new_handler.setFormatter(logging.Formatter(log_format, date_format))
575
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)
578
613
class Config(object):
579
614
"""Configuration of message tracing in bzrlib.