xref: /openbsd-src/usr.sbin/bgpctl/ometric.c (revision 81b1a5f567e3c330c826411b75b8cf197bb8da4b)
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