tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

metrics_store.c (4405B)


      1 /* Copyright (c) 2020-2021, The Tor Project, Inc. */
      2 /* See LICENSE for licensing information */
      3 
      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 **/
      9 
     10 #define METRICS_STORE_ENTRY_PRIVATE
     11 
     12 #include "orconfig.h"
     13 
     14 #include "lib/container/map.h"
     15 #include "lib/log/util_bug.h"
     16 #include "lib/malloc/malloc.h"
     17 
     18 #include "lib/metrics/metrics_store.h"
     19 #include "lib/metrics/metrics_store_entry.h"
     20 
     21 /* Format Drivers. */
     22 #include "lib/metrics/prometheus.h"
     23 
     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.
     28   *
     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;
     34 };
     35 
     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 *,
     38                               bool no_comment);
     39 
     40 /** Helper: Free a single entry in a metrics_store_t taking a void pointer
     41 * parameter. */
     42 static void
     43 metrics_store_free_void(void *p)
     44 {
     45  smartlist_t *list = p;
     46  SMARTLIST_FOREACH(list, metrics_store_entry_t *, entry,
     47                    metrics_store_entry_free(entry));
     48  smartlist_free(list);
     49 }
     50 
     51 #include <stdio.h>
     52 
     53 /** Put the given store output in the buffer data and use the format function
     54 * given in fmt to get it for each entry. */
     55 static void
     56 get_output(const metrics_store_t *store, buf_t *data, fmt_driver_fn_t fmt)
     57 {
     58  tor_assert(store);
     59  tor_assert(data);
     60  tor_assert(fmt);
     61 
     62  STRMAP_FOREACH(store->entries, key, const smartlist_t *, entries) {
     63    /* Indicate that we've formatted the comment already for the entries. */
     64    bool comment_formatted = false;
     65    SMARTLIST_FOREACH_BEGIN(entries, const metrics_store_entry_t *, entry) {
     66      fmt(entry, data, comment_formatted);
     67      comment_formatted = true;
     68    } SMARTLIST_FOREACH_END(entry);
     69  } STRMAP_FOREACH_END;
     70 }
     71 
     72 /** Return a newly allocated and initialized store of the given type. */
     73 metrics_store_t *
     74 metrics_store_new(void)
     75 {
     76  metrics_store_t *store = tor_malloc_zero(sizeof(*store));
     77 
     78  store->entries = strmap_new();
     79 
     80  return store;
     81 }
     82 
     83 /** Free the given store including all its entries. */
     84 void
     85 metrics_store_free_(metrics_store_t *store)
     86 {
     87  if (store == NULL) {
     88    return;
     89  }
     90 
     91  strmap_free(store->entries, metrics_store_free_void);
     92  tor_free(store);
     93 }
     94 
     95 /** Find all metrics entry in the given store identified by name. If not found,
     96 * NULL is returned. */
     97 smartlist_t *
     98 metrics_store_get_all(const metrics_store_t *store, const char *name)
     99 {
    100  tor_assert(store);
    101  tor_assert(name);
    102 
    103  return strmap_get(store->entries, name);
    104 }
    105 
    106 /** Add a new metrics entry to the given store and type. The name MUST be the
    107 * unique identifier. The help string can be omitted. */
    108 metrics_store_entry_t *
    109 metrics_store_add(metrics_store_t *store, metrics_type_t type,
    110                  const char *name, const char *help, size_t bucket_count,
    111                  const int64_t *buckets)
    112 
    113 {
    114  smartlist_t *entries;
    115  metrics_store_entry_t *entry;
    116 
    117  tor_assert(store);
    118  tor_assert(name);
    119 
    120  entries = metrics_store_get_all(store, name);
    121  if (!entries) {
    122    entries = smartlist_new();
    123    strmap_set(store->entries, name, entries);
    124  }
    125  entry = metrics_store_entry_new(type, name, help, bucket_count, buckets);
    126  smartlist_add(entries, entry);
    127 
    128  return entry;
    129 }
    130 
    131 /** Set the output of the given store of the format fmt into the given buffer
    132 * data. */
    133 void
    134 metrics_store_get_output(const metrics_format_t fmt,
    135                         const metrics_store_t *store, buf_t *data)
    136 {
    137  tor_assert(store);
    138 
    139  switch (fmt) {
    140  case METRICS_FORMAT_PROMETHEUS:
    141    get_output(store, data, prometheus_format_store_entry);
    142    break;
    143  default:
    144    // LCOV_EXCL_START
    145    tor_assert_unreached();
    146    // LCOV_EXCL_STOP
    147  }
    148 }
    149 
    150 /** Reset a store as in free its content. */
    151 void
    152 metrics_store_reset(metrics_store_t *store)
    153 {
    154  if (store == NULL) {
    155    return;
    156  }
    157  strmap_free(store->entries, metrics_store_free_void);
    158  store->entries = strmap_new();
    159 }