def run_daemon(previous_states, settings, start_time=None):
    if start_time:
        _sleep_until_interval(
            start_time, settings.collect_interval_s,
        )

    iterations = 1  # start 1 for the initial sync

    while True:
        start = time()

        _daemon_loop(iterations, previous_states, settings)
        iterations += 1

        _sleep_until_interval(
            start, settings.collect_interval_s,
        ) STDOUT_LOG_LEVELS = (logging.DEBUG, logging.INFO)
STDERR_LOG_LEVELS = (logging.WARNING, logging.ERROR, logging.CRITICAL)
class LogFilter(logging.Filter):
class LogFormatter(logging.Formatter):
    def __init__(self, *levels):
    def filter(self, record):
    def format(self, record):
def setup_logging(verbose, debug, default_level=logging.CRITICAL):
def setup_logging_from_settings(settings):
def print_exception(debug_only=False): def get_and_prepare_working_plugins(settings, include_slow=True):
    all_plugins = get_plugins()
    working_plugins = []

    for plugin in all_plugins:
        if not include_slow and plugin.is_slow:
            continue

        status = prepare_plugin(plugin, settings)

        if status is True:
            working_plugins.append(plugin)

    logger.info('Loaded plugins: {0}'.format(', '.join([
        plugin.name
        for plugin in working_plugins
    ])))

    return working_plugins def get_plugin_states(plugins, settings):
    '''
    Gets state output from multiple plugins.
    '''

    return [
        (plugin, get_plugin_state(plugin, settings))
        for plugin in plugins
    ] def backoff(function, *args, **kwargs):
    data = None
    interval = 0

    error_message = kwargs.pop('error_message', 'API error')
    max_wait = kwargs.pop('max_wait', 300)

    while data is None:
        try:
            return function(*args, **kwargs)

        except ApiError as e:
            if interval + 10 <= max_wait:
                interval += 10

            e.log()

        logger.critical('{0}, retrying in {1}s'.format(error_message, interval))
        sleep(interval) def ping(settings):
    return make_api_request(
        get_session().get,
        'server/{0}/ping'.format(settings.server_id),
        settings=settings,
    ) def shutdown(settings):
    return make_api_request(
        get_session().post,
        'server/{0}/shutdown'.format(settings.server_id),
        settings=settings,
    ) def sync_states(states, settings):
    '''
    Uploads a full state to api.servicecanary.com and returns any data sent back
    from the server (settings).
    '''

    return _upload_states_return_settings(
        'server/{0}/sync'.format(settings.server_id),
        make_sync_or_changes_dict(states),
        settings,
        json={
            'hostname': socket.gethostname(),
            'canaryd_version': __version__,
        },
    ) def ensure_config_directory():
    # Make sure the config directory exists
    config_directory = get_config_directory()

    if not path.exists(config_directory):
        logger.debug('Creating config directory: {0}'.format(config_directory))
        makedirs(config_directory) def get_settings(config_file=None):
    '''
    Cached/public version of _get_settings.
    '''

    global SETTINGS

    if SETTINGS is None:
        SETTINGS = _get_settings(config_file=config_file)

    return SETTINGS
import logging
import signal
from time import time
from canaryd_packages import click
from canaryd.daemon import run_daemon
from canaryd.log import logger, setup_logging, setup_logging_from_settings
from canaryd.plugin import (
    get_and_prepare_working_plugins,
    get_plugin_states,
)
from canaryd.remote import backoff, ping, shutdown, sync_states
from canaryd.settings import ensure_config_directory, get_settings
from canaryd.version import __version__
# canaryd
# File: canaryd/__main__.py
# Desc: entry point for canaryd






class GracefulExitRequested(Exception):
    pass


def handle_graceful_quit(signum, frame):
    raise GracefulExitRequested('yawn')


@click.command(context_settings={'help_option_names': ['-h', '--help']})
@click.option('-v', '--verbose', is_flag=True)
@click.option('-d', '--debug', is_flag=True)
@click.version_option(
    version=__version__,
    prog_name='canaryd',
    message='%(prog)s: v%(version)s',
)
def main(verbose, debug):
    '''
    Run the canaryd daemon.
    '''

    log_level = setup_logging(verbose, debug)

    logger.info('Starting canaryd v{0}'.format(__version__))
    logger.info('Log level set to: {0}'.format(
        logging.getLevelName(log_level),
    ))

    # Ensure the config directory exists
    ensure_config_directory()

    # Load the settings, using our config file if provided
    settings = get_settings()

    # Setup any log file/syslog
    setup_logging_from_settings(settings)

    if not settings.api_key or not settings.server_id:
        logger.critical('Missing api_key and/or server_id in config file')
        return

    # Initial ping for API presence
    logger.info('Ping API...')
    backoff(
        ping, settings,
        error_message='Could not ping',
        max_wait=settings.collect_interval_s,
    )

    # Load the plugin list
    plugins = get_and_prepare_working_plugins(settings)

    # Get the initial state
    logger.info('Getting initial state...')
    start_time = time()
    states = get_plugin_states(plugins, settings)

    # Filter out the non-working plugins and wrap as a (command, data) tuple
    # we don't track errors on the initial sync because often canaryd starts
    # early on a server meaning some things aren't up. The next state collection
    # will collect and sync these.
    working_states = []
    for plugin, status_data in states:
        status, data = status_data
        if status is not True:
            continue
        working_states.append((plugin, ('SYNC', data)))

    # Sync this state and get settings
    logger.info('Syncing initial state...')


    remote_settings = backoff(