1*81b1a5f5Stb /* $OpenBSD: ometric.c,v 1.10 2023/01/06 13:26:57 tb Exp $ */
277a10e6fSclaudio
377a10e6fSclaudio /*
477a10e6fSclaudio * Copyright (c) 2022 Claudio Jeker <claudio@openbsd.org>
577a10e6fSclaudio *
677a10e6fSclaudio * Permission to use, copy, modify, and distribute this software for any
777a10e6fSclaudio * purpose with or without fee is hereby granted, provided that the above
877a10e6fSclaudio * copyright notice and this permission notice appear in all copies.
977a10e6fSclaudio *
1077a10e6fSclaudio * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1177a10e6fSclaudio * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1277a10e6fSclaudio * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1377a10e6fSclaudio * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1477a10e6fSclaudio * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1577a10e6fSclaudio * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1677a10e6fSclaudio * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1777a10e6fSclaudio */
1877a10e6fSclaudio
1977a10e6fSclaudio #include <sys/queue.h>
208168f856Sclaudio #include <sys/time.h>
2177a10e6fSclaudio
2277a10e6fSclaudio #include <err.h>
2377a10e6fSclaudio #include <stdarg.h>
2477a10e6fSclaudio #include <stdint.h>
2577a10e6fSclaudio #include <stdio.h>
2677a10e6fSclaudio #include <stdlib.h>
2777a10e6fSclaudio #include <string.h>
2877a10e6fSclaudio
2977a10e6fSclaudio #include "ometric.h"
3077a10e6fSclaudio
3177a10e6fSclaudio struct olabel {
3277a10e6fSclaudio STAILQ_ENTRY(olabel) entry;
3377a10e6fSclaudio const char *key;
3477a10e6fSclaudio char *value;
3577a10e6fSclaudio };
3677a10e6fSclaudio
3777a10e6fSclaudio struct olabels {
3877a10e6fSclaudio STAILQ_HEAD(, olabel) labels;
3977a10e6fSclaudio struct olabels *next;
4077a10e6fSclaudio int refcnt;
4177a10e6fSclaudio };
4277a10e6fSclaudio
4377a10e6fSclaudio enum ovalue_type {
4477a10e6fSclaudio OVT_INTEGER,
4577a10e6fSclaudio OVT_DOUBLE,
4681e584e8Sclaudio OVT_TIMESPEC,
4777a10e6fSclaudio };
4877a10e6fSclaudio
4977a10e6fSclaudio struct ovalue {
5077a10e6fSclaudio STAILQ_ENTRY(ovalue) entry;
5177a10e6fSclaudio struct olabels *labels;
5277a10e6fSclaudio union {
535c88087bSclaudio unsigned long long i;
5477a10e6fSclaudio double f;
5581e584e8Sclaudio struct timespec ts;
5677a10e6fSclaudio } value;
5777a10e6fSclaudio enum ovalue_type valtype;
5877a10e6fSclaudio };
5977a10e6fSclaudio
6077a10e6fSclaudio STAILQ_HEAD(ovalues, ovalue);
6177a10e6fSclaudio
6277a10e6fSclaudio struct ometric {
6377a10e6fSclaudio STAILQ_ENTRY(ometric) entry;
6477a10e6fSclaudio struct ovalues vals;
6577a10e6fSclaudio const char *name;
6677a10e6fSclaudio const char *help;
6777a10e6fSclaudio const char *const *stateset;
6877a10e6fSclaudio size_t setsize;
6977a10e6fSclaudio enum ometric_type type;
7077a10e6fSclaudio };
7177a10e6fSclaudio
7277a10e6fSclaudio STAILQ_HEAD(, ometric) ometrics = STAILQ_HEAD_INITIALIZER(ometrics);
7377a10e6fSclaudio
740584fd62Sclaudio static const char *suffixes[] = { "_total", "_created", "_count",
750584fd62Sclaudio "_sum", "_bucket", "_gcount", "_gsum", "_info",
760584fd62Sclaudio };
770584fd62Sclaudio
780584fd62Sclaudio /*
790584fd62Sclaudio * Return true if name has one of the above suffixes.
800584fd62Sclaudio */
810584fd62Sclaudio static int
strsuffix(const char * name)820584fd62Sclaudio strsuffix(const char *name)
830584fd62Sclaudio {
840584fd62Sclaudio const char *suffix;
850584fd62Sclaudio size_t i;
860584fd62Sclaudio
870584fd62Sclaudio suffix = strrchr(name, '_');
880584fd62Sclaudio if (suffix == NULL)
890584fd62Sclaudio return 0;
900584fd62Sclaudio for (i = 0; i < sizeof(suffixes) / sizeof(suffixes[0]); i++) {
910584fd62Sclaudio if (strcmp(suffix, suffixes[i]) == 0)
920584fd62Sclaudio return 1;
930584fd62Sclaudio }
940584fd62Sclaudio return 0;
950584fd62Sclaudio }
960584fd62Sclaudio
970584fd62Sclaudio static void
ometric_check(const char * name)980584fd62Sclaudio ometric_check(const char *name)
990584fd62Sclaudio {
1000584fd62Sclaudio struct ometric *om;
1010584fd62Sclaudio
1020584fd62Sclaudio if (strsuffix(name))
1030584fd62Sclaudio errx(1, "reserved name suffix used: %s", name);
1040584fd62Sclaudio STAILQ_FOREACH(om, &ometrics, entry)
1050584fd62Sclaudio if (strcmp(name, om->name) == 0)
1060584fd62Sclaudio errx(1, "duplicate name: %s", name);
1070584fd62Sclaudio }
1080584fd62Sclaudio
10977a10e6fSclaudio /*
11077a10e6fSclaudio * Allocate and return new ometric. The name and help string need to remain
11177a10e6fSclaudio * valid until the ometric is freed. Normally constant strings should be used.
11277a10e6fSclaudio */
11377a10e6fSclaudio struct ometric *
ometric_new(enum ometric_type type,const char * name,const char * help)11477a10e6fSclaudio ometric_new(enum ometric_type type, const char *name, const char *help)
11577a10e6fSclaudio {
11677a10e6fSclaudio struct ometric *om;
11777a10e6fSclaudio
1180584fd62Sclaudio ometric_check(name);
1190584fd62Sclaudio
12077a10e6fSclaudio if ((om = calloc(1, sizeof(*om))) == NULL)
12177a10e6fSclaudio err(1, NULL);
12277a10e6fSclaudio
12377a10e6fSclaudio om->name = name;
12477a10e6fSclaudio om->help = help;
12577a10e6fSclaudio om->type = type;
12677a10e6fSclaudio STAILQ_INIT(&om->vals);
12777a10e6fSclaudio
12877a10e6fSclaudio STAILQ_INSERT_TAIL(&ometrics, om, entry);
12977a10e6fSclaudio
13077a10e6fSclaudio return om;
13177a10e6fSclaudio }
13277a10e6fSclaudio
13377a10e6fSclaudio /*
13477a10e6fSclaudio * Same as above but for a stateset. The states is an array of constant strings
13577a10e6fSclaudio * with statecnt elements. The states, name and help pointers need to remain
13677a10e6fSclaudio * valid until the ometric is freed.
13777a10e6fSclaudio */
13877a10e6fSclaudio struct ometric *
ometric_new_state(const char * const * states,size_t statecnt,const char * name,const char * help)13977a10e6fSclaudio ometric_new_state(const char * const *states, size_t statecnt, const char *name,
14077a10e6fSclaudio const char *help)
14177a10e6fSclaudio {
14277a10e6fSclaudio struct ometric *om;
14377a10e6fSclaudio
1440584fd62Sclaudio ometric_check(name);
1450584fd62Sclaudio
14677a10e6fSclaudio if ((om = calloc(1, sizeof(*om))) == NULL)
14777a10e6fSclaudio err(1, NULL);
14877a10e6fSclaudio
14977a10e6fSclaudio om->name = name;
15077a10e6fSclaudio om->help = help;
15177a10e6fSclaudio om->type = OMT_STATESET;
15277a10e6fSclaudio om->stateset = states;
15377a10e6fSclaudio om->setsize = statecnt;
15477a10e6fSclaudio STAILQ_INIT(&om->vals);
15577a10e6fSclaudio
15677a10e6fSclaudio STAILQ_INSERT_TAIL(&ometrics, om, entry);
15777a10e6fSclaudio
15877a10e6fSclaudio return om;
15977a10e6fSclaudio }
16077a10e6fSclaudio
16177a10e6fSclaudio void
ometric_free_all(void)16277a10e6fSclaudio ometric_free_all(void)
16377a10e6fSclaudio {
16477a10e6fSclaudio struct ometric *om;
16577a10e6fSclaudio struct ovalue *ov;
16677a10e6fSclaudio
16777a10e6fSclaudio while ((om = STAILQ_FIRST(&ometrics)) != NULL) {
16877a10e6fSclaudio STAILQ_REMOVE_HEAD(&ometrics, entry);
16977a10e6fSclaudio while ((ov = STAILQ_FIRST(&om->vals)) != NULL) {
17077a10e6fSclaudio STAILQ_REMOVE_HEAD(&om->vals, entry);
17177a10e6fSclaudio olabels_free(ov->labels);
17277a10e6fSclaudio free(ov);
17377a10e6fSclaudio }
17477a10e6fSclaudio free(om);
17577a10e6fSclaudio }
17677a10e6fSclaudio }
17777a10e6fSclaudio
17877a10e6fSclaudio static struct olabels *
olabels_ref(struct olabels * ol)17977a10e6fSclaudio olabels_ref(struct olabels *ol)
18077a10e6fSclaudio {
18177a10e6fSclaudio struct olabels *x = ol;
18277a10e6fSclaudio
18377a10e6fSclaudio while (x != NULL) {
18477a10e6fSclaudio x->refcnt++;
18577a10e6fSclaudio x = x->next;
18677a10e6fSclaudio }
18777a10e6fSclaudio
18877a10e6fSclaudio return ol;
18977a10e6fSclaudio }
19077a10e6fSclaudio
19177a10e6fSclaudio /*
19277a10e6fSclaudio * Create a new set of labels based on keys and values arrays.
19377a10e6fSclaudio * keys must end in a NULL element. values needs to hold as many elements
19477a10e6fSclaudio * but the elements can be NULL. values are copied for the olabel but
19577a10e6fSclaudio * keys needs to point to constant memory.
19677a10e6fSclaudio */
19777a10e6fSclaudio struct olabels *
olabels_new(const char * const * keys,const char ** values)19877a10e6fSclaudio olabels_new(const char * const *keys, const char **values)
19977a10e6fSclaudio {
20077a10e6fSclaudio struct olabels *ol;
20177a10e6fSclaudio struct olabel *l;
20277a10e6fSclaudio
20377a10e6fSclaudio if ((ol = malloc(sizeof(*ol))) == NULL)
20477a10e6fSclaudio err(1, NULL);
20577a10e6fSclaudio STAILQ_INIT(&ol->labels);
20677a10e6fSclaudio ol->refcnt = 1;
20777a10e6fSclaudio ol->next = NULL;
20877a10e6fSclaudio
20977a10e6fSclaudio while (*keys != NULL) {
21077a10e6fSclaudio if (*values && **values != '\0') {
21177a10e6fSclaudio if ((l = malloc(sizeof(*l))) == NULL)
21277a10e6fSclaudio err(1, NULL);
21377a10e6fSclaudio l->key = *keys;
21477a10e6fSclaudio if ((l->value = strdup(*values)) == NULL)
21577a10e6fSclaudio err(1, NULL);
21677a10e6fSclaudio STAILQ_INSERT_TAIL(&ol->labels, l, entry);
21777a10e6fSclaudio }
21877a10e6fSclaudio
21977a10e6fSclaudio keys++;
22077a10e6fSclaudio values++;
22177a10e6fSclaudio }
22277a10e6fSclaudio
22377a10e6fSclaudio return ol;
22477a10e6fSclaudio }
22577a10e6fSclaudio
22677a10e6fSclaudio /*
22777a10e6fSclaudio * Free olables once nothing uses them anymore.
22877a10e6fSclaudio */
22977a10e6fSclaudio void
olabels_free(struct olabels * ol)23077a10e6fSclaudio olabels_free(struct olabels *ol)
23177a10e6fSclaudio {
23277a10e6fSclaudio struct olabels *next;
23377a10e6fSclaudio struct olabel *l;
23477a10e6fSclaudio
23577a10e6fSclaudio for ( ; ol != NULL; ol = next) {
23677a10e6fSclaudio next = ol->next;
23777a10e6fSclaudio
23877a10e6fSclaudio if (--ol->refcnt == 0) {
23977a10e6fSclaudio while ((l = STAILQ_FIRST(&ol->labels)) != NULL) {
24077a10e6fSclaudio STAILQ_REMOVE_HEAD(&ol->labels, entry);
24177a10e6fSclaudio free(l->value);
24277a10e6fSclaudio free(l);
24377a10e6fSclaudio }
24477a10e6fSclaudio free(ol);
24577a10e6fSclaudio }
24677a10e6fSclaudio }
24777a10e6fSclaudio }
24877a10e6fSclaudio
24977a10e6fSclaudio /*
25077a10e6fSclaudio * Add one extra label onto the label stack. Once no longer used the
25177a10e6fSclaudio * value needs to be freed with olabels_free().
25277a10e6fSclaudio */
25377a10e6fSclaudio static struct olabels *
olabels_add_extras(struct olabels * ol,const char ** keys,const char ** values)254e70d5757Sclaudio olabels_add_extras(struct olabels *ol, const char **keys, const char **values)
25577a10e6fSclaudio {
25677a10e6fSclaudio struct olabels *new;
25777a10e6fSclaudio
25877a10e6fSclaudio new = olabels_new(keys, values);
25977a10e6fSclaudio new->next = olabels_ref(ol);
26077a10e6fSclaudio
26177a10e6fSclaudio return new;
26277a10e6fSclaudio }
26377a10e6fSclaudio
26477a10e6fSclaudio /*
26577a10e6fSclaudio * Output function called last.
26677a10e6fSclaudio */
26777a10e6fSclaudio static const char *
ometric_type(enum ometric_type type)26877a10e6fSclaudio ometric_type(enum ometric_type type)
26977a10e6fSclaudio {
27077a10e6fSclaudio switch (type) {
27177a10e6fSclaudio case OMT_GAUGE:
27277a10e6fSclaudio return "gauge";
27377a10e6fSclaudio case OMT_COUNTER:
27477a10e6fSclaudio return "counter";
27577a10e6fSclaudio case OMT_STATESET:
27677a10e6fSclaudio return "stateset";
27777a10e6fSclaudio case OMT_HISTOGRAM:
27877a10e6fSclaudio return "histogram";
27977a10e6fSclaudio case OMT_SUMMARY:
28077a10e6fSclaudio return "summary";
28102b39b00Sclaudio case OMT_INFO:
28202b39b00Sclaudio return "info";
28377a10e6fSclaudio default:
28477a10e6fSclaudio return "unknown";
28577a10e6fSclaudio }
28677a10e6fSclaudio }
28777a10e6fSclaudio
28860a4dc80Sclaudio static int
ometric_output_labels(FILE * out,const struct olabels * ol)28960a4dc80Sclaudio ometric_output_labels(FILE *out, const struct olabels *ol)
29077a10e6fSclaudio {
29177a10e6fSclaudio struct olabel *l;
29277a10e6fSclaudio const char *comma = "";
29377a10e6fSclaudio
29460a4dc80Sclaudio if (ol == NULL)
29560a4dc80Sclaudio return fprintf(out, " ");
29677a10e6fSclaudio
29760a4dc80Sclaudio if (fprintf(out, "{") < 0)
29860a4dc80Sclaudio return -1;
29977a10e6fSclaudio
30077a10e6fSclaudio while (ol != NULL) {
30177a10e6fSclaudio STAILQ_FOREACH(l, &ol->labels, entry) {
30260a4dc80Sclaudio if (fprintf(out, "%s%s=\"%s\"", comma, l->key,
30360a4dc80Sclaudio l->value) < 0)
30460a4dc80Sclaudio return -1;
30577a10e6fSclaudio comma = ",";
30677a10e6fSclaudio }
30777a10e6fSclaudio ol = ol->next;
30877a10e6fSclaudio }
30977a10e6fSclaudio
31060a4dc80Sclaudio return fprintf(out, "} ");
31177a10e6fSclaudio }
31277a10e6fSclaudio
31360a4dc80Sclaudio static int
ometric_output_value(FILE * out,const struct ovalue * ov)31460a4dc80Sclaudio ometric_output_value(FILE *out, const struct ovalue *ov)
31577a10e6fSclaudio {
31677a10e6fSclaudio switch (ov->valtype) {
31777a10e6fSclaudio case OVT_INTEGER:
31860a4dc80Sclaudio return fprintf(out, "%llu", ov->value.i);
31977a10e6fSclaudio case OVT_DOUBLE:
32060a4dc80Sclaudio return fprintf(out, "%g", ov->value.f);
32181e584e8Sclaudio case OVT_TIMESPEC:
32281e584e8Sclaudio return fprintf(out, "%lld.%09ld",
32381e584e8Sclaudio (long long)ov->value.ts.tv_sec, ov->value.ts.tv_nsec);
32477a10e6fSclaudio }
32560a4dc80Sclaudio return -1;
32677a10e6fSclaudio }
32777a10e6fSclaudio
3280584fd62Sclaudio static int
ometric_output_name(FILE * out,const struct ometric * om)3290584fd62Sclaudio ometric_output_name(FILE *out, const struct ometric *om)
3300584fd62Sclaudio {
3310584fd62Sclaudio const char *suffix;
3320584fd62Sclaudio
3330584fd62Sclaudio switch (om->type) {
3340584fd62Sclaudio case OMT_COUNTER:
3350584fd62Sclaudio suffix = "_total";
3360584fd62Sclaudio break;
3370584fd62Sclaudio case OMT_INFO:
3380584fd62Sclaudio suffix = "_info";
3390584fd62Sclaudio break;
3400584fd62Sclaudio default:
3410584fd62Sclaudio suffix = "";
3420584fd62Sclaudio break;
3430584fd62Sclaudio }
3440584fd62Sclaudio return fprintf(out, "%s%s", om->name, suffix);
3450584fd62Sclaudio }
3460584fd62Sclaudio
34777a10e6fSclaudio /*
34877a10e6fSclaudio * Output all metric values with TYPE and optional HELP strings.
34977a10e6fSclaudio */
35060a4dc80Sclaudio int
ometric_output_all(FILE * out)35160a4dc80Sclaudio ometric_output_all(FILE *out)
35277a10e6fSclaudio {
35377a10e6fSclaudio struct ometric *om;
35477a10e6fSclaudio struct ovalue *ov;
35577a10e6fSclaudio
35677a10e6fSclaudio STAILQ_FOREACH(om, &ometrics, entry) {
35777a10e6fSclaudio if (om->help)
35860a4dc80Sclaudio if (fprintf(out, "# HELP %s %s\n", om->name,
35960a4dc80Sclaudio om->help) < 0)
36060a4dc80Sclaudio return -1;
36160a4dc80Sclaudio
36260a4dc80Sclaudio if (fprintf(out, "# TYPE %s %s\n", om->name,
36360a4dc80Sclaudio ometric_type(om->type)) < 0)
36460a4dc80Sclaudio return -1;
36577a10e6fSclaudio
36677a10e6fSclaudio STAILQ_FOREACH(ov, &om->vals, entry) {
3670584fd62Sclaudio if (ometric_output_name(out, om) < 0)
36860a4dc80Sclaudio return -1;
36960a4dc80Sclaudio if (ometric_output_labels(out, ov->labels) < 0)
37060a4dc80Sclaudio return -1;
37160a4dc80Sclaudio if (ometric_output_value(out, ov) < 0)
37260a4dc80Sclaudio return -1;
37360a4dc80Sclaudio if (fprintf(out, "\n") < 0)
37460a4dc80Sclaudio return -1;
37577a10e6fSclaudio }
37677a10e6fSclaudio }
37777a10e6fSclaudio
37860a4dc80Sclaudio if (fprintf(out, "# EOF\n") < 0)
37960a4dc80Sclaudio return -1;
38060a4dc80Sclaudio return 0;
38177a10e6fSclaudio }
38277a10e6fSclaudio
38377a10e6fSclaudio /*
38477a10e6fSclaudio * Value setters
38577a10e6fSclaudio */
38677a10e6fSclaudio static void
ometric_set_int_value(struct ometric * om,uint64_t val,struct olabels * ol)38777a10e6fSclaudio ometric_set_int_value(struct ometric *om, uint64_t val, struct olabels *ol)
38877a10e6fSclaudio {
38977a10e6fSclaudio struct ovalue *ov;
39077a10e6fSclaudio
39177a10e6fSclaudio if ((ov = malloc(sizeof(*ov))) == NULL)
39277a10e6fSclaudio err(1, NULL);
39377a10e6fSclaudio
39477a10e6fSclaudio ov->value.i = val;
39577a10e6fSclaudio ov->valtype = OVT_INTEGER;
39677a10e6fSclaudio ov->labels = olabels_ref(ol);
39777a10e6fSclaudio
39877a10e6fSclaudio STAILQ_INSERT_TAIL(&om->vals, ov, entry);
39977a10e6fSclaudio }
40077a10e6fSclaudio
40177a10e6fSclaudio /*
40277a10e6fSclaudio * Set an integer value with label ol. ol can be NULL.
40377a10e6fSclaudio */
40477a10e6fSclaudio void
ometric_set_int(struct ometric * om,uint64_t val,struct olabels * ol)40577a10e6fSclaudio ometric_set_int(struct ometric *om, uint64_t val, struct olabels *ol)
40677a10e6fSclaudio {
40777a10e6fSclaudio if (om->type != OMT_COUNTER && om->type != OMT_GAUGE)
40877a10e6fSclaudio errx(1, "%s incorrect ometric type", __func__);
40977a10e6fSclaudio
41077a10e6fSclaudio ometric_set_int_value(om, val, ol);
41177a10e6fSclaudio }
41277a10e6fSclaudio
41377a10e6fSclaudio /*
41477a10e6fSclaudio * Set a floating point value with label ol. ol can be NULL.
41577a10e6fSclaudio */
41677a10e6fSclaudio void
ometric_set_float(struct ometric * om,double val,struct olabels * ol)41777a10e6fSclaudio ometric_set_float(struct ometric *om, double val, struct olabels *ol)
41877a10e6fSclaudio {
41977a10e6fSclaudio struct ovalue *ov;
42077a10e6fSclaudio
42177a10e6fSclaudio if (om->type != OMT_COUNTER && om->type != OMT_GAUGE)
42277a10e6fSclaudio errx(1, "%s incorrect ometric type", __func__);
42377a10e6fSclaudio
42477a10e6fSclaudio if ((ov = malloc(sizeof(*ov))) == NULL)
42577a10e6fSclaudio err(1, NULL);
42677a10e6fSclaudio
42777a10e6fSclaudio ov->value.f = val;
42877a10e6fSclaudio ov->valtype = OVT_DOUBLE;
42977a10e6fSclaudio ov->labels = olabels_ref(ol);
43077a10e6fSclaudio
43177a10e6fSclaudio STAILQ_INSERT_TAIL(&om->vals, ov, entry);
43277a10e6fSclaudio }
43377a10e6fSclaudio
43477a10e6fSclaudio /*
43581e584e8Sclaudio * Set an timespec value with label ol. ol can be NULL.
4368168f856Sclaudio */
4378168f856Sclaudio void
ometric_set_timespec(struct ometric * om,const struct timespec * ts,struct olabels * ol)43881e584e8Sclaudio ometric_set_timespec(struct ometric *om, const struct timespec *ts,
4398168f856Sclaudio struct olabels *ol)
4408168f856Sclaudio {
4418168f856Sclaudio struct ovalue *ov;
4428168f856Sclaudio
4438168f856Sclaudio if (om->type != OMT_GAUGE)
4448168f856Sclaudio errx(1, "%s incorrect ometric type", __func__);
4458168f856Sclaudio
4468168f856Sclaudio if ((ov = malloc(sizeof(*ov))) == NULL)
4478168f856Sclaudio err(1, NULL);
4488168f856Sclaudio
44981e584e8Sclaudio ov->value.ts = *ts;
45081e584e8Sclaudio ov->valtype = OVT_TIMESPEC;
4518168f856Sclaudio ov->labels = olabels_ref(ol);
4528168f856Sclaudio
4538168f856Sclaudio STAILQ_INSERT_TAIL(&om->vals, ov, entry);
4548168f856Sclaudio }
4558168f856Sclaudio
4568168f856Sclaudio /*
45777a10e6fSclaudio * Add an info value (which is the value 1 but with extra key-value pairs).
45877a10e6fSclaudio */
45977a10e6fSclaudio void
ometric_set_info(struct ometric * om,const char ** keys,const char ** values,struct olabels * ol)46077a10e6fSclaudio ometric_set_info(struct ometric *om, const char **keys, const char **values,
46177a10e6fSclaudio struct olabels *ol)
46277a10e6fSclaudio {
46377a10e6fSclaudio struct olabels *extra = NULL;
46477a10e6fSclaudio
46577a10e6fSclaudio if (om->type != OMT_INFO)
46677a10e6fSclaudio errx(1, "%s incorrect ometric type", __func__);
46777a10e6fSclaudio
468e70d5757Sclaudio if (keys != NULL)
469e70d5757Sclaudio extra = olabels_add_extras(ol, keys, values);
47077a10e6fSclaudio
47177a10e6fSclaudio ometric_set_int_value(om, 1, extra != NULL ? extra : ol);
47277a10e6fSclaudio olabels_free(extra);
47377a10e6fSclaudio }
47477a10e6fSclaudio
47577a10e6fSclaudio /*
47677a10e6fSclaudio * Set a stateset to one of its states.
47777a10e6fSclaudio */
47877a10e6fSclaudio void
ometric_set_state(struct ometric * om,const char * state,struct olabels * ol)47977a10e6fSclaudio ometric_set_state(struct ometric *om, const char *state, struct olabels *ol)
48077a10e6fSclaudio {
481d935d7a8Sclaudio struct olabels *extra;
48277a10e6fSclaudio size_t i;
48377a10e6fSclaudio int val;
48477a10e6fSclaudio
48577a10e6fSclaudio if (om->type != OMT_STATESET)
48677a10e6fSclaudio errx(1, "%s incorrect ometric type", __func__);
48777a10e6fSclaudio
48877a10e6fSclaudio for (i = 0; i < om->setsize; i++) {
48977a10e6fSclaudio if (strcasecmp(state, om->stateset[i]) == 0)
49077a10e6fSclaudio val = 1;
49177a10e6fSclaudio else
49277a10e6fSclaudio val = 0;
49377a10e6fSclaudio
494d935d7a8Sclaudio extra = olabels_add_extras(ol, OKV(om->name),
495d935d7a8Sclaudio OKV(om->stateset[i]));
496d935d7a8Sclaudio ometric_set_int_value(om, val, extra);
497d935d7a8Sclaudio olabels_free(extra);
49877a10e6fSclaudio }
49977a10e6fSclaudio }
50077a10e6fSclaudio
50177a10e6fSclaudio /*
50277a10e6fSclaudio * Set a value with an extra label, the key should be a constant string while
50377a10e6fSclaudio * the value is copied into the extra label.
50477a10e6fSclaudio */
50577a10e6fSclaudio void
ometric_set_int_with_labels(struct ometric * om,uint64_t val,const char ** keys,const char ** values,struct olabels * ol)506e70d5757Sclaudio ometric_set_int_with_labels(struct ometric *om, uint64_t val,
507e70d5757Sclaudio const char **keys, const char **values, struct olabels *ol)
50877a10e6fSclaudio {
50977a10e6fSclaudio struct olabels *extra;
51077a10e6fSclaudio
511e70d5757Sclaudio extra = olabels_add_extras(ol, keys, values);
51277a10e6fSclaudio ometric_set_int(om, val, extra);
51377a10e6fSclaudio olabels_free(extra);
51477a10e6fSclaudio }
5158168f856Sclaudio
5168168f856Sclaudio void
ometric_set_timespec_with_labels(struct ometric * om,struct timespec * ts,const char ** keys,const char ** values,struct olabels * ol)51781e584e8Sclaudio ometric_set_timespec_with_labels(struct ometric *om, struct timespec *ts,
5188168f856Sclaudio const char **keys, const char **values, struct olabels *ol)
5198168f856Sclaudio {
5208168f856Sclaudio struct olabels *extra;
5218168f856Sclaudio
5228168f856Sclaudio extra = olabels_add_extras(ol, keys, values);
52381e584e8Sclaudio ometric_set_timespec(om, ts, extra);
5248168f856Sclaudio olabels_free(extra);
5258168f856Sclaudio }
526