/usr/lib/python3/dist-packages/provisioningserver/logger/_common.py is in python3-maas-provisioningserver 2.4.0~beta2-6865-gec43e47e6-0ubuntu1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | # Copyright 2016 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Common parts of MAAS's logging machinery."""
__all__ = [
"DEFAULT_LOG_FORMAT",
"DEFAULT_LOG_FORMAT_DATE",
"DEFAULT_LOG_VERBOSITY",
"DEFAULT_LOG_VERBOSITY_LEVELS",
"get_module_for_file",
"LoggingMode",
"make_logging_level_names_consistent",
"warn_unless",
]
import enum
import functools
import logging
import sys
import time
# This format roughly matches Twisted's default, so that combined Twisted and
# Django logs are consistent with one another.
DEFAULT_LOG_FORMAT = "%(asctime)s %(name)s: [%(levelname)s] %(message)s"
DEFAULT_LOG_FORMAT_DATE = "%Y-%m-%d %H:%M:%S"
DEFAULT_LOG_VERBOSITY_LEVELS = {0, 1, 2, 3}
DEFAULT_LOG_VERBOSITY = 2
@enum.unique
class LoggingMode(enum.Enum):
"""The configuration mode for logging."""
# A command-line invocation: initialise the Twisted legacy logging system,
# but neither stdio nor warnings will be redirected.
COMMAND = "COMMAND"
# Running under `twistd`: the Twisted legacy logging system will be later
# initialised by `twistd`, and both stdio and warnings will be redirected
# to the log.
TWISTD = "TWISTD"
@classmethod
def guess(cls):
stdios = sys.stdin, sys.stdout, sys.stderr
if any(fd.isatty() for fd in stdios):
return cls.COMMAND # We're at the command-line.
else:
return cls.TWISTD # We're probably in `twistd`.
def make_logging_level_names_consistent():
"""Rename the standard library's logging levels to match Twisted's.
Twisted's new logging system in `twisted.logger` that is.
"""
for level in list(logging._levelToName):
if level == logging.NOTSET:
# When the logging level is not known in Twisted it's rendered as
# a hyphen. This is not a common occurrence with `logging` but we
# cater for it anyway.
name = "-"
elif level == logging.WARNING:
# "Warning" is more consistent with the other level names than
# "warn", so there is a fault in Twisted here. However it's easier
# to change the `logging` module to match Twisted than vice-versa.
name = "warn"
else:
# Twisted's level names are all lower-case.
name = logging.getLevelName(level).lower()
# For a preexisting level this will _replace_ the name.
logging.addLevelName(level, name)
@functools.lru_cache()
def get_module_for_file(filename):
"""Try to find the module from its file.
The module must already be loaded. If it's not found, `None` is returned.
"""
for module_name, module in sys.modules.items():
# Some modules, like `_imp`, do not have a `__file__` attribute.
if getattr(module, "__file__", None) == filename:
return module
else:
return None
def warn_unless(predicate, message):
"""Warn with `message` unless `predicate` is truthy.
This mimics the output of the intended final logging configuration, but
does so without using any existing logging system. It also prints to
`sys.__stdout__` rather than `sys.stdout` which may have been wrapped or
redirected. This makes it suitable for warning about failures when
configuring logging itself.
"""
if not predicate:
message = DEFAULT_LOG_FORMAT % dict(
asctime=time.strftime(DEFAULT_LOG_FORMAT_DATE, time.localtime()),
name="global", levelname="warn", message=message)
print(message, file=sys.__stdout__, flush=True)
def is_dev_environment():
"""Is this the development environment, or production?
Lazy import to avoid circular import issues.
"""
from provisioningserver.config import is_dev_environment
return is_dev_environment()
|