-
Notifications
You must be signed in to change notification settings - Fork 70
Add new logging structure. Fix cockpit. #565
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,41 +0,0 @@ | ||
| """ | ||
| Copyright 2015 Red Hat, Inc. | ||
|
|
||
| This file is part of Atomic App. | ||
|
|
||
| Atomic App is free software: you can redistribute it and/or modify | ||
| it under the terms of the GNU Lesser General Public License as published by | ||
| the Free Software Foundation, either version 3 of the License, or | ||
| (at your option) any later version. | ||
|
|
||
| Atomic App is distributed in the hope that it will be useful, | ||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| GNU Lesser General Public License for more details. | ||
|
|
||
| You should have received a copy of the GNU Lesser General Public License | ||
| along with Atomic App. If not, see <http://www.gnu.org/licenses/>. | ||
| """ | ||
|
|
||
| import logging | ||
|
|
||
|
|
||
| def set_logging(name="atomicapp", level=logging.DEBUG): | ||
| # create logger | ||
| logger = logging.getLogger() | ||
| logger.handlers = [] | ||
| logger.setLevel(level) | ||
|
|
||
| # create console handler | ||
| ch = logging.StreamHandler() | ||
|
|
||
| # create formatter | ||
| formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') | ||
|
|
||
| # add formatter to ch | ||
| ch.setFormatter(formatter) | ||
|
|
||
| # add ch to logger | ||
| logger.addHandler(ch) | ||
|
|
||
| set_logging(level=logging.DEBUG) # override this however you want | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,152 @@ | ||
| """ | ||
| Copyright 2015 Red Hat, Inc. | ||
|
|
||
| This file is part of Atomic App. | ||
|
|
||
| Atomic App is free software: you can redistribute it and/or modify | ||
| it under the terms of the GNU Lesser General Public License as published by | ||
| the Free Software Foundation, either version 3 of the License, or | ||
| (at your option) any later version. | ||
|
|
||
| Atomic App is distributed in the hope that it will be useful, | ||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| GNU Lesser General Public License for more details. | ||
|
|
||
| You should have received a copy of the GNU Lesser General Public License | ||
| along with Atomic App. If not, see <http://www.gnu.org/licenses/>. | ||
| """ | ||
|
|
||
| import sys | ||
| import logging | ||
|
|
||
| from atomicapp.constants import (LOGGER_COCKPIT, | ||
| LOGGER_DEFAULT) | ||
|
|
||
|
|
||
| class colorizeOutputFormatter(logging.Formatter): | ||
| """ | ||
| A class to colorize the log msgs based on log level | ||
| """ | ||
|
|
||
| def format(self, record): | ||
| # Call the parent class to do formatting. | ||
| msg = super(colorizeOutputFormatter, self).format(record) | ||
|
|
||
| # Now post process and colorize if needed | ||
| if record.levelno == logging.DEBUG: | ||
| msg = self._colorize(msg, 'cyan') | ||
| elif record.levelno == logging.WARNING: | ||
| msg = self._colorize(msg, 'yellow') | ||
| elif record.levelno == logging.INFO: | ||
| msg = self._colorize(msg, 'white') | ||
| elif record.levelno == logging.ERROR: | ||
| msg = self._colorize(msg, 'red') | ||
| else: | ||
| raise Exception("Invalid logging level {}".format(record.levelno)) | ||
| return self._make_unicode(msg) | ||
|
|
||
| def _colorize(self, text, color): | ||
| """ | ||
| Colorize based upon the color codes indicated. | ||
| """ | ||
| # Console color codes | ||
| colorCodes = { | ||
| 'white': '0', 'bright white': '1;37', | ||
| 'blue': '0;34', 'bright blue': '1;34', | ||
| 'green': '0;32', 'bright green': '1;32', | ||
| 'cyan': '0;36', 'bright cyan': '1;36', | ||
| 'red': '0;31', 'bright red': '1;31', | ||
| 'purple': '0;35', 'bright purple': '1;35', | ||
| 'yellow': '0;33', 'bright yellow': '1;33', | ||
| } | ||
| return "\033[" + colorCodes[color] + "m" + text + "\033[0m" | ||
|
|
||
| def _make_unicode(self, input): | ||
| """ | ||
| Convert all input to utf-8 for multi language support | ||
| """ | ||
| if type(input) != unicode: | ||
| input = input.decode('utf-8') | ||
| return input | ||
|
|
||
|
|
||
| class Logging: | ||
|
|
||
| @staticmethod | ||
| def setup_logging(verbose=None, quiet=None, logtype=None): | ||
| """ | ||
| This function sets up logging based on the logtype requested. | ||
| The 'none' level outputs no logs at all | ||
| The 'cockpit' level outputs just logs for the cockpit logger | ||
| The 'nocolor' level prints out normal log msgs (no cockpit) without color | ||
| The 'color' level prints out normal log msgs (no cockpit) with color | ||
| """ | ||
|
|
||
| # If no logtype was set then let's have a sane default | ||
| # If connected to a tty, then default to color, else, no color | ||
| if not logtype: | ||
| if sys.stdout.isatty(): | ||
| logtype = 'color' | ||
| else: | ||
| logtype = 'nocolor' | ||
|
|
||
| # Determine what logging level we should use | ||
| if verbose: | ||
| logging_level = logging.DEBUG | ||
| elif quiet: | ||
| logging_level = logging.WARNING | ||
| else: | ||
| logging_level = logging.INFO | ||
|
|
||
| # Get the loggers and clear out the handlers (allows this function | ||
| # to be ran more than once) | ||
| logger = logging.getLogger(LOGGER_DEFAULT) | ||
| logger.handlers = [] | ||
| cockpit_logger = logging.getLogger(LOGGER_COCKPIT) | ||
| cockpit_logger.handlers = [] | ||
|
|
||
| if logtype == 'none': | ||
| # blank out both loggers | ||
| logger.addHandler(logging.NullHandler()) | ||
| cockpit_logger.addHandler(logging.NullHandler()) | ||
| return | ||
|
|
||
| if logtype == 'cockpit': | ||
| # blank out normal log messages | ||
| logger.addHandler(logging.NullHandler()) | ||
|
|
||
| # configure cockpit logger | ||
| handler = logging.StreamHandler(stream=sys.stdout) | ||
| formatter = logging.Formatter('atomicapp.status.%(levelname)s.message=%(message)s') | ||
| handler.setFormatter(formatter) | ||
| cockpit_logger.addHandler(handler) | ||
| cockpit_logger.setLevel(logging_level) | ||
| return | ||
|
|
||
| if logtype == 'nocolor': | ||
| # blank out cockpit log messages | ||
| cockpit_logger.addHandler(logging.NullHandler()) | ||
|
|
||
| # configure logger for basic no color printing to stdout | ||
| handler = logging.StreamHandler(stream=sys.stdout) | ||
| formatter = logging.Formatter('%(asctime)s - [%(levelname)s] - %(filename)s - %(message)s') | ||
| handler.setFormatter(formatter) | ||
| logger.addHandler(handler) | ||
| logger.setLevel(logging_level) | ||
| return | ||
|
|
||
| if logtype == 'color': | ||
| # blank out cockpit log messages | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do we not need to add
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no, it gets created befores these if statements. It was a mistake to have |
||
| cockpit_logger.addHandler(logging.NullHandler()) | ||
|
|
||
| # configure logger for color printing to stdout | ||
| handler = logging.StreamHandler(stream=sys.stdout) | ||
| formatter = colorizeOutputFormatter('%(asctime)s - [%(levelname)s] - %(filename)s - %(message)s') | ||
| handler.setFormatter(formatter) | ||
| logger.addHandler(handler) | ||
| logger.setLevel(logging_level) | ||
| return | ||
|
|
||
| # If we made it here then there is an error | ||
| raise Exception("Invalid logging output type: {}".format(logtype)) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -25,7 +25,7 @@ | |
| from lockfile import LockFile | ||
| from lockfile import AlreadyLocked | ||
|
|
||
| from atomicapp import set_logging | ||
| from atomicapp.applogging import Logging | ||
| from atomicapp.constants import (__ATOMICAPPVERSION__, | ||
| __NULECULESPECVERSION__, | ||
| ANSWERS_FILE, | ||
|
|
@@ -34,12 +34,13 @@ | |
| CACHE_DIR, | ||
| HOST_DIR, | ||
| LOCK_FILE, | ||
| LOGGER_DEFAULT, | ||
| PROVIDERS) | ||
| from atomicapp.nulecule import NuleculeManager | ||
| from atomicapp.nulecule.exceptions import NuleculeException | ||
| from atomicapp.utils import Utils | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
| logger = logging.getLogger(LOGGER_DEFAULT) | ||
|
|
||
|
|
||
| def print_app_location(app_path): | ||
|
|
@@ -218,7 +219,7 @@ def create_parser(self): | |
| action="store_true", | ||
| help=( | ||
| "Don't actually call provider. The commands that should be " | ||
| "run will be sent to stdout but not run.")) | ||
| "run will be logged but not run.")) | ||
| globals_parser.add_argument( | ||
| "--answers-format", | ||
| dest="answers_format", | ||
|
|
@@ -249,6 +250,18 @@ def create_parser(self): | |
| "--providerapi", | ||
| dest="providerapi", | ||
| help='Value for providerapi answers option.') | ||
| globals_parser.add_argument( | ||
| "--logtype", | ||
| dest="logtype", | ||
| choices=['cockpit', 'color', 'nocolor', 'none'], | ||
| help=""" | ||
| Override the default logging output. The options are: | ||
| nocolor: we will only log to stdout; | ||
| color: log to stdout with color; | ||
| cockpit: used with cockpit integration; | ||
| none: atomicapp will disable any logging. | ||
| If nothing is set and logging to file then 'nocolor' by default. | ||
| If nothing is set and logging to tty then 'color' by default.""") | ||
|
|
||
| # === "run" SUBPARSER === | ||
| run_subparser = toplevel_subparsers.add_parser( | ||
|
|
@@ -367,6 +380,9 @@ def create_parser(self): | |
| def run(self): | ||
| cmdline = sys.argv[1:] # Grab args from cmdline | ||
|
|
||
| # Initial setup of logging (to allow for a few early debug statements) | ||
| Logging.setup_logging(verbose=True, quiet=False) | ||
|
|
||
| # If we are running in an openshift pod (via `oc new-app`) then | ||
| # there is no cmdline but we want to default to "atomicapp run". | ||
| if Utils.running_on_openshift(): | ||
|
|
@@ -399,11 +415,15 @@ def run(self): | |
| if args.mode: | ||
| args.action = args.mode # Allow mode to override 'action' | ||
| cmdline.insert(0, args.action) # Place 'action' at front | ||
| logger.info("Action/Mode Selected is: %s" % args.action) | ||
|
|
||
| # Finally, parse args and give error if necessary | ||
| args = self.parser.parse_args(cmdline) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this needs to be moved up before setup_logging, passing
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think I see what you are saying now. You are saying that
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Moving it down did make the test pass. Now just need to figure out what part of my logic is flawed in the first part.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @dustymabe Yeah, I'm not able to receive any debug information at all by passing -v or --verbose |
||
|
|
||
| # Setup logging (now with arguments from cmdline) and log a few msgs | ||
| Logging.setup_logging(args.verbose, args.quiet, args.logtype) | ||
| logger.info("Action/Mode Selected is: %s" % args.action) | ||
| logger.debug("Final parsed cmdline: {}".format(' '.join(cmdline))) | ||
|
|
||
| # In the case of Atomic CLI we want to allow the user to specify | ||
| # a directory if they want to for "run". For that reason we won't | ||
| # default the RUN label for Atomic App to provide an app_spec argument. | ||
|
|
@@ -425,17 +445,6 @@ def run(self): | |
| if hasattr(args, item) and getattr(args, item) is not None: | ||
| args.cli_answers[item] = getattr(args, item) | ||
|
|
||
| # Set logging level | ||
| if args.verbose: | ||
| set_logging(level=logging.DEBUG) | ||
| elif args.quiet: | ||
| set_logging(level=logging.WARNING) | ||
| else: | ||
| set_logging(level=logging.INFO) | ||
|
|
||
| # Now that we have set the logging level let's print out the cmdline | ||
| logger.debug("Final parsed cmdline: {}".format(' '.join(cmdline))) | ||
|
|
||
| lock = LockFile(os.path.join(Utils.getRoot(), LOCK_FILE)) | ||
| try: | ||
| lock.acquire(timeout=-1) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 for this code