from datetime import datetime from pcp import pmapi import cpmapi as c_api import sys def get_values(ctx, metrics): '''Given a list of metrics, it returns a dictionary of dictionaries in the following form: return[metric1] = {'indom1': [(ts0, ts1, .., tsN), (v0, v1, .., vN)], .... 'indomN': [(ts0, ts1, .., tsN), (v0, v1, .., vN)]} return[metric2] = {'indom1': [(ts0, ts1, .., tsX), (v0, v1, .., vX)], .... 'indomN': [(ts0, ts1, .., tsX), (v0, v1, .., vX)]} (ts0, .., tsN) are timestamps in datetime format and (v0, .., vN) are the actual values. If a metric has no indom use 0 as its key.''' start = context.pmGetArchiveLabel().start data = {} for metric in metrics: # For each metric start at the beginning of the file context.pmSetMode(c_api.PM_MODE_FORW, start, 0) #print("{0} metric, {1} pmids, {2} descs".format(metric, len(pmid), len(desc))) data[metric] = {} indoms = {} while 1: # Keep fetching data until pmFetch errors out pmid = context.pmLookupName(metric) # Moved both these in the while loop but no change desc = context.pmLookupDescs(pmid) # they used to be in the for metrics loop try: result = context.pmFetch(pmid) except pmapi.pmErr, error: # Exit if we are at the end of the file or if the record is corrupted # Signal any other issues if error.args[0] in [c_api.PM_ERR_EOL, c_api.PM_ERR_LOGREC]: break raise error time_val = result.contents.timestamp ts = datetime.fromtimestamp(time_val.tv_sec + time_val.tv_usec * 10**-6) for m in range(len(desc)): count = result.contents.get_numval(m) if count == 0: continue try: (insts, nodes) = context.pmGetInDomArchive(desc[m]) except pmapi.pmErr, error: if error.args[0] not in [c_api.PM_ERR_INDOM]: raise error insts = [0] nodes = [0] except Exception, error: raise error # BUG? Do not use range(len(insts)) because if the indoms change during # the pmFetch() loop pmExtractValue() will segfault # using range(count) fixes the segfault for inst in range(len(insts)): mtype = desc[m].contents.type value = context.pmExtractValue( result.contents.get_valfmt(m), result.contents.get_vlist(m, inst), mtype, mtype) node = nodes[inst] if mtype == c_api.PM_TYPE_STRING: tmp = value.cp elif mtype in [c_api.PM_TYPE_U64, c_api.PM_TYPE_64, c_api.PM_TYPE_U32, c_api.PM_TYPE_32]: tmp = value.ull elif mtype == c_api.PM_TYPE_FLOAT: tmp = value.f elif mtype == c_api.PM_TYPE_DOUBLE: tmp = value.d else: raise Exception("Metric has type: %s[%s]" % ( metric, mtype)) if node not in indoms: indoms[node] = [[ts,], [tmp,]] else: indoms[node][0].append(ts) indoms[node][1].append(tmp) context.pmFreeResult(result) data[metric] = indoms return data pmns = {} def traverse(metric): pmns[metric] = None context = pmapi.pmContext(c_api.PM_CONTEXT_ARCHIVE, sys.argv[1]) context.pmTraversePMNS('', traverse) metrics = sorted(pmns.keys()) ret = get_values(context, metrics) # verify that len(timestamps) == len(values) for every indom in every metric for metric in sorted(ret): indoms = ret[metric] for indom in indoms: (ts, values) = indoms[indom] if len(ts) != len(values): raise Exception('{0}[{1}]: {2} - {3}'.format(metric, indom, ts, values)) print('{0}[{1}] ok'.format(metric, indom)) # Look at one metric metric = 'network.interface.out.bytes' print print('Metric: {0}'.format(metric)) indoms = ret[metric] for i in indoms: print('Indom {0} has values: {1}'.format(i, len(indoms[i][1])))