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