From dbb0e2309177161349f707aca50e5be2baa2f5d2 Mon Sep 17 00:00:00 2001 From: Johannes Findeisen Date: Thu, 29 Sep 2022 02:59:40 +0200 Subject: [PATCH] Added file logging and a new parameter (-s) for logging to stdout. --- bin/linspector | 56 +++++++++++++++++++++++++++----- etc/linspector.conf | 3 +- linspector/core/configuration.py | 3 +- linspector/core/linspector.py | 2 ++ linspector/core/linspectord.py | 20 +++++++----- 5 files changed, 66 insertions(+), 18 deletions(-) diff --git a/bin/linspector b/bin/linspector index 0577162..b431e32 100755 --- a/bin/linspector +++ b/bin/linspector @@ -22,19 +22,20 @@ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ import argparse +import logging +import logging.handlers +import os import sys -from logging import getLogger - from linspector.core.configuration import Configuration from linspector.core.environment import Environment from linspector.core.linspector import Linspector from linspector.core.monitors import Monitors -__version__ = '0.18' +__version__ = '0.18.1' __author__ = 'Johannes Findeisen ' -logger = getLogger('linspector') +logger = logging.getLogger('linspector') def parse_args(): @@ -57,6 +58,9 @@ def parse_args(): parser.add_argument('-r', '--restart', default=False, dest='restart', action='store_true', help='restart the daemon if it is running(default: false)') + parser.add_argument('-s', '--stdout', default=False, dest='stdout', action='store_true', + help='log to stdout') + parser.add_argument('-v', '--version', action='version', version='%(prog)s ' + str(__version__)) return parser.parse_args() @@ -64,7 +68,6 @@ def parse_args(): def main(): args = parse_args() - environment = Environment() monitors = None notifications = {} @@ -72,13 +75,50 @@ def main(): services = {} tasks = {} + if args.stdout: + # setting pre initialization default log level to INFO. this changes after initialization + # of the configuration. maybe there are better solutions...? + logger.setLevel(logging.INFO) + stdout_formatter = logging.Formatter('[%(asctime)s] [%(levelname)s] %(message)s') + stdout_handler = logging.StreamHandler(sys.stdout) + stdout_handler.setFormatter(stdout_formatter) + logger.addHandler(stdout_handler) + try: configuration = Configuration(args.configuration_path, environment) #configuration.dump_to_ini() except Exception as err: - logger.error('[linspector] configuration error: {0}'.format(err)) + logger.critical('[linspector] configuration error: {0}'.format(err)) sys.exit(1) + if configuration.get_option('linspector', 'log_file'): + log_file = os.path.expanduser(configuration.get_option('linspector', 'log_file')) + if not os.path.exists(os.path.dirname(log_file)): + os.makedirs(os.path.dirname(log_file)) + + log_file_formatter = logging.Formatter('%(asctime)s:%(levelname)s:%(name)s:%(message)s') + log_file_handler = logging.handlers.RotatingFileHandler(log_file, + maxBytes=int( + configuration.get_option( + 'linspector', 'log_size')), + backupCount=int( + configuration.get_option( + 'linspector', 'log_count'))) + log_file_handler.setFormatter(log_file_formatter) + logger.addHandler(log_file_handler) + + # critical errors will always show up even when no log_level is set. this is most silent. + logger.setLevel(logging.CRITICAL) + log_level = configuration.get_option('linspector', 'log_level') + if log_level == "error": + logger.setLevel(logging.ERROR) + elif log_level == "warning": + logger.setLevel(logging.WARNING) + elif log_level == "info": + logger.setLevel(logging.INFO) + elif log_level == "debug": + logger.setLevel(logging.DEBUG) + try: monitors = Monitors(configuration, environment, notifications, services, tasks) except Exception as err: @@ -87,7 +127,7 @@ def main(): try: linspector = Linspector(configuration, environment, monitors, plugins) except Exception as err: - logger.error('[linspector] core initialization error: {0}'.format(err)) + logger.critical('[linspector] core initialization error: {0}'.format(err)) sys.exit(1) # daemon initialization @@ -103,7 +143,7 @@ def main(): else: linspectord.start() except Exception as err: - logger.error('[linspector] daemon initialization error: {0}'.format(err)) + logger.critical('[linspector] daemon error: {0}'.format(err)) sys.exit(1) diff --git a/etc/linspector.conf b/etc/linspector.conf index f661a25..227eee3 100644 --- a/etc/linspector.conf +++ b/etc/linspector.conf @@ -3,7 +3,8 @@ ; report core errors to the following users error_receivers = admin@example.com log_file = ~/code/linspector/log/linspector.log -log_level= verbose +; available log levels are: "error", "warning", "info" and "debug". +log_level= debug log_count = 5 log_size = 10485760 pid_file = /var/run/user/1000/linspector.pid diff --git a/linspector/core/configuration.py b/linspector/core/configuration.py index 0651253..4b59961 100644 --- a/linspector/core/configuration.py +++ b/linspector/core/configuration.py @@ -21,6 +21,7 @@ class Configuration: self.__configuration_path = configuration_path self.__environment = environment + logger.info('reading configuration file: ' + configuration_path + '/linspector.conf') if os.path.isfile(configuration_path + '/linspector.conf'): try: self.__configuration.read(configuration_path + '/linspector.conf', 'utf-8') @@ -39,7 +40,7 @@ class Configuration: section_list = glob.glob(configuration_path + '/' + target_section + '/*.conf') for section_file in section_list: - #print(__file__ + ' (60): ' + section_file) + #print(__file__ + ' (45): ' + section_file) configuration = configparser.ConfigParser() configuration.read(section_file, 'utf-8') for source_section in configuration.sections(): diff --git a/linspector/core/linspector.py b/linspector/core/linspector.py index d8d9900..ba26bd6 100644 --- a/linspector/core/linspector.py +++ b/linspector/core/linspector.py @@ -24,11 +24,13 @@ class Linspector: self.__plugins = plugins # load plugins + logger.info('loading plugins...') if configuration.get_option('linspector', 'plugins'): plugin_list = configuration.get_option('linspector', 'plugins') self.__plugin_list = plugin_list.split(',') for plugin_option in plugin_list.split(','): if plugin_option not in plugins: + logger.info('loading plugin: ' + plugin_option) plugin_package = 'linspector.plugins.' + plugin_option.lower() plugin_module = importlib.import_module(plugin_package) plugin = plugin_module.get(configuration, environment, self) diff --git a/linspector/core/linspectord.py b/linspector/core/linspectord.py index 613422a..1e2e1e7 100644 --- a/linspector/core/linspectord.py +++ b/linspector/core/linspectord.py @@ -14,6 +14,7 @@ from logging import getLogger logger = getLogger('linspector') +# TODO: there is a bug when stopping the daemon. the pid_file is not being deleted. NEEDS A FIX! class Linspectord: def __init__(self, configuration, environment, linspector): @@ -23,7 +24,7 @@ class Linspectord: try: self.__pid_file = configuration.get_option('linspector', 'pid_file') except Exception as err: - logger.error(str('daemonize error (no pid_file set): {0}'.format(err))) + logger.critical(str('daemonize error (no pid_file set): {0}'.format(err))) def daemonize(self): # daemonize the class using the UNIX double fork mechanism. @@ -35,7 +36,7 @@ class Linspectord: # exit first parent. sys.exit(0) except OSError as err: - logger.error(str('fork #1 failed: {0}'.format(err))) + logger.critical(str('fork #1 failed: {0}'.format(err))) sys.exit(1) # decouple from parent environment. @@ -50,7 +51,7 @@ class Linspectord: # Exit from second parent. sys.exit(0) except OSError as err: - logger.error(str('fork #2 failed: {0}'.format(err))) + logger.critical(str('fork #2 failed: {0}'.format(err))) sys.exit(1) # redirect standard file descriptors. @@ -76,7 +77,7 @@ class Linspectord: def start(self): # start the daemon. check for a pidfile to see if the daemon already runs before. - + logger.info('starting daemon using pid_file: ' + self.__pid_file) try: with open(self.__pid_file, 'r') as pf: pid = int(pf.read().strip()) @@ -85,7 +86,7 @@ class Linspectord: if pid: message = 'pid_file {0} already exist. daemon already running?' - logger.error(str(message.format(self.__pid_file))) + logger.critical(str(message.format(self.__pid_file))) sys.exit(1) # start the daemon. @@ -94,7 +95,7 @@ class Linspectord: def stop(self): # stop the daemon. - + logger.info('stopping daemon using pid_file: ' + self.__pid_file) # get the pid from the pid file. try: with open(self.__pid_file, 'r') as pf: @@ -118,15 +119,18 @@ class Linspectord: if os.path.exists(self.__pid_file): os.remove(self.__pid_file) else: - logger.error(str(err.args)) + logger.critical(str(err.args)) sys.exit(1) def restart(self): # restart the daemon. - + logger.info('restarting daemon using pid_file: ' + self.__pid_file) self.stop() self.start() + # maybe this function can be removed in the future because Linspector should rund endless when + # starting scheduled jobs. need to cover this in the future. for now, it is useful for testing + # while development because the daemon even runs when internally is nothing to do. @staticmethod def run(): while True: