On Wed, Oct 12, 2022 at 12:12:25PM +0200, Theo Buehler wrote: > On Fri, Oct 07, 2022 at 12:37:10PM +0200, Claudio Jeker wrote: > > This diff adds `bgpctl show metric` which is a command that dumps some > > stats out in openmetric format. This format can be ingested by e.g. > > prometheus and used for monitoring. > > > > The openmetric handling is in ometric.[ch]. It is fairly basic and not > > intended for long running processes. There is a struct ometric (which is > > one individual metric point). This metric point can have many different > > values with each value including an optional set of labels. Since the > > labels are used over and over again, I used a refcount on them. > > Also since most strings used in these functions are string literals I also > > don't copy them. Only the values of labels are copied since those are > > for example per peer. > > > > Using a small extra diff in bgplgd I can export the metrics into > > prometheus and visualize them with grafana. > > > > Consider this an MVP that can be extended with all the infos we want. > > This looks pretty good to me. I like the approach and I couldn't spot > anything really wrong with it. > > Some very minor comments inline for your consideration. >
Thanks, some comments below. > > +struct ometric * > > +ometric_new_state(const char * const *states, size_t statecnt, const char > > *name, > > + const char *help) > > +{ > > + struct ometric *om; > > Matter of taste, but I'd probably have made an ometric_new_internal() > that sets all fields, so ometric_new() and ometric_new_state() could be > thin wrappers. This would also avoid leaving stateset and setsize > uninitialized in ometric_new() (which I find a bit nasty). > > Or use calloc(). I switched to use calloc() in both cases. Not totally sold on ometric_new_state(), the statesets are a pain to work with and are highly inefficent (they turn into a metric point per state). > > +void > > +ometric_set_state(struct ometric *om, const char *state, struct olabels > > *ol) > > +{ > > + struct olabels *extra; > > + size_t i; > > + int val; > > + > > + if (om->type != OMT_STATESET) > > + errx(1, "%s incorrect ometric type", __func__); > > + > > + for (i = 0; i < om->setsize; i++) { > > + if (strcasecmp(state, om->stateset[i]) == 0) > > + val = 1; > > + else > > + val = 0; > > could simplify this to > > val = strcasecmp(state, om->stateset[i]) == 0; > > but I'm not sure if this is more readable Not sure either. I prefer the explicit version. So I left the code as is. > > +struct ometric *bgpd_info, *bgpd_scrape_time; > > +struct ometric *peer_info, *peer_state, *peer_up_time, *peer_down_time, > > + *peer_last_read, *peer_last_write; > > +struct ometric *peer_prefixes_tranmit, *peer_prefixes_receive; > > typo: peer_prefixes_transmit Fixed including all the other minor changes. -- :wq Claudio