aboutsummaryrefslogtreecommitdiffstats
path: root/nikola/log.py
diff options
context:
space:
mode:
authorLibravatarUnit 193 <unit193@unit193.net>2021-02-03 19:17:50 -0500
committerLibravatarUnit 193 <unit193@unit193.net>2021-02-03 19:17:50 -0500
commit475d074fd74425efbe783fad08f97f2df0c4909f (patch)
tree2acdae53999b3c74b716efa4edb5b40311fa356a /nikola/log.py
parentcd502d52787f666fff3254d7d7e7578930c813c2 (diff)
parent3a0d66f07b112b6d2bdc2b57bbf717a89a351ce6 (diff)
Update upstream source from tag 'upstream/8.1.2'
Update to upstream version '8.1.2' with Debian dir e5e966a9e6010ef70618dc9a61558fa4db35aceb
Diffstat (limited to 'nikola/log.py')
-rw-r--r--nikola/log.py152
1 files changed, 152 insertions, 0 deletions
diff --git a/nikola/log.py b/nikola/log.py
new file mode 100644
index 0000000..9960ba1
--- /dev/null
+++ b/nikola/log.py
@@ -0,0 +1,152 @@
+# -*- coding: utf-8 -*-
+
+# Copyright © 2012-2020 Roberto Alsina and others.
+
+# Permission is hereby granted, free of charge, to any
+# person obtaining a copy of this software and associated
+# documentation files (the "Software"), to deal in the
+# Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the
+# Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice
+# shall be included in all copies or substantial portions of
+# the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
+# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+"""Logging support."""
+
+import enum
+import logging
+import warnings
+
+from nikola import DEBUG
+
+__all__ = (
+ "get_logger",
+ "LOGGER",
+)
+
+
+# Handlers/formatters
+class ApplicationWarning(Exception):
+ """An application warning, raised in strict mode."""
+
+ pass
+
+
+class StrictModeExceptionHandler(logging.StreamHandler):
+ """A logging handler that raises an exception on warnings."""
+
+ def emit(self, record: logging.LogRecord) -> None:
+ """Emit a logging record."""
+ if record.levelno >= logging.WARNING:
+ raise ApplicationWarning(self.format(record))
+
+
+class ColorfulFormatter(logging.Formatter):
+ """Stream handler with colors."""
+
+ _colorful = False
+
+ def format(self, record: logging.LogRecord) -> str:
+ """Format a message and add colors to it."""
+ message = super().format(record)
+ return self.wrap_in_color(record).format(message)
+
+ def wrap_in_color(self, record: logging.LogRecord) -> str:
+ """Return the colorized string for this record."""
+ if not self._colorful:
+ return "{}"
+ if record.levelno >= logging.ERROR:
+ return "\033[1;31m{}\033[0m"
+ elif record.levelno >= logging.WARNING:
+ return "\033[1;33m{}\033[0m"
+ elif record.levelno >= logging.INFO:
+ return "\033[1m{}\033[0m"
+ return "\033[37m{}\033[0m"
+
+
+# Initial configuration
+class LoggingMode(enum.Enum):
+ """Logging mode options."""
+
+ NORMAL = 0
+ STRICT = 1
+ QUIET = 2
+
+
+def configure_logging(logging_mode: LoggingMode = LoggingMode.NORMAL) -> None:
+ """Configure logging for Nikola.
+
+ This method can be called multiple times, previous configuration will be overridden.
+ """
+ if DEBUG:
+ logging.root.level = logging.DEBUG
+ else:
+ logging.root.level = logging.INFO
+
+ if logging_mode == LoggingMode.QUIET:
+ logging.root.handlers = []
+ return
+
+ handler = logging.StreamHandler()
+ handler.setFormatter(
+ ColorfulFormatter(
+ fmt="[%(asctime)s] %(levelname)s: %(name)s: %(message)s",
+ datefmt="%Y-%m-%d %H:%M:%S",
+ )
+ )
+
+ handlers = [handler]
+ if logging_mode == LoggingMode.STRICT:
+ handlers.append(StrictModeExceptionHandler())
+
+ logging.root.handlers = handlers
+
+
+configure_logging()
+
+
+# For compatibility with old code written with Logbook in mind
+# TODO remove in v9
+def patch_notice_level(logger: logging.Logger) -> logging.Logger:
+ """Patch logger to issue WARNINGs with logger.notice."""
+ logger.notice = logger.warning
+ return logger
+
+
+# User-facing loggers
+def get_logger(name: str, handlers=None) -> logging.Logger:
+ """Get a logger with handlers attached."""
+ logger = logging.getLogger(name)
+ if handlers is not None:
+ for h in handlers:
+ logger.addHandler(h)
+ return patch_notice_level(logger)
+
+
+LOGGER = get_logger("Nikola")
+
+
+# Push warnings to logging
+def showwarning(message, category, filename, lineno, file=None, line=None):
+ """Show a warning (from the warnings module) to the user."""
+ try:
+ n = category.__name__
+ except AttributeError:
+ n = str(category)
+ get_logger(n).warning("{0}:{1}: {2}".format(filename, lineno, message))
+
+
+warnings.showwarning = showwarning