summaryrefslogtreecommitdiff
path: root/src/lib/metrics/metrics_store.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/metrics/metrics_store.c')
-rw-r--r--src/lib/metrics/metrics_store.c140
1 files changed, 140 insertions, 0 deletions
diff --git a/src/lib/metrics/metrics_store.c b/src/lib/metrics/metrics_store.c
new file mode 100644
index 0000000000..57847cc37c
--- /dev/null
+++ b/src/lib/metrics/metrics_store.c
@@ -0,0 +1,140 @@
+/* Copyright (c) 2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file metrics_store.c
+ * @brief Metrics interface to store them based on specific store type and get
+ * their MetricsPort output.
+ **/
+
+#define METRICS_STORE_ENTRY_PRIVATE
+
+#include "orconfig.h"
+
+#include "lib/container/map.h"
+#include "lib/log/util_bug.h"
+#include "lib/malloc/malloc.h"
+
+#include "lib/metrics/metrics_store.h"
+#include "lib/metrics/metrics_store_entry.h"
+
+/* Format Drivers. */
+#include "lib/metrics/prometheus.h"
+
+/** A metric store which contains a map of entries. */
+struct metrics_store_t {
+ /** Indexed by metrics entry name. An entry is a smartlist_t of one or more
+ * metrics_store_entry_t allowing for multiple metrics of the same name.
+ *
+ * The reason we allow multiple entries is because there are cases where one
+ * metrics can be used twice by the same entity but with different labels.
+ * One example is an onion service with multiple ports, the port specific
+ * metrics will have a port value as a label. */
+ strmap_t *entries;
+};
+
+/** Function pointer to the format function of a specific driver. */
+typedef void (fmt_driver_fn_t)(const metrics_store_entry_t *, buf_t *);
+
+/** Helper: Free a single entry in a metrics_store_t taking a void pointer
+ * parameter. */
+static void
+metrics_store_free_void(void *p)
+{
+ smartlist_t *list = p;
+ SMARTLIST_FOREACH(list, metrics_store_entry_t *, entry,
+ metrics_store_entry_free(entry));
+ smartlist_free(list);
+}
+
+/** Put the given store output in the buffer data and use the format function
+ * given in fmt to get it for each entry. */
+static void
+get_output(const metrics_store_t *store, buf_t *data, fmt_driver_fn_t fmt)
+{
+ tor_assert(store);
+ tor_assert(data);
+ tor_assert(fmt);
+
+ STRMAP_FOREACH(store->entries, key, const smartlist_t *, entries) {
+ SMARTLIST_FOREACH_BEGIN(entries, const metrics_store_entry_t *, entry) {
+ fmt(entry, data);
+ } SMARTLIST_FOREACH_END(entry);
+ } STRMAP_FOREACH_END;
+}
+
+/** Return a newly allocated and initialized store of the given type. */
+metrics_store_t *
+metrics_store_new(void)
+{
+ metrics_store_t *store = tor_malloc_zero(sizeof(*store));
+
+ store->entries = strmap_new();
+
+ return store;
+}
+
+/** Free the given store including all its entries. */
+void
+metrics_store_free_(metrics_store_t *store)
+{
+ if (store == NULL) {
+ return;
+ }
+
+ strmap_free(store->entries, metrics_store_free_void);
+ tor_free(store);
+}
+
+/** Find all metrics entry in the given store identified by name. If not found,
+ * NULL is returned. */
+smartlist_t *
+metrics_store_get_all(const metrics_store_t *store, const char *name)
+{
+ tor_assert(store);
+ tor_assert(name);
+
+ return strmap_get(store->entries, name);
+}
+
+/** Add a new metrics entry to the given store and type. The name MUST be the
+ * unique identifier. The help string can be omitted. */
+metrics_store_entry_t *
+metrics_store_add(metrics_store_t *store, metrics_type_t type,
+ const char *name, const char *help)
+{
+ smartlist_t *entries;
+ metrics_store_entry_t *entry;
+
+ tor_assert(store);
+ tor_assert(name);
+
+ entries = metrics_store_get_all(store, name);
+ if (!entries) {
+ entries = smartlist_new();
+ strmap_set(store->entries, name, entries);
+ }
+ entry = metrics_store_entry_new(type, name, help);
+ smartlist_add(entries, entry);
+
+ return entry;
+}
+
+/** Set the output of the given store of the format fmt into the given buffer
+ * data. */
+void
+metrics_store_get_output(const metrics_format_t fmt,
+ const metrics_store_t *store, buf_t *data)
+{
+ tor_assert(store);
+
+ switch (fmt) {
+ case METRICS_FORMAT_PROMETHEUS:
+ get_output(store, data, prometheus_format_store_entry);
+ break;
+ default:
+ // LCOV_EXCL_START
+ tor_assert_unreached();
+ // LCOV_EXCL_STOP
+ }
+}