~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/trace.py

  • Committer: Martin Packman
  • Date: 2012-01-05 10:37:58 UTC
  • mto: This revision was merged to the branch mainline in revision 6427.
  • Revision ID: martin.packman@canonical.com-20120105103758-wzftnmsip5iv9n2g
Revert addition of get_message_encoding function

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
71
70
 
72
71
import bzrlib
73
72
 
74
 
from bzrlib.symbol_versioning import (
75
 
    deprecated_function,
76
 
    deprecated_in,
77
 
    )
78
 
 
79
73
lazy_import(globals(), """
80
74
from bzrlib import (
81
75
    debug,
116
110
 
117
111
    :return: None
118
112
    """
119
 
    # FIXME note always emits utf-8, regardless of the terminal encoding
120
 
    #
121
113
    # FIXME: clearing the ui and then going through the abstract logging
122
114
    # framework is whack; we should probably have a logging Handler that
123
115
    # deals with terminal output if needed.
130
122
    _bzr_logger.warning(*args, **kwargs)
131
123
 
132
124
 
133
 
@deprecated_function(deprecated_in((2, 1, 0)))
134
 
def info(*args, **kwargs):
135
 
    """Deprecated: use trace.note instead."""
136
 
    note(*args, **kwargs)
137
 
 
138
 
 
139
 
@deprecated_function(deprecated_in((2, 1, 0)))
140
 
def log_error(*args, **kwargs):
141
 
    """Deprecated: use bzrlib.trace.show_error instead"""
142
 
    _bzr_logger.error(*args, **kwargs)
143
 
 
144
 
 
145
 
@deprecated_function(deprecated_in((2, 1, 0)))
146
 
def error(*args, **kwargs):
147
 
    """Deprecated: use bzrlib.trace.show_error instead"""
148
 
    _bzr_logger.error(*args, **kwargs)
149
 
 
150
 
 
151
125
def show_error(*args, **kwargs):
152
126
    """Show an error message to the user.
153
127
 
308
282
    """
309
283
    start_time = osutils.format_local_date(_bzr_log_start_time,
310
284
                                           timezone='local')
311
 
    # create encoded wrapper around stderr
312
285
    bzr_log_file = _open_bzr_log()
313
286
    if bzr_log_file is not None:
314
287
        bzr_log_file.write(start_time.encode('utf-8') + '\n')
317
290
        r'%Y-%m-%d %H:%M:%S')
318
291
    # after hooking output into bzr_log, we also need to attach a stderr
319
292
    # 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)
 
293
    stderr_handler = EncodedStreamHandler(sys.stderr,
 
294
        osutils.get_terminal_encoding(), 'replace', level=logging.INFO)
325
295
    logging.getLogger('bzr').addHandler(stderr_handler)
326
296
    return memento
327
297
 
336
306
    """
337
307
    global _trace_file
338
308
    # make a new handler
339
 
    new_handler = logging.StreamHandler(to_file)
340
 
    new_handler.setLevel(logging.DEBUG)
 
309
    new_handler = EncodedStreamHandler(to_file, "utf-8", level=logging.DEBUG)
341
310
    if log_format is None:
342
311
        log_format = '%(levelname)8s  %(message)s'
343
312
    new_handler.setFormatter(logging.Formatter(log_format, date_format))
514
483
        print_exception(exc_info, err_file)
515
484
        return errors.EXIT_ERROR
516
485
    exc_type, exc_object, exc_tb = exc_info
517
 
    if (isinstance(exc_object, IOError)
518
 
        and getattr(exc_object, 'errno', None) == errno.EPIPE):
519
 
        err_file.write("bzr: broken pipe\n")
520
 
        return errors.EXIT_ERROR
521
 
    elif isinstance(exc_object, KeyboardInterrupt):
 
486
    if isinstance(exc_object, KeyboardInterrupt):
522
487
        err_file.write("bzr: interrupted\n")
523
488
        return errors.EXIT_ERROR
524
489
    elif isinstance(exc_object, MemoryError):
536
501
    elif not getattr(exc_object, 'internal_error', True):
537
502
        report_user_error(exc_info, err_file)
538
503
        return errors.EXIT_ERROR
539
 
    elif isinstance(exc_object, (OSError, IOError)) or (
540
 
        # GZ 2010-05-20: Like (exc_type is pywintypes.error) but avoid import
541
 
        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
542
508
        # Might be nice to catch all of these and show them as something more
543
509
        # specific, but there are too many cases at the moment.
544
510
        report_user_error(exc_info, err_file)
582
548
    try:
583
549
        sys.stdout.flush()
584
550
        sys.stderr.flush()
 
551
    except ValueError, e:
 
552
        # On Windows, I get ValueError calling stdout.flush() on a closed
 
553
        # handle
 
554
        pass
585
555
    except IOError, e:
586
556
        import errno
587
557
        if e.errno in [errno.EINVAL, errno.EPIPE]:
597
567
        _trace_file.flush()
598
568
 
599
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
 
600
613
class Config(object):
601
614
    """Configuration of message tracing in bzrlib.
602
615