#!/usr/bin/env python

import argparse
import os
import sys
import time

import beaver.config
import beaver.transport
import beaver.utils
import beaver.worker

from beaver import __version__ as full_version


epilog_example = """
Beaver provides an lightweight method for shipping local log
files to Logstash. It does this using either redis, stdin,
zeromq as the transport. This means you'll need a redis,
stdin, zeromq input somewhere down the road to get the events.

Events are sent in logstash's json_event format. Options can
also be set as environment variables.

Example 1: Listen to all files in the default path of /var/log on standard out as json
    cli: beaver

Example 2: Listen to all files in the default path of /var/log on standard out with msgpack
    cli: BEAVER_FORMAT='msgpack' beaver

Example 3: Listen to all files in the default path of /var/log on standard out as a string
    cli: BEAVER_FORMAT='string' beaver

Example 4: Sending logs from /var/log files to a redis list
    cli: REDIS_URL="redis://localhost:6379/0" beaver -t redis

Example 5: Use environment variables to send logs from /var/log files to a redis list
    cli: REDIS_URL="redis://localhost:6379/0" BEAVER_PATH="/var/log" BEAVER_TRANSPORT=redis beaver

Example 6: Zeromq listening on port 5556 (all interfaces)
    cli: ZEROMQ_ADDRESS="tcp://*:5556" beaver -m bind -t zmq

Please see the readme for more complete examples.

"""
parser = argparse.ArgumentParser(description='Beaver logfile shipper',
                                epilog=epilog_example,
                                formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument('-m', '--mode', help='bind or connect mode', dest='mode', choices=['bind', 'connect'])
parser.add_argument('-p', '--path', help='path to log files', dest='path')
parser.add_argument('-f', '--files', help='space-separated filelist to watch, can include globs (*.log). Overrides --path argument', dest='files', nargs='+')
parser.add_argument('-t', '--transport', help='log transport method', dest='transport', choices=['rabbitmq', 'redis', 'stdout', 'zmq', 'udp'])
parser.add_argument('-c', '--configfile', help='ini config file path', dest='config')
parser.add_argument('-d', '--debug', help='enable debug mode', type=bool, dest='debug')
parser.add_argument('-v', '--version', help='output version and quit', dest='version', action='store_true')
parser.add_argument('--fqdn', help="use the machine's FQDN", dest="fqdn", action='store_true')


# Support env variable parsing as well
files = os.environ.get("BEAVER_FILES", None)
if files is not None:
    files = files.split(',')

bound = "bind" if os.environ.get("BIND", False) else None

parser.set_defaults(
    mode=os.environ.get("BEAVER_MODE", "bind" if os.environ.get("BIND", False) else "connect"),
    path=os.environ.get("BEAVER_PATH", '/var/log'),
    files=files,
    transport=os.environ.get("BEAVER_TRANSPORT", 'stdout'),
    config='/dev/null',
    debug=False,
    fqdn=False
)

args = parser.parse_args()

if args.version:
    import logging
    formatter = logging.Formatter('%(message)s')
    logger = beaver.utils.setup_custom_logger('beaver', debug=args.debug, formatter=formatter)
    logger.info("Beaver {0}".format(full_version))
    sys.exit(0)

logger = beaver.utils.setup_custom_logger('beaver', args.debug)


args.globs = files
configfile = beaver.config.Config(args.config)
try:
    args.files.extend(configfile.getfilepaths())
    args.globs.extend(configfile.getglobs())
except AttributeError:
    args.files = configfile.getfilepaths()
    args.globs = configfile.getglobs()

failure_count = 0
respawn_delay = 3
max_failure = 7

while 1:
    try:
        worker = beaver.worker.run_worker(configfile, args)
    except beaver.transport.TransportException, e:
        failure_count = failure_count + 1
        if failure_count > max_failure:
            failure_count = max_failure
        sleep_time = respawn_delay ** failure_count
        logger.info("Caught transport exception, respawning in %d seconds" % sleep_time)
        try:
            time.sleep(sleep_time)
        except KeyboardInterrupt:
            logger.info("User cancelled respawn.")
            sys.exit(0)
    except KeyboardInterrupt:
        logger.info("Shutting down. Please wait.")
        worker.close()
        logger.info("Shutdown complete.")
        sys.exit(0)
