#!/usr/bin/env python

from __future__ import print_function

# sniffwave_tally: Renate Hartog, PNSN May 2018
#
# wrapper for sniffwave to tally late packets and gaps
# Largely based on latte.py: Victor Kress, PNSN 2014/9/16
# $Id$

import os
import sys
import time
import re
import math
import requests
from subprocess import Popen,PIPE
from datetime import datetime

try:
    from squacapi_client.models.write_only_measurement_serializer \
    import WriteOnlyMeasurementSerializer

    from squacapi_client.pnsn_utilities \
    import get_client, make_channel_map, make_metric_map, perform_bulk_create

    no_squacapi = False
except Exception as e:
    print("Info: squacapi_client not available, cannot use --squac option")
    no_squacapi = True


LATENCY_THRESHOLD = 3.5 # good latency <= 3.5s
TOLERANCE = 1e-4 # tolerance when comparing begin and end time of packets to determine gaps and overlaps
default_seconds = 10

#DAVN.BHZ.UW.-- (0x32 0x30) 0 i4  40  40.0 2018/05/24 01:43:32.53 (1527126212.5250) 2018/05/24 01:43:33.50 (1527126213.5000) 0x20 0x20 i2 m71 t19 len 224 [D:8173.7s F: 0.0s]

# match seismic channels only
rechan=re.compile(r'[E,B,H][H,N][E,N,Z,1,2,3]')
# sample rate is the first non-integer
resrate=re.compile(r'[0-9]+\.[0-9]+')
# start- and endtimes are numbers surrounded by parenthesis
retime=re.compile(r'\(([0-9\.]+)\)')
# latency is preceded by D and can be negative:
relat=re.compile(r'D:([\- 0-9\.]+)s')
# scnl 4 fields separated by periods
resncl=re.compile(r'^[A-Z0-9]+\.[A-Z0-9]+\.[A-Z0-9]+\.[A-Z0-9-]+')
# size in bytes is preceded by len and consists of 4 integers: len 408
rebytes=re.compile(r'len([\s]*[0-9]{1,4})')



def usage():
    """ Create usage message """

    information = \
    """
        Usage: sniffwave_tally [--fname filename] [--bindir sniffwave-bin-dir] [--outdir output-dir] [--inst institution_id ] [--squac prefix] ring_name sta chan net loc duration

        where:
            ring_name:	name of earthworm ring to sniff
            sta:	station code or wild
            chan:	channel code or wild
            loc:	location code or wild (-- for no-location code)
            duration:	number of seconds for which to run sniffwave
        options:
            --bindir sniffwave-bin-dir:	full path of directory containing sniffwave executable (default = /home/eworm/bin)
            --outdir output-dir:	full path to of directory to put output files in (default = /tmp)
            --fname  filename:		name of output file (default = YYYY-mm-dd_sniffwave_tally.csv, where YYYY-mm-dd is current UTC date)
            --inst   institution:  institiution name to append to default output, e.g. YYYY-mm-dd_sniffwave_tally.PNSN.csv
            --squac  prefix: post latency and gaps measurements to squac, prefix will be prepended to the different metric names.
                     prerequisites: squac api user with contributor privileges and metric already has to exist in the SQUAC database. 
                     Measurements for metrics that are not yet defined in SQUAC will not be sent.  
                     metric names: prefix_ring_latency, prefix_ring_packet_length, prefix_ring_gaps_per_hour, prefix_ring_latency_le_3.5,
                                   prefix_ring_completeness, prefix_ring_completeness_incl_gap_penalty.
            --all               :  Add average and standard deviation of the measured latencies and packet lengths, as well as total number of bytes sent to the output.

        Default Output (for eewreport):
            creates or appends to file the following fields:
            scnl:	STA.CHAN.NET.LOC
            starttime:	starttime of first packet in measurement window (epoch seconds)
            endtime:	endtime of last packet in measurement window (epoch seconds)
            duration:	total duration of measurement window (seconds)
            npackets:	total number of packets seen during measurement window
            nlate:	number of packets with latency > 3.5s
            ngap:	number of gaps
            gap_dur:	total duration of gaps (seconds)
            noverlap:	number of packets that overlap previous packet
            overlap_dur:total duration of overlapping packets
            n_oo:	number of out-of-order packets
            oo_dur:	total duration of out-of-order packets
        Added with option all:
            latency:    average latency (s), defined as feed latency + 0.5 packet length
            latency_stdev:  approximate standard deviation of the latency
            packet_lenght:  average packet length (s)
            packet_stdev: approximate standard deviation of the packet length
    """
    print(information)
    return

def parseline(s):
    """
        Process a sniffwave output line

        Args:
            s (string): output line from running 'sniffwave RING_NAME sta chan net loc duration'

        Returns:
            tuple (scnl, dt, starttime, endtime, latency, size) or None::
            0-scnl = STA.CHAN.NET.LOC
            1-dt = 1.0/sample_rate
            2-starttime = starttime of packet in unix epoch seconds
            3-endtime = endtime of packet in unix epoch seconds
            4-latency = difference in s between now and endtime of packet
            5-size = length of packet in bytes as reported by sniffwave

    """
    if (sys.version_info > (3, 0)):
        s = s.decode('utf-8')

    scnl = s.lstrip().split(' ',1)[0]

    if s.rstrip()[-1] != ']':
        return None
    if not resncl.match(scnl): #line does not start with valid scnl
        return None
    chan = scnl.split(".")[1]
    if not rechan.match(chan):
        return None
    try:
        dt = 1.0/float(resrate.search(s).group(0)) # delta t is 1/sample_rate
        (starttime, endtime) = map(float,retime.findall(s))
        latency = float(relat.search(s).group(1))
        size = int(rebytes.search(s).group(1))
    except Exception as e:
        print('could not parse\n{}: {}'.format(s,e))
        return None
    return (scnl,dt,starttime,endtime,latency,size)

def average_stdev(x,x2,n):
    """
        Calculate approximation of standard deviation::
            stdev = sqrt( (x2)/n-(x/n)**2 )

        Args:
            x (float): summation of all values
            x2 (float): summation of all squared values
            n (integer): number of values

        Returns:
            float: average of values
            float: approximate standard deviation
    """
    if n == 0:
        return x, n
    squared = (x2/n) - (x/n)*(x/n)
    if squared >= 0:
        stdev = math.sqrt(squared)
    else:
        stdev = 0.
    return x/n, stdev


def eew_stationreport_input(scnldict):
    """
        Creates the minimal csv input to be used by eew_stationreport.
        See https://github.com/pnsn/station_metrics.
        Args:
            scnldict (dict): keyed on scnl, has to have nested dict keys:
                             'starttime' : starttime of earliest packet in epoch seconds
                             'endtime'   : endtime of last packet in epoch seconds
                             'npackets'  : number of packets
                             'nlate'     : number of bad packets (latency > 3.5s)
                             'ngap'      : number of gaps between starttime and endtime
                             'gap_dur'   : total duration of gaps in seconds
                             'noverlap'  : number of overlaps between starttime and endtime
                             'overlap_dur' : total duration of overlaps in seconds
                             'n_oo'      : number of out-of-order packets
                             'oo_dur'    : total duration of out-of-order packets
        Returns:
            [string]: [scnl,starttime,endtime,duration,n,nlate,ngap,gap_dur,
                       noverlap,overlap_dur,n_oo,oo_dur]
    """
    sep = ","
    key_list = ["starttime", "endtime", "duration", "npackets", "nlate", "ngap", \
                "gap_dur", "noverlap", "overlap_dur", "n_oo", "oo_dur"]
    header_list = ["# scnl"]
    header_list.extend(key_list)
    header = sep.join(header_list) + "\n"
    lines = ""
    for scnl in scnldict:
        scnldict[scnl]["duration"] = scnldict[scnl]["endtime"] - scnldict[scnl]["starttime"]
        line = scnl
        for k in key_list:
            line += sep
            line += str(scnldict[scnl][k])
        line += "\n"
        lines += line
    return header + lines

def latency_report(scnldict):
    """
        Creates csv input that can be used by eew_stationreport but has the
        additional metrics latency, latency_stdev, packet_length, and
        packet_stdev.
        See https://github.com/pnsn/station_metrics.
        Args:
            scnldict (dict): keyed on scnl, has to have nested dict keys:
                             'starttime' : starttime of earliest packet in epoch seconds
                             'endtime'   : endtime of last packet in epoch seconds
                             'npackets'  : number of packets
                             'nlate'     : number of bad packets (latency > 3.5s)
                             'ngap'      : number of gaps between starttime and endtime
                             'gap_dur'   : total duration of gaps in seconds
                             'noverlap'  : number of overlaps between starttime and endtime
                             'overlap_dur' : total duration of overlaps in seconds
                             'n_oo'      : number of out-of-order packets
                             'oo_dur'    : total duration of out-of-order packets
                             'latency'   : average latency (in s,feedlatency + 0.5 packet_length)
                             'latency_stdev' :  approximate standard deviation of latency
                             'packet_length' :  average packet length (s)
                             'packet_stdev': packet length stdev
                             'bytes': size of data in bytes
        Returns:
            [string]: [scnl,starttime,endtime,duration,n,nlate,ngap,gap_dur,
            noverlap,overlap_dur,n_oo,oo_dur,latency, latency_stdev,
            packet_length, packet_stdev, bytes]
    """
    sep = ","
    key_list = ["starttime", "endtime", "duration", "npackets", "nlate", "ngap", \
                "gap_dur", "noverlap", "overlap_dur", "n_oo", "oo_dur", "latency", "latency_stdev", \
                "packet_length", "packet_stdev", "bytes"]
    header_list = ["# scnl"]
    header_list.extend(key_list)
    header = sep.join(header_list) + "\n"
    lines = ""
    for scnl in scnldict:
        scnldict[scnl]["duration"] = scnldict[scnl]["endtime"] - scnldict[scnl]["starttime"]
        line = scnl
        for k in key_list:
            line += sep
            line += str(scnldict[scnl][k])
        line += "\n"
        lines += line
    return header + lines

def send_to_squac(scnldict, prefix):
    """
        Sends the measurements for the following metrics to SQUAC api (requires
        a SQUAC api user account with contributor privileges):

        prefix_ring_latency:  average data latency in s.
        prefix_ring_packet_length: average packet length during measurement window
        prefix_ring_gaps_per_hour: 3600 * (number of gaps/number of seconds in measurement window)
        prefix_ring_latency_le_3.5: percentage of packets with (data latency+0.5*packet_length) <= 3.5s
        prefix_ring_completeness: percentage completeness of the data as measured during this time window
        prefix_ring_completeness_incl_gap_penalty: percentage completeness, adding extra 30s for each gap.

        Only measurements for metrics that have already been defined in SQUAC will be sent.
        
        Args:
            scnldict (dict): keyed on scnl, has to have nested dict keys:
                             'starttime' : starttime of earliest packet in epoch seconds
                             'endtime'   : endtime of last packet in epoch seconds
                             'npackets'  : number of packets
                             'nlate'     : number of bad packets (latency > 3.5s)
                             'ngap'      : number of gaps between starttime and endtime
                             'gap_dur'   : total duration of gaps in seconds
                             'noverlap'  : number of overlaps between starttime and endtime
                             'overlap_dur' : total duration of overlaps in seconds
                             'n_oo'      : number of out-of-order packets
                             'oo_dur'    : total duration of out-of-order packets
                             'latency'   : average latency (in s,feedlatency + 0.5 packet_length)
                             'latency_stdev' :  approximate standard deviation of latency
                             'packet_length' :  average packet length (s)
                             'packet_stdev': packet length stdev
            prefix (string): string to prepend to metrics name.
        Returns:
            response: blah blah
    """
    # LOCAL, STAGING, PRODUCTION
#    HOST = 'https://staging-squacapi.pnsn.org'
    HOST = 'https://squacapi.pnsn.org'

    try:
        USER = os.environ['SQUACAPI_USER']
        PASSWORD = os.environ['SQUACAPI_PASSWD']

    except KeyError:
        sys.exit("Requires ENV vars SQUACAPI_USER, SQUACAPI_PASSWD")

    # create API client and retrieve foreign keys from the SQUAC database
    client = get_client(USER, PASSWORD, HOST)

    gap_penalty = 30 # seconds
    # let's automatically add scnl's that are in SQUAC but not yet part of the group to the channel group
    #channel_group = "PNSN Continuous Data"
    metric_names = [prefix + "_ring_latency", prefix + "_ring_packet_length", 
                    prefix + "_ring_gaps_per_hour", prefix + "_ring_latency_le_3.5",
                    prefix + "_ring_completeness", prefix + "_ring_completeness_incl_gap_penalty"]

    metric_names_string = ",".join(metric_names)
    metrics = client.v1_0_measurement_metrics_list(name=metric_names_string)
    metric_map = make_metric_map(metrics)
    # v1_0_nslc_channels_list() can be slow and sometimes timeout, try daily updated flat file from Alex
    try:
        r = requests.get("https://seismo.ess.washington.edu/ahutko/ShakeAlert_Chanfiles/squac_channel_map.txt")
        channel_map = {}
        for bline in r.iter_lines():
            line = bline.decode("utf-8")
            nslc = line.split()[0]
            scnl = nslc.split('.')[1] + '.' + nslc.split('.')[3] + '.' + nslc.split('.')[0] + '.' + nslc.split('.')[2]
            scnl_id = int(line.split()[1])
            channel_map[scnl] = scnl_id
        if ( len(channel_map) == 0 ): 1/0
    except:
        channels = client.v1_0_nslc_channels_list()
        channel_map = make_channel_map(channels)
    #channel_groups = client.v1_0_nslc_groups_list(name=channel_group)
    # create lookup maps from metric name/scnl to database IDs
    #channel_group_map = make_channel_group_map(channel_groups)
    if len(metric_map) == 0:
        print("Warning, no metric ids in SQUAC for the requested metrics, nothing to do")
        return None, None
    if len(channel_map) == 0:
        print("Warning, no channel ids in SQUAC, nothing to do")
        return None, None
    print("Loading the following metrics:")
    for m in metric_map:
        print("\t{}\n".format(m))

    measurements = []
    for scnl in scnldict:
        if scnl in channel_map:
            # Add to channel_group if it isn't in there yet
            # TO DO
            # loop over the metrics we are harvesting
            for m_name in metric_map:
                if '3.5' in m_name:
                    # percent packets not late
                    value = 100 * (scnldict[scnl]['npackets']-scnldict[scnl]['nlate'])/scnldict[scnl]['npackets']
                elif not '3.5' in m_name and 'latency' in m_name:
                    # average data latency
                    value = scnldict[scnl]['latency']
                elif 'gaps' in m_name:
                    # gaps in units count per hour
                    value = 3600. * (scnldict[scnl]['ngap']/scnldict[scnl]['duration'])
                elif 'packet_length' in m_name:
                    # average packet length in s
                    value = scnldict[scnl]['packet_length']
                elif "completeness" in m_name and "penalty" in m_name:
                    #  pct of timewindow that has data minus ngap*gap_penalty.
                    value = 100 * ( \
                        scnldict[scnl]['duration'] - \
                        scnldict[scnl]['gap_dur'] - \
                        gap_penalty * scnldict[scnl]['ngap']\
                        ) / scnldict[scnl]['duration']
                elif 'completeness' in m_name:
                    # pct of timewindow that has data.
                    value = 100 * (scnldict[scnl]['duration']-scnldict[scnl]['gap_dur'])/scnldict[scnl]['duration']
                measurement = WriteOnlyMeasurementSerializer(
                    metric=metric_map[m_name],
                    channel=channel_map[scnl],
                    value=value,
                    starttime=datetime.utcfromtimestamp(scnldict[scnl]['starttime']),
                    endtime=datetime.utcfromtimestamp(scnldict[scnl]['endtime'])
                )
                measurements.append(measurement)
        else:
            print("Channel {} not in SQUAC yet".format(scnl))

    response, errors = perform_bulk_create(measurements, client)
    return response, errors


def getStationDict(url='http://pnsn.org/stations.json'):
    '''gets station list from PNSN json feed and puts data into
    dictionary indexed on station and network name.
    stadict['sta']['net'].keys()=elev,lat,lon,type
    @return stadict - station dictionary'''
    import urllib
    import json
    u=urllib.urlopen(url)
    if not u:
        print('getStationDict() could not open {}'.format(url))
        return None
    l=u.readlines()
    u.close()
    d=json.loads(l[0],'UTF-8')
    stadict={}
    for s in d: #put into simpler station-keyed dictionary
        if not s['sta'] in stadict:
            stadict[s['sta']]={}
        stadict[s['sta']][s['net']]={'elev':float(s['elev']),
                                     'lat':float(s['lat']),
                                     'lon':float(s['lon']),
                                     'type':s['type']}
    return stadict

if __name__=="__main__":
    """
        Runs sniffwave and provides latency, gap, out-of-order, and completeness metric for the duration requested.
        Args:
            ring_name(string): name of earthworm ring to sniff, e.g. WAVE_RING
            sta(string): station code to sniff for, use 'wild' for all
            chan(string): channel code to sniff for, use 'wild' for all
            net(string): network code to sniff for, use 'wild' for all
            loc(string): location code to sniff for, use 'wild' for all
            duration(float): duration in s to sniff for (optional, default=10s)
            --fname(string): name of output-file, if omitted, output goes to outdir/YYYY-mm-dd_sniffwave_tally.csv
            --outdir(string): name of output directory, default = /tmp
            --bindir(string): full path to directory containing sniffwave executable (default = /home/eworm/bin)
            --inst(string): institution name
            --all: add average latency,stdev latency, average packet lenght, stdev packet length to output.
            --squac(string): prefix for ring_latency and ring_gaps metrics for squac
        Returns:
            int: status

        Example:
            sniffwave_tally WAVE_RING wild wild wild wild 600

        writes the following metrics to file:
             scnl, starttime, endtime, duration, npackets, nlate, ngap, gap_dur, noverlap, overlap_dur, n_oo, oo_dur
        with option --all:
             scnl, starttime, endtime, duration, npackets, nlate, ngap, gap_dur, noverlap, overlap_dur, n_oo, oo_dur,latency_ave,latency_stdev,packet_length_ave,packet_length_stdev

    """
    latlon=False
    output_all=False
    to_squac=False
    metric_prefix=""
    seconds=None # duration of running sniffwave or interval of which output is written
    bindir="/home/eworm/bin" # path to sniffwave
    outdir="/tmp" # path to output directory
    if len(sys.argv) >= 6:
        #set up command string
        try:
            index = sys.argv.index('--outdir')
            outdir = sys.argv[index+1]
            sys.argv.remove('--outdir')
            sys.argv.pop(index)
        except:
            pass #  keep default
        try:
            index = sys.argv.index('--inst')
            institution = sys.argv[index+1]
            sys.argv.remove('--inst')
            sys.argv.pop(index)
        except:
            pass #  keep default
        try:
            index = sys.argv.index('--fname')
            filename = sys.argv[index+1]
            sys.argv.remove('--fname')
            sys.argv.pop(index)
            try:
                filename = outdir + "/" + filename + "." + institution + ".csv"
            except:
                filename = outdir + "/" + filename + ".csv"
        except:
            # default: outdir/utc_date_sniffwave_tally.csv
            now = datetime.utcnow()
            try:
                filename = outdir + "/" + now.strftime("%Y-%m-%d") + "_sniffwave_tally." + institution + ".csv"
            except:
                filename = outdir + "/" + now.strftime("%Y-%m-%d") + "_sniffwave_tally.csv"
        try:
            index = sys.argv.index('--bindir')
            bindir = sys.argv[index+1]
            sys.argv.remove('--bindir')
            sys.argv.pop(index)
        except:
            pass # keep default
        try:
            index = sys.argv.index('--squac')
            metric_prefix = sys.argv[index+1]
            to_squac=True
            output_all = True
            sys.argv.remove('--squac')
            sys.argv.pop(index)
        except:
            pass #  keep default
        if '--latlon' in sys.argv:  #add lat-lon to output
            latlon=getStationDict()
            sys.argv.remove('--latlon')
        if '--all' in sys.argv:  #add latency and packet_length to output
            output_all = True
            sys.argv.remove('--all')
        larg=sys.argv[-1]
        if larg.isdigit():
            seconds=int(larg)
        if not seconds:
            seconds=default_seconds
            if larg=='y' or larg=='n':
                sys.argv[-1]='%s'%seconds
            else:
                sys.argv.append('%s'%seconds)
        print("writing  to  {}".format(filename))
        cmd=[bindir + '/sniffwave']+sys.argv[1:]
        unixstart=time.time()
    else:
        usage()
        sys.exit(0)

    if to_squac and not output_all:
        print("Error, to send metrics to SQUAC also specify the --all flag")
        sys.exit(1)
    if to_squac and no_squacapi:
        print("Error, squacapi_client not available")
        sys.exit(1)

    #run sniffwave and consume output lines while it runs
    scmd = ",".join(cmd).replace(",", " ")
    print("sniffwave command:  " + scmd)
    intervalstart = unixstart
    try:
        p=Popen(cmd,stdout=PIPE)
    except Exception as e:
        print("Error running {}: {}".format(cmd,e))
        sys.exit(1)
    output = p.stdout.readlines()
    now_unix = datetime.utcnow().timestamp()
    if output:
        scnldict={}
        for line in output:
            p=parseline(line)
            if p:
                (scnl,dt,starttime,endtime,lat,size)=p
                if ( endtime > intervalstart or endtime <= intervalstart ) and ( abs(starttime-now_unix) < 86400 ) :
                    packlen = endtime - starttime
                    latency = lat + 0.5*packlen
                    if scnl in scnldict:
                        scnldict[scnl]['packet_length'] += packlen
                        scnldict[scnl]['packet_squared'] += packlen*packlen
                        scnldict[scnl]['latency'] += latency
                        scnldict[scnl]['latency_squared'] += latency*latency
                        scnldict[scnl]['bytes'] += size
                        scnldict[scnl]['npackets']+=1
                        if latency > LATENCY_THRESHOLD:
                            scnldict[scnl]['nlate'] += 1
                        if starttime - (scnldict[scnl]['prev_endtime'] + dt) > TOLERANCE:
                            # gap!
                            scnldict[scnl]['ngap'] += 1
                            scnldict[scnl]['gap_dur'] += (starttime-(scnldict[scnl]['prev_endtime']+dt))
                        if starttime - (scnldict[scnl]['prev_endtime'] + dt) < -1*TOLERANCE and \
                           starttime >= scnldict[scnl]['prev_starttime']: # overlap!
                            scnldict[scnl]['noverlap'] += 1
                            scnldict[scnl]['overlap_dur'] += (starttime-(scnldict[scnl]['prev_endtime']+dt))
                        if endtime < scnldict[scnl]['prev_starttime']:
                            # starttime pre-dates a packet we've already seen, out-of-order!
                            scnldict[scnl]['n_oo'] += 1
                            scnldict[scnl]['oo_dur'] += packlen
                        scnldict[scnl]['prev_starttime'] = starttime
                        scnldict[scnl]['endtime'] = endtime
                        scnldict[scnl]['prev_endtime'] = endtime
                    else:
                        # first packet for this scnl
                        scnldict[scnl]={'starttime' : starttime,
                                        'prev_starttime' : starttime,
                                        'endtime' : endtime,
                                        'prev_endtime' : endtime,
                                        'ngap' : 0,
                                        'gap_dur' : 0.0,
                                        'noverlap' : 0,
                                        'overlap_dur' : 0.0,
                                        'n_oo' : 0,
                                        'oo_dur' : 0.0,
                                        'nlate' : 0,
                                        'packet_length':packlen,
                                        'packet_squared':packlen*packlen,
                                        'latency':latency,
                                        'latency_squared':latency*latency,
                                        'bytes' : 0,
                                        'npackets':1}
                        # check if first packet is late
                        if latency > LATENCY_THRESHOLD:
                            scnldict[scnl]['nlate'] += 1

    # output at the end of the sniffwave run
    for scnl in scnldict:
        # get average latency and approximate stdev
        ave, stdev = average_stdev(scnldict[scnl]['latency'], \
                                       scnldict[scnl]['latency_squared'], \
                                       scnldict[scnl]['npackets'])
        scnldict[scnl]['latency'] = ave
        scnldict[scnl]['latency_stdev'] = stdev
        # get average packet length and approximate stdev
        ave, stdev = average_stdev(scnldict[scnl]['packet_length'], \
                                       scnldict[scnl]['packet_squared'], \
                                       scnldict[scnl]['npackets'])
        scnldict[scnl]['packet_length'] = ave
        scnldict[scnl]['packet_stdev'] = stdev

    # write to file, create file or append
    if filename:
        with open(filename,'a+') as fh:
            if output_all:
                fh.write(latency_report(scnldict))
            else:
                fh.write(eew_stationreport_input(scnldict))
    else:
        if output_all:
            sys.stdout.write(latency_report(scnldict))
        else:
            sys.stdout.write(eew_stationreport_input(scnldict))

    if to_squac:
        res, err = send_to_squac(scnldict,metric_prefix)
        if res:
            print("Sent {} measurements to SQUAC, errors: {}".format(len(res), err))
        else:
            print("Nothing sent to SQUAC")

    sys.exit(0)
