thenaterhood/heartbeat

View on GitHub
src/heartbeat/__main__.py

Summary

Maintainability
A
1 hr
Test Coverage
#!/bin/env python3
import sys, os

if (sys.version_info < (3, 3)):
    sys.path.append('/lib/python3.2/site-packages')

from heartbeat.routing import EventRouter
from heartbeat.platform import get_config_manager
from heartbeat.monitoring import MonitorType, MonitorHandler
from heartbeat.plugin import PluginRegistry
import time
import logging, logging.handlers
import concurrent.futures
import signal


settings = get_config_manager()

logger = logging.getLogger("heartbeat")
logger.setLevel(logging.DEBUG)
formatter = logging.Formatter("%(asctime)s;%(levelname)s;%(name)s;%(message)s",
                              "%Y-%m-%d %H:%M:%S")
try:
    filehandler = logging.handlers.TimedRotatingFileHandler(
            filename=settings.heartbeat.log_dir+"/heartbeat.log",
            when='W0'
            )
    filehandler.setFormatter(formatter)
    logger.addHandler(filehandler)

except Exception:
    print("No write permissions to log directory. Trying current directory")
    try:
        filehandler = logging.handlers.TimedRotatingFileHandler(
                filename="./heartbeat.log",
                when="W0"
                )
        filehandler.setFormatter(formatter)
        logger.addHandler(filehandler)
    except Exception:
        print("Unable to write a log file. Proceeding without one.")

termhandler = logging.StreamHandler(sys.stdout)
termhandler.setLevel(logging.INFO)
logger.addHandler(termhandler)

class SignalHandling(object):
    """
    Does graceful signal handling for heartbeat.
    """
    def __enter__(self):
        signal.signal(signal.SIGQUIT, exit_heartbeat)
        signal.signal(signal.SIGTERM, exit_heartbeat)
        signal.signal(signal.SIGINT, exit_heartbeat)

    def __exit__(self, type, value, traceback):
        # Ideally this would restore the original
        # signal handlers, but that isn't functionality
        # that's needed right now, so we'll do nothing.
        pass


def exit_heartbeat(signal, frame):
    logger.debug("Received signal %i. Exiting gracefully.", signal)
    for p in PluginRegistry.get_active_plugins():
        logger.debug("Calling halt() on %s", str(p))
        p.halt()

    logger.info("Waiting 5 seconds for plugins to halt, then exiting...")
    time.sleep(5)

    os._exit(0)

def main():
    if (sys.version_info < (3, 3)):
        logger.error("Your Python version is older than 3.3. It is no longer officially supported!")

    logger.debug("Loading configuration")
    settings = get_config_manager()

    logger.debug("Loading plugins")
    PluginRegistry.populate_from_settings(settings)
    PluginRegistry.activate_plugins()

    logger.info("Bringing up notification/event handling")
    notifyPool = concurrent.futures.ThreadPoolExecutor(max_workers=5)

    dispatcher = EventRouter(notifyPool)

    hwmon = MonitorHandler(
        event_callback=dispatcher.put_event,
        interval=settings.heartbeat.query_interval,
        threadpool=None,
        logger=logger
    )

    required_workers = 1

    for plugin in PluginRegistry.get_active_plugins():
        for t, c in plugin.get_subscriptions().items():
            dispatcher.attach(t, c)
        for t, c in plugin.get_producers().items():
            required_workers += 1
            if t == MonitorType.REALTIME:
                hwmon.add_realtime_monitor(c)
            elif t == MonitorType.PERIODIC:
                hwmon.add_periodic_monitor(c)

    hwmon.threadpool = concurrent.futures.ThreadPoolExecutor(
            max_workers = required_workers
            )

    with SignalHandling() as sh:
        hwmon.start()
        while 1:
            time.sleep(1)

if __name__ == "__main__":
    main()