Skip to content

Commit

Permalink
Logging
Browse files Browse the repository at this point in the history
  • Loading branch information
Suszyński Krzysztof committed Jul 10, 2017
1 parent 8ae340b commit 32b61d4
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 19 deletions.
12 changes: 12 additions & 0 deletions puppeter/__init__.py
@@ -1,7 +1,19 @@
import logging

# The version of the app
__version__ = '0.1.0.dev0'
__program__ = 'puppeter'


def get_logger(cls):
name = __fullname(cls)
return logging.getLogger(name)


def __fullname(cls):
return cls.__module__ + "." + cls.__name__


if __name__ == '__main__':
from puppeter.main import main
main()
17 changes: 9 additions & 8 deletions puppeter/main.py
Expand Up @@ -5,6 +5,15 @@
from puppeter import __program__
from puppeter.presentation.cmdparser import CommandLineParser


def main(argv=sys.argv):
"""Entry point for the puppeter application"""
__load_modules(__program__)
parser = CommandLineParser(argv)
app = parser.parse()
app.run()


__ROOT_DIR = dirname(dirname(__file__))


Expand All @@ -24,11 +33,3 @@ def __load_modules(module_name):
# load the modules
for module_name_to_import in modules:
__import__(module_name_to_import)


def main(argv=sys.argv):
"""Entry point for the puppeter application"""
__load_modules(__program__)
parser = CommandLineParser(argv)
app = parser.parse()
app.run()
3 changes: 3 additions & 0 deletions puppeter/persistence/gateway/answers.py
@@ -1,3 +1,4 @@
import puppeter
from puppeter import container
from puppeter.domain.model.installer import Installer
from puppeter.domain.model.answers import Answers
Expand All @@ -17,6 +18,8 @@ def write_answers_to_file(self, answers, file):

def read_answers_from_file(self, file):
code = ruamel.yaml.load(file.read(), ruamel.yaml.RoundTripLoader)
log = puppeter.get_logger(YamlAnswersGateway)
log.debug("Answers loaded from file: %s", code)
installer = self.__load_installer(code['installer'])
return Answers(
installer=installer
Expand Down
94 changes: 94 additions & 0 deletions puppeter/presentation/app.py
@@ -0,0 +1,94 @@
import logging
import os
import sys
from logging import StreamHandler
from logging.handlers import SysLogHandler

import puppeter
from puppeter.domain.model.os import OsFamily
from puppeter.persistence.os import Facter


class App:

def __init__(self, parsed):
self._parsed = parsed

def run(self):
root = logging.getLogger()
level = self.__get_log_level(self._parsed.verbose)
root.setLevel(level)
handlers = (self.__syslog_handler(), self.__stderr_handler())
for hndl in handlers:
root.addHandler(hndl)

@staticmethod
def __stderr_handler():
handler = StreamHandler(stream=sys.stderr)
fmt = '%(levelname)s: %(message)s'
handler.setFormatter(ColoredFormatter(fmt=fmt))
handler.setLevel(logging.NOTSET)
return handler

@staticmethod
def __syslog_handler():
osfamily = Facter.get(OsFamily)
if osfamily in (OsFamily.Debian, OsFamily.RedHat, OsFamily.Suse):
handler = SysLogHandler(address='/dev/log')
else:
handler = SysLogHandler()
fmt = puppeter.__program__ + '[%(process)d]: %(levelname)s %(name)s - %(message)s'
handler.setFormatter(logging.Formatter(fmt=fmt))
handler.setLevel(logging.INFO)
return handler

@staticmethod
def __get_log_level(verbosity):
if verbosity is None:
verbosity = 0
if verbosity > 2:
verbosity = 2
levels = {
0: logging.WARNING,
1: logging.INFO,
2: logging.DEBUG
}
return levels[verbosity]


def color_code(fg, bg=None):
if bg is not None:
return FGBG_COLOR_SEQ % (fg, bg)
else:
return FG_COLOR_SEQ % fg


RESET_SEQ = "\033[0m"
FG_COLOR_SEQ = "\033[38;5;%dm"
FGBG_COLOR_SEQ = "\033[38;5;%d;48;5;%dm"
# ref: https://unix.stackexchange.com/a/124409/145501
COLORS = {
'WARNING': color_code(fg=226),
'INFO': color_code(fg=155),
'DEBUG': color_code(fg=244),
'CRITICAL': color_code(fg=219, bg=196),
'ERROR': color_code(fg=196)
}
try:
SUPPORTS_256_COLORS = os.environ['XTERM_256_COLORS'] == '1'
except KeyError:
SUPPORTS_256_COLORS = False


class ColoredFormatter(logging.Formatter):

def __init__(self, fmt, use_color=SUPPORTS_256_COLORS):
logging.Formatter.__init__(self, fmt=fmt)
self.use_color = use_color

def format(self, record):
formatted = logging.Formatter.format(self, record)
levelname = record.levelname
if self.use_color and levelname in COLORS:
formatted = COLORS[levelname] + formatted + RESET_SEQ
return formatted
2 changes: 1 addition & 1 deletion puppeter/presentation/cmdparser.py
Expand Up @@ -52,7 +52,7 @@ def parse(self):
metavar='FILE',
help='An answer file to be used to perform unattended setup')
parser.add_argument('--verbose', '-v', action='count',
help='Print more verbose output (up to 3 verbosity flags are supported)')
help='Print more verbose output (up to 2 verbosity flags are supported)')
parser.add_argument('--version', action=_VersionAction, version='%(prog)s ' + puppeter.__version__)
parser.add_argument('--execute', '-e', action='store_true',
help='Executes setup commands instead of printing them')
Expand Down
31 changes: 21 additions & 10 deletions puppeter/presentation/unattendedapp.py
@@ -1,17 +1,28 @@
from puppeter.domain.gateway.answers import AnswersGateway
import puppeter
from puppeter import container
from pprint import pprint
from puppeter.domain.model.answers import Answers # NOQA
from puppeter.domain.gateway.answers import AnswersGateway
from puppeter.presentation.app import App


class UnattendedApp:
class UnattendedApp(App):
def __init__(self, parsed):
self.__parsed = parsed
App.__init__(self, parsed)
self.__log = puppeter.get_logger(UnattendedApp)

def run(self):
file = self.__parsed.answers
answers = self.__gw().read_answers_from_file(file)
pprint(answers)
App.run(self)
file = self._parsed.answers
answers = self.__load_answers(container.get(AnswersGateway), file)
if self._parsed.execute:
self.__log.warning('Installation will be performed from answer file:'
' %s. System will be altered!!!', file.name)
else:
self.__log.info('Installation commands will be generated based on answers file'
' %s and printed out. System will NOT be altered.', file.name)
self.__log.debug(answers)

def __gw(self):
# type: () -> AnswersGateway
return container.get(AnswersGateway)
@staticmethod
def __load_answers(gateway, file):
# type: (AnswersGateway, file) -> Answers
return gateway.read_answers_from_file(file)

0 comments on commit 32b61d4

Please sign in to comment.