~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/trace.py

  • Committer: Martin Packman
  • Date: 2011-12-05 14:21:55 UTC
  • mfrom: (6015.44.9 2.4)
  • mto: This revision was merged to the branch mainline in revision 6345.
  • Revision ID: martin.packman@canonical.com-20111205142155-t7s4lr5aau50dp8i
Merge 2.4 into bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
54
54
# increased cost of logging.py is not so bad, and we could standardize on
55
55
# that.
56
56
 
57
 
import codecs
58
57
import logging
59
58
import os
60
59
import sys
111
110
 
112
111
    :return: None
113
112
    """
114
 
    # FIXME note always emits utf-8, regardless of the terminal encoding
115
 
    #
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.
285
282
    """
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)
303
296
    return memento
304
297
 
313
306
    """
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()
576
568
 
577
569
 
 
570
class EncodedStreamHandler(logging.Handler):
 
571
    """Robustly write logging events to a stream using the specified encoding
 
572
 
 
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.
 
576
 
 
577
    The stream is not closed so sys.stdout or sys.stderr may be passed.
 
578
    """
 
579
 
 
580
    def __init__(self, stream, encoding=None, errors='strict', level=0):
 
581
        logging.Handler.__init__(self, level)
 
582
        self.stream = stream
 
583
        if encoding is None:
 
584
            encoding = getattr(stream, "encoding", "ascii")
 
585
        self.encoding = encoding
 
586
        self.errors = errors
 
587
 
 
588
    def flush(self):
 
589
        flush = getattr(self.stream, "flush", None)
 
590
        if flush is not None:
 
591
            flush()
 
592
 
 
593
    def emit(self, record):
 
594
        try:
 
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")
 
599
        except Exception:
 
600
            log_exception_quietly()
 
601
            # Try saving the details that would have been logged in some form
 
602
            msg = args = "<Unformattable>"
 
603
            try:
 
604
                msg = repr(record.msg).encode("ascii")
 
605
                args = repr(record.args).encode("ascii")
 
606
            except Exception:
 
607
                pass
 
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)
 
611
 
 
612
 
578
613
class Config(object):
579
614
    """Configuration of message tracing in bzrlib.
580
615