~bzr-pqm/bzr/bzr.dev

1 by mbp at sourcefrog
import from baz patch-364
1
# This program is free software; you can redistribute it and/or modify
2
# it under the terms of the GNU General Public License as published by
3
# the Free Software Foundation; either version 2 of the License, or
4
# (at your option) any later version.
5
6
# This program is distributed in the hope that it will be useful,
7
# but WITHOUT ANY WARRANTY; without even the implied warranty of
8
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
9
# GNU General Public License for more details.
10
11
# You should have received a copy of the GNU General Public License
12
# along with this program; if not, write to the Free Software
13
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
14
15
344 by Martin Pool
- It's not an error to use the library without
16
"""Messages and logging for bazaar-ng
17
1097 by Martin Pool
- send trace messages out through python logging module
18
Messages are sent out through the Python logging library.
19
20
They can be sent to two places: to stderr, and to ~/.bzr.log.
21
22
~/.bzr.log gets all messages, and tracebacks of all uncaught
23
exceptions.
24
25
Normally stderr only gets messages of level INFO and higher, and gets
26
only a summary of exceptions, not the traceback.
344 by Martin Pool
- It's not an error to use the library without
27
"""
28
29
1097 by Martin Pool
- send trace messages out through python logging module
30
# TODO: in debug mode, stderr should get full tracebacks and also
31
# debug messages.  (Is this really needed?)
32
33
# TODO: When running the test suites, we should add an additional
34
# logger that sends messages into the test log file.
35
1185.16.74 by Martin Pool
doc
36
# FIXME: Unfortunately it turns out that python's logging module
37
# is quite expensive, even when the message is not printed by any handlers.
38
# We should perhaps change back to just simply doing it here.
39
1097 by Martin Pool
- send trace messages out through python logging module
40
41
import sys
42
import os
43
import logging
44
import traceback
45
46
1101 by Martin Pool
- add global definition to quieten pychecker
47
_file_handler = None
1111 by Martin Pool
- add functions to enable and disable default logging, so that we can
48
_stderr_handler = None
1101 by Martin Pool
- add global definition to quieten pychecker
49
50
1097 by Martin Pool
- send trace messages out through python logging module
51
class QuietFormatter(logging.Formatter):
52
    """Formatter that supresses the details of errors.
53
54
    This is used by default on stderr so as not to scare the user.
55
    """
56
    # At first I tried overriding formatException to suppress the
57
    # exception details, but that has global effect: no loggers
58
    # can get the exception details is we suppress them here.
59
60
    def format(self, record):
61
        if record.levelno >= logging.WARNING:
1393.1.57 by Martin Pool
- no 'bzr' prefix on info messages
62
            s = 'bzr: ' + record.levelname + ': '
63
        else:
64
            s = ''
1097 by Martin Pool
- send trace messages out through python logging module
65
            
1289 by Martin Pool
- wrap wide strings when showing exceptions
66
        s += record.getMessage()
67
1334 by Martin Pool
- turn off word-wrapping of error messages
68
        ##import textwrap
69
        ##s = textwrap.fill(s)
1097 by Martin Pool
- send trace messages out through python logging module
70
            
71
        if record.exc_info:
72
            # give just a summary of the exception, not the whole thing
73
            exinfo = traceback.extract_tb(record.exc_info[2])
74
            # the format of this string matches one of the REs
75
            s += '\n'
76
            s += ('  at %s line %d, in %s()\n' % exinfo[-1][:3])
77
            s += '  see ~/.bzr.log for debug information'
78
79
        return s
80
        
81
82
83
84
################
85
# configure convenient aliases for output routines
86
87
_bzr_logger = logging.getLogger('bzr')
88
1111 by Martin Pool
- add functions to enable and disable default logging, so that we can
89
info = note = _bzr_logger.info
1097 by Martin Pool
- send trace messages out through python logging module
90
warning =   _bzr_logger.warning
91
log_error = _bzr_logger.error
92
error =     _bzr_logger.error
93
mutter =    _bzr_logger.debug
94
debug =     _bzr_logger.debug
95
96
97
98
99
# we do the rollover using this code, rather than the default from python
100
# logging, because we only want to rollover at program startup, not on each
101
# message.  maybe that's not a good enough reason.
257 by Martin Pool
- Write less startup junk to .bzr.log
102
261 by Martin Pool
- auto-rollover of .bzr.log
103
def _rollover_trace_maybe(trace_fname):
359 by Martin Pool
- pychecker fixups
104
    import stat
261 by Martin Pool
- auto-rollover of .bzr.log
105
    try:
106
        size = os.stat(trace_fname)[stat.ST_SIZE]
333 by Martin Pool
- allow trace file to grow up to 4MB
107
        if size <= 4 << 20:
261 by Martin Pool
- auto-rollover of .bzr.log
108
            return
109
        old_fname = trace_fname + '.old'
110
1185.1.40 by Robert Collins
Merge what applied of Alexander Belchenko's win32 patch.
111
        from osutils import rename
112
        rename(trace_fname, old_fname)
261 by Martin Pool
- auto-rollover of .bzr.log
113
114
    except OSError:
115
        return
116
117
118
1111 by Martin Pool
- add functions to enable and disable default logging, so that we can
119
def open_tracefile(tracefilename='~/.bzr.log'):
59 by mbp at sourcefrog
lift out tracefile creation code
120
    # Messages are always written to here, so that we have some
121
    # information if something goes wrong.  In a future version this
122
    # file will be removed on successful completion.
1097 by Martin Pool
- send trace messages out through python logging module
123
    global _file_handler
359 by Martin Pool
- pychecker fixups
124
    import stat, codecs
59 by mbp at sourcefrog
lift out tracefile creation code
125
397 by Martin Pool
- open_tracefile takes a tracefilename parameter
126
    trace_fname = os.path.join(os.path.expanduser(tracefilename))
261 by Martin Pool
- auto-rollover of .bzr.log
127
    _rollover_trace_maybe(trace_fname)
257 by Martin Pool
- Write less startup junk to .bzr.log
128
129
    # buffering=1 means line buffered
403 by Martin Pool
- Don't give an error if the trace file can't be opened
130
    try:
1097 by Martin Pool
- send trace messages out through python logging module
131
        tf = codecs.open(trace_fname, 'at', 'utf8', buffering=1)
403 by Martin Pool
- Don't give an error if the trace file can't be opened
132
1097 by Martin Pool
- send trace messages out through python logging module
133
        if os.fstat(tf.fileno())[stat.ST_SIZE] == 0:
1100 by Martin Pool
- fix name error reported by Andrew Bennetts
134
            tf.write("\nthis is a debug log for diagnosing/reporting problems in bzr\n")
135
            tf.write("you can delete or truncate this file, or include sections in\n")
136
            tf.write("bug reports to bazaar-ng@lists.canonical.com\n\n")
1097 by Martin Pool
- send trace messages out through python logging module
137
        
138
        _file_handler = logging.StreamHandler(tf)
139
        fmt = r'[%(process)5d] %(asctime)s.%(msecs)03d %(levelname)s: %(message)s'
140
        datefmt = r'%a %H:%M:%S'
141
        _file_handler.setFormatter(logging.Formatter(fmt, datefmt))
142
        _file_handler.setLevel(logging.DEBUG)
143
        logging.getLogger('').addHandler(_file_handler)
403 by Martin Pool
- Don't give an error if the trace file can't be opened
144
145
    except IOError, e:
146
        warning("failed to open trace file: %s" % (e))
260 by Martin Pool
- remove atexit() dependency for writing out execution times
147
1097 by Martin Pool
- send trace messages out through python logging module
148
1111 by Martin Pool
- add functions to enable and disable default logging, so that we can
149
def log_startup(argv):
150
    import bzrlib
151
152
    debug('bzr %s invoked on python %s (%s)',
153
          bzrlib.__version__,
154
          '.'.join(map(str, sys.version_info)),
155
          sys.platform)
156
157
    debug('  arguments: %r', argv)
1185.16.73 by Martin Pool
- in error messages, show cwd as repr in case it's in unicode
158
    debug('  working dir: %r', os.getcwdu())
1111 by Martin Pool
- add functions to enable and disable default logging, so that we can
159
1097 by Martin Pool
- send trace messages out through python logging module
160
161
def log_exception(msg=None):
1185.16.82 by mbp at sourcefrog
- give a quieter warning if a plugin can't be loaded
162
    """Log the last exception to stderr and the trace file.
1097 by Martin Pool
- send trace messages out through python logging module
163
164
    The exception string representation is used as the error
165
    summary, unless msg is given.
166
    """
1185.16.120 by Martin Pool
Show exception class in error messages
167
    ei = sys.exc_info()
1097 by Martin Pool
- send trace messages out through python logging module
168
    if msg == None:
1108 by Martin Pool
- more cleanups of error reporting
169
        msg = str(ei[1])
1135 by Martin Pool
- robustness of trace.log_exception
170
    if msg and (msg[-1] == '\n'):
1108 by Martin Pool
- more cleanups of error reporting
171
        msg = msg[:-1]
1185.16.120 by Martin Pool
Show exception class in error messages
172
    msg += '\n  command: %s' % ' '.join(repr(arg) for arg in sys.argv)
173
    msg += '\n      pwd: %r' % os.getcwdu()
174
    msg += '\n    error: %s' % ei[0]        # exception type
175
    _bzr_logger.exception(msg)
1111 by Martin Pool
- add functions to enable and disable default logging, so that we can
176
177
1185.16.82 by mbp at sourcefrog
- give a quieter warning if a plugin can't be loaded
178
def log_exception_quietly():
179
    """Log the last exception to the trace file only.
180
181
    Used for exceptions that occur internally and that may be 
182
    interesting to developers but not to users.  For example, 
183
    errors loading plugins.
184
    """
185
    debug(traceback.format_exc())
186
187
1111 by Martin Pool
- add functions to enable and disable default logging, so that we can
188
def enable_default_logging():
189
    """Configure default logging to stderr and .bzr.log"""
190
    global _stderr_handler, _file_handler
191
192
    _stderr_handler = logging.StreamHandler()
1359 by Martin Pool
- merge in new BZR_NOISY vs BZR_DEBUG stuff from main
193
    _stderr_handler.setFormatter(QuietFormatter())
194
1111 by Martin Pool
- add functions to enable and disable default logging, so that we can
195
    if not _file_handler:
1359 by Martin Pool
- merge in new BZR_NOISY vs BZR_DEBUG stuff from main
196
        open_tracefile()
197
198
    if os.environ.get('BZR_DEBUG'):
199
        level = logging.DEBUG
200
    else:
201
        level = logging.INFO
202
203
    _stderr_handler.setLevel(logging.INFO)
204
    _file_handler.setLevel(level)
1185.16.136 by Martin Pool
Set logger level depending on BZR_DEBUG to reduce work
205
    _bzr_logger.setLevel(level) 
1359 by Martin Pool
- merge in new BZR_NOISY vs BZR_DEBUG stuff from main
206
1111 by Martin Pool
- add functions to enable and disable default logging, so that we can
207
    logging.getLogger('').addHandler(_stderr_handler)
208
209
210
def disable_default_logging():
211
    """Turn off default log handlers.
212
213
    This is intended to be used by the test framework, which doesn't
214
    want leakage from the code-under-test into the main logs.
215
    """
1112 by Martin Pool
- disable standard logging to .bzr.log and stderr while running
216
217
    l = logging.getLogger('')
218
    l.removeHandler(_stderr_handler)
219
    if _file_handler:
220
        l.removeHandler(_file_handler)