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 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 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 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 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 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