~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
36
37
import sys
38
import os
39
import logging
40
import traceback
41
42
1101 by Martin Pool
- add global definition to quieten pychecker
43
_file_handler = None
1111 by Martin Pool
- add functions to enable and disable default logging, so that we can
44
_stderr_handler = None
1101 by Martin Pool
- add global definition to quieten pychecker
45
46
1097 by Martin Pool
- send trace messages out through python logging module
47
class QuietFormatter(logging.Formatter):
48
    """Formatter that supresses the details of errors.
49
50
    This is used by default on stderr so as not to scare the user.
51
    """
52
    # At first I tried overriding formatException to suppress the
53
    # exception details, but that has global effect: no loggers
54
    # can get the exception details is we suppress them here.
55
56
    def format(self, record):
57
        if record.levelno >= logging.WARNING:
1393.1.57 by Martin Pool
- no 'bzr' prefix on info messages
58
            s = 'bzr: ' + record.levelname + ': '
59
        else:
60
            s = ''
1097 by Martin Pool
- send trace messages out through python logging module
61
            
1289 by Martin Pool
- wrap wide strings when showing exceptions
62
        s += record.getMessage()
63
1334 by Martin Pool
- turn off word-wrapping of error messages
64
        ##import textwrap
65
        ##s = textwrap.fill(s)
1097 by Martin Pool
- send trace messages out through python logging module
66
            
67
        if record.exc_info:
68
            # give just a summary of the exception, not the whole thing
69
            exinfo = traceback.extract_tb(record.exc_info[2])
70
            # the format of this string matches one of the REs
71
            s += '\n'
72
            s += ('  at %s line %d, in %s()\n' % exinfo[-1][:3])
73
            s += '  see ~/.bzr.log for debug information'
74
75
        return s
76
        
77
78
79
80
################
81
# configure convenient aliases for output routines
82
83
_bzr_logger = logging.getLogger('bzr')
84
_bzr_logger.setLevel(logging.DEBUG) 
85
1111 by Martin Pool
- add functions to enable and disable default logging, so that we can
86
info = note = _bzr_logger.info
1097 by Martin Pool
- send trace messages out through python logging module
87
warning =   _bzr_logger.warning
88
log_error = _bzr_logger.error
89
error =     _bzr_logger.error
90
mutter =    _bzr_logger.debug
91
debug =     _bzr_logger.debug
92
93
94
95
96
# we do the rollover using this code, rather than the default from python
97
# logging, because we only want to rollover at program startup, not on each
98
# message.  maybe that's not a good enough reason.
257 by Martin Pool
- Write less startup junk to .bzr.log
99
261 by Martin Pool
- auto-rollover of .bzr.log
100
def _rollover_trace_maybe(trace_fname):
359 by Martin Pool
- pychecker fixups
101
    import stat
261 by Martin Pool
- auto-rollover of .bzr.log
102
    try:
103
        size = os.stat(trace_fname)[stat.ST_SIZE]
333 by Martin Pool
- allow trace file to grow up to 4MB
104
        if size <= 4 << 20:
261 by Martin Pool
- auto-rollover of .bzr.log
105
            return
106
        old_fname = trace_fname + '.old'
107
1185.1.40 by Robert Collins
Merge what applied of Alexander Belchenko's win32 patch.
108
        from osutils import rename
109
        rename(trace_fname, old_fname)
261 by Martin Pool
- auto-rollover of .bzr.log
110
111
    except OSError:
112
        return
113
114
115
1111 by Martin Pool
- add functions to enable and disable default logging, so that we can
116
def open_tracefile(tracefilename='~/.bzr.log'):
59 by mbp at sourcefrog
lift out tracefile creation code
117
    # Messages are always written to here, so that we have some
118
    # information if something goes wrong.  In a future version this
119
    # file will be removed on successful completion.
1097 by Martin Pool
- send trace messages out through python logging module
120
    global _file_handler
359 by Martin Pool
- pychecker fixups
121
    import stat, codecs
59 by mbp at sourcefrog
lift out tracefile creation code
122
397 by Martin Pool
- open_tracefile takes a tracefilename parameter
123
    trace_fname = os.path.join(os.path.expanduser(tracefilename))
261 by Martin Pool
- auto-rollover of .bzr.log
124
    _rollover_trace_maybe(trace_fname)
257 by Martin Pool
- Write less startup junk to .bzr.log
125
126
    # buffering=1 means line buffered
403 by Martin Pool
- Don't give an error if the trace file can't be opened
127
    try:
1097 by Martin Pool
- send trace messages out through python logging module
128
        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
129
1097 by Martin Pool
- send trace messages out through python logging module
130
        if os.fstat(tf.fileno())[stat.ST_SIZE] == 0:
1100 by Martin Pool
- fix name error reported by Andrew Bennetts
131
            tf.write("\nthis is a debug log for diagnosing/reporting problems in bzr\n")
132
            tf.write("you can delete or truncate this file, or include sections in\n")
133
            tf.write("bug reports to bazaar-ng@lists.canonical.com\n\n")
1097 by Martin Pool
- send trace messages out through python logging module
134
        
135
        _file_handler = logging.StreamHandler(tf)
136
        fmt = r'[%(process)5d] %(asctime)s.%(msecs)03d %(levelname)s: %(message)s'
137
        datefmt = r'%a %H:%M:%S'
138
        _file_handler.setFormatter(logging.Formatter(fmt, datefmt))
139
        _file_handler.setLevel(logging.DEBUG)
140
        logging.getLogger('').addHandler(_file_handler)
403 by Martin Pool
- Don't give an error if the trace file can't be opened
141
142
    except IOError, e:
143
        warning("failed to open trace file: %s" % (e))
260 by Martin Pool
- remove atexit() dependency for writing out execution times
144
1097 by Martin Pool
- send trace messages out through python logging module
145
1111 by Martin Pool
- add functions to enable and disable default logging, so that we can
146
def log_startup(argv):
147
    import bzrlib
148
149
    debug('bzr %s invoked on python %s (%s)',
150
          bzrlib.__version__,
151
          '.'.join(map(str, sys.version_info)),
152
          sys.platform)
153
154
    debug('  arguments: %r', argv)
155
    debug('  working dir: %s', os.getcwdu())
156
1097 by Martin Pool
- send trace messages out through python logging module
157
158
def log_exception(msg=None):
159
    """Log the last exception into the trace file.
160
161
    The exception string representation is used as the error
162
    summary, unless msg is given.
163
    """
1185.15.9 by Martin Pool
[patch] show argv and pwd in exceptions (from ddaa)
164
    command = ' '.join(repr(arg) for arg in sys.argv)
165
    prefix = "command: %s\npwd: %s\n" % (command, os.getcwd())
1097 by Martin Pool
- send trace messages out through python logging module
166
    if msg == None:
167
        ei = sys.exc_info()
1108 by Martin Pool
- more cleanups of error reporting
168
        msg = str(ei[1])
1135 by Martin Pool
- robustness of trace.log_exception
169
    if msg and (msg[-1] == '\n'):
1108 by Martin Pool
- more cleanups of error reporting
170
        msg = msg[:-1]
1393.1.62 by Martin Pool
cleanup
171
    ## msg = "(%s) %s" % (str(type(ei[1])), msg)
1185.15.9 by Martin Pool
[patch] show argv and pwd in exceptions (from ddaa)
172
    _bzr_logger.exception(prefix + msg)
1111 by Martin Pool
- add functions to enable and disable default logging, so that we can
173
174
175
176
def enable_default_logging():
177
    """Configure default logging to stderr and .bzr.log"""
178
    global _stderr_handler, _file_handler
179
180
    _stderr_handler = logging.StreamHandler()
1359 by Martin Pool
- merge in new BZR_NOISY vs BZR_DEBUG stuff from main
181
    _stderr_handler.setFormatter(QuietFormatter())
182
1111 by Martin Pool
- add functions to enable and disable default logging, so that we can
183
    if not _file_handler:
1359 by Martin Pool
- merge in new BZR_NOISY vs BZR_DEBUG stuff from main
184
        open_tracefile()
185
186
    if os.environ.get('BZR_DEBUG'):
187
        level = logging.DEBUG
188
    else:
189
        level = logging.INFO
190
191
    _stderr_handler.setLevel(logging.INFO)
192
    _file_handler.setLevel(level)
193
1111 by Martin Pool
- add functions to enable and disable default logging, so that we can
194
    logging.getLogger('').addHandler(_stderr_handler)
195
196
197
def disable_default_logging():
198
    """Turn off default log handlers.
199
200
    This is intended to be used by the test framework, which doesn't
201
    want leakage from the code-under-test into the main logs.
202
    """
1112 by Martin Pool
- disable standard logging to .bzr.log and stderr while running
203
204
    l = logging.getLogger('')
205
    l.removeHandler(_stderr_handler)
206
    if _file_handler:
207
        l.removeHandler(_file_handler)