On Tue, Dec 06, 2022 at 05:12:59PM +0100, Claudio Jeker wrote: > When implementing this initially I thought that suffixes are merely a > suggestion but now I realize that the spec is a more strict about them. > So introduce a list of reserved suffixes and bail out if a metric is added > that uses such a suffix. Also fail if a metric name is reused. > > The output code change is currently good enough. Since there is no support > for the more complex types like histogram and the _created value for > counters is deliberatly not implemented.
I'm ok with this. A suggestion below (and a couple tiny nits). > Index: ometric.c > =================================================================== > RCS file: /cvs/src/usr.sbin/bgpctl/ometric.c,v > retrieving revision 1.6 > diff -u -p -r1.6 ometric.c > --- ometric.c 6 Dec 2022 11:27:58 -0000 1.6 > +++ ometric.c 6 Dec 2022 15:51:33 -0000 > @@ -71,6 +71,51 @@ struct ometric { > > STAILQ_HEAD(, ometric) ometrics = STAILQ_HEAD_INITIALIZER(ometrics); > > +static const struct { > + const char *suffix; > + size_t suffix_len; > +} suffixes[] = { > + { "_total", sizeof("_total") - 1 }, > + { "_created", sizeof("_created") - 1 }, > + { "_count", sizeof("_count") - 1 }, > + { "_sum", sizeof("_sum") - 1 }, > + { "_bucket", sizeof("_bucket") - 1 }, > + { "_gcount", sizeof("_gcount") - 1 }, > + { "_gsum", sizeof("_gsum") - 1 }, > + { "_info", sizeof("_info") - 1 }, > +}; > + > +/* > + * Return true if name has one of the above suffixes. > + */ > +static int > +strsuffix(const char *name) > +{ > + size_t i, len; > + > + len = strlen(name); I was wondering if it's worth doing a strrchr up front to simplify the rest: suffix = strrchr(name, '_'); if (suffix == NULL) return 0; len = strlen(suffix); for (i = 0; i < sizeof(suffixes) / sizeof(suffixes[0]); i++) { if (len != suffixes[i].suffix_len) continue; if (strcmp(suffix, suffixes[i].suffix) == 0) return 1; } return 0; Once we get there, we could also drop len and .suffix_len, use a plain array of strings, and do this: const char *suffixes[] = { "_total", "_created", ... }; ... suffix = strrchr(name, '_'); if (suffix == NULL) return 0; for (i = 0; i < sizeof(suffixes) / sizeof(suffixes[0]); i++) { if (strcmp(suffix, suffixes[i]) == 0) return 1; } return 0; ... > + for (i = 0; i < sizeof(suffixes) / sizeof(suffixes[0]); i++) { > + if (len < suffixes[i].suffix_len) > + continue; > + if (strcmp(name + len - suffixes[i].suffix_len, > + suffixes[i].suffix) == 0) > + return 1; > + } > + return 0; Trailing tab after ; > +} > + > +static void > +ometric_check(const char *name) > +{ > + struct ometric *om; > + > + if (strsuffix(name)) > + errx(1, "reserved name suffix used: %s", name); > + STAILQ_FOREACH(om, &ometrics, entry) > + if (strcmp(name, om->name) == 0) > + errx(1, "duplicate name: %s", name); > +} > + > /* > * Allocate and return new ometric. The name and help string need to remain > * valid until the ometric is freed. Normally constant strings should be > used. > @@ -80,6 +125,8 @@ ometric_new(enum ometric_type type, cons > { > struct ometric *om; > > + ometric_check(name); > + > if ((om = calloc(1, sizeof(*om))) == NULL) > err(1, NULL); > > @@ -88,6 +135,7 @@ ometric_new(enum ometric_type type, cons > om->type = type; > STAILQ_INIT(&om->vals); > > + I'd not add an extra empty line. > STAILQ_INSERT_TAIL(&ometrics, om, entry); > > return om; > @@ -104,6 +152,8 @@ ometric_new_state(const char * const *st > { > struct ometric *om; > > + ometric_check(name); > + > if ((om = calloc(1, sizeof(*om))) == NULL) > err(1, NULL); > > @@ -284,6 +334,25 @@ ometric_output_value(FILE *out, const st > return -1; > } > > +static int > +ometric_output_name(FILE *out, const struct ometric *om) > +{ > + const char *suffix; > + > + switch (om->type) { > + case OMT_COUNTER: > + suffix = "_total"; > + break; > + case OMT_INFO: > + suffix = "_info"; > + break; > + default: > + suffix = ""; > + break; > + } > + return fprintf(out, "%s%s", om->name, suffix); > +} > + > /* > * Output all metric values with TYPE and optional HELP strings. > */ > @@ -304,7 +373,7 @@ ometric_output_all(FILE *out) > return -1; > > STAILQ_FOREACH(ov, &om->vals, entry) { > - if (fprintf(out, "%s", om->name) < 0) > + if (ometric_output_name(out, om) < 0) > return -1; > if (ometric_output_labels(out, ov->labels) < 0) > return -1; > Index: output_ometric.c > =================================================================== > RCS file: /cvs/src/usr.sbin/bgpctl/output_ometric.c,v > retrieving revision 1.7 > diff -u -p -r1.7 output_ometric.c > --- output_ometric.c 6 Dec 2022 11:27:58 -0000 1.7 > +++ output_ometric.c 6 Dec 2022 15:52:11 -0000 > @@ -58,7 +58,7 @@ ometric_head(struct parse_result *arg) > char hostname[HOST_NAME_MAX + 1]; > char *domainname; > > - bgpd_info = ometric_new(OMT_INFO, "bgpd_info", "bgpd information"); > + bgpd_info = ometric_new(OMT_INFO, "bgpd", "bgpd information"); > bgpd_scrape_time = ometric_new(OMT_GAUGE, "bgpd_scrape_seconds", > "bgpd scrape time in seconds"); > > @@ -82,7 +82,7 @@ ometric_head(struct parse_result *arg) > * per neighbor stats: attrs will be remote_as, remote_addr, > * description and group > */ > - peer_info = ometric_new(OMT_INFO, "bgpd_peer_info", > + peer_info = ometric_new(OMT_INFO, "bgpd_peer", > "peer information"); > peer_state = ometric_new_state(statenames, > sizeof(statenames) / sizeof(statenames[0]), "bgpd_peer_state", > @@ -105,65 +105,65 @@ ometric_head(struct parse_result *arg) > "number of prefixes received from peer"); > > peer_message_transmit = ometric_new(OMT_COUNTER, > - "bgpd_peer_message_transmit_total", > + "bgpd_peer_message_transmit", > "per message type count of transmitted messages"); > peer_message_receive = ometric_new(OMT_COUNTER, > - "bgpd_peer_message_receive_total", > + "bgpd_peer_message_receive", > "per message type count of received messages"); > > peer_update_transmit = ometric_new(OMT_COUNTER, > - "bgpd_peer_update_transmit_total", > + "bgpd_peer_update_transmit", > "number of prefixes sent as update"); > peer_update_pending = ometric_new(OMT_COUNTER, > - "bgpd_peer_update_pending_total", > + "bgpd_peer_update_pending", > "number of pending update prefixes"); > peer_update_receive = ometric_new(OMT_COUNTER, > - "bgpd_peer_update_receive_total", > + "bgpd_peer_update_receive", > "number of prefixes received as update"); > > peer_withdraw_transmit = ometric_new(OMT_COUNTER, > - "bgpd_peer_withdraw_transmit_total", > + "bgpd_peer_withdraw_transmit", > "number of withdrawn prefixes sent to peer"); > peer_withdraw_pending = ometric_new(OMT_COUNTER, > - "bgpd_peer_withdraw_pending_total", > + "bgpd_peer_withdraw_pending", > "number of pending withdrawn prefixes"); > peer_withdraw_receive = ometric_new(OMT_COUNTER, > - "bgpd_peer_withdraw_receive_total", > + "bgpd_peer_withdraw_receive", > "number of withdrawn prefixes received from peer"); > > peer_rr_req_transmit = ometric_new(OMT_COUNTER, > - "bgpd_peer_route_refresh_req_transmit_total", > + "bgpd_peer_route_refresh_req_transmit", > "number of route-refresh request transmitted to peer"); > peer_rr_req_receive = ometric_new(OMT_COUNTER, > - "bgpd_peer_route_refresh_req_receive_total", > + "bgpd_peer_route_refresh_req_receive", > "number of route-refresh request received from peer"); > peer_rr_borr_transmit = ometric_new(OMT_COUNTER, > - "bgpd_peer_route_refresh_borr_transmit_total", > + "bgpd_peer_route_refresh_borr_transmit", > "number of ext. route-refresh BORR messages transmitted to peer"); > peer_rr_borr_receive = ometric_new(OMT_COUNTER, > - "bgpd_peer_route_refresh_borr_receive_total", > + "bgpd_peer_route_refresh_borr_receive", > "number of ext. route-refresh BORR messages received from peer"); > peer_rr_eorr_transmit = ometric_new(OMT_COUNTER, > - "bgpd_peer_route_refresh_eorr_transmit_total", > + "bgpd_peer_route_refresh_eorr_transmit", > "number of ext. route-refresh EORR messages transmitted to peer"); > peer_rr_eorr_receive = ometric_new(OMT_COUNTER, > - "bgpd_peer_route_refresh_eorr_receive_total", > + "bgpd_peer_route_refresh_eorr_receive", > "number of ext. route-refresh EORR messages received from peer"); > > /* RDE memory statistics */ > rde_mem_size = ometric_new(OMT_GAUGE, > "bgpd_rde_memory_usage_bytes", "memory usage in bytes"); > rde_mem_count = ometric_new(OMT_GAUGE, > - "bgpd_rde_memory_count", "number of object in use"); > + "bgpd_rde_memory_usage_objects", "number of object in use"); > rde_mem_ref_count = ometric_new(OMT_GAUGE, > - "bgpd_rde_memory_reference_count", "number of references held"); > + "bgpd_rde_memory_usage_references", "number of references held"); > > rde_set_size = ometric_new(OMT_GAUGE, > "bgpd_rde_set_usage_bytes", "memory usage of set in bytes"); > rde_set_count = ometric_new(OMT_GAUGE, > - "bgpd_rde_set_count", "number of object in set"); > + "bgpd_rde_set_usage_objects", "number of object in set"); > rde_table_count = ometric_new(OMT_GAUGE, > - "bgpd_rde_table_count", "number of as_set tables"); > + "bgpd_rde_set_usage_tables", "number of as_set tables"); > } > > static void >