~timo-jyrinki/ubuntu/trusty/pitivi/backport_utopic_fixes

« back to all changes in this revision

Viewing changes to pitivi/utils/loggable.py

  • Committer: Package Import Robot
  • Author(s): Sebastian Dröge
  • Date: 2014-03-29 15:22:50 UTC
  • mto: (3.1.23 experimental)
  • mto: This revision was merged to the branch mainline in revision 44.
  • Revision ID: package-import@ubuntu.com-20140329152250-flg9onx416bqf3e3
Tags: upstream-0.93
Import upstream version 0.93

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# Pitivi video editor
2
2
#
3
 
#       pitivi/log/loggable.py
 
3
#       pitivi/utils/loggable.py
4
4
#
5
5
# Copyright (c) 2009, Alessandro Decina <alessandro.decina@collabora.co.uk>
6
6
#
280
280
    @return: The name of the level
281
281
    @rtype: str
282
282
    """
283
 
    assert isinstance(level, int) and level > 0 and level < 6, \
 
283
    assert isinstance(level, int) and level > 0 and level < 7, \
284
284
        TypeError("Bad debug level")
285
285
    return getLevelNames()[level - 1]
286
286
 
427
427
    @param where: how many frames to go back up, or function
428
428
    @type  where: int (negative) or function
429
429
 
430
 
    @return: tuple of (file, line)
431
 
    @rtype:  tuple of (str, int)
 
430
    @return: tuple of (file, line, function_name)
 
431
    @rtype:  tuple of (str, int, str)
432
432
    """
433
433
    co = None
434
434
    lineno = None
458
458
            stackFrame = stackFrame.f_back
459
459
 
460
460
    if not co:
461
 
        return "<unknown file>", 0
 
461
        return "<unknown file>", 0, None
462
462
 
463
463
    return scrubFilename(co.co_filename), lineno, name
464
464
 
519
519
        message = format % args
520
520
    else:
521
521
        message = format
522
 
 
523
 
    # first all the unlimited ones
524
 
    if _log_handlers:
 
522
    funcname = None
 
523
 
 
524
    if level > getCategoryLevel(category):
 
525
        handlers = _log_handlers
 
526
    else:
 
527
        handlers = _log_handlers + _log_handlers_limited
 
528
 
 
529
    if handlers:
525
530
        if filePath is None and line is None:
526
531
            (filePath, line, funcname) = getFileLine(where=where)
527
532
        ret['filePath'] = filePath
528
533
        ret['line'] = line
529
534
        if funcname:
530
535
            message = "\033[00m\033[32;01m%s:\033[00m %s" % (funcname, message)
531
 
        for handler in _log_handlers:
 
536
        for handler in handlers:
532
537
            try:
533
 
                handler(level, object, category, file, line, message)
 
538
                handler(level, object, category, filePath, line, message)
534
539
            except TypeError, e:
535
540
                raise SystemError("handler %r raised a TypeError: %s" % (
536
541
                    handler, getExceptionMessage(e)))
537
542
 
538
 
    if level > getCategoryLevel(category):
539
 
        return ret
540
 
 
541
 
    if _log_handlers_limited:
542
 
        if filePath is None and line is None:
543
 
            (filePath, line, funcname) = getFileLine(where=where)
544
 
        ret['filePath'] = filePath
545
 
        ret['line'] = line
546
 
        if funcname:
547
 
            message = "\033[00m\033[32;01m%s:\033[00m %s" % (funcname, message)
548
 
        for handler in _log_handlers_limited:
549
 
            # set this a second time, just in case there weren't unlimited
550
 
            # loggers there before
551
 
            try:
552
 
                handler(level, object, category, filePath, line, message)
553
 
            except TypeError:
554
 
                raise SystemError("handler %r raised a TypeError" % handler)
555
 
 
556
 
        return ret
 
543
    return ret
557
544
 
558
545
 
559
546
def errorObject(object, cat, format, *args):
563
550
    """
564
551
    doLog(ERROR, object, cat, format, args)
565
552
 
566
 
    # we do the import here because having it globally causes weird import
567
 
    # errors if our gstreactor also imports .log, which brings in errors
568
 
    # and pb stuff
569
553
    if args:
570
554
        raise SystemExit(format % args)
571
555
    else:
660
644
    sys.stderr.flush()
661
645
 
662
646
 
663
 
def _preformatLevels(noColorEnvVarName):
 
647
def _preformatLevels(enableColorOutput):
664
648
    format = '%-5s'
665
649
 
666
 
    if (noColorEnvVarName is not None
667
 
        and (noColorEnvVarName not in os.environ
668
 
             or not os.environ[noColorEnvVarName])):
669
 
 
 
650
    if enableColorOutput:
670
651
        t = TerminalController()
671
652
        formatter = lambda level: ''.join((t.BOLD, getattr(t, COLORS[level]),
672
653
                            format % (_LEVEL_NAMES[level - 1], ), t.NORMAL))
681
662
# setup functions
682
663
 
683
664
 
684
 
def init(envVarName, enableColorOutput=False, enableCrackOutput=True):
 
665
def init(envVarName, enableColorOutput=True, enableCrackOutput=True):
685
666
    """
686
667
    Initialize the logging system and parse the environment variable
687
668
    of the given name.
697
678
    global _ENV_VAR_NAME
698
679
    _ENV_VAR_NAME = envVarName
699
680
 
700
 
    if enableColorOutput:
701
 
        _preformatLevels(envVarName + "_NO_COLOR")
702
 
    else:
703
 
        _preformatLevels(None)
 
681
    _preformatLevels(enableColorOutput)
704
682
 
705
683
    if envVarName in os.environ:
706
684
        # install a log handler that uses the value of the environment var
951
929
        marker to multiple elements at a time helps debugging.
952
930
        @param marker: A string write to the log.
953
931
        @type marker: str
954
 
        @param level: The log level. It can be log.WARN, log.INFO,
955
 
        log.DEBUG, log.ERROR or log.LOG.
 
932
        @param level: The log level. It can be log.ERROR, etc.
956
933
        @type  level: int
957
934
        """
958
935
        logHandlers = {WARN: self.warning,
1024
1001
        return doLog(level, self.logObjectName(), self.logCategory,
1025
1002
                  format, args, where=where, **kwargs)
1026
1003
 
1027
 
    def warningFailure(self, failure, swallow=True):
1028
 
        """
1029
 
        Log a warning about a Twisted Failure. Useful as an errback handler:
1030
 
        d.addErrback(self.warningFailure)
1031
 
 
1032
 
        @param swallow: whether to swallow the failure or not
1033
 
        @type  swallow: bool
1034
 
        """
1035
 
        if _canShortcutLogging(self.logCategory, WARN):
1036
 
            if swallow:
1037
 
                return
1038
 
            return failure
1039
 
        warningObject(self.logObjectName(), self.logCategory,
1040
 
            *self.logFunction(getFailureMessage(failure)))
1041
 
        if not swallow:
1042
 
            return failure
1043
 
 
1044
1004
    def logFunction(self, *args):
1045
1005
        """Overridable log function.  Default just returns passed message."""
1046
1006
        return args
1057
1017
    def handleException(self, exc):
1058
1018
        self.warning(getExceptionMessage(exc))
1059
1019
 
1060
 
# Twisted helper stuff
1061
 
 
1062
 
# private stuff
1063
 
_initializedTwisted = False
1064
 
 
1065
 
# make a singleton
1066
 
__theTwistedLogObserver = None
1067
 
 
1068
 
 
1069
 
def _getTheTwistedLogObserver():
1070
 
    # used internally and in test
1071
 
    global __theTwistedLogObserver
1072
 
 
1073
 
    if not __theTwistedLogObserver:
1074
 
        __theTwistedLogObserver = TwistedLogObserver()
1075
 
 
1076
 
    return __theTwistedLogObserver
1077
 
 
1078
 
 
1079
 
# public helper methods
1080
 
 
1081
 
 
1082
 
def getFailureMessage(failure):
1083
 
    """
1084
 
    Return a short message based on L{twisted.python.failure.Failure}.
1085
 
    Tries to find where the exception was triggered.
1086
 
    """
1087
 
    exc = str(failure.type)
1088
 
    msg = failure.getErrorMessage()
1089
 
    if len(failure.frames) == 0:
1090
 
        return "failure %(exc)s: %(msg)s" % locals()
1091
 
 
1092
 
    (func, filename, line, some, other) = failure.frames[-1]
1093
 
    filename = scrubFilename(filename)
1094
 
    return "failure %(exc)s at %(filename)s:%(line)s: %(func)s(): %(msg)s" % locals()
1095
 
 
1096
 
 
1097
 
def warningFailure(failure, swallow=True):
1098
 
    """
1099
 
    Log a warning about a Failure. Useful as an errback handler:
1100
 
    d.addErrback(warningFailure)
1101
 
 
1102
 
    @param swallow: whether to swallow the failure or not
1103
 
    @type  swallow: bool
1104
 
    """
1105
 
    warning('', getFailureMessage(failure))
1106
 
    if not swallow:
1107
 
        return failure
1108
 
 
1109
 
 
1110
 
def logTwisted():
1111
 
    """
1112
 
    Integrate twisted's logger with our logger.
1113
 
 
1114
 
    This is done in a separate method because calling this imports and sets
1115
 
    up a reactor.  Since we want basic logging working before choosing a
1116
 
    reactor, we need to separate these.
1117
 
    """
1118
 
    global _initializedTwisted
1119
 
 
1120
 
    if _initializedTwisted:
1121
 
        return
1122
 
 
1123
 
    debug('log', 'Integrating twisted logger')
1124
 
 
1125
 
    # integrate twisted's logging with us
1126
 
    from twisted.python import log as tlog
1127
 
 
1128
 
    # this call imports the reactor
1129
 
    # that is why we do this in a separate method
1130
 
    from twisted.spread import pb
1131
 
 
1132
 
    # we don't want logs for pb.Error types since they
1133
 
    # are specifically raised to be handled on the other side
1134
 
    observer = _getTheTwistedLogObserver()
1135
 
    observer.ignoreErrors([pb.Error, ])
1136
 
    tlog.startLoggingWithObserver(observer.emit, False)
1137
 
 
1138
 
    _initializedTwisted = True
1139
 
 
1140
 
 
1141
 
# we need an object as the observer because startLoggingWithObserver
1142
 
# expects a bound method
1143
 
 
1144
 
 
1145
 
class TwistedLogObserver(BaseLoggable):
1146
 
    """
1147
 
    Twisted log observer that integrates with our logging.
1148
 
    """
1149
 
    logCategory = "logobserver"
1150
 
 
1151
 
    def __init__(self):
1152
 
        self._ignoreErrors = []  # Failure types
1153
 
 
1154
 
    def emit(self, eventDict):
1155
 
        method = log  # by default, lowest level
1156
 
        edm = eventDict['message']
1157
 
        if not edm:
1158
 
            if eventDict['isError'] and 'failure' in eventDict:
1159
 
                f = eventDict['failure']
1160
 
                for failureType in self._ignoreErrors:
1161
 
                    r = f.check(failureType)
1162
 
                    if r:
1163
 
                        self.debug("Failure of type %r, ignoring" % failureType)
1164
 
                        return
1165
 
 
1166
 
                self.log("Failure %r" % f)
1167
 
 
1168
 
                method = debug  # tracebacks from errors at debug level
1169
 
                msg = "A twisted traceback occurred."
1170
 
                if getCategoryLevel("twisted") < WARN:
1171
 
                    msg += "  Run with debug level >= 2 to see the traceback."
1172
 
                # and an additional warning
1173
 
                warning('twisted', msg)
1174
 
                text = f.getTraceback()
1175
 
                safeprintf(sys.stderr, "\nTwisted traceback:\n")
1176
 
                safeprintf(sys.stderr, text + '\n')
1177
 
            elif 'format' in eventDict:
1178
 
                text = eventDict['format'] % eventDict
1179
 
            else:
1180
 
                # we don't know how to log this
1181
 
                return
1182
 
        else:
1183
 
            text = ' '.join(map(str, edm))
1184
 
 
1185
 
        fmtDict = {'system': eventDict['system'],
1186
 
                   'text': text.replace("\n", "\n\t")}
1187
 
        msgStr = " [%(system)s] %(text)s\n" % fmtDict
1188
 
        # because msgstr can contain %, as in a backtrace, make sure we
1189
 
        # don't try to splice it
1190
 
        method('twisted', msgStr)
1191
 
 
1192
 
    def ignoreErrors(self, *types):
1193
 
        for failureType in types:
1194
 
            self._ignoreErrors.append(failureType)
1195
 
 
1196
 
    def clearIgnores(self):
1197
 
        self._ignoreErrors = []
1198
 
 
1199
1020
 
1200
1021
class Loggable(BaseLoggable):
1201
1022
    def __init__(self, logCategory=None):