diff options
Diffstat (limited to 'collectors/python.d.plugin/python_modules/bases/loggers.py')
-rw-r--r-- | collectors/python.d.plugin/python_modules/bases/loggers.py | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/collectors/python.d.plugin/python_modules/bases/loggers.py b/collectors/python.d.plugin/python_modules/bases/loggers.py new file mode 100644 index 00000000..7ae8ab0c --- /dev/null +++ b/collectors/python.d.plugin/python_modules/bases/loggers.py @@ -0,0 +1,198 @@ +# -*- coding: utf-8 -*- +# Description: +# Author: Ilya Mashchenko (ilyam8) +# SPDX-License-Identifier: GPL-3.0-or-later + +import logging +import os +import stat +import traceback + +from sys import exc_info + +try: + from time import monotonic as time +except ImportError: + from time import time + +from bases.collection import on_try_except_finally, unicode_str + +LOGGING_LEVELS = { + 'CRITICAL': 50, + 'ERROR': 40, + 'WARNING': 30, + 'INFO': 20, + 'DEBUG': 10, + 'NOTSET': 0, +} + + +def is_stderr_connected_to_journal(): + journal_stream = os.environ.get("JOURNAL_STREAM") + if not journal_stream: + return False + + colon_index = journal_stream.find(":") + if colon_index <= 0: + return False + + device, inode = journal_stream[:colon_index], journal_stream[colon_index + 1:] + + try: + device_number, inode_number = os.fstat(2)[stat.ST_DEV], os.fstat(2)[stat.ST_INO] + except OSError: + return False + + return str(device_number) == device and str(inode_number) == inode + + +is_journal = is_stderr_connected_to_journal() + +DEFAULT_LOG_LINE_FORMAT = '%(asctime)s: %(name)s %(levelname)s : %(message)s' +PYTHON_D_LOG_LINE_FORMAT = '%(asctime)s: %(name)s %(levelname)s: %(module_name)s[%(job_name)s] : %(message)s' + +if is_journal: + DEFAULT_LOG_LINE_FORMAT = '%(name)s %(levelname)s : %(message)s' + PYTHON_D_LOG_LINE_FORMAT = '%(name)s %(levelname)s: %(module_name)s[%(job_name)s] : %(message)s ' + +DEFAULT_LOG_TIME_FORMAT = '%Y-%m-%d %H:%M:%S' +PYTHON_D_LOG_NAME = 'python.d' + + +def add_traceback(func): + def on_call(*args): + self = args[0] + + if not self.log_traceback: + func(*args) + else: + if exc_info()[0]: + func(*args) + func(self, traceback.format_exc()) + else: + func(*args) + + return on_call + + +class BaseLogger(object): + def __init__( + self, + logger_name, + log_fmt=DEFAULT_LOG_LINE_FORMAT, + date_fmt=DEFAULT_LOG_TIME_FORMAT, + handler=logging.StreamHandler, + ): + self.logger = logging.getLogger(logger_name) + self._muted = False + if not self.has_handlers(): + self.severity = 'INFO' + self.logger.addHandler(handler()) + self.set_formatter(fmt=log_fmt, date_fmt=date_fmt) + + def __repr__(self): + return '<Logger: {name})>'.format(name=self.logger.name) + + def set_formatter(self, fmt, date_fmt=DEFAULT_LOG_TIME_FORMAT): + if self.has_handlers(): + self.logger.handlers[0].setFormatter(logging.Formatter(fmt=fmt, datefmt=date_fmt)) + + def has_handlers(self): + return self.logger.handlers + + @property + def severity(self): + return self.logger.getEffectiveLevel() + + @severity.setter + def severity(self, level): + if level in LOGGING_LEVELS: + self.logger.setLevel(LOGGING_LEVELS[level]) + + def _log(self, level, *msg, **kwargs): + if not self._muted: + self.logger.log(level, ' '.join(map(unicode_str, msg)), **kwargs) + + def debug(self, *msg, **kwargs): + self._log(logging.DEBUG, *msg, **kwargs) + + def info(self, *msg, **kwargs): + self._log(logging.INFO, *msg, **kwargs) + + def warning(self, *msg, **kwargs): + self._log(logging.WARN, *msg, **kwargs) + + def error(self, *msg, **kwargs): + self._log(logging.ERROR, *msg, **kwargs) + + def alert(self, *msg, **kwargs): + self._log(logging.CRITICAL, *msg, **kwargs) + + @on_try_except_finally(on_finally=(exit, 1)) + def fatal(self, *msg, **kwargs): + self._log(logging.CRITICAL, *msg, **kwargs) + + def mute(self): + self._muted = True + + def unmute(self): + self._muted = False + + +class PythonDLogger(object): + def __init__( + self, + logger_name=PYTHON_D_LOG_NAME, + log_fmt=PYTHON_D_LOG_LINE_FORMAT, + ): + self.logger = BaseLogger(logger_name, log_fmt=log_fmt) + self.module_name = 'plugin' + self.job_name = 'main' + + _LOG_TRACEBACK = False + + @property + def log_traceback(self): + return PythonDLogger._LOG_TRACEBACK + + @log_traceback.setter + def log_traceback(self, value): + PythonDLogger._LOG_TRACEBACK = value + + def debug(self, *msg): + self.logger.debug(*msg, extra={ + 'module_name': self.module_name, + 'job_name': self.job_name or self.module_name, + }) + + def info(self, *msg): + self.logger.info(*msg, extra={ + 'module_name': self.module_name, + 'job_name': self.job_name or self.module_name, + }) + + def warning(self, *msg): + self.logger.warning(*msg, extra={ + 'module_name': self.module_name, + 'job_name': self.job_name or self.module_name, + }) + + @add_traceback + def error(self, *msg): + self.logger.error(*msg, extra={ + 'module_name': self.module_name, + 'job_name': self.job_name or self.module_name, + }) + + @add_traceback + def alert(self, *msg): + self.logger.alert(*msg, extra={ + 'module_name': self.module_name, + 'job_name': self.job_name or self.module_name, + }) + + def fatal(self, *msg): + self.logger.fatal(*msg, extra={ + 'module_name': self.module_name, + 'job_name': self.job_name or self.module_name, + }) |