Update copyrights to 2021, using "make update-copyright"
[tor.git] / src / lib / metrics / metrics_store.c
blob4cab5245f31474728eeba233f9d1c8c36a4d1668
1 /* Copyright (c) 2020-2021, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
4 /**
5 * @file metrics_store.c
6 * @brief Metrics interface to store them based on specific store type and get
7 * their MetricsPort output.
8 **/
10 #define METRICS_STORE_ENTRY_PRIVATE
12 #include "orconfig.h"
14 #include "lib/container/map.h"
15 #include "lib/log/util_bug.h"
16 #include "lib/malloc/malloc.h"
18 #include "lib/metrics/metrics_store.h"
19 #include "lib/metrics/metrics_store_entry.h"
21 /* Format Drivers. */
22 #include "lib/metrics/prometheus.h"
24 /** A metric store which contains a map of entries. */
25 struct metrics_store_t {
26 /** Indexed by metrics entry name. An entry is a smartlist_t of one or more
27 * metrics_store_entry_t allowing for multiple metrics of the same name.
29 * The reason we allow multiple entries is because there are cases where one
30 * metrics can be used twice by the same entity but with different labels.
31 * One example is an onion service with multiple ports, the port specific
32 * metrics will have a port value as a label. */
33 strmap_t *entries;
36 /** Function pointer to the format function of a specific driver. */
37 typedef void (fmt_driver_fn_t)(const metrics_store_entry_t *, buf_t *);
39 /** Helper: Free a single entry in a metrics_store_t taking a void pointer
40 * parameter. */
41 static void
42 metrics_store_free_void(void *p)
44 smartlist_t *list = p;
45 SMARTLIST_FOREACH(list, metrics_store_entry_t *, entry,
46 metrics_store_entry_free(entry));
47 smartlist_free(list);
50 /** Put the given store output in the buffer data and use the format function
51 * given in fmt to get it for each entry. */
52 static void
53 get_output(const metrics_store_t *store, buf_t *data, fmt_driver_fn_t fmt)
55 tor_assert(store);
56 tor_assert(data);
57 tor_assert(fmt);
59 STRMAP_FOREACH(store->entries, key, const smartlist_t *, entries) {
60 SMARTLIST_FOREACH_BEGIN(entries, const metrics_store_entry_t *, entry) {
61 fmt(entry, data);
62 } SMARTLIST_FOREACH_END(entry);
63 } STRMAP_FOREACH_END;
66 /** Return a newly allocated and initialized store of the given type. */
67 metrics_store_t *
68 metrics_store_new(void)
70 metrics_store_t *store = tor_malloc_zero(sizeof(*store));
72 store->entries = strmap_new();
74 return store;
77 /** Free the given store including all its entries. */
78 void
79 metrics_store_free_(metrics_store_t *store)
81 if (store == NULL) {
82 return;
85 strmap_free(store->entries, metrics_store_free_void);
86 tor_free(store);
89 /** Find all metrics entry in the given store identified by name. If not found,
90 * NULL is returned. */
91 smartlist_t *
92 metrics_store_get_all(const metrics_store_t *store, const char *name)
94 tor_assert(store);
95 tor_assert(name);
97 return strmap_get(store->entries, name);
100 /** Add a new metrics entry to the given store and type. The name MUST be the
101 * unique identifier. The help string can be omitted. */
102 metrics_store_entry_t *
103 metrics_store_add(metrics_store_t *store, metrics_type_t type,
104 const char *name, const char *help)
106 smartlist_t *entries;
107 metrics_store_entry_t *entry;
109 tor_assert(store);
110 tor_assert(name);
112 entries = metrics_store_get_all(store, name);
113 if (!entries) {
114 entries = smartlist_new();
115 strmap_set(store->entries, name, entries);
117 entry = metrics_store_entry_new(type, name, help);
118 smartlist_add(entries, entry);
120 return entry;
123 /** Set the output of the given store of the format fmt into the given buffer
124 * data. */
125 void
126 metrics_store_get_output(const metrics_format_t fmt,
127 const metrics_store_t *store, buf_t *data)
129 tor_assert(store);
131 switch (fmt) {
132 case METRICS_FORMAT_PROMETHEUS:
133 get_output(store, data, prometheus_format_store_entry);
134 break;
135 default:
136 // LCOV_EXCL_START
137 tor_assert_unreached();
138 // LCOV_EXCL_STOP