# Program name: metricator_reader.py
# Compatibility: Python 3.x
# Purpose - read nmon data from fifo file
# Author - Guilhem Marchand

import os
import sys
import optparse
import logging
import re
import subprocess

# script version
version = '3.0.0'

#################################################
#      Variables
#################################################

# Set logging format
logging.root
logging.root.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(levelname)s %(message)s')
handler = logging.StreamHandler()
handler.setFormatter(formatter)
logging.root.addHandler(handler)

# Verify SPLUNK_HOME environment variable is available, the script is expected to be launched by Splunk
# which will set this.
# for debugging or manual run, please set this variable manually
try:
    os.environ["SPLUNK_HOME"]
except KeyError:
    logging.error(
        'The environment variable SPLUNK_HOME could not be verified, if you want to run this script manually you need'
        ' to export it before processing')
    sys.exit(1)

# SPLUNK_HOME environment variable
SPLUNK_HOME = os.environ['SPLUNK_HOME']

# APP_VAR directory
APP_VAR = SPLUNK_HOME + '/var/log/metricator/var'
if not os.path.exists(APP_VAR):
    logging.info(
        'The application var directory does not exist yet, we are not ready to start')
    sys.exit(0)

# APP Directories for TA-metricator-for-nmon
TA_NMON_APP = SPLUNK_HOME + '/etc/apps/TA-metricator-for-nmon'
TA_NMON_APP_CLUSTERED = SPLUNK_HOME + '/etc/slave-apps/TA-metricator-for-nmon'

# Empty APP
APP = ''

# Verify APP exist
if os.path.exists(TA_NMON_APP):
    APP = TA_NMON_APP
elif os.path.exists(TA_NMON_APP_CLUSTERED):
    APP = TA_NMON_APP_CLUSTERED
else:
    msg = 'The Application root directory could not be found, is the TA-metricator-for-nmon ? We tried: ' + \
          str(TA_NMON_APP) + ' ' + str(TA_NMON_APP_CLUSTERED)
    logging.error(msg)
    sys.exit(1)

# metricator_reader.sh
fifo_reader = APP + "/bin/metricator_reader.sh"

#################################################
#      Arguments
#################################################

parser = optparse.OptionParser(usage='usage: %prog [options]', version='%prog '+version)

parser.add_option('-F', '--fifo', action='store', type='string', dest='fifo_name',
                  help='set the fifo file to be read')
parser.add_option('--dumpargs', action='store_true', dest='dumpargs',
                  help='only dump the passed arguments and exit (for debugging purposes only)')

(options, args) = parser.parse_args()

if options.dumpargs:
    print("options: ", options)
    print("args: ", args)
    sys.exit(0)

if not options.fifo_name:
    logging.error(
        'The fifo file option has not been set (-F fifo_name or --fifo fifo_name)')
    sys.exit(1)
else:
    fifo_name = options.fifo_name

# define the full path to the fifo file
fifo_path = APP_VAR + '/nmon_repository/' + fifo_name + '/nmon.fifo'

# At startup, rotate any existing non empty .dat file if nmon_data.dat is not empty

# define the various files to be written

# realtime files
nmon_config_dat = APP_VAR + '/nmon_repository/' + fifo_name + '/nmon_config.dat'
nmon_header_dat = APP_VAR + '/nmon_repository/' + fifo_name + '/nmon_header.dat'
nmon_data_dat = APP_VAR + '/nmon_repository/' + fifo_name + '/nmon_data.dat'
nmon_timestamp_dat = APP_VAR + '/nmon_repository/' + fifo_name + '/nmon_timestamp.dat'
nmon_external_dat = APP_VAR + '/nmon_repository/' + fifo_name + '/nmon_external.dat'
nmon_external_header_dat = APP_VAR + '/nmon_repository/' + fifo_name + '/nmon_external_header.dat'
nmon_error_dat = APP_VAR + '/nmon_repository/' + fifo_name + '/nmon_error.dat'
nmon_dat = {nmon_config_dat, nmon_header_dat, nmon_timestamp_dat, nmon_data_dat, nmon_external_dat,
            nmon_external_header_dat, nmon_error_dat}

# Manage existing files and do the rotation if required
if os.path.exists(nmon_data_dat) and os.path.getsize(nmon_data_dat) > 0:
    for file in nmon_dat:
        rotated_file = str(file) + ".rotated"
        if os.path.isfile(rotated_file):
            os.remove(rotated_file)
        if os.path.isfile(file):
            os.rename(file, rotated_file)

elif os.path.exists(nmon_data_dat):
    for file in nmon_dat:
        if os.path.isfile(file):
            os.remove(file)

####################################################################
#           Main Program
####################################################################

# Verify the fifo file exists, and start processing
if not os.path.exists(fifo_path):
    logging.info(
        'The fifo file ' + fifo_path + ' does not exist yet, we are not ready to start')
    sys.exit(0)
else:
    # we use the metricator_reader.sh to read the fifo file, benchmarks have shown more stability than
    # opening the fifo file in pure Python
    cmd = fifo_reader + " " + fifo_path
    p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, universal_newlines=True)

    while 1:
        line = str(p.stdout.readline())
        if line == '' and p.poll() != None:
            break

        # Manage nmon config
        nmon_config_match = re.match(r'^[AAA|BBB].+', str(line))
        nmon_header_match = re.match(r'^(?!AAA|BBB|TOP)[a-zA-Z0-9\-\_]*,(?!T\d{3,})[^,]*,(?!T\d{3,})[^,]*.*', str(line))
        nmon_header_TOP_match = re.match(r'^TOP,(?!\d*,)', str(line))
        nmon_timestamp_match = re.match(r'^ZZZZ,T\d*', str(line))
        nmon_error_match = re.match(r'^ERROR,T\d*', str(line))

        if nmon_config_match:
            with open(nmon_config_dat, "a") as nmon_config:
                print(str(line))
                nmon_config.write(line)

        elif nmon_header_match:
            with open(nmon_header_dat, "a") as nmon_header:
                nmon_header.write(line)

        elif nmon_header_TOP_match:
            with open(nmon_header_dat, "a") as nmon_header:
                nmon_header.write(line)

        elif nmon_error_match:
            with open(nmon_error_dat, "a") as nmon_error:
                nmon_error.write(line)

        # timestamp management: write the nmon timestamp in nmon_data and as well nmon_timestamp for later use
        elif nmon_timestamp_match:
            with open(nmon_timestamp_dat, "a") as nmon_timestamp:
                nmon_timestamp.write(line)
            with open(nmon_data_dat, "a") as nmon_data:
                nmon_data.write(line)

        else:
            with open(nmon_data_dat, "a") as nmon_data:
                nmon_data.write(line)
