1 /* $OpenBSD: output-ometric.c,v 1.12 2024/11/02 12:30:28 job 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
set_common_stats(const struct repotalstats * in,struct ometric * metric,struct olabels * ol)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_gap,
51 OKV("type", "state"), OKV("manifest", "sequence gap"), 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 ometric_set_int_with_labels(metric, in->vaps_overflowed,
88 OKV("type", "state"), OKV("vap overflowed"), ol);
89
90 if (experimental) {
91 ometric_set_int_with_labels(metric, in->spls,
92 OKV("type", "state"), OKV("spl", "valid"), ol);
93 ometric_set_int_with_labels(metric, in->spls_fail,
94 OKV("type", "state"), OKV("spl", "failed parse"), ol);
95 ometric_set_int_with_labels(metric, in->spls_invalid,
96 OKV("type", "state"), OKV("spl", "invalid"), ol);
97 }
98
99 ometric_set_int_with_labels(metric, in->vsps,
100 OKV("type", "state"), OKV("vsp", "total"), ol);
101 ometric_set_int_with_labels(metric, in->vsps_uniqs,
102 OKV("type", "state"), OKV("vsp", "unique"), ol);
103 }
104
105 static void
ta_stats(int id)106 ta_stats(int id)
107 {
108 struct olabels *ol;
109 const char *keys[2] = { "name", NULL };
110 const char *values[2];
111
112 values[0] = taldescs[id];
113 values[1] = NULL;
114
115 ol = olabels_new(keys, values);
116 set_common_stats(&talstats[id], rpki_ta_obj, ol);
117 olabels_free(ol);
118 }
119
120 static void
repo_tal_stats(const struct repo * rp,const struct repotalstats * in,void * arg)121 repo_tal_stats(const struct repo *rp, const struct repotalstats *in, void *arg)
122 {
123 struct olabels *ol;
124 const char *keys[4] = { "name", "carepo", "notify", NULL };
125 const char *values[4];
126 int talid = *(int *)arg;
127
128 values[0] = taldescs[talid];
129 repo_fetch_uris(rp, &values[1], &values[2]);
130 values[3] = NULL;
131
132 ol = olabels_new(keys, values);
133 set_common_stats(in, rpki_repo_obj, ol);
134 olabels_free(ol);
135 }
136
137 static void
repo_stats(const struct repo * rp,const struct repostats * in,void * arg)138 repo_stats(const struct repo *rp, const struct repostats *in, void *arg)
139 {
140 struct olabels *ol;
141 const char *keys[3] = { "carepo", "notify", NULL };
142 const char *values[3];
143
144 repo_fetch_uris(rp, &values[0], &values[1]);
145 values[2] = NULL;
146
147 ol = olabels_new(keys, values);
148 ometric_set_timespec(rpki_repo_duration, &in->sync_time, ol);
149
150 ometric_set_int_with_labels(rpki_repo_obj, in->new_files,
151 OKV("type", "state"), OKV("files", "new"), ol);
152 ometric_set_int_with_labels(rpki_repo_obj, in->del_files,
153 OKV("type", "state"), OKV("files", "deleted"), ol);
154 ometric_set_int_with_labels(rpki_repo_obj, in->extra_files,
155 OKV("type", "state"), OKV("files", "extra"), ol);
156 ometric_set_int_with_labels(rpki_repo_obj, in->del_extra_files,
157 OKV("type", "state"), OKV("files", "deleted_extra"), ol);
158 ometric_set_int_with_labels(rpki_repo_obj, in->del_dirs,
159 OKV("type", "state"), OKV("dirs", "deleted"), ol);
160
161 ometric_set_state(rpki_repo_state, repo_states[repo_synced(rp)], ol);
162 if (repo_synced(rp))
163 ometric_set_state(rpki_repo_proto, repo_proto(rp), ol);
164 olabels_free(ol);
165 }
166
167 int
output_ometric(FILE * out,struct vrp_tree * vrps,struct brk_tree * brks,struct vap_tree * vaps,struct vsp_tree * vsps,struct stats * st)168 output_ometric(FILE *out, struct vrp_tree *vrps, struct brk_tree *brks,
169 struct vap_tree *vaps, struct vsp_tree *vsps, struct stats *st)
170 {
171 struct olabels *ol;
172 const char *keys[4] = { "nodename", "domainname", "release", NULL };
173 const char *values[4];
174 char hostname[HOST_NAME_MAX + 1];
175 char *domainname;
176 struct timespec now_time;
177 int rv, i;
178
179 rpki_info = ometric_new(OMT_INFO, "rpki_client",
180 "rpki-client information");
181 rpki_completion_time = ometric_new(OMT_GAUGE,
182 "rpki_client_job_completion_time",
183 "end of this run as epoch timestamp");
184
185 rpki_repo = ometric_new(OMT_GAUGE, "rpki_client_repository",
186 "total number of repositories");
187 rpki_obj = ometric_new(OMT_GAUGE, "rpki_client_objects",
188 "total number of objects");
189
190 rpki_duration = ometric_new(OMT_GAUGE, "rpki_client_duration",
191 "duration in seconds");
192
193 rpki_ta_obj = ometric_new(OMT_GAUGE, "rpki_client_ta_objects",
194 "total number of objects per TAL");
195 rpki_repo_obj = ometric_new(OMT_GAUGE, "rpki_client_repository_objects",
196 "total number of objects per repository");
197 rpki_repo_duration = ometric_new(OMT_GAUGE,
198 "rpki_client_repository_duration",
199 "duration used to sync this repository in seconds");
200 rpki_repo_state = ometric_new_state(repo_states,
201 sizeof(repo_states) / sizeof(repo_states[0]),
202 "rpki_client_repository_state",
203 "repository state");
204 rpki_repo_proto = ometric_new_state(repo_protos,
205 sizeof(repo_protos) / sizeof(repo_protos[0]),
206 "rpki_client_repository_protos",
207 "used protocol to sync repository");
208
209 /*
210 * Dump statistics
211 */
212 if (gethostname(hostname, sizeof(hostname)))
213 err(1, "gethostname");
214 if ((domainname = strchr(hostname, '.')))
215 *domainname++ = '\0';
216
217 values[0] = hostname;
218 values[1] = domainname;
219 values[2] = RPKI_VERSION;
220 values[3] = NULL;
221
222 ol = olabels_new(keys, values);
223 ometric_set_info(rpki_info, NULL, NULL, ol);
224 olabels_free(ol);
225
226 for (i = 0; i < talsz; i++) {
227 repo_tal_stats_collect(repo_tal_stats, i, &i);
228 ta_stats(i);
229 }
230 repo_stats_collect(repo_stats, NULL);
231 set_common_stats(&st->repo_tal_stats, rpki_obj, NULL);
232
233 ometric_set_int_with_labels(rpki_repo, st->rsync_repos,
234 OKV("type", "state"), OKV("rsync", "synced"), NULL);
235 ometric_set_int_with_labels(rpki_repo, st->rsync_fails,
236 OKV("type", "state"), OKV("rsync", "failed"), NULL);
237 ometric_set_int_with_labels(rpki_repo, st->http_repos,
238 OKV("type", "state"), OKV("http", "synced"), NULL);
239 ometric_set_int_with_labels(rpki_repo, st->http_fails,
240 OKV("type", "state"), OKV("http", "failed"), NULL);
241 ometric_set_int_with_labels(rpki_repo, st->rrdp_repos,
242 OKV("type", "state"), OKV("rrdp", "synced"), NULL);
243 ometric_set_int_with_labels(rpki_repo, st->rrdp_fails,
244 OKV("type", "state"), OKV("rrdp", "failed"), NULL);
245
246 ometric_set_timespec_with_labels(rpki_duration, &st->elapsed_time,
247 OKV("type"), OKV("elapsed"), NULL);
248 ometric_set_timespec_with_labels(rpki_duration, &st->user_time,
249 OKV("type"), OKV("user"), NULL);
250 ometric_set_timespec_with_labels(rpki_duration, &st->system_time,
251 OKV("type"), OKV("system"), NULL);
252
253 clock_gettime(CLOCK_REALTIME, &now_time);
254 ometric_set_timespec(rpki_completion_time, &now_time, NULL);
255
256 rv = ometric_output_all(out);
257 ometric_free_all();
258
259 return rv;
260 }
261