Added file logging and a new parameter (-s) for logging to stdout.

This commit is contained in:
Johannes Findeisen 2022-09-29 02:59:40 +02:00
commit dbb0e23091
5 changed files with 66 additions and 18 deletions

View file

@ -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. OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
""" """
import argparse import argparse
import logging
import logging.handlers
import os
import sys import sys
from logging import getLogger
from linspector.core.configuration import Configuration from linspector.core.configuration import Configuration
from linspector.core.environment import Environment from linspector.core.environment import Environment
from linspector.core.linspector import Linspector from linspector.core.linspector import Linspector
from linspector.core.monitors import Monitors from linspector.core.monitors import Monitors
__version__ = '0.18' __version__ = '0.18.1'
__author__ = 'Johannes Findeisen <you@hanez.org>' __author__ = 'Johannes Findeisen <you@hanez.org>'
logger = getLogger('linspector') logger = logging.getLogger('linspector')
def parse_args(): def parse_args():
@ -57,6 +58,9 @@ def parse_args():
parser.add_argument('-r', '--restart', default=False, dest='restart', action='store_true', parser.add_argument('-r', '--restart', default=False, dest='restart', action='store_true',
help='restart the daemon if it is running(default: false)') 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__)) parser.add_argument('-v', '--version', action='version', version='%(prog)s ' + str(__version__))
return parser.parse_args() return parser.parse_args()
@ -64,7 +68,6 @@ def parse_args():
def main(): def main():
args = parse_args() args = parse_args()
environment = Environment() environment = Environment()
monitors = None monitors = None
notifications = {} notifications = {}
@ -72,13 +75,50 @@ def main():
services = {} services = {}
tasks = {} 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: try:
configuration = Configuration(args.configuration_path, environment) configuration = Configuration(args.configuration_path, environment)
#configuration.dump_to_ini() #configuration.dump_to_ini()
except Exception as err: except Exception as err:
logger.error('[linspector] configuration error: {0}'.format(err)) logger.critical('[linspector] configuration error: {0}'.format(err))
sys.exit(1) 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: try:
monitors = Monitors(configuration, environment, notifications, services, tasks) monitors = Monitors(configuration, environment, notifications, services, tasks)
except Exception as err: except Exception as err:
@ -87,7 +127,7 @@ def main():
try: try:
linspector = Linspector(configuration, environment, monitors, plugins) linspector = Linspector(configuration, environment, monitors, plugins)
except Exception as err: 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) sys.exit(1)
# daemon initialization # daemon initialization
@ -103,7 +143,7 @@ def main():
else: else:
linspectord.start() linspectord.start()
except Exception as err: except Exception as err:
logger.error('[linspector] daemon initialization error: {0}'.format(err)) logger.critical('[linspector] daemon error: {0}'.format(err))
sys.exit(1) sys.exit(1)

View file

@ -3,7 +3,8 @@
; report core errors to the following users ; report core errors to the following users
error_receivers = admin@example.com error_receivers = admin@example.com
log_file = ~/code/linspector/log/linspector.log 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_count = 5
log_size = 10485760 log_size = 10485760
pid_file = /var/run/user/1000/linspector.pid pid_file = /var/run/user/1000/linspector.pid

View file

@ -21,6 +21,7 @@ class Configuration:
self.__configuration_path = configuration_path self.__configuration_path = configuration_path
self.__environment = environment self.__environment = environment
logger.info('reading configuration file: ' + configuration_path + '/linspector.conf')
if os.path.isfile(configuration_path + '/linspector.conf'): if os.path.isfile(configuration_path + '/linspector.conf'):
try: try:
self.__configuration.read(configuration_path + '/linspector.conf', 'utf-8') self.__configuration.read(configuration_path + '/linspector.conf', 'utf-8')
@ -39,7 +40,7 @@ class Configuration:
section_list = glob.glob(configuration_path + '/' + target_section + '/*.conf') section_list = glob.glob(configuration_path + '/' + target_section + '/*.conf')
for section_file in section_list: for section_file in section_list:
#print(__file__ + ' (60): ' + section_file) #print(__file__ + ' (45): ' + section_file)
configuration = configparser.ConfigParser() configuration = configparser.ConfigParser()
configuration.read(section_file, 'utf-8') configuration.read(section_file, 'utf-8')
for source_section in configuration.sections(): for source_section in configuration.sections():

View file

@ -24,11 +24,13 @@ class Linspector:
self.__plugins = plugins self.__plugins = plugins
# load plugins # load plugins
logger.info('loading plugins...')
if configuration.get_option('linspector', 'plugins'): if configuration.get_option('linspector', 'plugins'):
plugin_list = configuration.get_option('linspector', 'plugins') plugin_list = configuration.get_option('linspector', 'plugins')
self.__plugin_list = plugin_list.split(',') self.__plugin_list = plugin_list.split(',')
for plugin_option in plugin_list.split(','): for plugin_option in plugin_list.split(','):
if plugin_option not in plugins: if plugin_option not in plugins:
logger.info('loading plugin: ' + plugin_option)
plugin_package = 'linspector.plugins.' + plugin_option.lower() plugin_package = 'linspector.plugins.' + plugin_option.lower()
plugin_module = importlib.import_module(plugin_package) plugin_module = importlib.import_module(plugin_package)
plugin = plugin_module.get(configuration, environment, self) plugin = plugin_module.get(configuration, environment, self)

View file

@ -14,6 +14,7 @@ from logging import getLogger
logger = getLogger('linspector') logger = getLogger('linspector')
# TODO: there is a bug when stopping the daemon. the pid_file is not being deleted. NEEDS A FIX!
class Linspectord: class Linspectord:
def __init__(self, configuration, environment, linspector): def __init__(self, configuration, environment, linspector):
@ -23,7 +24,7 @@ class Linspectord:
try: try:
self.__pid_file = configuration.get_option('linspector', 'pid_file') self.__pid_file = configuration.get_option('linspector', 'pid_file')
except Exception as err: 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): def daemonize(self):
# daemonize the class using the UNIX double fork mechanism. # daemonize the class using the UNIX double fork mechanism.
@ -35,7 +36,7 @@ class Linspectord:
# exit first parent. # exit first parent.
sys.exit(0) sys.exit(0)
except OSError as err: 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) sys.exit(1)
# decouple from parent environment. # decouple from parent environment.
@ -50,7 +51,7 @@ class Linspectord:
# Exit from second parent. # Exit from second parent.
sys.exit(0) sys.exit(0)
except OSError as err: 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) sys.exit(1)
# redirect standard file descriptors. # redirect standard file descriptors.
@ -76,7 +77,7 @@ class Linspectord:
def start(self): def start(self):
# start the daemon. check for a pidfile to see if the daemon already runs before. # 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: try:
with open(self.__pid_file, 'r') as pf: with open(self.__pid_file, 'r') as pf:
pid = int(pf.read().strip()) pid = int(pf.read().strip())
@ -85,7 +86,7 @@ class Linspectord:
if pid: if pid:
message = 'pid_file {0} already exist. daemon already running?' 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) sys.exit(1)
# start the daemon. # start the daemon.
@ -94,7 +95,7 @@ class Linspectord:
def stop(self): def stop(self):
# stop the daemon. # stop the daemon.
logger.info('stopping daemon using pid_file: ' + self.__pid_file)
# get the pid from the pid file. # get the pid from the pid file.
try: try:
with open(self.__pid_file, 'r') as pf: with open(self.__pid_file, 'r') as pf:
@ -118,15 +119,18 @@ class Linspectord:
if os.path.exists(self.__pid_file): if os.path.exists(self.__pid_file):
os.remove(self.__pid_file) os.remove(self.__pid_file)
else: else:
logger.error(str(err.args)) logger.critical(str(err.args))
sys.exit(1) sys.exit(1)
def restart(self): def restart(self):
# restart the daemon. # restart the daemon.
logger.info('restarting daemon using pid_file: ' + self.__pid_file)
self.stop() self.stop()
self.start() 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 @staticmethod
def run(): def run():
while True: while True: