We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
LOG_FILTER cannot be used with '%s'ed messages
Currently LOG_FILTER doesn’t allow ignoring messages with '%s' placeholders, because `ignore_key` variable in `filter` method of `log` module use 'getMessage()' method of `LogRecord` class, but not `msg` field.

Example which isn’t work:

```
LOG_FILTER = [
    (logging.WARN, 'Empty alt attribute for image %s in %s')
]
```

The problem is that now no way to suppress such warnings. I guess, filtering by `msg` field doesn’t break anything, but allow to more complex filtering.

Or maybe better intruduce another varible, say LOG_FILTER_GROUP, with such functionality.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pelican/log.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 from __future__ import print_function, unicode_literals
3 
4 import locale
5 import logging
6 import os
7 import sys
8 from collections import Mapping, defaultdict
9 
10 import six
11 
12 __all__ = [
13     'init'
14 ]
15 
16 
17 class BaseFormatter(logging.Formatter):
18     def __init__(self, fmt=None, datefmt=None):
19         FORMAT = '%(customlevelname)s %(message)s'
20         super(BaseFormatter, self).__init__(fmt=FORMAT, datefmt=datefmt)
21 
22     def format(self, record):
23         customlevel = self._get_levelname(record.levelname)
24         record.__dict__['customlevelname'] = customlevel
25         # format multiline messages 'nicely' to make it clear they are together
26         record.msg = record.msg.replace('\n', '\n  | ')
27         return super(BaseFormatter, self).format(record)
28 
29     def formatException(self, ei):
30         ''' prefix traceback info for better representation '''
31         # .formatException returns a bytestring in py2 and unicode in py3
32         # since .format will handle unicode conversion,
33         # str() calls are used to normalize formatting string
34         s = super(BaseFormatter, self).formatException(ei)
35         # fancy format traceback
36         s = str('\n').join(str('  | ') + line for line in s.splitlines())
37         # separate the traceback from the preceding lines
38         s = str('  |___\n{}').format(s)
39         return s
40 
41     def _get_levelname(self, name):
42         ''' NOOP: overridden by subclasses '''
43         return name
44 
45 
46 class ANSIFormatter(BaseFormatter):
47     ANSI_CODES = {
48         'red': '\033[1;31m',
49         'yellow': '\033[1;33m',
50         'cyan': '\033[1;36m',
51         'white': '\033[1;37m',
52         'bgred': '\033[1;41m',
53         'bggrey': '\033[1;100m',
54         'reset': '\033[0;m'}
55 
56     LEVEL_COLORS = {
57         'INFO': 'cyan',
58         'WARNING': 'yellow',
59         'ERROR': 'red',
60         'CRITICAL': 'bgred',
61         'DEBUG': 'bggrey'}
62 
63     def _get_levelname(self, name):
64         color = self.ANSI_CODES[self.LEVEL_COLORS.get(name, 'white')]
65         if name == 'INFO':
66             fmt = '{0}->{2}'
67         else:
68             fmt = '{0}{1}{2}:'
69         return fmt.format(color, name, self.ANSI_CODES['reset'])
70 
71 
72 class TextFormatter(BaseFormatter):
73     """
74     Convert a `logging.LogRecord' object into text.
75     """
76 
77     def _get_levelname(self, name):
78         if name == 'INFO':
79             return '->'
80         else:
81             return name + ':'
82 
83 
84 class LimitFilter(logging.Filter):
85     """
86     Remove duplicates records, and limit the number of records in the same
87     group.
88 
89     Groups are specified by the message to use when the number of records in
90     the same group hit the limit.
91     E.g.: log.warning(('43 is not the answer', 'More erroneous answers'))
92     """
93 
94     _ignore = set()
95     _threshold = 5
96     _group_count = defaultdict(int)
97 
98     def filter(self, record):
99         # don't limit log messages for anything above "warning"
100         if record.levelno > logging.WARN:
101             return True
102 
103         # extract group
104         group = record.__dict__.get('limit_msg', None)
105         group_args = record.__dict__.get('limit_args', ())
106 
107         # ignore record if it was already raised
108         # use .getMessage() and not .msg for string formatting
109         ignore_key = (record.levelno, record.getMessage())
110         if ignore_key in self._ignore:
111             return False
112         else:
113             self._ignore.add(ignore_key)
114 
115         # check if we went over threshold
116         if group:
117             key = (record.levelno, group)
118             self._group_count[key] += 1
119             if self._group_count[key] == self._threshold:
120                 record.msg = group
121                 record.args = group_args
122             elif self._group_count[key] > self._threshold:
123                 return False
124         return True
125 
126 
127 class SafeLogger(logging.Logger):
128     """
129     Base Logger which properly encodes Exceptions in Py2
130     """
131     _exc_encoding = locale.getpreferredencoding()
132 
133     def _log(self, level, msg, args, exc_info=None, extra=None):
134         # if the only argument is a Mapping, Logger uses that for formatting
135         # format values for that case
136         if args and len(args) == 1 and isinstance(args[0], Mapping):
137             args = ({k: self._decode_arg(v) for k, v in args[0].items()},)
138         # otherwise, format each arg
139         else:
140             args = tuple(self._decode_arg(arg) for arg in args)
141         super(SafeLogger, self)._log(
142             level, msg, args, exc_info=exc_info, extra=extra)
143 
144     def _decode_arg(self, arg):
145         '''
146         properly decode an arg for Py2 if it's Exception
147 
148 
149         localized systems have errors in native language if locale is set
150         so convert the message to unicode with the correct encoding
151         '''
152         if isinstance(arg, Exception):
153             text = '%s: %s' % (arg.__class__.__name__, arg)
154             if six.PY2:
155                 text = text.decode(self._exc_encoding)
156             return text
157         else:
158             return arg
159 
160 
161 class LimitLogger(SafeLogger):
162     """
163     A logger which adds LimitFilter automatically
164     """
165 
166     limit_filter = LimitFilter()
167 
168     def __init__(self, *args, **kwargs):
169         super(LimitLogger, self).__init__(*args, **kwargs)
170         self.enable_filter()
171 
172     def disable_filter(self):
173         self.removeFilter(LimitLogger.limit_filter)
174 
175     def enable_filter(self):
176         self.addFilter(LimitLogger.limit_filter)
177 
178 
179 class FatalLogger(LimitLogger):
180     warnings_fatal = False
181     errors_fatal = False
182 
183     def warning(self, *args, **kwargs):
184         super(FatalLogger, self).warning(*args, **kwargs)
185         if FatalLogger.warnings_fatal:
186             raise RuntimeError('Warning encountered')
187 
188     def error(self, *args, **kwargs):
189         super(FatalLogger, self).error(*args, **kwargs)
190         if FatalLogger.errors_fatal:
191             raise RuntimeError('Error encountered')
192 
193 logging.setLoggerClass(FatalLogger)
194 
195 
196 def supports_color():
197     """
198     Returns True if the running system's terminal supports color,
199     and False otherwise.
200 
201     from django.core.management.color
202     """
203     plat = sys.platform
204     supported_platform = plat != 'Pocket PC' and \
205         (plat != 'win32' or 'ANSICON' in os.environ)
206 
207     # isatty is not always implemented, #6223.
208     is_a_tty = hasattr(sys.stdout, 'isatty') and sys.stdout.isatty()
209     if not supported_platform or not is_a_tty:
210         return False
211     return True
212 
213 
214 def get_formatter():
215     if supports_color():
216         return ANSIFormatter()
217     else:
218         return TextFormatter()
219 
220 
221 def init(level=None, fatal='', handler=logging.StreamHandler(), name=None):
222     FatalLogger.warnings_fatal = fatal.startswith('warning')
223     FatalLogger.errors_fatal = bool(fatal)
224 
225     logger = logging.getLogger(name)
226 
227     handler.setFormatter(get_formatter())
228     logger.addHandler(handler)
229 
230     if level:
231         logger.setLevel(level)
232 
233 
234 def log_warnings():
235     import warnings
236     logging.captureWarnings(True)
237     warnings.simplefilter("default", DeprecationWarning)
238     init(logging.DEBUG, name='py.warnings')
239 
240 
241 if __name__ == '__main__':
242     init(level=logging.DEBUG)
243 
244     root_logger = logging.getLogger()
245     root_logger.debug('debug')
246     root_logger.info('info')
247     root_logger.warning('warning')
248     root_logger.error('error')
249     root_logger.critical('critical')
250
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/pelican/log.py b/pelican/log.py
--- a/pelican/log.py
+++ b/pelican/log.py
@@ -92,6 +92,7 @@
     """
 
     _ignore = set()
+    _raised_messages = set()
     _threshold = 5
     _group_count = defaultdict(int)
 
@@ -105,12 +106,18 @@
         group_args = record.__dict__.get('limit_args', ())
 
         # ignore record if it was already raised
-        # use .getMessage() and not .msg for string formatting
-        ignore_key = (record.levelno, record.getMessage())
-        if ignore_key in self._ignore:
+        message_key = (record.levelno, record.getMessage())
+        if message_key in self._raised_messages:
             return False
         else:
-            self._ignore.add(ignore_key)
+            self._raised_messages.add(message_key)
+
+        # ignore LOG_FILTER records by templates when "debug" isn't enabled
+        logger_level = logging.getLogger().getEffectiveLevel()
+        if logger_level > logging.DEBUG:
+            ignore_key = (record.levelno, record.msg)
+            if ignore_key in self._ignore:
+                return False
 
         # check if we went over threshold
         if group:

{"golden_diff": "diff --git a/pelican/log.py b/pelican/log.py\n--- a/pelican/log.py\n+++ b/pelican/log.py\n@@ -92,6 +92,7 @@\n     \"\"\"\n \n     _ignore = set()\n+    _raised_messages = set()\n     _threshold = 5\n     _group_count = defaultdict(int)\n \n@@ -105,12 +106,18 @@\n         group_args = record.__dict__.get('limit_args', ())\n \n         # ignore record if it was already raised\n-        # use .getMessage() and not .msg for string formatting\n-        ignore_key = (record.levelno, record.getMessage())\n-        if ignore_key in self._ignore:\n+        message_key = (record.levelno, record.getMessage())\n+        if message_key in self._raised_messages:\n             return False\n         else:\n-            self._ignore.add(ignore_key)\n+            self._raised_messages.add(message_key)\n+\n+        # ignore LOG_FILTER records by templates when \"debug\" isn't enabled\n+        logger_level = logging.getLogger().getEffectiveLevel()\n+        if logger_level > logging.DEBUG:\n+            ignore_key = (record.levelno, record.msg)\n+            if ignore_key in self._ignore:\n+                return False\n \n         # check if we went over threshold\n         if group:\n", "issue": "LOG_FILTER cannot be used with '%s'ed messages\nCurrently LOG_FILTER doesn\u2019t allow ignoring messages with '%s' placeholders, because `ignore_key` variable in `filter` method of `log` module use 'getMessage()' method of `LogRecord` class, but not `msg` field.\n\nExample which isn\u2019t work:\n\n```\nLOG_FILTER = [\n    (logging.WARN, 'Empty alt attribute for image %s in %s')\n]\n```\n\nThe problem is that now no way to suppress such warnings. I guess, filtering by `msg` field doesn\u2019t break anything, but allow to more complex filtering.\n\nOr maybe better intruduce another varible, say LOG_FILTER_GROUP, with such functionality.\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\nfrom __future__ import print_function, unicode_literals\n\nimport locale\nimport logging\nimport os\nimport sys\nfrom collections import Mapping, defaultdict\n\nimport six\n\n__all__ = [\n    'init'\n]\n\n\nclass BaseFormatter(logging.Formatter):\n    def __init__(self, fmt=None, datefmt=None):\n        FORMAT = '%(customlevelname)s %(message)s'\n        super(BaseFormatter, self).__init__(fmt=FORMAT, datefmt=datefmt)\n\n    def format(self, record):\n        customlevel = self._get_levelname(record.levelname)\n        record.__dict__['customlevelname'] = customlevel\n        # format multiline messages 'nicely' to make it clear they are together\n        record.msg = record.msg.replace('\\n', '\\n  | ')\n        return super(BaseFormatter, self).format(record)\n\n    def formatException(self, ei):\n        ''' prefix traceback info for better representation '''\n        # .formatException returns a bytestring in py2 and unicode in py3\n        # since .format will handle unicode conversion,\n        # str() calls are used to normalize formatting string\n        s = super(BaseFormatter, self).formatException(ei)\n        # fancy format traceback\n        s = str('\\n').join(str('  | ') + line for line in s.splitlines())\n        # separate the traceback from the preceding lines\n        s = str('  |___\\n{}').format(s)\n        return s\n\n    def _get_levelname(self, name):\n        ''' NOOP: overridden by subclasses '''\n        return name\n\n\nclass ANSIFormatter(BaseFormatter):\n    ANSI_CODES = {\n        'red': '\\033[1;31m',\n        'yellow': '\\033[1;33m',\n        'cyan': '\\033[1;36m',\n        'white': '\\033[1;37m',\n        'bgred': '\\033[1;41m',\n        'bggrey': '\\033[1;100m',\n        'reset': '\\033[0;m'}\n\n    LEVEL_COLORS = {\n        'INFO': 'cyan',\n        'WARNING': 'yellow',\n        'ERROR': 'red',\n        'CRITICAL': 'bgred',\n        'DEBUG': 'bggrey'}\n\n    def _get_levelname(self, name):\n        color = self.ANSI_CODES[self.LEVEL_COLORS.get(name, 'white')]\n        if name == 'INFO':\n            fmt = '{0}->{2}'\n        else:\n            fmt = '{0}{1}{2}:'\n        return fmt.format(color, name, self.ANSI_CODES['reset'])\n\n\nclass TextFormatter(BaseFormatter):\n    \"\"\"\n    Convert a `logging.LogRecord' object into text.\n    \"\"\"\n\n    def _get_levelname(self, name):\n        if name == 'INFO':\n            return '->'\n        else:\n            return name + ':'\n\n\nclass LimitFilter(logging.Filter):\n    \"\"\"\n    Remove duplicates records, and limit the number of records in the same\n    group.\n\n    Groups are specified by the message to use when the number of records in\n    the same group hit the limit.\n    E.g.: log.warning(('43 is not the answer', 'More erroneous answers'))\n    \"\"\"\n\n    _ignore = set()\n    _threshold = 5\n    _group_count = defaultdict(int)\n\n    def filter(self, record):\n        # don't limit log messages for anything above \"warning\"\n        if record.levelno > logging.WARN:\n            return True\n\n        # extract group\n        group = record.__dict__.get('limit_msg', None)\n        group_args = record.__dict__.get('limit_args', ())\n\n        # ignore record if it was already raised\n        # use .getMessage() and not .msg for string formatting\n        ignore_key = (record.levelno, record.getMessage())\n        if ignore_key in self._ignore:\n            return False\n        else:\n            self._ignore.add(ignore_key)\n\n        # check if we went over threshold\n        if group:\n            key = (record.levelno, group)\n            self._group_count[key] += 1\n            if self._group_count[key] == self._threshold:\n                record.msg = group\n                record.args = group_args\n            elif self._group_count[key] > self._threshold:\n                return False\n        return True\n\n\nclass SafeLogger(logging.Logger):\n    \"\"\"\n    Base Logger which properly encodes Exceptions in Py2\n    \"\"\"\n    _exc_encoding = locale.getpreferredencoding()\n\n    def _log(self, level, msg, args, exc_info=None, extra=None):\n        # if the only argument is a Mapping, Logger uses that for formatting\n        # format values for that case\n        if args and len(args) == 1 and isinstance(args[0], Mapping):\n            args = ({k: self._decode_arg(v) for k, v in args[0].items()},)\n        # otherwise, format each arg\n        else:\n            args = tuple(self._decode_arg(arg) for arg in args)\n        super(SafeLogger, self)._log(\n            level, msg, args, exc_info=exc_info, extra=extra)\n\n    def _decode_arg(self, arg):\n        '''\n        properly decode an arg for Py2 if it's Exception\n\n\n        localized systems have errors in native language if locale is set\n        so convert the message to unicode with the correct encoding\n        '''\n        if isinstance(arg, Exception):\n            text = '%s: %s' % (arg.__class__.__name__, arg)\n            if six.PY2:\n                text = text.decode(self._exc_encoding)\n            return text\n        else:\n            return arg\n\n\nclass LimitLogger(SafeLogger):\n    \"\"\"\n    A logger which adds LimitFilter automatically\n    \"\"\"\n\n    limit_filter = LimitFilter()\n\n    def __init__(self, *args, **kwargs):\n        super(LimitLogger, self).__init__(*args, **kwargs)\n        self.enable_filter()\n\n    def disable_filter(self):\n        self.removeFilter(LimitLogger.limit_filter)\n\n    def enable_filter(self):\n        self.addFilter(LimitLogger.limit_filter)\n\n\nclass FatalLogger(LimitLogger):\n    warnings_fatal = False\n    errors_fatal = False\n\n    def warning(self, *args, **kwargs):\n        super(FatalLogger, self).warning(*args, **kwargs)\n        if FatalLogger.warnings_fatal:\n            raise RuntimeError('Warning encountered')\n\n    def error(self, *args, **kwargs):\n        super(FatalLogger, self).error(*args, **kwargs)\n        if FatalLogger.errors_fatal:\n            raise RuntimeError('Error encountered')\n\nlogging.setLoggerClass(FatalLogger)\n\n\ndef supports_color():\n    \"\"\"\n    Returns True if the running system's terminal supports color,\n    and False otherwise.\n\n    from django.core.management.color\n    \"\"\"\n    plat = sys.platform\n    supported_platform = plat != 'Pocket PC' and \\\n        (plat != 'win32' or 'ANSICON' in os.environ)\n\n    # isatty is not always implemented, #6223.\n    is_a_tty = hasattr(sys.stdout, 'isatty') and sys.stdout.isatty()\n    if not supported_platform or not is_a_tty:\n        return False\n    return True\n\n\ndef get_formatter():\n    if supports_color():\n        return ANSIFormatter()\n    else:\n        return TextFormatter()\n\n\ndef init(level=None, fatal='', handler=logging.StreamHandler(), name=None):\n    FatalLogger.warnings_fatal = fatal.startswith('warning')\n    FatalLogger.errors_fatal = bool(fatal)\n\n    logger = logging.getLogger(name)\n\n    handler.setFormatter(get_formatter())\n    logger.addHandler(handler)\n\n    if level:\n        logger.setLevel(level)\n\n\ndef log_warnings():\n    import warnings\n    logging.captureWarnings(True)\n    warnings.simplefilter(\"default\", DeprecationWarning)\n    init(logging.DEBUG, name='py.warnings')\n\n\nif __name__ == '__main__':\n    init(level=logging.DEBUG)\n\n    root_logger = logging.getLogger()\n    root_logger.debug('debug')\n    root_logger.info('info')\n    root_logger.warning('warning')\n    root_logger.error('error')\n    root_logger.critical('critical')\n", "path": "pelican/log.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\nfrom __future__ import print_function, unicode_literals\n\nimport locale\nimport logging\nimport os\nimport sys\nfrom collections import Mapping, defaultdict\n\nimport six\n\n__all__ = [\n    'init'\n]\n\n\nclass BaseFormatter(logging.Formatter):\n    def __init__(self, fmt=None, datefmt=None):\n        FORMAT = '%(customlevelname)s %(message)s'\n        super(BaseFormatter, self).__init__(fmt=FORMAT, datefmt=datefmt)\n\n    def format(self, record):\n        customlevel = self._get_levelname(record.levelname)\n        record.__dict__['customlevelname'] = customlevel\n        # format multiline messages 'nicely' to make it clear they are together\n        record.msg = record.msg.replace('\\n', '\\n  | ')\n        return super(BaseFormatter, self).format(record)\n\n    def formatException(self, ei):\n        ''' prefix traceback info for better representation '''\n        # .formatException returns a bytestring in py2 and unicode in py3\n        # since .format will handle unicode conversion,\n        # str() calls are used to normalize formatting string\n        s = super(BaseFormatter, self).formatException(ei)\n        # fancy format traceback\n        s = str('\\n').join(str('  | ') + line for line in s.splitlines())\n        # separate the traceback from the preceding lines\n        s = str('  |___\\n{}').format(s)\n        return s\n\n    def _get_levelname(self, name):\n        ''' NOOP: overridden by subclasses '''\n        return name\n\n\nclass ANSIFormatter(BaseFormatter):\n    ANSI_CODES = {\n        'red': '\\033[1;31m',\n        'yellow': '\\033[1;33m',\n        'cyan': '\\033[1;36m',\n        'white': '\\033[1;37m',\n        'bgred': '\\033[1;41m',\n        'bggrey': '\\033[1;100m',\n        'reset': '\\033[0;m'}\n\n    LEVEL_COLORS = {\n        'INFO': 'cyan',\n        'WARNING': 'yellow',\n        'ERROR': 'red',\n        'CRITICAL': 'bgred',\n        'DEBUG': 'bggrey'}\n\n    def _get_levelname(self, name):\n        color = self.ANSI_CODES[self.LEVEL_COLORS.get(name, 'white')]\n        if name == 'INFO':\n            fmt = '{0}->{2}'\n        else:\n            fmt = '{0}{1}{2}:'\n        return fmt.format(color, name, self.ANSI_CODES['reset'])\n\n\nclass TextFormatter(BaseFormatter):\n    \"\"\"\n    Convert a `logging.LogRecord' object into text.\n    \"\"\"\n\n    def _get_levelname(self, name):\n        if name == 'INFO':\n            return '->'\n        else:\n            return name + ':'\n\n\nclass LimitFilter(logging.Filter):\n    \"\"\"\n    Remove duplicates records, and limit the number of records in the same\n    group.\n\n    Groups are specified by the message to use when the number of records in\n    the same group hit the limit.\n    E.g.: log.warning(('43 is not the answer', 'More erroneous answers'))\n    \"\"\"\n\n    _ignore = set()\n    _raised_messages = set()\n    _threshold = 5\n    _group_count = defaultdict(int)\n\n    def filter(self, record):\n        # don't limit log messages for anything above \"warning\"\n        if record.levelno > logging.WARN:\n            return True\n\n        # extract group\n        group = record.__dict__.get('limit_msg', None)\n        group_args = record.__dict__.get('limit_args', ())\n\n        # ignore record if it was already raised\n        message_key = (record.levelno, record.getMessage())\n        if message_key in self._raised_messages:\n            return False\n        else:\n            self._raised_messages.add(message_key)\n\n        # ignore LOG_FILTER records by templates when \"debug\" isn't enabled\n        logger_level = logging.getLogger().getEffectiveLevel()\n        if logger_level > logging.DEBUG:\n            ignore_key = (record.levelno, record.msg)\n            if ignore_key in self._ignore:\n                return False\n\n        # check if we went over threshold\n        if group:\n            key = (record.levelno, group)\n            self._group_count[key] += 1\n            if self._group_count[key] == self._threshold:\n                record.msg = group\n                record.args = group_args\n            elif self._group_count[key] > self._threshold:\n                return False\n        return True\n\n\nclass SafeLogger(logging.Logger):\n    \"\"\"\n    Base Logger which properly encodes Exceptions in Py2\n    \"\"\"\n    _exc_encoding = locale.getpreferredencoding()\n\n    def _log(self, level, msg, args, exc_info=None, extra=None):\n        # if the only argument is a Mapping, Logger uses that for formatting\n        # format values for that case\n        if args and len(args) == 1 and isinstance(args[0], Mapping):\n            args = ({k: self._decode_arg(v) for k, v in args[0].items()},)\n        # otherwise, format each arg\n        else:\n            args = tuple(self._decode_arg(arg) for arg in args)\n        super(SafeLogger, self)._log(\n            level, msg, args, exc_info=exc_info, extra=extra)\n\n    def _decode_arg(self, arg):\n        '''\n        properly decode an arg for Py2 if it's Exception\n\n\n        localized systems have errors in native language if locale is set\n        so convert the message to unicode with the correct encoding\n        '''\n        if isinstance(arg, Exception):\n            text = '%s: %s' % (arg.__class__.__name__, arg)\n            if six.PY2:\n                text = text.decode(self._exc_encoding)\n            return text\n        else:\n            return arg\n\n\nclass LimitLogger(SafeLogger):\n    \"\"\"\n    A logger which adds LimitFilter automatically\n    \"\"\"\n\n    limit_filter = LimitFilter()\n\n    def __init__(self, *args, **kwargs):\n        super(LimitLogger, self).__init__(*args, **kwargs)\n        self.enable_filter()\n\n    def disable_filter(self):\n        self.removeFilter(LimitLogger.limit_filter)\n\n    def enable_filter(self):\n        self.addFilter(LimitLogger.limit_filter)\n\n\nclass FatalLogger(LimitLogger):\n    warnings_fatal = False\n    errors_fatal = False\n\n    def warning(self, *args, **kwargs):\n        super(FatalLogger, self).warning(*args, **kwargs)\n        if FatalLogger.warnings_fatal:\n            raise RuntimeError('Warning encountered')\n\n    def error(self, *args, **kwargs):\n        super(FatalLogger, self).error(*args, **kwargs)\n        if FatalLogger.errors_fatal:\n            raise RuntimeError('Error encountered')\n\nlogging.setLoggerClass(FatalLogger)\n\n\ndef supports_color():\n    \"\"\"\n    Returns True if the running system's terminal supports color,\n    and False otherwise.\n\n    from django.core.management.color\n    \"\"\"\n    plat = sys.platform\n    supported_platform = plat != 'Pocket PC' and \\\n        (plat != 'win32' or 'ANSICON' in os.environ)\n\n    # isatty is not always implemented, #6223.\n    is_a_tty = hasattr(sys.stdout, 'isatty') and sys.stdout.isatty()\n    if not supported_platform or not is_a_tty:\n        return False\n    return True\n\n\ndef get_formatter():\n    if supports_color():\n        return ANSIFormatter()\n    else:\n        return TextFormatter()\n\n\ndef init(level=None, fatal='', handler=logging.StreamHandler(), name=None):\n    FatalLogger.warnings_fatal = fatal.startswith('warning')\n    FatalLogger.errors_fatal = bool(fatal)\n\n    logger = logging.getLogger(name)\n\n    handler.setFormatter(get_formatter())\n    logger.addHandler(handler)\n\n    if level:\n        logger.setLevel(level)\n\n\ndef log_warnings():\n    import warnings\n    logging.captureWarnings(True)\n    warnings.simplefilter(\"default\", DeprecationWarning)\n    init(logging.DEBUG, name='py.warnings')\n\n\nif __name__ == '__main__':\n    init(level=logging.DEBUG)\n\n    root_logger = logging.getLogger()\n    root_logger.debug('debug')\n    root_logger.info('info')\n    root_logger.warning('warning')\n    root_logger.error('error')\n    root_logger.critical('critical')\n", "path": "pelican/log.py"}]}