libprom  1.2.0
C based libraries to expose metrics in Promtheus exposition format
libprom documentation

Introduction

libprom is a small suite of C libraries which can be used to maintain metrics on-the-fly and to expose them automatically in the Prometheus exposition format when needed.

In this brief tutorial you will learn how to create and register metrics, update metric samples, and expose metrics over HTTP.

In the old original version awefully long function and type names were used. They got renamed for better readability and more compact code. Now the following prefix abbreviation are used instead of:

  • pcr .. prom_collector_registry
  • phb .. prom_histogram_buckets
  • pll .. prom_linked_list
  • pmf .. prom_metric_formatter
  • pms .. prom_metric_sample
  • ppl .. prom_process_limits
  • pps .. prom_process_stat[s]
  • psb .. prom_string_builder
  • ppc .. prom_process_collector (formerly prom_collector_process)

Creating and Registering Metrics

First thing to do is to create the prom collector registry. A prom collector registry is basically an associative array of prom collectors keyed by their names. It is recommended to use the default prom collector registry (it has the name "default"). Use pcr_init() to set it up. Under the hood it also initializes the default prom collector, where all your prom metrics alias counters, gauges, histograms will be added by default. If PROM_PROCESS gets passed as an argument, a prom collector named process gets initialized as well, which contains and collects several metrics about the running process/thread. A prom collector is basically an associative array of prom metrics keyed by their names.

After that, write a metric initialization function, which creates the required metrics and registers them with the prom collector of choice. Usually one would use the pcr_register_metric() function: It will add the metrics to the default prom collector which is registered with the default prom collector registry.

If one has created his own, non-default prom collector registry using pcr_registry_new(), one may use pcr_registry_get() with the name parameter set to default to get a reference to its default collector instance, or create a new collector using pcr_new() and register it with the registry via pcr_register_collector(). To add metrics to the related container, use prom_collector_add_metric().

However, here an easy example, which uses the default prom collector registry including the "process" collector:

#incldue "prom.h"
prom_counter_t *my_counter;
void foo_metric_init(void) {
my_counter = prom_counter_new("my_counter", "counts things", 0, NULL);
if (my_counter != NULL && pcr_register_metric(my_counter))
PROM_INFO("metric '%s' registered.", my_counter->name);
}
// prefix all metric names with "myapp_" and report the overall scrape time
foo_metric_init();
}

If you need more metrics, add them as needed. libprom supports metrics with the following metric types:

Updating Metric Sample Values

Now that we have a metric created and registered our metric(s), we can update its value as needed. For example:

void my_lib_do_something(void) {
printf("I did a really important thing!\n");
prom_counter_inc(my_counter, NULL);
}

This function will increment the default metric sample for my_counter. Since we are not using metric labels, we pass NULL as the second argument.

Metric Exposition Over HTTP

To expose all the metrics of all enabled collectors in a given prom collector registry via HTTP, one needs to activate the registry using promhttp_set_active_collector_registry() - if the passed registry is NULL, the default prom collector registry will be used instead. Note: Only one registry at a time is active.

After firing up the HTTP handler via promhttp_start_daemon(), the HTTP handler calls the pcr_bridge() on /metrics request. This in turn instructs the registry's prom metric formatter (pmf) to reset its internal stringbuilder, i.e. clear its buffer via pmf_clear() and populate the response by calling pmf_load_metrics(). This function calls the collect_fn() function of each registered collector to get the list of metrics to include in the HTTP response. Finally the formatter iterates through the returned list of metrics, and appends them in Prometheus exposition format to its internal stringbuilder. When all prom collectors of the registry have been processed, the contents of the formmatter's stringbuilder gets dumped as a single string via pmf_dump() and append to the HTTP response of the request - the http handler takes care of the rest.

So basically do something like this:

struct MHD_Daemon *daemon = promhttp_start_daemon(MHD_USE_SELECT_INTERNALLY, PORT, NULL, NULL);
if (daemon == NULL)
return 1;

collect_fn()

As explained above, to dump registered metrics in Prometheus exposition format, the formatter calls the collect_fn() function of all registered prom collectors and is per default the integral part when generating the response for a /metrics request. So what does it, is expected to do?

For any default prom collector collect_fn() does nothing but just returns the list of registered metrics unless one had set another function to call using prom_collector_set_collect_fn(). However, the process prom collector automatically created and registered via pcr_init(PROM_PROCESS, ...) reads in all process related data now, updates the values of the relevant metrics and after that it returns the list of metrics to include iin the response as well.

So the take-away here is, that collect_fn() may trigger other things like metric updates, too. But since it is per default part of the HTTP resonse generation, it should be very fast to prevent any timeouts. Depending on the flags passed to the promhttp_start_daemon() call the http daemon may answers any request one after another.

FAQ

I do not want to maintain any metric on-the-fly?

So you only want to convert some collected data to Prometheus exposition format and export it via HTTP? In this case you do not need libprom but just need to have a look at promhttp.c. Copy-and-paste and change the line, where pcr_bridge(PROM_ACTIVE_REGISTRY) gets called. Replace it with a call to your own function which should return the desired metrics as a string. That's it.

But I want to re-use the metrics maintained by the "process" collector.

In this case you can do the same as above and use pcr_init(PROM_PROCESS, ...) to initialize the default prom registry PROM_COLLECTOR_REGISTRY. When it is time to expose the metrics just call pcr_bridge(PROM_COLLECTOR_REGISTRY) and append the returned string to the output of your own export.

Where to Go From Here?

Take a look at the Files tab in this documentation site for more information about the public API available to you. Also, you can take a look at the examples directory at the Github repository for inspiration.

promhttp_start_daemon
struct MHD_Daemon * promhttp_start_daemon(unsigned int flags, unsigned short port, MHD_AcceptPolicyCallback apc, void *apc_cls)
Start a daemon in the background and return a reference to it.
prom_counter_inc
int prom_counter_inc(prom_counter_t *self, const char **label_values)
Increment the given counter by 1.
pcr_init
int pcr_init(PROM_INIT_FLAGS features, const char *mprefix)
Initializes the default collector registry PROM_COLLECTOR_REGISTRY named REGISTRY_NAME_DEFAULT.
pcr_register_metric
int pcr_register_metric(prom_metric_t *metric)
Registers a metric with the default collector on PROM_COLLECTOR_REGISTRY.
PROM_PROCESS
@ PROM_PROCESS
Automatically setup and attach a process collector, which collects stats of this process on pcr_bridg...
Definition: prom_collector_registry.h:57
promhttp_set_active_collector_registry
void promhttp_set_active_collector_registry(pcr_t *registry)
Sets the active registry for metric scraping.
PROM_INFO
#define PROM_INFO(fmt,...)
Log an info message prefixed with the location of this macro within the source code (file,...
Definition: prom_log.h:102
prom_counter_new
prom_counter_t * prom_counter_new(const char *name, const char *help, size_t label_key_count, const char **label_keys)
Construct a new metric of type counter (or short: counter).
PROM_SCRAPETIME
@ PROM_SCRAPETIME
Automatically create and use a metric to monitor the time needed to dump all the metrics of all regis...
Definition: prom_collector_registry.h:63
prom_counter_t
prom_metric_t prom_counter_t
Prometheus metric: counter.
Definition: prom_counter.h:36