~vishvananda/nova/network-refactor

« back to all changes in this revision

Viewing changes to vendor/Twisted-10.0.0/twisted/python/log.py

  • Committer: Jesse Andrews
  • Date: 2010-05-28 06:05:26 UTC
  • Revision ID: git-v1:bf6e6e718cdc7488e2da87b21e258ccc065fe499
initial commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- test-case-name: twisted.test.test_log -*-
 
2
# Copyright (c) 2001-2009 Twisted Matrix Laboratories.
 
3
# See LICENSE for details.
 
4
 
 
5
"""
 
6
Logging and metrics infrastructure.
 
7
"""
 
8
 
 
9
from __future__ import division
 
10
 
 
11
import sys
 
12
import time
 
13
import warnings
 
14
from datetime import datetime
 
15
import logging
 
16
 
 
17
from zope.interface import Interface
 
18
 
 
19
from twisted.python import util, context, reflect
 
20
 
 
21
 
 
22
 
 
23
class ILogContext:
 
24
    """
 
25
    Actually, this interface is just a synoym for the dictionary interface,
 
26
    but it serves as a key for the default information in a log.
 
27
 
 
28
    I do not inherit from Interface because the world is a cruel place.
 
29
    """
 
30
 
 
31
 
 
32
 
 
33
class ILogObserver(Interface):
 
34
    """
 
35
    An observer which can do something with log events.
 
36
    
 
37
    Given that most log observers are actually bound methods, it's okay to not
 
38
    explicitly declare provision of this interface.
 
39
    """
 
40
    def __call__(eventDict):
 
41
        """
 
42
        Log an event.
 
43
 
 
44
        @type eventDict: C{dict} with C{str} keys.
 
45
        @param eventDict: A dictionary with arbitrary keys.  However, these
 
46
            keys are often available:
 
47
              - C{message}: A C{tuple} of C{str} containing messages to be
 
48
                logged.
 
49
              - C{system}: A C{str} which indicates the "system" which is
 
50
                generating this event.
 
51
              - C{isError}: A C{bool} indicating whether this event represents
 
52
                an error.
 
53
              - C{failure}: A L{failure.Failure} instance
 
54
              - C{why}: Used as header of the traceback in case of errors.
 
55
              - C{format}: A string format used in place of C{message} to
 
56
                customize the event.  The intent is for the observer to format
 
57
                a message by doing something like C{format % eventDict}.
 
58
        """
 
59
 
 
60
 
 
61
 
 
62
context.setDefault(ILogContext,
 
63
                   {"isError": 0,
 
64
                    "system": "-"})
 
65
 
 
66
def callWithContext(ctx, func, *args, **kw):
 
67
    newCtx = context.get(ILogContext).copy()
 
68
    newCtx.update(ctx)
 
69
    return context.call({ILogContext: newCtx}, func, *args, **kw)
 
70
 
 
71
def callWithLogger(logger, func, *args, **kw):
 
72
    """
 
73
    Utility method which wraps a function in a try:/except:, logs a failure if
 
74
    one occurrs, and uses the system's logPrefix.
 
75
    """
 
76
    try:
 
77
        lp = logger.logPrefix()
 
78
    except KeyboardInterrupt:
 
79
        raise
 
80
    except:
 
81
        lp = '(buggy logPrefix method)'
 
82
        err(system=lp)
 
83
    try:
 
84
        return callWithContext({"system": lp}, func, *args, **kw)
 
85
    except KeyboardInterrupt:
 
86
        raise
 
87
    except:
 
88
        err(system=lp)
 
89
 
 
90
 
 
91
 
 
92
_keepErrors = 0
 
93
_keptErrors = []
 
94
_ignoreErrors = []
 
95
 
 
96
def startKeepingErrors():
 
97
    """
 
98
    DEPRECATED in Twisted 2.5.
 
99
 
 
100
    Support function for testing frameworks.
 
101
 
 
102
    Start keeping errors in a buffer which can be retrieved (and emptied) with
 
103
    flushErrors.
 
104
    """
 
105
    warnings.warn("log.startKeepingErrors is deprecated since Twisted 2.5",
 
106
                  category=DeprecationWarning, stacklevel=2)
 
107
    global _keepErrors
 
108
    _keepErrors = 1
 
109
 
 
110
 
 
111
def flushErrors(*errorTypes):
 
112
    """
 
113
    DEPRECATED in Twisted 2.5.  See L{TestCase.flushLoggedErrors}.
 
114
 
 
115
    Support function for testing frameworks.
 
116
 
 
117
    Return a list of errors that occurred since the last call to flushErrors().
 
118
    (This will return None unless startKeepingErrors has been called.)
 
119
    """
 
120
 
 
121
    warnings.warn("log.flushErrors is deprecated since Twisted 2.5. "
 
122
                  "If you need to flush errors from within a unittest, "
 
123
                  "use TestCase.flushLoggedErrors instead.",
 
124
                  category=DeprecationWarning, stacklevel=2)
 
125
    return _flushErrors(*errorTypes)
 
126
 
 
127
 
 
128
def _flushErrors(*errorTypes):
 
129
    """
 
130
    PRIVATE. DEPRECATED. DON'T USE.
 
131
    """
 
132
    global _keptErrors
 
133
    k = _keptErrors
 
134
    _keptErrors = []
 
135
    if errorTypes:
 
136
        for erk in k:
 
137
            shouldReLog = 1
 
138
            for errT in errorTypes:
 
139
                if erk.check(errT):
 
140
                    shouldReLog = 0
 
141
            if shouldReLog:
 
142
                err(erk)
 
143
    return k
 
144
 
 
145
def ignoreErrors(*types):
 
146
    """
 
147
    DEPRECATED
 
148
    """
 
149
    warnings.warn("log.ignoreErrors is deprecated since Twisted 2.5",
 
150
                  category=DeprecationWarning, stacklevel=2)
 
151
    _ignore(*types)
 
152
 
 
153
def _ignore(*types):
 
154
    """
 
155
    PRIVATE. DEPRECATED. DON'T USE.
 
156
    """
 
157
    for type in types:
 
158
        _ignoreErrors.append(type)
 
159
 
 
160
def clearIgnores():
 
161
    """
 
162
    DEPRECATED
 
163
    """
 
164
    warnings.warn("log.clearIgnores is deprecated since Twisted 2.5",
 
165
                  category=DeprecationWarning, stacklevel=2)
 
166
    _clearIgnores()
 
167
 
 
168
def _clearIgnores():
 
169
    """
 
170
    PRIVATE. DEPRECATED. DON'T USE.
 
171
    """
 
172
    global _ignoreErrors
 
173
    _ignoreErrors = []
 
174
 
 
175
 
 
176
def err(_stuff=None, _why=None, **kw):
 
177
    """
 
178
    Write a failure to the log.
 
179
 
 
180
    The C{_stuff} and C{_why} parameters use an underscore prefix to lessen
 
181
    the chance of colliding with a keyword argument the application wishes
 
182
    to pass.  It is intended that they be supplied with arguments passed
 
183
    positionally, not by keyword.
 
184
 
 
185
    @param _stuff: The failure to log.  If C{_stuff} is C{None} a new
 
186
        L{Failure} will be created from the current exception state.  If
 
187
        C{_stuff} is an C{Exception} instance it will be wrapped in a
 
188
        L{Failure}.
 
189
    @type _stuff: C{NoneType}, C{Exception}, or L{Failure}.
 
190
 
 
191
    @param _why: The source of this failure.  This will be logged along with
 
192
        C{_stuff} and should describe the context in which the failure
 
193
        occurred.
 
194
    @type _why: C{str}
 
195
    """
 
196
    if _stuff is None:
 
197
        _stuff = failure.Failure()
 
198
    if isinstance(_stuff, failure.Failure):
 
199
        if _keepErrors:
 
200
            if _ignoreErrors:
 
201
                keep = 0
 
202
                for err in _ignoreErrors:
 
203
                    r = _stuff.check(err)
 
204
                    if r:
 
205
                        keep = 0
 
206
                        break
 
207
                    else:
 
208
                        keep = 1
 
209
                if keep:
 
210
                    _keptErrors.append(_stuff)
 
211
            else:
 
212
                _keptErrors.append(_stuff)
 
213
        msg(failure=_stuff, why=_why, isError=1, **kw)
 
214
    elif isinstance(_stuff, Exception):
 
215
        msg(failure=failure.Failure(_stuff), why=_why, isError=1, **kw)
 
216
    else:
 
217
        msg(repr(_stuff), why=_why, isError=1, **kw)
 
218
 
 
219
deferr = err
 
220
 
 
221
 
 
222
class Logger:
 
223
    """
 
224
    This represents a class which may 'own' a log. Used by subclassing.
 
225
    """
 
226
    def logPrefix(self):
 
227
        """
 
228
        Override this method to insert custom logging behavior.  Its
 
229
        return value will be inserted in front of every line.  It may
 
230
        be called more times than the number of output lines.
 
231
        """
 
232
        return '-'
 
233
 
 
234
 
 
235
class LogPublisher:
 
236
    """
 
237
    Class for singleton log message publishing.
 
238
    """
 
239
 
 
240
    synchronized = ['msg']
 
241
 
 
242
    def __init__(self):
 
243
        self.observers = []
 
244
 
 
245
    def addObserver(self, other):
 
246
        """
 
247
        Add a new observer.
 
248
 
 
249
        @type other: Provider of L{ILogObserver}
 
250
        @param other: A callable object that will be called with each new log
 
251
            message (a dict).
 
252
        """
 
253
        assert callable(other)
 
254
        self.observers.append(other)
 
255
 
 
256
    def removeObserver(self, other):
 
257
        """
 
258
        Remove an observer.
 
259
        """
 
260
        self.observers.remove(other)
 
261
 
 
262
    def msg(self, *message, **kw):
 
263
        """
 
264
        Log a new message.
 
265
 
 
266
        For example::
 
267
 
 
268
        >>> log.msg('Hello, world.')
 
269
 
 
270
        In particular, you MUST avoid the forms::
 
271
 
 
272
        >>> log.msg(u'Hello, world.')
 
273
        >>> log.msg('Hello ', 'world.')
 
274
 
 
275
        These forms work (sometimes) by accident and will be disabled
 
276
        entirely in the future.
 
277
        """
 
278
        actualEventDict = (context.get(ILogContext) or {}).copy()
 
279
        actualEventDict.update(kw)
 
280
        actualEventDict['message'] = message
 
281
        actualEventDict['time'] = time.time()
 
282
        for i in xrange(len(self.observers) - 1, -1, -1):
 
283
            try:
 
284
                self.observers[i](actualEventDict)
 
285
            except KeyboardInterrupt:
 
286
                # Don't swallow keyboard interrupt!
 
287
                raise
 
288
            except UnicodeEncodeError:
 
289
                raise
 
290
            except:
 
291
                observer = self.observers[i]
 
292
                self.observers[i] = lambda event: None
 
293
                err(failure.Failure(),
 
294
                    "Log observer %s failed." % (observer,))
 
295
                self.observers[i] = observer
 
296
 
 
297
 
 
298
    def showwarning(self, message, category, filename, lineno, file=None,
 
299
                    line=None):
 
300
        """
 
301
        Twisted-enabled wrapper around L{warnings.showwarning}.
 
302
 
 
303
        If C{file} is C{None}, the default behaviour is to emit the warning to
 
304
        the log system, otherwise the original L{warnings.showwarning} Python
 
305
        function is called.
 
306
        """
 
307
        if file is None:
 
308
            self.msg(warning=message, category=reflect.qual(category),
 
309
                     filename=filename, lineno=lineno,
 
310
                     format="%(filename)s:%(lineno)s: %(category)s: %(warning)s")
 
311
        else:
 
312
            if sys.version_info < (2, 6):
 
313
                _oldshowwarning(message, category, filename, lineno, file)
 
314
            else:
 
315
                _oldshowwarning(message, category, filename, lineno, file, line)
 
316
 
 
317
 
 
318
 
 
319
 
 
320
try:
 
321
    theLogPublisher
 
322
except NameError:
 
323
    theLogPublisher = LogPublisher()
 
324
    addObserver = theLogPublisher.addObserver
 
325
    removeObserver = theLogPublisher.removeObserver
 
326
    msg = theLogPublisher.msg
 
327
    showwarning = theLogPublisher.showwarning
 
328
 
 
329
 
 
330
def _safeFormat(fmtString, fmtDict):
 
331
    """
 
332
    Try to format the string C{fmtString} using C{fmtDict} arguments,
 
333
    swallowing all errors to always return a string.
 
334
    """
 
335
    # There's a way we could make this if not safer at least more
 
336
    # informative: perhaps some sort of str/repr wrapper objects
 
337
    # could be wrapped around the things inside of C{fmtDict}. That way
 
338
    # if the event dict contains an object with a bad __repr__, we
 
339
    # can only cry about that individual object instead of the
 
340
    # entire event dict.
 
341
    try:
 
342
        text = fmtString % fmtDict
 
343
    except KeyboardInterrupt:
 
344
        raise
 
345
    except:
 
346
        try:
 
347
            text = ('Invalid format string or unformattable object in log message: %r, %s' % (fmtString, fmtDict))
 
348
        except:
 
349
            try:
 
350
                text = 'UNFORMATTABLE OBJECT WRITTEN TO LOG with fmt %r, MESSAGE LOST' % (fmtString,)
 
351
            except:
 
352
                text = 'PATHOLOGICAL ERROR IN BOTH FORMAT STRING AND MESSAGE DETAILS, MESSAGE LOST'
 
353
    return text
 
354
 
 
355
 
 
356
def textFromEventDict(eventDict):
 
357
    """
 
358
    Extract text from an event dict passed to a log observer. If it cannot
 
359
    handle the dict, it returns None.
 
360
 
 
361
    The possible keys of eventDict are:
 
362
     - C{message}: by default, it holds the final text. It's required, but can
 
363
       be empty if either C{isError} or C{format} is provided (the first
 
364
       having the priority).
 
365
     - C{isError}: boolean indicating the nature of the event.
 
366
     - C{failure}: L{failure.Failure} instance, required if the event is an
 
367
       error.
 
368
     - C{why}: if defined, used as header of the traceback in case of errors.
 
369
     - C{format}: string format used in place of C{message} to customize
 
370
       the event. It uses all keys present in C{eventDict} to format
 
371
       the text.
 
372
    Other keys will be used when applying the C{format}, or ignored.
 
373
    """
 
374
    edm = eventDict['message']
 
375
    if not edm:
 
376
        if eventDict['isError'] and 'failure' in eventDict:
 
377
            text = ((eventDict.get('why') or 'Unhandled Error')
 
378
                    + '\n' + eventDict['failure'].getTraceback())
 
379
        elif 'format' in eventDict:
 
380
            text = _safeFormat(eventDict['format'], eventDict)
 
381
        else:
 
382
            # we don't know how to log this
 
383
            return
 
384
    else:
 
385
        text = ' '.join(map(reflect.safe_str, edm))
 
386
    return text
 
387
 
 
388
 
 
389
class FileLogObserver:
 
390
    """
 
391
    Log observer that writes to a file-like object.
 
392
 
 
393
    @type timeFormat: C{str} or C{NoneType}
 
394
    @ivar timeFormat: If not C{None}, the format string passed to strftime().
 
395
    """
 
396
    timeFormat = None
 
397
 
 
398
    def __init__(self, f):
 
399
        self.write = f.write
 
400
        self.flush = f.flush
 
401
 
 
402
    def getTimezoneOffset(self, when):
 
403
        """
 
404
        Return the current local timezone offset from UTC.
 
405
 
 
406
        @type when: C{int}
 
407
        @param when: POSIX (ie, UTC) timestamp for which to find the offset.
 
408
 
 
409
        @rtype: C{int}
 
410
        @return: The number of seconds offset from UTC.  West is positive,
 
411
        east is negative.
 
412
        """
 
413
        offset = datetime.utcfromtimestamp(when) - datetime.fromtimestamp(when)
 
414
        return offset.days * (60 * 60 * 24) + offset.seconds
 
415
 
 
416
    def formatTime(self, when):
 
417
        """
 
418
        Format the given UTC value as a string representing that time in the
 
419
        local timezone.
 
420
 
 
421
        By default it's formatted as a ISO8601-like string (ISO8601 date and
 
422
        ISO8601 time separated by a space). It can be customized using the
 
423
        C{timeFormat} attribute, which will be used as input for the underlying
 
424
        C{time.strftime} call.
 
425
 
 
426
        @type when: C{int}
 
427
        @param when: POSIX (ie, UTC) timestamp for which to find the offset.
 
428
 
 
429
        @rtype: C{str}
 
430
        """
 
431
        if self.timeFormat is not None:
 
432
            return time.strftime(self.timeFormat, time.localtime(when))
 
433
 
 
434
        tzOffset = -self.getTimezoneOffset(when)
 
435
        when = datetime.utcfromtimestamp(when + tzOffset)
 
436
        tzHour = abs(int(tzOffset / 60 / 60))
 
437
        tzMin = abs(int(tzOffset / 60 % 60))
 
438
        if tzOffset < 0:
 
439
            tzSign = '-'
 
440
        else:
 
441
            tzSign = '+'
 
442
        return '%d-%02d-%02d %02d:%02d:%02d%s%02d%02d' % (
 
443
            when.year, when.month, when.day,
 
444
            when.hour, when.minute, when.second,
 
445
            tzSign, tzHour, tzMin)
 
446
 
 
447
    def emit(self, eventDict):
 
448
        text = textFromEventDict(eventDict)
 
449
        if text is None:
 
450
            return
 
451
 
 
452
        timeStr = self.formatTime(eventDict['time'])
 
453
        fmtDict = {'system': eventDict['system'], 'text': text.replace("\n", "\n\t")}
 
454
        msgStr = _safeFormat("[%(system)s] %(text)s\n", fmtDict)
 
455
 
 
456
        util.untilConcludes(self.write, timeStr + " " + msgStr)
 
457
        util.untilConcludes(self.flush)  # Hoorj!
 
458
 
 
459
    def start(self):
 
460
        """
 
461
        Start observing log events.
 
462
        """
 
463
        addObserver(self.emit)
 
464
 
 
465
    def stop(self):
 
466
        """
 
467
        Stop observing log events.
 
468
        """
 
469
        removeObserver(self.emit)
 
470
 
 
471
 
 
472
class PythonLoggingObserver(object):
 
473
    """
 
474
    Output twisted messages to Python standard library L{logging} module.
 
475
 
 
476
    WARNING: specific logging configurations (example: network) can lead to
 
477
    a blocking system. Nothing is done here to prevent that, so be sure to not
 
478
    use this: code within Twisted, such as twisted.web, assumes that logging
 
479
    does not block.
 
480
    """
 
481
 
 
482
    def __init__(self, loggerName="twisted"):
 
483
        """
 
484
        @param loggerName: identifier used for getting logger.
 
485
        @type loggerName: C{str}
 
486
        """
 
487
        self.logger = logging.getLogger(loggerName)
 
488
 
 
489
    def emit(self, eventDict):
 
490
        """
 
491
        Receive a twisted log entry, format it and bridge it to python.
 
492
 
 
493
        By default the logging level used is info; log.err produces error
 
494
        level, and you can customize the level by using the C{logLevel} key::
 
495
 
 
496
        >>> log.msg('debugging', logLevel=logging.DEBUG)
 
497
 
 
498
        """
 
499
        if 'logLevel' in eventDict:
 
500
            level = eventDict['logLevel']
 
501
        elif eventDict['isError']:
 
502
            level = logging.ERROR
 
503
        else:
 
504
            level = logging.INFO
 
505
        text = textFromEventDict(eventDict)
 
506
        if text is None:
 
507
            return
 
508
        self.logger.log(level, text)
 
509
 
 
510
    def start(self):
 
511
        """
 
512
        Start observing log events.
 
513
        """
 
514
        addObserver(self.emit)
 
515
 
 
516
    def stop(self):
 
517
        """
 
518
        Stop observing log events.
 
519
        """
 
520
        removeObserver(self.emit)
 
521
 
 
522
 
 
523
class StdioOnnaStick:
 
524
    """
 
525
    Class that pretends to be stout/err.
 
526
    """
 
527
 
 
528
    closed = 0
 
529
    softspace = 0
 
530
    mode = 'wb'
 
531
    name = '<stdio (log)>'
 
532
 
 
533
    def __init__(self, isError=0):
 
534
        self.isError = isError
 
535
        self.buf = ''
 
536
 
 
537
    def close(self):
 
538
        pass
 
539
 
 
540
    def fileno(self):
 
541
        return -1
 
542
 
 
543
    def flush(self):
 
544
        pass
 
545
 
 
546
    def read(self):
 
547
        raise IOError("can't read from the log!")
 
548
 
 
549
    readline = read
 
550
    readlines = read
 
551
    seek = read
 
552
    tell = read
 
553
 
 
554
    def write(self, data):
 
555
        d = (self.buf + data).split('\n')
 
556
        self.buf = d[-1]
 
557
        messages = d[0:-1]
 
558
        for message in messages:
 
559
            msg(message, printed=1, isError=self.isError)
 
560
 
 
561
    def writelines(self, lines):
 
562
        for line in lines:
 
563
            msg(line, printed=1, isError=self.isError)
 
564
 
 
565
 
 
566
try:
 
567
    _oldshowwarning
 
568
except NameError:
 
569
    _oldshowwarning = None
 
570
 
 
571
 
 
572
def startLogging(file, *a, **kw):
 
573
    """
 
574
    Initialize logging to a specified file.
 
575
 
 
576
    @return: A L{FileLogObserver} if a new observer is added, None otherwise.
 
577
    """
 
578
    if isinstance(file, StdioOnnaStick):
 
579
        return
 
580
    flo = FileLogObserver(file)
 
581
    startLoggingWithObserver(flo.emit, *a, **kw)
 
582
    return flo
 
583
 
 
584
 
 
585
 
 
586
def startLoggingWithObserver(observer, setStdout=1):
 
587
    """
 
588
    Initialize logging to a specified observer. If setStdout is true
 
589
    (defaults to yes), also redirect sys.stdout and sys.stderr
 
590
    to the specified file.
 
591
    """
 
592
    global defaultObserver, _oldshowwarning
 
593
    if not _oldshowwarning:
 
594
        _oldshowwarning = warnings.showwarning
 
595
        warnings.showwarning = showwarning
 
596
    if defaultObserver:
 
597
        defaultObserver.stop()
 
598
        defaultObserver = None
 
599
    addObserver(observer)
 
600
    msg("Log opened.")
 
601
    if setStdout:
 
602
        sys.stdout = logfile
 
603
        sys.stderr = logerr
 
604
 
 
605
 
 
606
class NullFile:
 
607
    softspace = 0
 
608
    def read(self): pass
 
609
    def write(self, bytes): pass
 
610
    def flush(self): pass
 
611
    def close(self): pass
 
612
 
 
613
 
 
614
def discardLogs():
 
615
    """
 
616
    Throw away all logs.
 
617
    """
 
618
    global logfile
 
619
    logfile = NullFile()
 
620
 
 
621
 
 
622
# Prevent logfile from being erased on reload.  This only works in cpython.
 
623
try:
 
624
    logfile
 
625
except NameError:
 
626
    logfile = StdioOnnaStick(0)
 
627
    logerr = StdioOnnaStick(1)
 
628
 
 
629
 
 
630
class DefaultObserver:
 
631
    """
 
632
    Default observer.
 
633
 
 
634
    Will ignore all non-error messages and send error messages to sys.stderr.
 
635
    Will be removed when startLogging() is called for the first time.
 
636
    """
 
637
 
 
638
    def _emit(self, eventDict):
 
639
        if eventDict["isError"]:
 
640
            if 'failure' in eventDict:
 
641
                text = eventDict['failure'].getTraceback()
 
642
            else:
 
643
                text = " ".join([str(m) for m in eventDict["message"]]) + "\n"
 
644
            sys.stderr.write(text)
 
645
            sys.stderr.flush()
 
646
 
 
647
    def start(self):
 
648
        addObserver(self._emit)
 
649
 
 
650
    def stop(self):
 
651
        removeObserver(self._emit)
 
652
 
 
653
 
 
654
# Some more sibling imports, at the bottom and unqualified to avoid
 
655
# unresolvable circularity
 
656
import threadable, failure
 
657
threadable.synchronize(LogPublisher)
 
658
 
 
659
 
 
660
try:
 
661
    defaultObserver
 
662
except NameError:
 
663
    defaultObserver = DefaultObserver()
 
664
    defaultObserver.start()
 
665