mirror of
https://github.com/kevingruesser/bootstrap-vz.git
synced 2025-08-22 09:50:37 +00:00
Refactor logging setup to be more modular
This commit is contained in:
parent
9d8821235f
commit
7fe9c1ba36
2 changed files with 77 additions and 54 deletions
|
@ -4,6 +4,48 @@ both to a file and to the console.
|
|||
import logging
|
||||
|
||||
|
||||
def get_console_handler(debug):
|
||||
"""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)
|
||||
:return: The console logging handler
|
||||
"""
|
||||
# Create a console log handler
|
||||
import sys
|
||||
console_handler = logging.StreamHandler(sys.stderr)
|
||||
# We want to colorize the output to the console, so we add a formatter
|
||||
console_handler.setFormatter(ConsoleFormatter())
|
||||
# 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
|
||||
|
@ -22,40 +64,6 @@ def get_log_filename(manifest_path):
|
|||
return filename
|
||||
|
||||
|
||||
def setup_logger(logfile=None, debug=False):
|
||||
"""Sets up the python logger to log to both a file and the console
|
||||
|
||||
:param str logfile: Path to a logfile
|
||||
:param bool debug: Whether to log debug output to the console
|
||||
"""
|
||||
root = logging.getLogger()
|
||||
# Make sure all logging statements are processed by our handlers, they decide the log level
|
||||
root.setLevel(logging.NOTSET)
|
||||
|
||||
# Only enable logging to file if a destination was supplied
|
||||
if logfile is not None:
|
||||
# Create a file log handler
|
||||
file_handler = logging.FileHandler(logfile)
|
||||
# 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)
|
||||
root.addHandler(file_handler)
|
||||
|
||||
# Create a console log handler
|
||||
import sys
|
||||
console_handler = logging.StreamHandler(sys.stderr)
|
||||
# We want to colorize the output to the console, so we add a formatter
|
||||
console_handler.setFormatter(ConsoleFormatter())
|
||||
# Set the log level depending on the debug argument
|
||||
if debug:
|
||||
console_handler.setLevel(logging.DEBUG)
|
||||
else:
|
||||
console_handler.setLevel(logging.INFO)
|
||||
root.addHandler(console_handler)
|
||||
|
||||
|
||||
class ConsoleFormatter(logging.Formatter):
|
||||
"""Formats log statements for the console
|
||||
"""
|
||||
|
|
|
@ -17,20 +17,14 @@ def main():
|
|||
if os.geteuid() != 0 and not opts['--dry-run']:
|
||||
raise Exception('This program requires root privileges.')
|
||||
|
||||
import log
|
||||
# Log to file unless --log is a single dash
|
||||
if opts['--log'] != '-':
|
||||
# Setup logging
|
||||
if not os.path.exists(opts['--log']):
|
||||
os.makedirs(opts['--log'])
|
||||
log_filename = log.get_log_filename(opts['MANIFEST'])
|
||||
logfile = os.path.join(opts['--log'], log_filename)
|
||||
else:
|
||||
logfile = None
|
||||
log.setup_logger(logfile=logfile, debug=opts['--debug'])
|
||||
# Set up logging
|
||||
setup_loggers(opts)
|
||||
|
||||
# Everything has been set up, begin the bootstrapping process
|
||||
run(opts)
|
||||
run(opts['MANIFEST'],
|
||||
debug=opts['--debug'],
|
||||
pause_on_error=opts['--pause-on-error'],
|
||||
dry_run=opts['--dry-run'])
|
||||
|
||||
|
||||
def get_opts():
|
||||
|
@ -49,18 +43,39 @@ Options:
|
|||
--debug Print debugging information
|
||||
-h, --help show this help
|
||||
"""
|
||||
opts = docopt(usage)
|
||||
return opts
|
||||
return docopt(usage)
|
||||
|
||||
|
||||
def run(opts):
|
||||
def setup_loggers(opts):
|
||||
"""Sets up the file and console loggers
|
||||
|
||||
:params dict opts: Dictionary of options from the commandline
|
||||
"""
|
||||
import logging
|
||||
root = logging.getLogger()
|
||||
root.setLevel(logging.NOTSET)
|
||||
|
||||
import log
|
||||
# Log to file unless --log is a single dash
|
||||
if opts['--log'] != '-':
|
||||
import os.path
|
||||
log_filename = log.get_log_filename(opts['MANIFEST'])
|
||||
logpath = os.path.join(opts['--log'], log_filename)
|
||||
file_handler = log.get_file_handler(path=logpath, debug=True)
|
||||
root.addHandler(file_handler)
|
||||
|
||||
console_handler = log.get_console_handler(debug=opts['--debug'])
|
||||
root.addHandler(console_handler)
|
||||
|
||||
|
||||
def run(manifest_path, debug=False, pause_on_error=False, dry_run=False):
|
||||
"""Runs the bootstrapping process
|
||||
|
||||
:params dict opts: Dictionary of options from the commandline
|
||||
"""
|
||||
# Load the manifest
|
||||
from manifest import Manifest
|
||||
manifest = Manifest(opts['MANIFEST'])
|
||||
manifest = Manifest(manifest_path)
|
||||
|
||||
# Get the tasklist
|
||||
from tasklist import load_tasks
|
||||
|
@ -71,18 +86,18 @@ def run(opts):
|
|||
|
||||
# Create the bootstrap information object that'll be used throughout the bootstrapping process
|
||||
from bootstrapinfo import BootstrapInformation
|
||||
bootstrap_info = BootstrapInformation(manifest=manifest, debug=opts['--debug'])
|
||||
bootstrap_info = BootstrapInformation(manifest=manifest, debug=debug)
|
||||
|
||||
try:
|
||||
# Run all the tasks the tasklist has gathered
|
||||
tasklist.run(info=bootstrap_info, dry_run=opts['--dry-run'])
|
||||
tasklist.run(info=bootstrap_info, dry_run=dry_run)
|
||||
# We're done! :-)
|
||||
log.info('Successfully completed bootstrapping')
|
||||
return bootstrap_info
|
||||
except (Exception, KeyboardInterrupt) as e:
|
||||
# When an error occurs, log it and begin rollback
|
||||
log.exception(e)
|
||||
if opts['--pause-on-error']:
|
||||
if pause_on_error:
|
||||
# The --pause-on-error is useful when the user wants to inspect the volume before rollback
|
||||
raw_input('Press Enter to commence rollback')
|
||||
log.error('Rolling back')
|
||||
|
@ -106,6 +121,6 @@ def run(opts):
|
|||
rollback_tasklist = TaskList(rollback_tasks)
|
||||
|
||||
# Run the rollback tasklist
|
||||
rollback_tasklist.run(info=bootstrap_info, dry_run=opts['--dry-run'])
|
||||
rollback_tasklist.run(info=bootstrap_info, dry_run=dry_run)
|
||||
log.info('Successfully completed rollback')
|
||||
raise e
|
||||
|
|
Loading…
Add table
Reference in a new issue