xref: /openbsd-src/usr.sbin/rpki-client/ometric.c (revision 796ad6a2ae7bd233e9839727ca34a0aa63269e98)
1*796ad6a2Sderaadt /*	$OpenBSD: ometric.c,v 1.2 2023/01/06 13:22:00 deraadt Exp $ */
24f5f25cbSclaudio 
34f5f25cbSclaudio /*
44f5f25cbSclaudio  * Copyright (c) 2022 Claudio Jeker <claudio@openbsd.org>
54f5f25cbSclaudio  *
64f5f25cbSclaudio  * Permission to use, copy, modify, and distribute this software for any
74f5f25cbSclaudio  * purpose with or without fee is hereby granted, provided that the above
84f5f25cbSclaudio  * copyright notice and this permission notice appear in all copies.
94f5f25cbSclaudio  *
104f5f25cbSclaudio  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
114f5f25cbSclaudio  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
124f5f25cbSclaudio  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
134f5f25cbSclaudio  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
144f5f25cbSclaudio  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
154f5f25cbSclaudio  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
164f5f25cbSclaudio  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
174f5f25cbSclaudio  */
184f5f25cbSclaudio 
194f5f25cbSclaudio #include <sys/queue.h>
204f5f25cbSclaudio #include <sys/time.h>
214f5f25cbSclaudio 
224f5f25cbSclaudio #include <err.h>
234f5f25cbSclaudio #include <stdarg.h>
244f5f25cbSclaudio #include <stdint.h>
254f5f25cbSclaudio #include <stdio.h>
264f5f25cbSclaudio #include <stdlib.h>
274f5f25cbSclaudio #include <string.h>
284f5f25cbSclaudio 
294f5f25cbSclaudio #include "ometric.h"
304f5f25cbSclaudio 
314f5f25cbSclaudio struct olabel {
324f5f25cbSclaudio 	STAILQ_ENTRY(olabel)	 entry;
334f5f25cbSclaudio 	const char		*key;
344f5f25cbSclaudio 	char			*value;
354f5f25cbSclaudio };
364f5f25cbSclaudio 
374f5f25cbSclaudio struct olabels {
384f5f25cbSclaudio 	STAILQ_HEAD(, olabel)	 labels;
394f5f25cbSclaudio 	struct olabels		*next;
404f5f25cbSclaudio 	int			 refcnt;
414f5f25cbSclaudio };
424f5f25cbSclaudio 
434f5f25cbSclaudio enum ovalue_type {
444f5f25cbSclaudio 	OVT_INTEGER,
454f5f25cbSclaudio 	OVT_DOUBLE,
464f5f25cbSclaudio 	OVT_TIMESPEC,
474f5f25cbSclaudio };
484f5f25cbSclaudio 
494f5f25cbSclaudio struct ovalue {
504f5f25cbSclaudio 	STAILQ_ENTRY(ovalue)	 entry;
514f5f25cbSclaudio 	struct olabels		*labels;
524f5f25cbSclaudio 	union {
534f5f25cbSclaudio 		unsigned long long	i;
544f5f25cbSclaudio 		double			f;
554f5f25cbSclaudio 		struct timespec		ts;
564f5f25cbSclaudio 	}			 value;
574f5f25cbSclaudio 	enum ovalue_type	 valtype;
584f5f25cbSclaudio };
594f5f25cbSclaudio 
604f5f25cbSclaudio STAILQ_HEAD(ovalues, ovalue);
614f5f25cbSclaudio 
624f5f25cbSclaudio struct ometric {
634f5f25cbSclaudio 	STAILQ_ENTRY(ometric)	 entry;
644f5f25cbSclaudio 	struct ovalues		 vals;
654f5f25cbSclaudio 	const char		*name;
664f5f25cbSclaudio 	const char		*help;
674f5f25cbSclaudio 	const char *const	*stateset;
684f5f25cbSclaudio 	size_t			 setsize;
694f5f25cbSclaudio 	enum ometric_type	 type;
704f5f25cbSclaudio };
714f5f25cbSclaudio 
724f5f25cbSclaudio STAILQ_HEAD(, ometric)	ometrics = STAILQ_HEAD_INITIALIZER(ometrics);
734f5f25cbSclaudio 
744f5f25cbSclaudio static const char *suffixes[] = { "_total", "_created", "_count",
754f5f25cbSclaudio 	"_sum", "_bucket", "_gcount", "_gsum", "_info",
764f5f25cbSclaudio };
774f5f25cbSclaudio 
784f5f25cbSclaudio /*
794f5f25cbSclaudio  * Return true if name has one of the above suffixes.
804f5f25cbSclaudio  */
814f5f25cbSclaudio static int
strsuffix(const char * name)824f5f25cbSclaudio strsuffix(const char *name)
834f5f25cbSclaudio {
844f5f25cbSclaudio 	const char *suffix;
854f5f25cbSclaudio 	size_t	i;
864f5f25cbSclaudio 
874f5f25cbSclaudio 	suffix = strrchr(name, '_');
884f5f25cbSclaudio 	if (suffix == NULL)
894f5f25cbSclaudio 		return 0;
904f5f25cbSclaudio 	for (i = 0; i < sizeof(suffixes) / sizeof(suffixes[0]); i++) {
914f5f25cbSclaudio 		if (strcmp(suffix, suffixes[i]) == 0)
924f5f25cbSclaudio 			return 1;
934f5f25cbSclaudio 	}
944f5f25cbSclaudio 	return 0;
954f5f25cbSclaudio }
964f5f25cbSclaudio 
974f5f25cbSclaudio static void
ometric_check(const char * name)984f5f25cbSclaudio ometric_check(const char *name)
994f5f25cbSclaudio {
1004f5f25cbSclaudio 	struct ometric *om;
1014f5f25cbSclaudio 
1024f5f25cbSclaudio 	if (strsuffix(name))
1034f5f25cbSclaudio 		errx(1, "reserved name suffix used: %s", name);
1044f5f25cbSclaudio 	STAILQ_FOREACH(om, &ometrics, entry)
1054f5f25cbSclaudio 		if (strcmp(name, om->name) == 0)
1064f5f25cbSclaudio 			errx(1, "duplicate name: %s", name);
1074f5f25cbSclaudio }
1084f5f25cbSclaudio 
1094f5f25cbSclaudio /*
1104f5f25cbSclaudio  * Allocate and return new ometric. The name and help string need to remain
1114f5f25cbSclaudio  * valid until the ometric is freed. Normally constant strings should be used.
1124f5f25cbSclaudio  */
1134f5f25cbSclaudio struct ometric *
ometric_new(enum ometric_type type,const char * name,const char * help)1144f5f25cbSclaudio ometric_new(enum ometric_type type, const char *name, const char *help)
1154f5f25cbSclaudio {
1164f5f25cbSclaudio 	struct ometric *om;
1174f5f25cbSclaudio 
1184f5f25cbSclaudio 	ometric_check(name);
1194f5f25cbSclaudio 
1204f5f25cbSclaudio 	if ((om = calloc(1, sizeof(*om))) == NULL)
1214f5f25cbSclaudio 		err(1, NULL);
1224f5f25cbSclaudio 
1234f5f25cbSclaudio 	om->name = name;
1244f5f25cbSclaudio 	om->help = help;
1254f5f25cbSclaudio 	om->type = type;
1264f5f25cbSclaudio 	STAILQ_INIT(&om->vals);
1274f5f25cbSclaudio 
1284f5f25cbSclaudio 	STAILQ_INSERT_TAIL(&ometrics, om, entry);
1294f5f25cbSclaudio 
1304f5f25cbSclaudio 	return om;
1314f5f25cbSclaudio }
1324f5f25cbSclaudio 
1334f5f25cbSclaudio /*
1344f5f25cbSclaudio  * Same as above but for a stateset. The states is an array of constant strings
1354f5f25cbSclaudio  * with statecnt elements. The states, name and help pointers need to remain
1364f5f25cbSclaudio  * valid until the ometric is freed.
1374f5f25cbSclaudio  */
1384f5f25cbSclaudio struct ometric *
ometric_new_state(const char * const * states,size_t statecnt,const char * name,const char * help)1394f5f25cbSclaudio ometric_new_state(const char * const *states, size_t statecnt, const char *name,
1404f5f25cbSclaudio     const char *help)
1414f5f25cbSclaudio {
1424f5f25cbSclaudio 	struct ometric *om;
1434f5f25cbSclaudio 
1444f5f25cbSclaudio 	ometric_check(name);
1454f5f25cbSclaudio 
1464f5f25cbSclaudio 	if ((om = calloc(1, sizeof(*om))) == NULL)
1474f5f25cbSclaudio 		err(1, NULL);
1484f5f25cbSclaudio 
1494f5f25cbSclaudio 	om->name = name;
1504f5f25cbSclaudio 	om->help = help;
1514f5f25cbSclaudio 	om->type = OMT_STATESET;
1524f5f25cbSclaudio 	om->stateset = states;
1534f5f25cbSclaudio 	om->setsize = statecnt;
1544f5f25cbSclaudio 	STAILQ_INIT(&om->vals);
1554f5f25cbSclaudio 
1564f5f25cbSclaudio 	STAILQ_INSERT_TAIL(&ometrics, om, entry);
1574f5f25cbSclaudio 
1584f5f25cbSclaudio 	return om;
1594f5f25cbSclaudio }
1604f5f25cbSclaudio 
1614f5f25cbSclaudio void
ometric_free_all(void)1624f5f25cbSclaudio ometric_free_all(void)
1634f5f25cbSclaudio {
1644f5f25cbSclaudio 	struct ometric *om;
1654f5f25cbSclaudio 	struct ovalue *ov;
1664f5f25cbSclaudio 
1674f5f25cbSclaudio 	while ((om = STAILQ_FIRST(&ometrics)) != NULL) {
1684f5f25cbSclaudio 		STAILQ_REMOVE_HEAD(&ometrics, entry);
1694f5f25cbSclaudio 		while ((ov = STAILQ_FIRST(&om->vals)) != NULL) {
1704f5f25cbSclaudio 			STAILQ_REMOVE_HEAD(&om->vals, entry);
1714f5f25cbSclaudio 			olabels_free(ov->labels);
1724f5f25cbSclaudio 			free(ov);
1734f5f25cbSclaudio 		}
1744f5f25cbSclaudio 		free(om);
1754f5f25cbSclaudio 	}
1764f5f25cbSclaudio }
1774f5f25cbSclaudio 
1784f5f25cbSclaudio static struct olabels *
olabels_ref(struct olabels * ol)1794f5f25cbSclaudio olabels_ref(struct olabels *ol)
1804f5f25cbSclaudio {
1814f5f25cbSclaudio 	struct olabels *x = ol;
1824f5f25cbSclaudio 
1834f5f25cbSclaudio 	while (x != NULL) {
1844f5f25cbSclaudio 		x->refcnt++;
1854f5f25cbSclaudio 		x = x->next;
1864f5f25cbSclaudio 	}
1874f5f25cbSclaudio 
1884f5f25cbSclaudio 	return ol;
1894f5f25cbSclaudio }
1904f5f25cbSclaudio 
1914f5f25cbSclaudio /*
1924f5f25cbSclaudio  * Create a new set of labels based on keys and values arrays.
1934f5f25cbSclaudio  * keys must end in a NULL element. values needs to hold as many elements
1944f5f25cbSclaudio  * but the elements can be NULL. values are copied for the olabel but
1954f5f25cbSclaudio  * keys needs to point to constant memory.
1964f5f25cbSclaudio  */
1974f5f25cbSclaudio struct olabels *
olabels_new(const char * const * keys,const char ** values)1984f5f25cbSclaudio olabels_new(const char * const *keys, const char **values)
1994f5f25cbSclaudio {
2004f5f25cbSclaudio 	struct olabels *ol;
2014f5f25cbSclaudio 	struct olabel  *l;
2024f5f25cbSclaudio 
2034f5f25cbSclaudio 	if ((ol = malloc(sizeof(*ol))) == NULL)
2044f5f25cbSclaudio 		err(1, NULL);
2054f5f25cbSclaudio 	STAILQ_INIT(&ol->labels);
2064f5f25cbSclaudio 	ol->refcnt = 1;
2074f5f25cbSclaudio 	ol->next = NULL;
2084f5f25cbSclaudio 
2094f5f25cbSclaudio 	while (*keys != NULL) {
2104f5f25cbSclaudio 		if (*values && **values != '\0') {
2114f5f25cbSclaudio 			if ((l = malloc(sizeof(*l))) == NULL)
2124f5f25cbSclaudio 				err(1, NULL);
2134f5f25cbSclaudio 			l->key = *keys;
2144f5f25cbSclaudio 			if ((l->value = strdup(*values)) == NULL)
2154f5f25cbSclaudio 				err(1, NULL);
2164f5f25cbSclaudio 			STAILQ_INSERT_TAIL(&ol->labels, l, entry);
2174f5f25cbSclaudio 		}
2184f5f25cbSclaudio 
2194f5f25cbSclaudio 		keys++;
2204f5f25cbSclaudio 		values++;
2214f5f25cbSclaudio 	}
2224f5f25cbSclaudio 
2234f5f25cbSclaudio 	return ol;
2244f5f25cbSclaudio }
2254f5f25cbSclaudio 
2264f5f25cbSclaudio /*
2274f5f25cbSclaudio  * Free olables once nothing uses them anymore.
2284f5f25cbSclaudio  */
2294f5f25cbSclaudio void
olabels_free(struct olabels * ol)2304f5f25cbSclaudio olabels_free(struct olabels *ol)
2314f5f25cbSclaudio {
2324f5f25cbSclaudio 	struct olabels *next;
2334f5f25cbSclaudio 	struct olabel  *l;
2344f5f25cbSclaudio 
2354f5f25cbSclaudio 	for ( ; ol != NULL; ol = next) {
2364f5f25cbSclaudio 		next = ol->next;
2374f5f25cbSclaudio 
2384f5f25cbSclaudio 		if (--ol->refcnt == 0) {
2394f5f25cbSclaudio 			while ((l = STAILQ_FIRST(&ol->labels)) != NULL) {
2404f5f25cbSclaudio 				STAILQ_REMOVE_HEAD(&ol->labels, entry);
2414f5f25cbSclaudio 				free(l->value);
2424f5f25cbSclaudio 				free(l);
2434f5f25cbSclaudio 			}
2444f5f25cbSclaudio 			free(ol);
2454f5f25cbSclaudio 		}
2464f5f25cbSclaudio 	}
2474f5f25cbSclaudio }
2484f5f25cbSclaudio 
2494f5f25cbSclaudio /*
2504f5f25cbSclaudio  * Add one extra label onto the label stack. Once no longer used the
2514f5f25cbSclaudio  * value needs to be freed with olabels_free().
2524f5f25cbSclaudio  */
2534f5f25cbSclaudio static struct olabels *
olabels_add_extras(struct olabels * ol,const char ** keys,const char ** values)2544f5f25cbSclaudio olabels_add_extras(struct olabels *ol, const char **keys, const char **values)
2554f5f25cbSclaudio {
2564f5f25cbSclaudio 	struct olabels *new;
2574f5f25cbSclaudio 
2584f5f25cbSclaudio 	new = olabels_new(keys, values);
2594f5f25cbSclaudio 	new->next = olabels_ref(ol);
2604f5f25cbSclaudio 
2614f5f25cbSclaudio 	return new;
2624f5f25cbSclaudio }
2634f5f25cbSclaudio 
2644f5f25cbSclaudio /*
2654f5f25cbSclaudio  * Output function called last.
2664f5f25cbSclaudio  */
2674f5f25cbSclaudio static const char *
ometric_type(enum ometric_type type)2684f5f25cbSclaudio ometric_type(enum ometric_type type)
2694f5f25cbSclaudio {
2704f5f25cbSclaudio 	switch (type) {
2714f5f25cbSclaudio 	case OMT_GAUGE:
2724f5f25cbSclaudio 		return "gauge";
2734f5f25cbSclaudio 	case OMT_COUNTER:
2744f5f25cbSclaudio 		return "counter";
2754f5f25cbSclaudio 	case OMT_STATESET:
2764f5f25cbSclaudio 		/* return "stateset"; node_exporter does not like this type */
2774f5f25cbSclaudio 		return "gauge";
2784f5f25cbSclaudio 	case OMT_HISTOGRAM:
2794f5f25cbSclaudio 		return "histogram";
2804f5f25cbSclaudio 	case OMT_SUMMARY:
2814f5f25cbSclaudio 		return "summary";
2824f5f25cbSclaudio 	case OMT_INFO:
2834f5f25cbSclaudio 		/* return "info"; node_exporter does not like this type */
2844f5f25cbSclaudio 		return "gauge";
2854f5f25cbSclaudio 	default:
2864f5f25cbSclaudio 		return "unknown";
2874f5f25cbSclaudio 	}
2884f5f25cbSclaudio }
2894f5f25cbSclaudio 
2904f5f25cbSclaudio static int
ometric_output_labels(FILE * out,const struct olabels * ol)2914f5f25cbSclaudio ometric_output_labels(FILE *out, const struct olabels *ol)
2924f5f25cbSclaudio {
2934f5f25cbSclaudio 	struct olabel *l;
2944f5f25cbSclaudio 	const char *comma = "";
2954f5f25cbSclaudio 
2964f5f25cbSclaudio 	if (ol == NULL)
2974f5f25cbSclaudio 		return fprintf(out, " ");
2984f5f25cbSclaudio 
2994f5f25cbSclaudio 	if (fprintf(out, "{") < 0)
3004f5f25cbSclaudio 		return -1;
3014f5f25cbSclaudio 
3024f5f25cbSclaudio 	while (ol != NULL) {
3034f5f25cbSclaudio 		STAILQ_FOREACH(l, &ol->labels, entry) {
3044f5f25cbSclaudio 			if (fprintf(out, "%s%s=\"%s\"", comma, l->key,
3054f5f25cbSclaudio 			    l->value) < 0)
3064f5f25cbSclaudio 				return -1;
3074f5f25cbSclaudio 			comma = ",";
3084f5f25cbSclaudio 		}
3094f5f25cbSclaudio 		ol = ol->next;
3104f5f25cbSclaudio 	}
3114f5f25cbSclaudio 
3124f5f25cbSclaudio 	return fprintf(out, "} ");
3134f5f25cbSclaudio }
3144f5f25cbSclaudio 
3154f5f25cbSclaudio static int
ometric_output_value(FILE * out,const struct ovalue * ov)3164f5f25cbSclaudio ometric_output_value(FILE *out, const struct ovalue *ov)
3174f5f25cbSclaudio {
3184f5f25cbSclaudio 	switch (ov->valtype) {
3194f5f25cbSclaudio 	case OVT_INTEGER:
3204f5f25cbSclaudio 		return fprintf(out, "%llu", ov->value.i);
3214f5f25cbSclaudio 	case OVT_DOUBLE:
3224f5f25cbSclaudio 		return fprintf(out, "%g", ov->value.f);
3234f5f25cbSclaudio 	case OVT_TIMESPEC:
3244f5f25cbSclaudio 		return fprintf(out, "%lld.%09ld",
3254f5f25cbSclaudio 		    (long long)ov->value.ts.tv_sec, ov->value.ts.tv_nsec);
3264f5f25cbSclaudio 	}
3274f5f25cbSclaudio 	return -1;
3284f5f25cbSclaudio }
3294f5f25cbSclaudio 
3304f5f25cbSclaudio static int
ometric_output_name(FILE * out,const struct ometric * om)3314f5f25cbSclaudio ometric_output_name(FILE *out, const struct ometric *om)
3324f5f25cbSclaudio {
3334f5f25cbSclaudio 	const char *suffix;
3344f5f25cbSclaudio 
3354f5f25cbSclaudio 	switch (om->type) {
3364f5f25cbSclaudio 	case OMT_COUNTER:
3374f5f25cbSclaudio 		suffix = "_total";
3384f5f25cbSclaudio 		break;
3394f5f25cbSclaudio 	case OMT_INFO:
3404f5f25cbSclaudio 		suffix = "_info";
3414f5f25cbSclaudio 		break;
3424f5f25cbSclaudio 	default:
3434f5f25cbSclaudio 		suffix = "";
3444f5f25cbSclaudio 		break;
3454f5f25cbSclaudio 	}
3464f5f25cbSclaudio 	return fprintf(out, "%s%s", om->name, suffix);
3474f5f25cbSclaudio }
3484f5f25cbSclaudio 
3494f5f25cbSclaudio /*
3504f5f25cbSclaudio  * Output all metric values with TYPE and optional HELP strings.
3514f5f25cbSclaudio  */
3524f5f25cbSclaudio int
ometric_output_all(FILE * out)3534f5f25cbSclaudio ometric_output_all(FILE *out)
3544f5f25cbSclaudio {
3554f5f25cbSclaudio 	struct ometric *om;
3564f5f25cbSclaudio 	struct ovalue *ov;
3574f5f25cbSclaudio 
3584f5f25cbSclaudio 	STAILQ_FOREACH(om, &ometrics, entry) {
3594f5f25cbSclaudio 		if (om->help)
3604f5f25cbSclaudio 			if (fprintf(out, "# HELP %s %s\n", om->name,
3614f5f25cbSclaudio 			    om->help) < 0)
3624f5f25cbSclaudio 				return -1;
3634f5f25cbSclaudio 
3644f5f25cbSclaudio 		if (fprintf(out, "# TYPE %s %s\n", om->name,
3654f5f25cbSclaudio 		    ometric_type(om->type)) < 0)
3664f5f25cbSclaudio 			return -1;
3674f5f25cbSclaudio 
3684f5f25cbSclaudio 		STAILQ_FOREACH(ov, &om->vals, entry) {
3694f5f25cbSclaudio 			if (ometric_output_name(out, om) < 0)
3704f5f25cbSclaudio 				return -1;
3714f5f25cbSclaudio 			if (ometric_output_labels(out, ov->labels) < 0)
3724f5f25cbSclaudio 				return -1;
3734f5f25cbSclaudio 			if (ometric_output_value(out, ov) < 0)
3744f5f25cbSclaudio 				return -1;
3754f5f25cbSclaudio 			if (fprintf(out, "\n") < 0)
3764f5f25cbSclaudio 				return -1;
3774f5f25cbSclaudio 		}
3784f5f25cbSclaudio 	}
3794f5f25cbSclaudio 
3804f5f25cbSclaudio 	if (fprintf(out, "# EOF\n") < 0)
3814f5f25cbSclaudio 		return -1;
3824f5f25cbSclaudio 	return 0;
3834f5f25cbSclaudio }
3844f5f25cbSclaudio 
3854f5f25cbSclaudio /*
3864f5f25cbSclaudio  * Value setters
3874f5f25cbSclaudio  */
3884f5f25cbSclaudio static void
ometric_set_int_value(struct ometric * om,uint64_t val,struct olabels * ol)3894f5f25cbSclaudio ometric_set_int_value(struct ometric *om, uint64_t val, struct olabels *ol)
3904f5f25cbSclaudio {
3914f5f25cbSclaudio 	struct ovalue *ov;
3924f5f25cbSclaudio 
3934f5f25cbSclaudio 	if ((ov = malloc(sizeof(*ov))) == NULL)
3944f5f25cbSclaudio 		err(1, NULL);
3954f5f25cbSclaudio 
3964f5f25cbSclaudio 	ov->value.i = val;
3974f5f25cbSclaudio 	ov->valtype = OVT_INTEGER;
3984f5f25cbSclaudio 	ov->labels = olabels_ref(ol);
3994f5f25cbSclaudio 
4004f5f25cbSclaudio 	STAILQ_INSERT_TAIL(&om->vals, ov, entry);
4014f5f25cbSclaudio }
4024f5f25cbSclaudio 
4034f5f25cbSclaudio /*
4044f5f25cbSclaudio  * Set an integer value with label ol. ol can be NULL.
4054f5f25cbSclaudio  */
4064f5f25cbSclaudio void
ometric_set_int(struct ometric * om,uint64_t val,struct olabels * ol)4074f5f25cbSclaudio ometric_set_int(struct ometric *om, uint64_t val, struct olabels *ol)
4084f5f25cbSclaudio {
4094f5f25cbSclaudio 	if (om->type != OMT_COUNTER && om->type != OMT_GAUGE)
4104f5f25cbSclaudio 		errx(1, "%s incorrect ometric type", __func__);
4114f5f25cbSclaudio 
4124f5f25cbSclaudio 	ometric_set_int_value(om, val, ol);
4134f5f25cbSclaudio }
4144f5f25cbSclaudio 
4154f5f25cbSclaudio /*
4164f5f25cbSclaudio  * Set a floating point value with label ol. ol can be NULL.
4174f5f25cbSclaudio  */
4184f5f25cbSclaudio void
ometric_set_float(struct ometric * om,double val,struct olabels * ol)4194f5f25cbSclaudio ometric_set_float(struct ometric *om, double val, struct olabels *ol)
4204f5f25cbSclaudio {
4214f5f25cbSclaudio 	struct ovalue *ov;
4224f5f25cbSclaudio 
4234f5f25cbSclaudio 	if (om->type != OMT_COUNTER && om->type != OMT_GAUGE)
4244f5f25cbSclaudio 		errx(1, "%s incorrect ometric type", __func__);
4254f5f25cbSclaudio 
4264f5f25cbSclaudio 	if ((ov = malloc(sizeof(*ov))) == NULL)
4274f5f25cbSclaudio 		err(1, NULL);
4284f5f25cbSclaudio 
4294f5f25cbSclaudio 	ov->value.f = val;
4304f5f25cbSclaudio 	ov->valtype = OVT_DOUBLE;
4314f5f25cbSclaudio 	ov->labels = olabels_ref(ol);
4324f5f25cbSclaudio 
4334f5f25cbSclaudio 	STAILQ_INSERT_TAIL(&om->vals, ov, entry);
4344f5f25cbSclaudio }
4354f5f25cbSclaudio 
4364f5f25cbSclaudio /*
4374f5f25cbSclaudio  * Set an timespec value with label ol. ol can be NULL.
4384f5f25cbSclaudio  */
4394f5f25cbSclaudio void
ometric_set_timespec(struct ometric * om,const struct timespec * ts,struct olabels * ol)4404f5f25cbSclaudio ometric_set_timespec(struct ometric *om, const struct timespec *ts,
4414f5f25cbSclaudio     struct olabels *ol)
4424f5f25cbSclaudio {
4434f5f25cbSclaudio 	struct ovalue *ov;
4444f5f25cbSclaudio 
4454f5f25cbSclaudio 	if (om->type != OMT_GAUGE)
4464f5f25cbSclaudio 		errx(1, "%s incorrect ometric type", __func__);
4474f5f25cbSclaudio 
4484f5f25cbSclaudio 	if ((ov = malloc(sizeof(*ov))) == NULL)
4494f5f25cbSclaudio 		err(1, NULL);
4504f5f25cbSclaudio 
4514f5f25cbSclaudio 	ov->value.ts = *ts;
4524f5f25cbSclaudio 	ov->valtype = OVT_TIMESPEC;
4534f5f25cbSclaudio 	ov->labels = olabels_ref(ol);
4544f5f25cbSclaudio 
4554f5f25cbSclaudio 	STAILQ_INSERT_TAIL(&om->vals, ov, entry);
4564f5f25cbSclaudio }
4574f5f25cbSclaudio 
4584f5f25cbSclaudio /*
4594f5f25cbSclaudio  * Add an info value (which is the value 1 but with extra key-value pairs).
4604f5f25cbSclaudio  */
4614f5f25cbSclaudio void
ometric_set_info(struct ometric * om,const char ** keys,const char ** values,struct olabels * ol)4624f5f25cbSclaudio ometric_set_info(struct ometric *om, const char **keys, const char **values,
4634f5f25cbSclaudio     struct olabels *ol)
4644f5f25cbSclaudio {
4654f5f25cbSclaudio 	struct olabels *extra = NULL;
4664f5f25cbSclaudio 
4674f5f25cbSclaudio 	if (om->type != OMT_INFO)
4684f5f25cbSclaudio 		errx(1, "%s incorrect ometric type", __func__);
4694f5f25cbSclaudio 
4704f5f25cbSclaudio 	if (keys != NULL)
4714f5f25cbSclaudio 		extra = olabels_add_extras(ol, keys, values);
4724f5f25cbSclaudio 
4734f5f25cbSclaudio 	ometric_set_int_value(om, 1, extra != NULL ? extra : ol);
4744f5f25cbSclaudio 	olabels_free(extra);
4754f5f25cbSclaudio }
4764f5f25cbSclaudio 
4774f5f25cbSclaudio /*
4784f5f25cbSclaudio  * Set a stateset to one of its states.
4794f5f25cbSclaudio  */
4804f5f25cbSclaudio void
ometric_set_state(struct ometric * om,const char * state,struct olabels * ol)4814f5f25cbSclaudio ometric_set_state(struct ometric *om, const char *state, struct olabels *ol)
4824f5f25cbSclaudio {
4834f5f25cbSclaudio 	struct olabels *extra;
4844f5f25cbSclaudio 	size_t i;
4854f5f25cbSclaudio 	int val;
4864f5f25cbSclaudio 
4874f5f25cbSclaudio 	if (om->type != OMT_STATESET)
4884f5f25cbSclaudio 		errx(1, "%s incorrect ometric type", __func__);
4894f5f25cbSclaudio 
4904f5f25cbSclaudio 	for (i = 0; i < om->setsize; i++) {
4914f5f25cbSclaudio 		if (strcasecmp(state, om->stateset[i]) == 0)
4924f5f25cbSclaudio 			val = 1;
4934f5f25cbSclaudio 		else
4944f5f25cbSclaudio 			val = 0;
4954f5f25cbSclaudio 
4964f5f25cbSclaudio 		extra = olabels_add_extras(ol, OKV(om->name),
4974f5f25cbSclaudio 		    OKV(om->stateset[i]));
4984f5f25cbSclaudio 		ometric_set_int_value(om, val, extra);
4994f5f25cbSclaudio 		olabels_free(extra);
5004f5f25cbSclaudio 	}
5014f5f25cbSclaudio }
5024f5f25cbSclaudio 
5034f5f25cbSclaudio /*
5044f5f25cbSclaudio  * Set a value with an extra label, the key should be a constant string while
5054f5f25cbSclaudio  * the value is copied into the extra label.
5064f5f25cbSclaudio  */
5074f5f25cbSclaudio void
ometric_set_int_with_labels(struct ometric * om,uint64_t val,const char ** keys,const char ** values,struct olabels * ol)5084f5f25cbSclaudio ometric_set_int_with_labels(struct ometric *om, uint64_t val,
5094f5f25cbSclaudio     const char **keys, const char **values, struct olabels *ol)
5104f5f25cbSclaudio {
5114f5f25cbSclaudio 	struct olabels *extra;
5124f5f25cbSclaudio 
5134f5f25cbSclaudio 	extra = olabels_add_extras(ol, keys, values);
5144f5f25cbSclaudio 	ometric_set_int(om, val, extra);
5154f5f25cbSclaudio 	olabels_free(extra);
5164f5f25cbSclaudio }
5174f5f25cbSclaudio 
5184f5f25cbSclaudio void
ometric_set_timespec_with_labels(struct ometric * om,struct timespec * ts,const char ** keys,const char ** values,struct olabels * ol)5194f5f25cbSclaudio ometric_set_timespec_with_labels(struct ometric *om, struct timespec *ts,
5204f5f25cbSclaudio     const char **keys, const char **values, struct olabels *ol)
5214f5f25cbSclaudio {
5224f5f25cbSclaudio 	struct olabels *extra;
5234f5f25cbSclaudio 
5244f5f25cbSclaudio 	extra = olabels_add_extras(ol, keys, values);
5254f5f25cbSclaudio 	ometric_set_timespec(om, ts, extra);
5264f5f25cbSclaudio 	olabels_free(extra);
5274f5f25cbSclaudio }
528