diff options
Diffstat (limited to 'src/pmevent/doargs.c')
-rw-r--r-- | src/pmevent/doargs.c | 517 |
1 files changed, 517 insertions, 0 deletions
diff --git a/src/pmevent/doargs.c b/src/pmevent/doargs.c new file mode 100644 index 0000000..0692c31 --- /dev/null +++ b/src/pmevent/doargs.c @@ -0,0 +1,517 @@ +/* + * Copyright (c) 1995-2001 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2008-2009 Aconex. All Rights Reserved. + * Copyright (c) 2011 Red Hat Inc. + * Copyright (c) 2011 Ken McDonell. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "pmevent.h" + +static int setupEventTrace(int, char **, int, char *); +static char *options = "a:D:gh:K:LO:p:S:s:T:t:vx:zZ:?"; +static char usage[] = + "Usage: %s [options] metricname ...\n\n" + "Options:\n" + " -a archive metrics source is a PCP archive\n" + " -g start in GUI mode with new time control\n" + " -h host metrics source is PMCD on host\n" + " -K spec optional additional PMDA spec for local connection\n" + " spec is of the form op,domain,dso-path,init-routine\n" + " -L metrics source is a local context\n" + " -O offset initial offset into the reporting time window\n" + " -p port port number for connection to existing time control\n" + " -S starttime start of the reporting time window\n" + " -s samples terminate after this many samples\n" + " -T endtime end of the reporting time window\n" + " -t interval sample interval [default 1 second]\n" + " -v increase diagnostic output\n" + " -x filter optionally enable and filter the event stream\n" + " -Z timezone set reporting timezone\n" + " -z set reporting timezone to local timezone of metrics source\n"; + +/* process command line options and flags - exits on error */ +void +doargs(int argc, char **argv) +{ + int c; + long d; + int errflag = 0; + int m; + int src = 0; + int have_context = 0; + int sts; + char *endnum; + char *errmsg; + char *Sflag = NULL; /* argument of -S flag */ + char *Tflag = NULL; /* argument of -T flag */ + char *Oflag = NULL; /* argument of -O flag */ + char *xflag = NULL; /* argument of -x flag */ + int zflag = 0; /* for -z */ + char *tz = NULL; /* for -Z timezone */ + int tzh; /* initial timezone handle */ + struct timeval logStart; + metric_t *mp; + pmMetricSpec *msp; + char *msg; + static pmLogLabel label; + static char *default_host_conn = "local:"; + char *host_conn = default_host_conn; /* argument of -h */ + const char *tmp; + + delta.tv_sec = 1; + delta.tv_usec = 0; + samples = ALL_SAMPLES; + + /* extract command-line arguments */ + while ((c = getopt(argc, argv, options)) != EOF) { + switch (c) { + + case 'a': /* archive */ + if (++src > 1) { + fprintf(stderr, "%s: at most one of -a/-h/-L allowed\n", pmProgname); + errflag++; + } + ahtype = PM_CONTEXT_ARCHIVE; + archive = optarg; + break; + + case 'D': /* debug flag */ + sts = __pmParseDebug(optarg); + if (sts < 0) { + fprintf(stderr, "%s: unrecognized debug flag specification (%s)\n", + pmProgname, optarg); + errflag++; + } + else + pmDebug |= sts; + break; + + case 'g': /* use "gui" mode */ + if (port != -1) { + fprintf(stderr, "%s: at most one of -g and -p allowed\n", pmProgname); + errflag++; + } + else + gui = 1; + break; + + case 'h': /* host name */ + if (++src > 1) { + fprintf(stderr, "%s: at most one of -a/-h/-L allowed\n", pmProgname); + errflag++; + } + ahtype = PM_CONTEXT_HOST; + host_conn = optarg; + break; + + case 'K': /* update local PMDA table */ + if ((errmsg = __pmSpecLocalPMDA(optarg)) != NULL) { + fprintf(stderr, "%s: illegal -K argument\n", pmProgname); + fputs(errmsg, stderr); + fputc('\n', stderr); + errflag++; + } + break; + + case 'L': /* use local context */ + if (++src > 1) { + fprintf(stderr, "%s: at most one of -a/-h/-L allowed\n", pmProgname); + errflag++; + } + ahtype = PM_CONTEXT_LOCAL; + break; + + case 'O': /* start report time offset */ + Oflag = optarg; + break; + + case 'p': /* port for slave of existing time control */ + if (gui == 1) { + fprintf(stderr, "%s: at most one of -g and -p allowed\n", pmProgname); + errflag++; + } + else { + port = (int)strtol(optarg, &endnum, 10); + if (*endnum != '\0' || port < 0) { + fprintf(stderr, "%s: -p requires a positive numeric argument\n", pmProgname); + port = -1; + errflag++; + } + } + break; + + case 's': /* sample count */ + d = (int)strtol(optarg, &endnum, 10); + if (Tflag) { + fprintf(stderr, "%s: at most one of -s and -T allowed\n", pmProgname); + errflag++; + } + else if (*endnum != '\0' || d < 0) { + fprintf(stderr, "%s: -s requires a positive numeric argument\n", pmProgname); + errflag++; + } + else + samples = d; + break; + + case 'S': /* start report time */ + Sflag = optarg; + break; + + case 't': /* sampling interval */ + if (pmParseInterval(optarg, &delta, &msg) < 0) { + fprintf(stderr, "%s: illegal -t argument\n", pmProgname); + fputs(msg, stderr); + free(msg); + errflag++; + } + break; + + case 'T': /* end reporting time */ + if (samples != ALL_SAMPLES) { + fprintf(stderr, "%s: at most one of -s and -T allowed\n", pmProgname); + errflag++; + } + Tflag = optarg; + break; + + case 'v': + verbose++; + break; + + case 'x': + xflag = optarg; + break; + + case 'z': /* timezone from metrics source */ + if (tz != NULL) { + fprintf(stderr, "%s: at most one of -Z and/or -z allowed\n", pmProgname); + errflag++; + } + zflag++; + break; + + case 'Z': /* $TZ timezone */ + if (zflag) { + fprintf(stderr, "%s: at most one of -Z and/or -z allowed\n", pmProgname); + errflag++; + } + tz = optarg; + break; + + case '?': + fprintf(stderr, usage, pmProgname); + exit(EXIT_FAILURE); + + default: + errflag++; + } + } + + if (errflag) { + fprintf(stderr, usage, pmProgname); + exit(EXIT_FAILURE); + } + + if (optind >= argc) { + fprintf(stderr, "Error: no metricname specified\n"); + exit(EXIT_FAILURE); + } + + /* parse uniform metric spec */ + for ( ; optind < argc; optind++) { + if (ahtype == PM_CONTEXT_ARCHIVE) + sts = pmParseMetricSpec(argv[optind], 1, archive, &msp, &msg); + else + sts = pmParseMetricSpec(argv[optind], 0, host_conn, &msp, &msg); + if (sts < 0) { + fprintf(stderr, "%s: bad metric specification\n", pmProgname); + fputs(msg, stderr); + free(msg); + exit(EXIT_FAILURE); + } + + if (msp->isarch == 0) { + if (ahtype == -1) { + ahtype = PM_CONTEXT_HOST; + host_conn = msp->source; + } + else if ((ahtype == PM_CONTEXT_ARCHIVE) || + (ahtype == PM_CONTEXT_LOCAL && + (strcmp(msp->source, default_host_conn)))) { + fprintf(stderr, "%s: %s: only one type of metric source allowed\n", pmProgname, argv[optind]); + exit(EXIT_FAILURE); + } + else if (strcmp(host_conn, msp->source) != 0) { + fprintf(stderr, "%s: %s: only one metric source allowed, found hosts %s and %s\n", pmProgname, argv[optind], host_conn, msp->source); + exit(EXIT_FAILURE); + } + } + else if (msp->isarch == 1) { + if (ahtype == -1) { + ahtype = PM_CONTEXT_ARCHIVE; + archive = msp->source; + } + else if (ahtype != PM_CONTEXT_ARCHIVE) { + fprintf(stderr, "%s: %s: only one type of metric source allowed\n", pmProgname, argv[optind]); + exit(EXIT_FAILURE); + } + else if (strcmp(archive, msp->source) != 0) { + fprintf(stderr, "%s: %s: only one metric source allowed, found archives %s and %s\n", pmProgname, argv[optind], archive, msp->source); + exit(EXIT_FAILURE); + } + } + else if (msp->isarch == 2) { + if (ahtype == -1) { + ahtype = PM_CONTEXT_LOCAL; + } + else if (ahtype != PM_CONTEXT_LOCAL) { + fprintf(stderr, "%s: %s: only one type of metric source allowed\n", pmProgname, argv[optind]); + exit(EXIT_FAILURE); + } + } + + if (!have_context) { + if (ahtype == PM_CONTEXT_ARCHIVE) { + /* open connection to archive */ + if ((sts = pmNewContext(PM_CONTEXT_ARCHIVE, archive)) < 0) { + fprintf(stderr, "%s: Cannot open archive \"%s\": %s\n", + pmProgname, msp->source, pmErrStr(sts)); + exit(EXIT_FAILURE); + } + ctxhandle = sts; + if ((sts = pmGetArchiveLabel(&label)) < 0) { + fprintf(stderr, "%s: Cannot get archive label record: %s\n", + pmProgname, pmErrStr(sts)); + exit(EXIT_FAILURE); + } + have_context = 1; + logStart = label.ll_start; + host = label.ll_hostname; + if ((sts = pmGetArchiveEnd(&last)) < 0) { + fprintf(stderr, "%s: Cannot determine end of archive: %s", + pmProgname, pmErrStr(sts)); + exit(EXIT_FAILURE); + } + } + else { + /* open connection to host or local context */ + if ((sts = pmNewContext(ahtype, host_conn)) < 0) { + if (ahtype == PM_CONTEXT_HOST) + fprintf(stderr, "%s: Cannot connect to PMCD on host \"%s\": %s\n", + pmProgname, msp->source, pmErrStr(sts)); + else + fprintf(stderr, "%s: Cannot establish local context: %s\n", + pmProgname, pmErrStr(sts)); + exit(EXIT_FAILURE); + } + ctxhandle = sts; + have_context = 1; + __pmtimevalNow(&logStart); + } + } + + /* Look up the host name according to the pmcd or the archive. */ + tmp = pmGetContextHostName(ctxhandle); + if (strlen(tmp) == 0) { + fprintf(stderr, "%s: pmGetContextHostName(%d) failed\n", + pmProgname, ctxhandle); + exit(EXIT_FAILURE); + } + if ((host = strdup(tmp)) == NULL) + __pmNoMem("host name copy", strlen(tmp)+1, PM_FATAL_ERR); + + for (m = 0; m < nmetric; m++) { + if (strcmp(msp->metric, metrictab[m].name) == 0) + break; + } + if (m < nmetric) + mp = &metrictab[m]; + else { + nmetric++; + metrictab = (metric_t *)realloc(metrictab, nmetric*sizeof(metrictab[0])); + if (metrictab == NULL) { + __pmNoMem("metrictab", nmetric*sizeof(metrictab[0]), PM_FATAL_ERR); + /*NOTREACHED*/ + } + mp = &metrictab[nmetric-1]; + mp->name = msp->metric; + if ((sts = pmLookupName(1, &mp->name, &mp->pmid)) < 0) { + fprintf(stderr, "%s: pmLookupName: %s: %s\n", pmProgname, mp->name, pmErrStr(sts)); + exit(EXIT_FAILURE); + } + if ((sts = pmLookupDesc(mp->pmid, &mp->desc)) < 0) { + fprintf(stderr, "%s: pmLookupDesc: %s: %s\n", pmProgname, mp->name, pmErrStr(sts)); + exit(EXIT_FAILURE); + } + if (mp->desc.type != PM_TYPE_EVENT && + mp->desc.type != PM_TYPE_HIGHRES_EVENT) { + fprintf(stderr, "%s: %s: metrics must be of event type\n", pmProgname, mp->name); + exit(EXIT_FAILURE); + } + mp->ninst = 0; + mp->iname = NULL; + mp->inst = NULL; + mp->ihash.nodes = 0; + mp->ihash.hsize = 0; + mp->ihash.hash = NULL; + } + + if (msp->ninst > 0) { + int i; + int j; + if (mp->desc.indom == PM_INDOM_NULL) { + fprintf(stderr, "%s: %s: singular metrics do not have instances\n", pmProgname, argv[optind]); + exit(EXIT_FAILURE); + } + i = mp->ninst; + mp->ninst += msp->ninst; + mp->iname = (char **)realloc(mp->iname, mp->ninst*sizeof(mp->iname[0])); + if (mp->iname == NULL) { + __pmNoMem("iname[]", mp->ninst*sizeof(mp->iname[0]), PM_FATAL_ERR); + /*NOTREACHED*/ + } + mp->inst = (int *)realloc(mp->inst, mp->ninst*sizeof(mp->inst[0])); + if (mp->inst == NULL) { + __pmNoMem("inst[]", mp->ninst*sizeof(mp->inst[0]), PM_FATAL_ERR); + /*NOTREACHED*/ + } + for (j = 0; j < msp->ninst; j++, i++) { + mp->iname[i] = msp->inst[j]; + if (ahtype == PM_CONTEXT_ARCHIVE) + sts = pmLookupInDomArchive(mp->desc.indom, mp->iname[i]); + else + sts = pmLookupInDom(mp->desc.indom, mp->iname[i]); + if (sts < 0) { + fprintf(stderr, "%s: pmLookupInDom: %s[%s]: %s\n", pmProgname, mp->name, mp->iname[i], pmErrStr(sts)); + exit(EXIT_FAILURE); + } + mp->inst[i] = sts; + } + } + + /* + * don't call pmFreeMetricSpec(msp) because we retain pointers into + * the structure + */ + } + + if (zflag) { + if ((tzh = pmNewContextZone()) < 0) { + fprintf(stderr, "%s: Cannot set context timezone: %s\n", + pmProgname, pmErrStr(tzh)); + exit(EXIT_FAILURE); + } + if (ahtype == PM_CONTEXT_ARCHIVE) { + printf("Note: timezone set to local timezone of host \"%s\" from archive\n\n", + host); + } + else { + printf("Note: timezone set to local timezone of host \"%s\"\n\n", host); + } + } + else if (tz != NULL) { + if ((tzh = pmNewZone(tz)) < 0) { + fprintf(stderr, "%s: Cannot set timezone to \"%s\": %s\n", + pmProgname, tz, pmErrStr(tzh)); + exit(EXIT_FAILURE); + } + printf("Note: timezone set to \"TZ=%s\"\n\n", tz); + } + + if (pmParseTimeWindow(Sflag, Tflag, NULL, Oflag, + &logStart, &last, &first, &last, &now, &msg) < 0) { + fprintf(stderr, "%s", msg); + exit(EXIT_FAILURE); + } + + if (setupEventTrace(argc, argv, ahtype, xflag) < 0) + exit(EXIT_FAILURE); + + if (pmDebug & DBG_TRACE_APPL0) { + char timebuf[26]; + char *tp; + int i; + fprintf(stderr, "first=%.6f", __pmtimevalToReal(&first)); + tp = pmCtime(&first.tv_sec, timebuf); + /* + * tp -> Ddd Mmm DD HH:MM:SS YYYY\n + * 0 4 8 1 1 2 2 2 + * 1 8 0 3 4 + */ + fprintf(stderr, " [%24.24s]\n", tp); + fprintf(stderr, "now=%.6f", __pmtimevalToReal(&now)); + tp = pmCtime(&now.tv_sec, timebuf); + fprintf(stderr, " [%24.24s]\n", tp); + fprintf(stderr, "last=%.6f", __pmtimevalToReal(&last)); + tp = pmCtime(&last.tv_sec, timebuf); + fprintf(stderr, " [%24.24s]\n", tp); + fprintf(stderr, "delta=%.6f\n", __pmtimevalToReal(&delta)); + if (samples != ALL_SAMPLES) + fprintf(stderr, "samples=%ld\n", samples); + for (m = 0; m < nmetric; m++) { + fprintf(stderr, "[%d] metric: %s", m, metrictab[m].name); + if (metrictab[m].ninst > 0) { + fprintf(stderr, " instance:"); + for (i = 0; i < metrictab[m].ninst; i++) { + if (i == 0) + fputc(' ', stderr); + else + fprintf(stderr, ", "); + fprintf(stderr, "%s (%d)", metrictab[m].iname[i], metrictab[m].inst[i]); + } + fputc('\n', stderr); + } + } + } +} + +int +setupEventTrace(int argc, char **argv, int ahtype, char *xflag) +{ + pmValueSet pmvs; + pmValueBlock *pmvbp; + pmResult store = { .numpmid = 1 }; + int m, vlen; + + if (ahtype == PM_CONTEXT_ARCHIVE) + return 0; /* nothing to do at this stage */ + + if (ahtype == PM_CONTEXT_HOST) + __pmSetClientIdArgv(argc, argv); + + /* build pmResult for pmStore call if we're explicitly enabling events */ + if (xflag != NULL) { + vlen = PM_VAL_HDR_SIZE + strlen(xflag) + 1; + pmvbp = (pmValueBlock *)malloc(vlen); + if (!pmvbp) + __pmNoMem("store", vlen, PM_FATAL_ERR); + pmvbp->vtype = PM_TYPE_STRING; + pmvbp->vlen = vlen; + strcpy(pmvbp->vbuf, xflag); + + store.vset[0] = &pmvs; + for (m = 0; m < nmetric; m++) { + pmvs.pmid = metrictab[m].pmid; + pmvs.numval = 1; + pmvs.valfmt = PM_VAL_SPTR; + pmvs.vlist[0].inst = PM_IN_NULL; + pmvs.vlist[0].value.pval = pmvbp; + + pmStore(&store); + } + + free(pmvbp); + } + return 0; +} |