Merge pull request #5541 from pradyunsg/refactor/logging

Refactor the logging setup into a separate function and cleanup
This commit is contained in:
Pradyun Gedam 2018-07-16 12:07:40 +05:30 committed by GitHub
commit f77a63faa9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 105 additions and 90 deletions

View File

@ -24,7 +24,7 @@ from pip._internal.status_codes import (
ERROR, PREVIOUS_BUILD_DIR_ERROR, SUCCESS, UNKNOWN_ERROR,
VIRTUALENV_NOT_FOUND,
)
from pip._internal.utils.logging import IndentingFormatter
from pip._internal.utils.logging import setup_logging
from pip._internal.utils.misc import get_prog, normalize_path
from pip._internal.utils.outdated import pip_version_check
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
@ -42,7 +42,6 @@ class Command(object):
usage = None # type: Optional[str]
hidden = False # type: bool
ignore_require_venv = False # type: bool
log_streams = ("ext://sys.stdout", "ext://sys.stderr")
def __init__(self, isolated=False):
parser_kw = {
@ -114,89 +113,15 @@ class Command(object):
# Set verbosity so that it can be used elsewhere.
self.verbosity = options.verbose - options.quiet
if self.verbosity >= 1:
level = "DEBUG"
elif self.verbosity == -1:
level = "WARNING"
elif self.verbosity == -2:
level = "ERROR"
elif self.verbosity <= -3:
level = "CRITICAL"
else:
level = "INFO"
setup_logging(
verbosity=self.verbosity,
no_color=options.no_color,
user_log_file=options.log,
)
# The root logger should match the "console" level *unless* we
# specified "--log" to send debug logs to a file.
root_level = level
if options.log:
root_level = "DEBUG"
logger_class = "pip._internal.utils.logging.ColorizedStreamHandler"
handler_class = "pip._internal.utils.logging.BetterRotatingFileHandler"
logging.config.dictConfig({
"version": 1,
"disable_existing_loggers": False,
"filters": {
"exclude_warnings": {
"()": "pip._internal.utils.logging.MaxLevelFilter",
"level": logging.WARNING,
},
},
"formatters": {
"indent": {
"()": IndentingFormatter,
"format": "%(message)s",
},
},
"handlers": {
"console": {
"level": level,
"class": logger_class,
"no_color": options.no_color,
"stream": self.log_streams[0],
"filters": ["exclude_warnings"],
"formatter": "indent",
},
"console_errors": {
"level": "WARNING",
"class": logger_class,
"no_color": options.no_color,
"stream": self.log_streams[1],
"formatter": "indent",
},
"user_log": {
"level": "DEBUG",
"class": handler_class,
"filename": options.log or "/dev/null",
"delay": True,
"formatter": "indent",
},
},
"root": {
"level": root_level,
"handlers": list(filter(None, [
"console",
"console_errors",
"user_log" if options.log else None,
])),
},
# Disable any logging besides WARNING unless we have DEBUG level
# logging enabled. These use both pip._vendor and the bare names
# for the case where someone unbundles our libraries.
"loggers": {
name: {
"level": (
"WARNING" if level in ["INFO", "ERROR"] else "DEBUG"
)
} for name in [
"pip._vendor", "distlib", "requests", "urllib3"
]
},
})
# TODO: try to get these passing down from the command?
# without resorting to os.environ to hold these.
# TODO: Try to get these passing down from the command?
# without resorting to os.environ to hold these.
# This also affects isolated builds and it should.
if options.no_input:
os.environ['PIP_NO_INPUT'] = '1'
@ -212,8 +137,6 @@ class Command(object):
)
sys.exit(VIRTUALENV_NOT_FOUND)
original_root_handlers = set(logging.root.handlers)
try:
status = self.run(options, args)
# FIXME: all commands should return an exit status
@ -258,10 +181,9 @@ class Command(object):
)
with session:
pip_version_check(session, options)
# Avoid leaking loggers
for handler in set(logging.root.handlers) - original_root_handlers:
# this method benefit from the Logger class internal lock
logging.root.removeHandler(handler)
# Shutdown the logging module
logging.shutdown()
return SUCCESS

View File

@ -130,3 +130,96 @@ class MaxLevelFilter(logging.Filter):
def filter(self, record):
return record.levelno < self.level
def setup_logging(verbosity, no_color, user_log_file):
"""Configures and sets up all of the logging
"""
# Determine the level to be logging at.
if verbosity >= 1:
level = "DEBUG"
elif verbosity == -1:
level = "WARNING"
elif verbosity == -2:
level = "ERROR"
elif verbosity <= -3:
level = "CRITICAL"
else:
level = "INFO"
# The "root" logger should match the "console" level *unless* we also need
# to log to a user log file.
include_user_log = user_log_file is not None
if include_user_log:
additional_log_file = user_log_file
root_level = "DEBUG"
else:
additional_log_file = "/dev/null"
root_level = level
# Disable any logging besides WARNING unless we have DEBUG level logging
# enabled for vendored libraries.
vendored_log_level = "WARNING" if level in ["INFO", "ERROR"] else "DEBUG"
# Shorthands for clarity
log_streams = {
"stdout": "ext://sys.stdout",
"stderr": "ext://sys.stderr",
}
handler_classes = {
"stream": "pip._internal.utils.logging.ColorizedStreamHandler",
"file": "pip._internal.utils.logging.BetterRotatingFileHandler",
}
logging.config.dictConfig({
"version": 1,
"disable_existing_loggers": False,
"filters": {
"exclude_warnings": {
"()": "pip._internal.utils.logging.MaxLevelFilter",
"level": logging.WARNING,
},
},
"formatters": {
"indent": {
"()": IndentingFormatter,
"format": "%(message)s",
},
},
"handlers": {
"console": {
"level": level,
"class": handler_classes["stream"],
"no_color": no_color,
"stream": log_streams["stdout"],
"filters": ["exclude_warnings"],
"formatter": "indent",
},
"console_errors": {
"level": "WARNING",
"class": handler_classes["stream"],
"no_color": no_color,
"stream": log_streams["stderr"],
"formatter": "indent",
},
"user_log": {
"level": "DEBUG",
"class": handler_classes["file"],
"filename": additional_log_file,
"delay": True,
"formatter": "indent",
},
},
"root": {
"level": root_level,
"handlers": ["console", "console_errors"] + (
["user_log"] if include_user_log else []
),
},
"loggers": {
"pip._vendor": {
"level": vendored_log_level
}
},
})