17

I've looked at the syntax example in prometheus-cpp and the very similar go one in the main prometheus documentation, and I'm not sure how I'm supposed to use similar code in my C++ application. Go uses a global variable to hold the counter, C++ uses a local reference within the instrumented function. Auto references means that I can't easily put counters into a wrapper, but 10 lines of overhead every time I want to increment a counter isn't acceptable.

Naively it looks like this:

void SomeClass::a_little_method() {
    auto start = get_accurate_time();

    // actual code that the method
    // uses to do whatever it does
    // in less than ten lines of code

    auto& counter_family = BuildCounter()
            .Name("little_method")
            .Help("little method execution count and duration")
            .Labels({
        {"My Application", "metrics"}
    })
    .Register(*global_registry_pointer);
    auto& call_counter = counter_family.Add({
        {"calls", "count"}
    });
    auto& execution_timer = counter_family.Add({
        {"calls", "duration"}
    });
    call_counter.Increment();
    execution_timer.Increment(get_accurate_time() - start);
}

There is much more instrumentation than code being instrumented. It gets worse as more things get instrumented, the prometheus guide "there should be a counter for every log line" means every log line gains 8 or 10 lines of prometheus verbiage. And there's two local variables created, used once, then destroyed.

Solution One: More Global Variables

Prometheus-cpp has its global "registry" object, so presumably the intent is that I just add a bunch of "counter family" globals followed by a huge pile of global "counter" variables. That means the program won't run at all if prometheus fails to initialise, but at least each counter is only set up once. At least the library of counters is all in one place so it's easy to see and organise.

Solution Two: a wrapper thread that exposes Increment() methods

I could declare all those auto reference variables in one giant method, finish the method with a "while not terminated sleep" call and run it as a thread. Then expose those local counter variables via a set of Increment methods. But this feels as though I'm working against the intent of the library author.

Solution Three: do it properly??

I really want a single line per counter increment, ideally as a method on an injectable/mockable class. Preferably with the other prometheus wrapper duration wrapper. My program should run even if prometheus isn't available or can't run for some reason (I'm not running a server thats sole purpose is to play with prometheus).

SomeClass::SomeClass(... prometheus...)
SomeClass::wrap_a_little_method() {
    prometheus.observe_duration([&]() {
        a_little_method();
    }
    prometheus.Increment(a_little_method_call_count);
}

(there's no prometheus-cpp tag and I don't have the rep to create one, sorry)

Code Abominator
  • 1,571
  • 18
  • 23

0 Answers0