1 /*	$OpenBSD: output-ometric.c,v 1.5 2023/06/29 14:33:35 tb Exp $ */
2 /*
3  * Copyright (c) 2022 Claudio Jeker <claudio@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <err.h>
19 #include <limits.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 
25 #include "extern.h"
26 #include "ometric.h"
27 #include "version.h"
28 
29 static struct ometric *rpki_info, *rpki_completion_time, *rpki_duration;
30 static struct ometric *rpki_repo, *rpki_obj, *rpki_ta_obj;
31 static struct ometric *rpki_repo_obj, *rpki_repo_duration;
32 static struct ometric *rpki_repo_state, *rpki_repo_proto;
33 
34 static const char * const repo_states[2] = { "failed", "synced" };
35 static const char * const repo_protos[3] = { "rrdp", "rsync", "https" };
36 
37 static void
38 set_common_stats(const struct repotalstats *in, struct ometric *metric,
39     struct olabels *ol)
40 {
41 	ometric_set_int_with_labels(metric, in->certs,
42 	    OKV("type", "state"), OKV("cert", "valid"), ol);
43 	ometric_set_int_with_labels(metric, in->certs_fail,
44 	    OKV("type", "state"), OKV("cert", "failed parse"), ol);
45 
46 	ometric_set_int_with_labels(metric, in->mfts,
47 	    OKV("type", "state"), OKV("manifest", "valid"), ol);
48 	ometric_set_int_with_labels(metric, in->mfts_fail,
49 	    OKV("type", "state"), OKV("manifest", "failed parse"), ol);
50 	ometric_set_int_with_labels(metric, in->mfts_stale,
51 	    OKV("type", "state"), OKV("manifest", "stale"), ol);
52 
53 	ometric_set_int_with_labels(metric, in->roas,
54 	    OKV("type", "state"), OKV("roa", "valid"), ol);
55 	ometric_set_int_with_labels(metric, in->roas_fail,
56 	    OKV("type", "state"), OKV("roa", "failed parse"), ol);
57 	ometric_set_int_with_labels(metric, in->roas_invalid,
58 	    OKV("type", "state"), OKV("roa", "invalid"), ol);
59 
60 	ometric_set_int_with_labels(metric, in->aspas,
61 	    OKV("type", "state"), OKV("aspa", "valid"), ol);
62 	ometric_set_int_with_labels(metric, in->aspas_fail,
63 	    OKV("type", "state"), OKV("aspa", "failed parse"), ol);
64 	ometric_set_int_with_labels(metric, in->aspas_invalid,
65 	    OKV("type", "state"), OKV("aspa", "invalid"), ol);
66 
67 	ometric_set_int_with_labels(metric, in->brks,
68 	    OKV("type", "state"), OKV("router_key", "valid"), ol);
69 	ometric_set_int_with_labels(metric, in->crls,
70 	    OKV("type", "state"), OKV("crl", "valid"), ol);
71 	ometric_set_int_with_labels(metric, in->gbrs,
72 	    OKV("type", "state"), OKV("gbr", "valid"), ol);
73 	ometric_set_int_with_labels(metric, in->taks,
74 	    OKV("type", "state"), OKV("tak", "valid"), ol);
75 
76 	ometric_set_int_with_labels(metric, in->vrps,
77 	    OKV("type", "state"), OKV("vrp", "total"), ol);
78 	ometric_set_int_with_labels(metric, in->vrps_uniqs,
79 	    OKV("type", "state"), OKV("vrp", "unique"), ol);
80 
81 	ometric_set_int_with_labels(metric, in->vaps,
82 	    OKV("type", "state"), OKV("vap", "total"), ol);
83 	ometric_set_int_with_labels(metric, in->vaps_uniqs,
84 	    OKV("type", "state"), OKV("vap", "unique"), ol);
85 	ometric_set_int_with_labels(metric, in->vaps_pas,
86 	    OKV("type", "state"), OKV("vap providers", "total"), ol);
87 }
88 
89 static void
90 ta_stats(int id)
91 {
92 	struct olabels *ol;
93 	const char *keys[2] = { "name", NULL };
94 	const char *values[2];
95 
96 	values[0] = taldescs[id];
97 	values[1] = NULL;
98 
99 	ol = olabels_new(keys, values);
100 	set_common_stats(&talstats[id], rpki_ta_obj, ol);
101 	olabels_free(ol);
102 }
103 
104 static void
105 repo_tal_stats(const struct repo *rp, const struct repotalstats *in, void *arg)
106 {
107 	struct olabels *ol;
108 	const char *keys[4] = { "name", "carepo", "notify", NULL };
109 	const char *values[4];
110 	int talid = *(int *)arg;
111 
112 	values[0] = taldescs[talid];
113 	repo_fetch_uris(rp, &values[1], &values[2]);
114 	values[3] = NULL;
115 
116 	ol = olabels_new(keys, values);
117 	set_common_stats(in, rpki_repo_obj, ol);
118 	olabels_free(ol);
119 }
120 
121 static void
122 repo_stats(const struct repo *rp, const struct repostats *in, void *arg)
123 {
124 	struct olabels *ol;
125 	const char *keys[3] = { "carepo", "notify", NULL };
126 	const char *values[3];
127 
128 	repo_fetch_uris(rp, &values[0], &values[1]);
129 	values[2] = NULL;
130 
131 	ol = olabels_new(keys, values);
132 	ometric_set_timespec(rpki_repo_duration, &in->sync_time, ol);
133 
134 	ometric_set_int_with_labels(rpki_repo_obj, in->del_files,
135 	    OKV("type", "state"), OKV("files", "deleted"), ol);
136 	ometric_set_int_with_labels(rpki_repo_obj, in->extra_files,
137 	    OKV("type", "state"), OKV("files", "extra"), ol);
138 	ometric_set_int_with_labels(rpki_repo_obj, in->del_extra_files,
139 	    OKV("type", "state"), OKV("files", "deleted_extra"), ol);
140 	ometric_set_int_with_labels(rpki_repo_obj, in->del_dirs,
141 	    OKV("type", "state"), OKV("dirs", "deleted"), ol);
142 
143 	ometric_set_state(rpki_repo_state, repo_states[repo_synced(rp)], ol);
144 	if (repo_synced(rp))
145 		ometric_set_state(rpki_repo_proto, repo_proto(rp), ol);
146 	olabels_free(ol);
147 }
148 
149 int
150 output_ometric(FILE *out, struct vrp_tree *vrps, struct brk_tree *brks,
151     struct vap_tree *vaps, struct stats *st)
152 {
153 	struct olabels *ol;
154 	const char *keys[4] = { "nodename", "domainname", "release", NULL };
155 	const char *values[4];
156 	char hostname[HOST_NAME_MAX + 1];
157 	char *domainname;
158 	struct timespec now_time;
159 	int rv, i;
160 
161 	rpki_info = ometric_new(OMT_INFO, "rpki_client",
162 	    "rpki-client information");
163 	rpki_completion_time = ometric_new(OMT_GAUGE,
164 	    "rpki_client_job_completion_time",
165 	    "end of this run as epoch timestamp");
166 
167 	rpki_repo = ometric_new(OMT_GAUGE, "rpki_client_repository",
168 	    "total number of repositories");
169 	rpki_obj = ometric_new(OMT_GAUGE, "rpki_client_objects",
170 	    "total number of objects");
171 
172 	rpki_duration = ometric_new(OMT_GAUGE, "rpki_client_duration",
173 	    "duration in seconds");
174 
175 	rpki_ta_obj = ometric_new(OMT_GAUGE, "rpki_client_ta_objects",
176 	    "total number of objects per TAL");
177 	rpki_repo_obj = ometric_new(OMT_GAUGE, "rpki_client_repository_objects",
178 	    "total number of objects per repository");
179 	rpki_repo_duration = ometric_new(OMT_GAUGE,
180 	    "rpki_client_repository_duration",
181 	    "duration used to sync this repository in seconds");
182 	rpki_repo_state = ometric_new_state(repo_states,
183 	    sizeof(repo_states) / sizeof(repo_states[0]),
184 	    "rpki_client_repository_state",
185 	    "repository state");
186 	rpki_repo_proto = ometric_new_state(repo_protos,
187 	    sizeof(repo_protos) / sizeof(repo_protos[0]),
188 	    "rpki_client_repository_protos",
189 	    "used protocol to sync repository");
190 
191 	/*
192 	 * Dump statistics
193 	 */
194 	if (gethostname(hostname, sizeof(hostname)))
195 		err(1, "gethostname");
196 	if ((domainname = strchr(hostname, '.')))
197 		*domainname++ = '\0';
198 
199 	values[0] = hostname;
200 	values[1] = domainname;
201 	values[2] = RPKI_VERSION;
202 	values[3] = NULL;
203 
204 	ol = olabels_new(keys, values);
205 	ometric_set_info(rpki_info, NULL, NULL, ol);
206 	olabels_free(ol);
207 
208 	for (i = 0; i < talsz; i++) {
209 		repo_tal_stats_collect(repo_tal_stats, i, &i);
210 		ta_stats(i);
211 	}
212 	repo_stats_collect(repo_stats, NULL);
213 	set_common_stats(&st->repo_tal_stats, rpki_obj, NULL);
214 
215 	ometric_set_int_with_labels(rpki_repo, st->rsync_repos,
216 	    OKV("type", "state"), OKV("rsync", "synced"), NULL);
217 	ometric_set_int_with_labels(rpki_repo, st->rsync_fails,
218 	    OKV("type", "state"), OKV("rsync", "failed"), NULL);
219 	ometric_set_int_with_labels(rpki_repo, st->http_repos,
220 	    OKV("type", "state"), OKV("http", "synced"), NULL);
221 	ometric_set_int_with_labels(rpki_repo, st->http_fails,
222 	    OKV("type", "state"), OKV("http", "failed"), NULL);
223 	ometric_set_int_with_labels(rpki_repo, st->rrdp_repos,
224 	    OKV("type", "state"), OKV("rrdp", "synced"), NULL);
225 	ometric_set_int_with_labels(rpki_repo, st->rrdp_fails,
226 	    OKV("type", "state"), OKV("rrdp", "failed"), NULL);
227 
228 	ometric_set_timespec_with_labels(rpki_duration, &st->elapsed_time,
229 	    OKV("type"), OKV("elapsed"), NULL);
230 	ometric_set_timespec_with_labels(rpki_duration, &st->user_time,
231 	    OKV("type"), OKV("user"), NULL);
232 	ometric_set_timespec_with_labels(rpki_duration, &st->system_time,
233 	    OKV("type"), OKV("system"), NULL);
234 
235 	clock_gettime(CLOCK_REALTIME, &now_time);
236 	ometric_set_timespec(rpki_completion_time, &now_time, NULL);
237 
238 	rv = ometric_output_all(out);
239 	ometric_free_all();
240 
241 	return rv;
242 }
243