<commit_before>##
# Copyright (c) 2006-2007 Apple Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
##

"""
Classes and functions to do better logging.

Example usage in a module:

    from twistedcaldav.log import Logger
    log = Logger()

    log.info("Blah blah")

Or in a class:

    from twistedcaldav.log import LoggingMixIn

    class Foo (LoggingMixIn):
        def oops(self):
            self.log_error("Oops!")

C{Logger}s have namespaces, for which logging can be configured
independently.  Namespaces may be specified by passing in a
C{namespace} argument to L{Logger} when instantiating it, but if none
is given, the logger will derive its own namespace by using the module
name of the callable that instantiating it, or, in the case of a
L{LoggingMixIn}, by using the fully qualified name of the class.

In the first example above, the namespace would be C{some.module}, and
in the second example, it would be C{some.module.Foo}.
"""

__all__ = [
    "logLevels",
    "cmpLogLevels",
    "pythonLogLevelForLevel",
    "logLevelForNamespace",
    "setLogLevelForNamespace",
    "clearLogLevels",
    "logLevelsByNamespace",
    "Logger",
    "LoggingMixIn",
    "InvalidLogLevelError",
]

import inspect
import logging

from twisted.python import log

from StringIO import StringIO

from twisted.internet.defer import succeed

from twisted.web2 import responsecode
from twisted.web2.dav.util import allDataFromStream
from twisted.web2.stream import MemoryStream

logLevels = (
    "debug",
    "info",
    "warn",
    "error",
)

logLevelIndexes = dict(zip(logLevels, xrange(0, len(logLevels))))

def cmpLogLevels(a, b):
    """
    Compare two log levels.
    @param a: a log level
    @param b: a log level
    @return: a negative integer if C{a < b}, C{0} if C{a == b}, or a
        positive integer if C{a > b}.
    """
    return cmp(logLevelIndexes[a], logLevelIndexes[b])

##
# Mappings to Python's logging module
##

pythonLogLevelMapping = {
    "debug"   : logging.DEBUG,
    "info"    : logging.INFO,
    "warn"    : logging.WARNING,
    "error"   : logging.ERROR,
   #"critical": logging.CRITICAL,
}

def pythonLogLevelForLevel(level):
    """
    @param: a log level
    @return: a L{logging} module log level
    """
    if level in pythonLogLevelMapping:
        return pythonLogLevelMapping[level]

    raise InvalidLogLevelError(level)

#    #
#    # In case we add log levels that don't map to pythong logging levels:
#    #
#    for l in logLevels:
#        print "Trying %s: %s, %s" % (l, l in pythonLogLevelMapping, cmpLogLevels(level, l) <= 0)
#        if l in pythonLogLevelMapping and cmpLogLevels(level, l) <= 0:
#            return pythonLogLevelMapping[l]
#
#    return logging.CRITICAL

##
# Tools for managing log levels
##

def logLevelForNamespace(namespace):
    """
    @param namespace: a logging namespace, or C{None} to set the
        default log level.
    @return: the log level for the given namespace.
    """
    if not namespace:
        return logLevelsByNamespace[None]

    if namespace in logLevelsByNamespace:
        return logLevelsByNamespace[namespace]

    segments = namespace.split(".")
    index = len(segments) - 1

    while index > 0:
        namespace = ".".join(segments[:index])
        if namespace in logLevelsByNamespace:
            return logLevelsByNamespace[namespace]
        index -= 1

    return logLevelsByNamespace[None]

def setLogLevelForNamespace(namespace, level):
    """
    Sets the log level for a logging namespace.
    @param namespace: a logging namespace
    @param level: the log level for the given namespace.
    """
    if level not in logLevels:
        raise InvalidLogLevelError(level)

    if namespace:
        logLevelsByNamespace[namespace] = level
    else:
        logLevelsByNamespace[None] = level

def clearLogLevels():
    """
    Clears all log levels to the default.
    """
    logLevelsByNamespace.clear()
    logLevelsByNamespace[None] = "info"  # Default log level

logLevelsByNamespace = {}
clearLogLevels()

##
# Loggers
##

class Logger (object):
    """
    Logging object.
    """
    def __init__(self, namespace=None):
        """
        @param namespace: The namespace for this logger.  Uses a
            dotted notation, as used by python modules.  If not
            C{None}, then the name of the module of the caller
            is used.
        """
        if namespace is None:
            currentFrame = inspect.currentframe()
            callerFrame  = currentFrame.f_back
            callerModule = callerFrame.f_globals["__name__"]

            namespace = callerModule

        self.namespace = namespace

    def __repr__(self):
        return "<%s %r>" % (self.__class__.__name__, self.namespace)

    def emit(self, level, message, **kwargs):
        """
        Called internally to emit log messages at a given log level.
        """
        assert level in logLevels, "Unknown log level: %r" % (level,)

        # FIXME: Filtering should be done by the log observer(s)
        if self.willLogAtLevel(level):
            log.msg(
                # FIXME: This formatting should be done by the log observer(s)
                "[%s#%s] %s" % (self.namespace, level, message),
                isError = (cmpLogLevels(level, "error") >= 0),
                level = level,
                logLevel = pythonLogLevelForLevel(level),
                namespace = self.namespace,
                **kwargs
            )

    def level(self):
        """
        @return: the logging level for this logger's namespace.
        """
        return logLevelForNamespace(self.namespace)

    def setLevel(self, level):
        """
        Set the logging level for this logger's namespace.
        @param level: a logging level
        """
        setLogLevelForNamespace(self.namespace, level)

    def willLogAtLevel(self, level):
        """
        @param level: a logging level
        @return: C{True} if this logger will log at the given logging
            level.
        """
        return cmpLogLevels(self.level(), level) <= 0<commit_msg>Don't set isError; it's not for strings.<commit_after>##
# Copyright (c) 2006-2007 Apple Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
##

"""
Classes and functions to do better logging.

Example usage in a module:

    from twistedcaldav.log import Logger
    log = Logger()

    log.info("Blah blah")

Or in a class:

    from twistedcaldav.log import LoggingMixIn

    class Foo (LoggingMixIn):
        def oops(self):
            self.log_error("Oops!")

C{Logger}s have namespaces, for which logging can be configured
independently.  Namespaces may be specified by passing in a
C{namespace} argument to L{Logger} when instantiating it, but if none
is given, the logger will derive its own namespace by using the module
name of the callable that instantiating it, or, in the case of a
L{LoggingMixIn}, by using the fully qualified name of the class.

In the first example above, the namespace would be C{some.module}, and
in the second example, it would be C{some.module.Foo}.
"""

__all__ = [
    "logLevels",
    "cmpLogLevels",
    "pythonLogLevelForLevel",
    "logLevelForNamespace",
    "setLogLevelForNamespace",
    "clearLogLevels",
    "logLevelsByNamespace",
    "Logger",
    "LoggingMixIn",
    "InvalidLogLevelError",
]

import inspect
import logging

from twisted.python import log

from StringIO import StringIO

from twisted.internet.defer import succeed

from twisted.web2 import responsecode
from twisted.web2.dav.util import allDataFromStream
from twisted.web2.stream import MemoryStream

logLevels = (
    "debug",
    "info",
    "warn",
    "error",
)

logLevelIndexes = dict(zip(logLevels, xrange(0, len(logLevels))))

def cmpLogLevels(a, b):
    """
    Compare two log levels.
    @param a: a log level
    @param b: a log level
    @return: a negative integer if C{a < b}, C{0} if C{a == b}, or a
        positive integer if C{a > b}.
    """
    return cmp(logLevelIndexes[a], logLevelIndexes[b])

##
# Mappings to Python's logging module
##

pythonLogLevelMapping = {
    "debug"   : logging.DEBUG,
    "info"    : logging.INFO,
    "warn"    : logging.WARNING,
    "error"   : logging.ERROR,
   #"critical": logging.CRITICAL,
}

def pythonLogLevelForLevel(level):
    """
    @param: a log level
    @return: a L{logging} module log level
    """
    if level in pythonLogLevelMapping:
        return pythonLogLevelMapping[level]

    raise InvalidLogLevelError(level)

#    #
#    # In case we add log levels that don't map to pythong logging levels:
#    #
#    for l in logLevels:
#        print "Trying %s: %s, %s" % (l, l in pythonLogLevelMapping, cmpLogLevels(level, l) <= 0)
#        if l in pythonLogLevelMapping and cmpLogLevels(level, l) <= 0:
#            return pythonLogLevelMapping[l]
#
#    return logging.CRITICAL

##
# Tools for managing log levels
##

def logLevelForNamespace(namespace):
    """
    @param namespace: a logging namespace, or C{None} to set the
        default log level.
    @return: the log level for the given namespace.
    """
    if not namespace:
        return logLevelsByNamespace[None]

    if namespace in logLevelsByNamespace:
        return logLevelsByNamespace[namespace]

    segments = namespace.split(".")
    index = len(segments) - 1

    while index > 0:
        namespace = ".".join(segments[:index])
        if namespace in logLevelsByNamespace:
            return logLevelsByNamespace[namespace]
        index -= 1

    return logLevelsByNamespace[None]

def setLogLevelForNamespace(namespace, level):
    """
    Sets the log level for a logging namespace.
    @param namespace: a logging namespace
    @param level: the log level for the given namespace.
    """
    if level not in logLevels:
        raise InvalidLogLevelError(level)

    if namespace:
        logLevelsByNamespace[namespace] = level
    else:
        logLevelsByNamespace[None] = level

def clearLogLevels():
    """
    Clears all log levels to the default.
    """
    logLevelsByNamespace.clear()
    logLevelsByNamespace[None] = "info"  # Default log level

logLevelsByNamespace = {}
clearLogLevels()

##
# Loggers
##

class Logger (object):
    """
    Logging object.
    """
    def __init__(self, namespace=None):
        """
        @param namespace: The namespace for this logger.  Uses a
            dotted notation, as used by python modules.  If not
            C{None}, then the name of the module of the caller
            is used.
        """
        if namespace is None:
            currentFrame = inspect.currentframe()
            callerFrame  = currentFrame.f_back
            callerModule = callerFrame.f_globals["__name__"]

            namespace = callerModule

        self.namespace = namespace

    def __repr__(self):
        return "<%s %r>" % (self.__class__.__name__, self.namespace)

    def emit(self, level, message, **kwargs):
        """
        Called internally to emit log messages at a given log level.
        """
        assert level in logLevels, "Unknown log level: %r" % (level,)

        # FIXME: Filtering should be done by the log observer(s)
        if self.willLogAtLevel(level):
            log.msg(
                # FIXME: This formatting should be done by the log observer(s)
                "[%s#%s] %s" % (self.namespace, level, message),
                level = level,
                logLevel = pythonLogLevelForLevel(level),
                namespace = self.namespace,
                **kwargs
            )

    def level(self):
        """
        @return: the logging level for this logger's namespace.
        """
        return logLevelForNamespace(self.namespace)

    def setLevel(self, level):
        """
        Set the logging level for this logger's namespace.
        @param level: a logging level
        """
        setLogLevelForNamespace(self.namespace, level)

    def willLogAtLevel(self, level):
        """
        @param level: a logging level
        @return: C{True} if this logger will log at the given logging
            level.
        """
        return cmpLogLevels(self.level(), level) <= 0
{'fraction_non_alphanumeric': 0.09395412425945618, 'fraction_numerical': 0.003569801002582409, 'mean_word_length': 2.7194915254237286, 'pattern_counts': {'":': 2, '<': 13, '<?xml version=': 0, '>': 10, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4699317', 'n_tokens_mistral': 3893, 'n_tokens_neox': 3735, 'n_words': 1319}