~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
        s = 'bzr: '
58
        if record.levelno >= logging.WARNING:
59
            s += record.levelname + ': '
60
            
1289 by Martin Pool
- wrap wide strings when showing exceptions
61
        s += record.getMessage()
62
63
        import textwrap
64
        s = textwrap.fill(s)
1097 by Martin Pool
- send trace messages out through python logging module
65
            
66
        if record.exc_info:
67
            # give just a summary of the exception, not the whole thing
68
            exinfo = traceback.extract_tb(record.exc_info[2])
69
            # the format of this string matches one of the REs
70
            s += '\n'
71
            s += ('  at %s line %d, in %s()\n' % exinfo[-1][:3])
72
            s += '  see ~/.bzr.log for debug information'
73
74
        return s
75
        
76
77
78
79
################
80
# configure convenient aliases for output routines
81
82
_bzr_logger = logging.getLogger('bzr')
83
_bzr_logger.setLevel(logging.DEBUG) 
84
1111 by Martin Pool
- add functions to enable and disable default logging, so that we can
85
info = note = _bzr_logger.info
1097 by Martin Pool
- send trace messages out through python logging module
86
warning =   _bzr_logger.warning
87
log_error = _bzr_logger.error
88
error =     _bzr_logger.error
89
mutter =    _bzr_logger.debug
90
debug =     _bzr_logger.debug
91
92
93
94
95
# we do the rollover using this code, rather than the default from python
96
# logging, because we only want to rollover at program startup, not on each
97
# message.  maybe that's not a good enough reason.
257 by Martin Pool
- Write less startup junk to .bzr.log
98
261 by Martin Pool
- auto-rollover of .bzr.log
99
def _rollover_trace_maybe(trace_fname):
359 by Martin Pool
- pychecker fixups
100
    import stat
261 by Martin Pool
- auto-rollover of .bzr.log
101
    try:
102
        size = os.stat(trace_fname)[stat.ST_SIZE]
333 by Martin Pool
- allow trace file to grow up to 4MB
103
        if size <= 4 << 20:
261 by Martin Pool
- auto-rollover of .bzr.log
104
            return
105
        old_fname = trace_fname + '.old'
106
107
        try:
108
            # must remove before rename on windows
109
            os.remove(old_fname)
110
        except OSError:
111
            pass
112
113
        try:
114
            # might fail if in use on windows
115
            os.rename(trace_fname, old_fname)
116
        except OSError:
117
            pass
118
    except OSError:
119
        return
120
121
122
1111 by Martin Pool
- add functions to enable and disable default logging, so that we can
123
def open_tracefile(tracefilename='~/.bzr.log'):
59 by mbp at sourcefrog
lift out tracefile creation code
124
    # Messages are always written to here, so that we have some
125
    # information if something goes wrong.  In a future version this
126
    # file will be removed on successful completion.
1097 by Martin Pool
- send trace messages out through python logging module
127
    global _file_handler
359 by Martin Pool
- pychecker fixups
128
    import stat, codecs
59 by mbp at sourcefrog
lift out tracefile creation code
129
397 by Martin Pool
- open_tracefile takes a tracefilename parameter
130
    trace_fname = os.path.join(os.path.expanduser(tracefilename))
261 by Martin Pool
- auto-rollover of .bzr.log
131
    _rollover_trace_maybe(trace_fname)
257 by Martin Pool
- Write less startup junk to .bzr.log
132
133
    # buffering=1 means line buffered
403 by Martin Pool
- Don't give an error if the trace file can't be opened
134
    try:
1097 by Martin Pool
- send trace messages out through python logging module
135
        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
136
1097 by Martin Pool
- send trace messages out through python logging module
137
        if os.fstat(tf.fileno())[stat.ST_SIZE] == 0:
1100 by Martin Pool
- fix name error reported by Andrew Bennetts
138
            tf.write("\nthis is a debug log for diagnosing/reporting problems in bzr\n")
139
            tf.write("you can delete or truncate this file, or include sections in\n")
140
            tf.write("bug reports to bazaar-ng@lists.canonical.com\n\n")
1097 by Martin Pool
- send trace messages out through python logging module
141
        
142
        _file_handler = logging.StreamHandler(tf)
143
        fmt = r'[%(process)5d] %(asctime)s.%(msecs)03d %(levelname)s: %(message)s'
144
        datefmt = r'%a %H:%M:%S'
145
        _file_handler.setFormatter(logging.Formatter(fmt, datefmt))
146
        _file_handler.setLevel(logging.DEBUG)
147
        logging.getLogger('').addHandler(_file_handler)
403 by Martin Pool
- Don't give an error if the trace file can't be opened
148
149
    except IOError, e:
150
        warning("failed to open trace file: %s" % (e))
260 by Martin Pool
- remove atexit() dependency for writing out execution times
151
1097 by Martin Pool
- send trace messages out through python logging module
152
1111 by Martin Pool
- add functions to enable and disable default logging, so that we can
153
def log_startup(argv):
154
    import bzrlib
155
156
    debug('bzr %s invoked on python %s (%s)',
157
          bzrlib.__version__,
158
          '.'.join(map(str, sys.version_info)),
159
          sys.platform)
160
161
    debug('  arguments: %r', argv)
162
    debug('  working dir: %s', os.getcwdu())
163
1097 by Martin Pool
- send trace messages out through python logging module
164
165
def log_exception(msg=None):
166
    """Log the last exception into the trace file.
167
168
    The exception string representation is used as the error
169
    summary, unless msg is given.
170
    """
171
    if msg == None:
172
        ei = sys.exc_info()
1108 by Martin Pool
- more cleanups of error reporting
173
        msg = str(ei[1])
174
1135 by Martin Pool
- robustness of trace.log_exception
175
    if msg and (msg[-1] == '\n'):
1108 by Martin Pool
- more cleanups of error reporting
176
        msg = msg[:-1]
269 by Martin Pool
- Put proper prefix at start of exceptions in trace file
177
        
1097 by Martin Pool
- send trace messages out through python logging module
178
    _bzr_logger.exception(msg)
1111 by Martin Pool
- add functions to enable and disable default logging, so that we can
179
180
181
182
def enable_default_logging():
183
    """Configure default logging to stderr and .bzr.log"""
184
    global _stderr_handler, _file_handler
185
186
    _stderr_handler = logging.StreamHandler()
187
188
    if not _file_handler:
1190 by Martin Pool
- when BZR_DEBUG is set, show all trace to stderr and full exceptions
189
        open_tracefile()                # also adds it
1111 by Martin Pool
- add functions to enable and disable default logging, so that we can
190
1202 by Martin Pool
- better interpretation of
191
    debug_flag = False
192
    try:
193
        debug_flag = bool(os.environ['BZR_DEBUG'])
194
    except:
195
        pass
196
        
197
    if debug_flag:
1111 by Martin Pool
- add functions to enable and disable default logging, so that we can
198
        level = logging.DEBUG
1226 by Martin Pool
- better BZR_DEBUG trace output
199
        fmt = '%(levelname)8s: %(message)s'
200
        _stderr_handler.setFormatter(logging.Formatter(fmt))
1111 by Martin Pool
- add functions to enable and disable default logging, so that we can
201
    else:
202
        level = logging.INFO
1190 by Martin Pool
- when BZR_DEBUG is set, show all trace to stderr and full exceptions
203
        # show only summary of exceptions
204
        _stderr_handler.setFormatter(QuietFormatter())
1111 by Martin Pool
- add functions to enable and disable default logging, so that we can
205
1190 by Martin Pool
- when BZR_DEBUG is set, show all trace to stderr and full exceptions
206
    _stderr_handler.setLevel(level)
1111 by Martin Pool
- add functions to enable and disable default logging, so that we can
207
    _file_handler.setLevel(level)
208
209
    logging.getLogger('').addHandler(_stderr_handler)
210
211
212
213
def disable_default_logging():
214
    """Turn off default log handlers.
215
216
    This is intended to be used by the test framework, which doesn't
217
    want leakage from the code-under-test into the main logs.
218
    """
1112 by Martin Pool
- disable standard logging to .bzr.log and stderr while running
219
220
    l = logging.getLogger('')
221
    l.removeHandler(_stderr_handler)
222
    if _file_handler:
223
        l.removeHandler(_file_handler)