unattended loggly config file for Amazon linux, such as used by ElasticBeanstalk.
#!/usr/bin/env python | |
# loggly_eb.py | |
''' | |
For configuring loggly on AWD elastic beanstalk instances. | |
Tested on the following EB configurations: | |
64 bit Amazon Linux 2017.03 v.2.5.2 running Python 3.4 | |
This is a RHEL-like linux, with rsyslog and no journald. | |
No checks are made at runtime to test the validity of the account/token or to verify | |
log delivery. Use the regular 'configure-linux.sh' script interactively for that. | |
Settings are taken from environment variables, overridable with command line arguments: | |
- LOGGLY_ACCOUNT - the account name at Loggly | |
- LOGGLY_TOKEN - the loggly authentication token (a UUID) for submitting data | |
- LOGGLY_TAGS - a space-separated string of additional tags to apply to the log | |
- LOGGLY_HOSTNAME - the hostname to report in syslog. If not specified, the default | |
as reported by gethostname() is used. | |
- LOGGLY_DOMAIN - domain name appended to hostname. Useful to name a cluster of | |
virtual hosts. | |
''' | |
from __future__ import print_function | |
import os | |
import os.path | |
import sys | |
import argparse | |
import subprocess | |
import shlex | |
import textwrap | |
import shutil | |
import socket | |
import six | |
LOGGLY_DISTRIBUTION_ID = '41058' | |
LOGS_01_HOST = 'logs-01.loggly.com' | |
LOGGLY_SYSLOG_PORT = 514 | |
# directory location for syslog | |
RSYSLOG_ETCDIR_CONF = '/etc/rsyslog.d' | |
# name and location of loggly syslog file | |
LOGGLY_RSYSLOG_CONFFILE = RSYSLOG_ETCDIR_CONF + '/22-loggly.conf' | |
# name and location of loggly syslog backup file | |
LOGGLY_RSYSLOG_CONFFILE_BACKUP = LOGGLY_RSYSLOG_CONFFILE + '.loggly.bk' | |
# rsyslog service name | |
RSYSLOG_SERVICE = 'rsyslog' | |
def main(): | |
# parse args | |
parser = argparse.ArgumentParser(description='Initialize loggly logging') | |
parser.add_argument('--account', '-a', default=os.environ.get('LOGGLY_ACCOUNT'), help='The Loggly account name (default from LOGGLY_ACCOUNT)') | |
parser.add_argument('--token', '-t', default=os.environ.get('LOGGLY_TOKEN'), help='The Loggly authentication token (default from LOGGLY_TOKEN)') | |
parser.add_argument('--tags', nargs='*', help='Additional tags (default from LOGGLY_TAGS)') | |
parser.add_argument('--hostname', default=os.environ.get('LOGGLY_HOSTNAME')) | |
parser.add_argument('--domain', default=os.environ.get('LOGGLY_DOMAIN')) | |
parser.add_argument('--remove', '-r', action='store_true', help='remove loggly configuration') | |
args = parser.parse_args() | |
if args.remove: | |
unconfigure() | |
return | |
if not args.account or not args.token: | |
# No loggly configuration | |
print("No Loggly credentials. '%s -h' for help" % parser.prog) | |
unconfigure(quiet=True) | |
return | |
if args.tags is not None: | |
tags = args.tags | |
elif os.environ.get('LOGGLY_TAGS'): | |
tags = shlex.split(os.environ['LOGGLY_TAGS']) | |
else: | |
tags = None | |
config = { | |
'account': args.account, | |
'token': args.token, | |
'tags': tags, | |
'hostname': args.hostname, | |
'domain' : args.domain, | |
} | |
configure(config) | |
def configure(config): | |
log("INFO: Initiating Configure Loggly for Linux.") | |
# if all the above check passes, write the 22-loggly.conf file | |
write_rsyslog_conf(config) | |
# restart rsyslog service | |
restart_rsyslog() | |
log("SUCCESS: Linux system successfully configured to send logs via Loggly.") | |
def write_rsyslog_conf(config): | |
'''write the contents to 22-loggly.conf file''' | |
contents = get_loggly_conf(config) | |
write_script = False | |
if os.path.exists(LOGGLY_RSYSLOG_CONFFILE): | |
log("INFO: Loggly rsyslog file %r already exist." % LOGGLY_RSYSLOG_CONFFILE) | |
with open(LOGGLY_RSYSLOG_CONFFILE, "rb") as fd: | |
old_contents = fd.read() | |
if six.b(contents) != old_contents: | |
log("WARN: Loggly rsyslog file %r content has changed." % LOGGLY_RSYSLOG_CONFFILE) | |
log("INFO: Going to back up the conf file: %r to %r" % (LOGGLY_RSYSLOG_CONFFILE, LOGGLY_RSYSLOG_CONFFILE_BACKUP)) | |
shutil.move(LOGGLY_RSYSLOG_CONFFILE, LOGGLY_RSYSLOG_CONFFILE_BACKUP) | |
write_script = True | |
else: | |
write_script = True | |
if write_script: | |
with open(LOGGLY_RSYSLOG_CONFFILE, "wb") as fd: | |
fd.write(six.b(contents)) | |
log("INFO: Loggly rsyslog file %r written." % LOGGLY_RSYSLOG_CONFFILE) | |
def unconfigure(quiet=False): | |
# in quiet mode, don't log anything if not configured | |
if quiet and not os.path.exists(LOGGLY_RSYSLOG_CONFFILE): | |
return | |
log("INFO: Initiating uninstall Loggly for Linux.") | |
# remove 22-loggly.conf file | |
remove_loggly_conf() | |
# restart rsyslog service | |
restart_rsyslog() | |
log("SUCCESS: Uninstalled Loggly configuration from Linux system.") | |
def remove_loggly_conf(): | |
'''delete 22-loggly.conf file''' | |
if os.path.exists(LOGGLY_RSYSLOG_CONFFILE): | |
os.unlink(LOGGLY_RSYSLOG_CONFFILE) | |
return True | |
def restart_rsyslog(): | |
'''restart rsyslog''' | |
log("INFO: Restarting the %s service." % RSYSLOG_SERVICE) | |
code = subprocess.call(['service', RSYSLOG_SERVICE, 'restart']) | |
if code: | |
log("WARNING: %s did not restart gracefully. Please restart %s manually." % (RSYSLOG_SERVICE, RSYSLOG_SERVICE)) | |
def log(msg): | |
print(msg) | |
if msg.startswith('ERROR'): | |
sys.exit(1) | |
def get_loggly_conf(config): | |
template = r''' | |
# ------------------------------------------------------- | |
# Syslog Logging Directives for Loggly (%(account)s.loggly.com) | |
# ------------------------------------------------------- | |
# Define the template used for sending logs to Loggly. Do not change this format. | |
$template LogglyFormat,"<%%pri%%>%%protocol-version%% %%timestamp:::date-rfc3339%% %(hostname)s %%app-name%% %%procid%% %%msgid%% [%(token)s@%(distribution_id)s %(tags)s] %%msg%%\n" | |
$WorkDirectory /var/spool/rsyslog # where to place spool files | |
$ActionQueueFileName fwdRule1 # unique name prefix for spool files | |
$ActionQueueMaxDiskSpace 1g # 1gb space limit (use as much as possible) | |
$ActionQueueSaveOnShutdown on # save messages to disk on shutdown | |
$ActionQueueType LinkedList # run asynchronously | |
$ActionResumeRetryCount -1 # infinite retries if host is down | |
# Send messages to Loggly over TCP using the template. | |
*.* @@%(logs_host)s:%(logs_port)d;LogglyFormat | |
# ------------------------------------------------------- | |
''' | |
# preprocess data | |
args = dict(config) | |
if not args.get('hostname') and not args.get('domain'): | |
# simply use the rsyslog macro | |
args['hostname'] = '%HOSTNAME%' | |
else: | |
# construct a fixed hostname to send | |
if not args.get('hostname'): | |
args['hostname'] = socket.gethostname() | |
if args.get('domain'): | |
args['hostname'] = args['hostname'].split('.')[0] + '.' + args['domain'] | |
tags = ['Rsyslog'] | |
if args.get('tags'): | |
tags += args['tags'] | |
args['tags'] = ' '.join((r'tag=\"%s\"' % tag) for tag in tags) | |
args['distribution_id'] = LOGGLY_DISTRIBUTION_ID | |
args['logs_host'] = LOGS_01_HOST | |
args['logs_port'] = LOGGLY_SYSLOG_PORT | |
return textwrap.dedent(template[1:]) % args | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment