Keep hold of metrics for performant instrumentation
I am curious the best practice to keep hold of a Counter/Gauge/etc after calling BuildCounter()
auto& packet_counter = BuildCounter()
.Name("observed_packets_total")
.Help("Number of observed packets")
.Register(*registry);
// add and remember dimensional data, incrementing those is very cheap
auto& tcp_rx_counter =
packet_counter.Add({{"protocol", "tcp"}, {"direction", "rx"}});
Clearly in real life, tcp_rx_counter will probably be a member of a class e.g. CTCPConnection::tcp_rx_counter, used in method like CTCPConnection::ReadBytes() But as we only get a reference, this restricts us a bit. In real-world code, would you simply use std::reference_wrapper<Counter> or is there a trick I've missed here? What does production code look like?
Commenting because I am interested in the answer as well. @jdx-john if you have a solution, please share.
Sorry for the late reply. The model is a single ownership model. Ownership means who is responsible for deleting that memory.
- the registry owns the memory of the metric
- the components who are calling into the metric (counter increase) hold non-owning references to the metrics, this can be references, raw pointers, reference wrappers,
gsl::not_null, etc.
The lifetime of the registry should be the lifetime of the program. If that's not the case for you, some manual syncronization between registry destruction and users of the metrics might be required to prevent dangling pointers to the metrics.
Does that make sense @jdx-john and @dnck?
Hi @jupp0r - yep, after reading the code some more, your answer helps a lot. I've instrumented our code base and it's working as expected. Thanks a lot for your project!