bootstrap-vz/bootstrapvz/base/log.py
Anders Ingemann f62c8ade99 Convert indentation from tabs to spaces (4)
Up until now I didn't see the point of using spaces for indentation.
However, the previous commit (a18bec3) was quite eye opening.
Given that python is an indentation aware language, the amount of
mistakes that went unnoticed because tabs and spaces were used
at the same time (tabs for indentation and spaces for alignment)
were unacceptable.

E101,W191 have been re-enable in the tox flake8 checker and
the documentation has been modified accordingly.

The following files have been left as-is:
* bootstrapvz/common/assets/extlinux/extlinux.conf
* bootstrapvz/common/assets/init.d/expand-root
* bootstrapvz/common/assets/init.d/generate-ssh-hostkeys
* bootstrapvz/common/assets/init.d/squeeze/generate-ssh-hostkeys
* bootstrapvz/plugins/docker_daemon/assets/init.d/docker
* bootstrapvz/providers/ec2/assets/bin/growpart
* bootstrapvz/providers/ec2/assets/grub.d/40_custom
* bootstrapvz/providers/ec2/assets/init.d/ec2-get-credentials
* bootstrapvz/providers/ec2/assets/init.d/ec2-run-user-data
* docs/_static/taskoverview.coffee
* docs/_static/taskoverview.less
* tests/unit/subprocess.sh
2016-06-04 11:38:16 +02:00

104 lines
3.8 KiB
Python

"""This module holds functions and classes responsible for formatting the log output
both to a file and to the console.
"""
import logging
def get_console_handler(debug, colorize):
"""Returns a log handler for the console
The handler color codes the different log levels
:params bool debug: Whether to set the log level to DEBUG (otherwise INFO)
:params bool colorize: Whether to colorize console output
:return: The console logging handler
"""
# Create a console log handler
import sys
console_handler = logging.StreamHandler(sys.stderr)
if colorize:
# We want to colorize the output to the console, so we add a formatter
console_handler.setFormatter(ColorFormatter())
# Set the log level depending on the debug argument
if debug:
console_handler.setLevel(logging.DEBUG)
else:
console_handler.setLevel(logging.INFO)
return console_handler
def get_file_handler(path, debug):
"""Returns a log handler for the given path
If the parent directory of the logpath does not exist it will be created
The handler outputs relative timestamps (to when it was created)
:params str path: The full path to the logfile
:params bool debug: Whether to set the log level to DEBUG (otherwise INFO)
:return: The file logging handler
"""
import os.path
if not os.path.exists(os.path.dirname(path)):
os.makedirs(os.path.dirname(path))
# Create the log handler
file_handler = logging.FileHandler(path)
# Absolute timestamps are rather useless when bootstrapping, it's much more interesting
# to see how long things take, so we log in a relative format instead
file_handler.setFormatter(FileFormatter('[%(relativeCreated)s] %(levelname)s: %(message)s'))
# The file log handler always logs everything
file_handler.setLevel(logging.DEBUG)
return file_handler
def get_log_filename(manifest_path):
"""Returns the path to a logfile given a manifest
The logfile name is constructed from the current timestamp and the basename of the manifest
:param str manifest_path: The path to the manifest
:return: The path to the logfile
:rtype: str
"""
import os.path
from datetime import datetime
manifest_basename = os.path.basename(manifest_path)
manifest_name, _ = os.path.splitext(manifest_basename)
timestamp = datetime.now().strftime('%Y%m%d%H%M%S')
filename = '{timestamp}_{name}.log'.format(timestamp=timestamp, name=manifest_name)
return filename
class SourceFormatter(logging.Formatter):
"""Adds a [source] tag to the log message if it exists
The python docs suggest using a LoggingAdapter, but that would mean we'd
have to use it everywhere we log something (and only when called remotely),
which is not feasible.
"""
def format(self, record):
extra = getattr(record, 'extra', {})
if 'source' in extra:
record.msg = '[{source}] {message}'.format(source=record.extra['source'],
message=record.msg)
return super(SourceFormatter, self).format(record)
class ColorFormatter(SourceFormatter):
"""Colorizes log messages depending on the loglevel
"""
level_colors = {logging.ERROR: 'red',
logging.WARNING: 'magenta',
logging.INFO: 'blue',
}
def format(self, record):
# Colorize the message if we have a color for it (DEBUG has no color)
from termcolor import colored
record.msg = colored(record.msg, self.level_colors.get(record.levelno, None))
return super(ColorFormatter, self).format(record)
class FileFormatter(SourceFormatter):
"""Formats log statements for output to file
Currently this is just a stub
"""
def format(self, record):
return super(FileFormatter, self).format(record)