Tor 0.4.9.0-alpha-dev
metrics_store_entry.c
Go to the documentation of this file.
1/* Copyright (c) 2020-2021, The Tor Project, Inc. */
2/* See LICENSE for licensing information */
3
4/**
5 * @file metrics_store_entry.c
6 * @brief Metrics store entry which contains the gathered data.
7 **/
8
9#include "metrics_common.h"
10#define METRICS_STORE_ENTRY_PRIVATE
11
12#include <string.h>
13
14#include "orconfig.h"
15
17#include "lib/log/util_bug.h"
18#include "lib/malloc/malloc.h"
19
21
22/*
23 * Public API.
24 */
25
26/** Return newly allocated store entry of the specified type. */
27metrics_store_entry_t *
29 const char *help, size_t bucket_count,
30 const int64_t *buckets)
31{
32 metrics_store_entry_t *entry = tor_malloc_zero(sizeof(*entry));
33
35
36 entry->type = type;
37 entry->name = tor_strdup(name);
38 entry->labels = smartlist_new();
39 if (help) {
40 entry->help = tor_strdup(help);
41 }
42
43 if (type == METRICS_TYPE_HISTOGRAM && bucket_count > 0) {
44 tor_assert(buckets);
45
46 entry->u.histogram.bucket_count = bucket_count;
47 entry->u.histogram.buckets =
48 tor_malloc_zero(sizeof(metrics_histogram_bucket_t) * bucket_count);
49
50 for (size_t i = 0; i < bucket_count; ++i) {
51 entry->u.histogram.buckets[i].bucket = buckets[i];
52 }
53 }
54
55 return entry;
56}
57
58/** Free a store entry. */
59void
60metrics_store_entry_free_(metrics_store_entry_t *entry)
61{
62 if (!entry) {
63 return;
64 }
65 SMARTLIST_FOREACH(entry->labels, char *, l, tor_free(l));
66 smartlist_free(entry->labels);
67 tor_free(entry->name);
68 tor_free(entry->help);
69
70 if (entry->type == METRICS_TYPE_HISTOGRAM) {
71 tor_free(entry->u.histogram.buckets);
72 }
73
74 tor_free(entry);
75}
76
77/** Update a store entry with value. */
78void
79metrics_store_entry_update(metrics_store_entry_t *entry, const int64_t value)
80{
81 tor_assert(entry);
82
83 /* Histogram values are updated using metrics_store_hist_entry_update */
84 if (BUG(entry->type == METRICS_TYPE_HISTOGRAM)) {
85 return;
86 }
87
88 switch (entry->type) {
89 case METRICS_TYPE_COUNTER:
90 /* Counter can ONLY be positive. */
91 if (BUG(value < 0)) {
92 return;
93 }
94 entry->u.counter.value += value;
95 break;
96 case METRICS_TYPE_GAUGE:
97 /* Gauge can increment or decrement. And can be positive or negative. */
98 entry->u.gauge.value += value;
99 break;
100 case METRICS_TYPE_HISTOGRAM:
101 tor_assert_unreached();
102 }
103}
104
105/** Update a store entry with value for the specified observation obs.
106 *
107 * Note: entry **must** be a histogram. */
108void
109metrics_store_hist_entry_update(metrics_store_entry_t *entry,
110 const int64_t value, const int64_t obs)
111{
112 if (BUG(entry->type != METRICS_TYPE_HISTOGRAM)) {
113 return;
114 }
115
116 /* Counter can ONLY be positive for histograms. */
117 if (BUG(value < 0)) {
118 return;
119 }
120
121 /* If we're about to overflow or underflow the sum, reset all counters back
122 * to 0 before recording the observation. */
123 if (PREDICT_UNLIKELY(
124 (obs > 0 && entry->u.histogram.sum > INT64_MAX - obs) ||
125 (obs < 0 && entry->u.histogram.sum < INT64_MIN - obs))) {
127 }
128
129 entry->u.histogram.count += value;
130 entry->u.histogram.sum += obs;
131
132 for (size_t i = 0; i < entry->u.histogram.bucket_count; ++i) {
133 metrics_histogram_bucket_t *hb = &entry->u.histogram.buckets[i];
134 if (obs <= hb->bucket) {
135 hb->value += value;
136 }
137 }
138}
139
140/** Reset a store entry that is set its metric data to 0. */
141void
142metrics_store_entry_reset(metrics_store_entry_t *entry)
143{
144 tor_assert(entry);
145
146 switch (entry->type) {
147 case METRICS_TYPE_COUNTER: FALLTHROUGH;
148 case METRICS_TYPE_GAUGE:
149 /* Everything back to 0. */
150 memset(&entry->u, 0, sizeof(entry->u));
151 break;
152 case METRICS_TYPE_HISTOGRAM:
153 for (size_t i = 0; i < entry->u.histogram.bucket_count; ++i) {
154 metrics_histogram_bucket_t *hb = &entry->u.histogram.buckets[i];
155 hb->value = 0;
156 }
157 entry->u.histogram.sum = 0;
158 entry->u.histogram.count = 0;
159 break;
160 }
161}
162
163/** Return store entry value. */
164int64_t
165metrics_store_entry_get_value(const metrics_store_entry_t *entry)
166{
167 tor_assert(entry);
168
169 /* Histogram values are accessed using metrics_store_hist_entry_get_value. */
170 if (BUG(entry->type == METRICS_TYPE_HISTOGRAM)) {
171 return 0;
172 }
173
174 switch (entry->type) {
175 case METRICS_TYPE_COUNTER:
176 if (entry->u.counter.value > INT64_MAX) {
177 return INT64_MAX;
178 }
179 return entry->u.counter.value;
180 case METRICS_TYPE_GAUGE:
181 return entry->u.gauge.value;
182 case METRICS_TYPE_HISTOGRAM:
183 tor_assert_unreached();
184 return 0;
185 }
186
187 // LCOV_EXCL_START
188 tor_assert_unreached();
189 // LCOV_EXCL_STOP
190}
191
192/** Return store entry value for the specified bucket.
193 *
194 * Note: entry **must** be a histogram. */
195uint64_t
196metrics_store_hist_entry_get_value(const metrics_store_entry_t *entry,
197 const int64_t bucket)
198{
199 tor_assert(entry);
200
201 if (BUG(entry->type != METRICS_TYPE_HISTOGRAM)) {
202 return 0;
203 }
204
205 for (size_t i = 0; i <= entry->u.histogram.bucket_count; ++i) {
206 metrics_histogram_bucket_t hb = entry->u.histogram.buckets[i];
207 if (bucket == hb.bucket) {
208 if (hb.value > INT64_MAX) {
209 return INT64_MAX;
210 } else {
211 return hb.value;
212 }
213 }
214 }
215
216 tor_assertf_nonfatal(false, "attempted to get the value of non-existent "
217 "bucket %" PRId64, bucket);
218 return 0;
219}
220
221/** Add a label into the given entry.*/
222void
223metrics_store_entry_add_label(metrics_store_entry_t *entry,
224 const char *label)
225{
226 tor_assert(entry);
227 tor_assert(label);
228
229 smartlist_add(entry->labels, tor_strdup(label));
230}
231
232/** Return true iff the given entry has the given label. */
233bool
234metrics_store_entry_has_label(const metrics_store_entry_t *entry,
235 const char *label)
236{
237 tor_assert(entry);
238 tor_assert(label);
239
240 return smartlist_contains_string(entry->labels, label);
241}
242
243/** Return the first entry that has the given label, or NULL if none
244 * of the entries have the label. */
245metrics_store_entry_t *
247 const char *label)
248{
249 tor_assert(entries);
250 tor_assert(label);
251
252 SMARTLIST_FOREACH_BEGIN(entries, metrics_store_entry_t *, entry) {
253 tor_assert(entry);
254
255 if (smartlist_contains_string(entry->labels, label)) {
256 return entry;
257 }
258 } SMARTLIST_FOREACH_END(entry);
259
260 return NULL;
261}
262
263/** Return true iff the specified entry is a histogram. */
264bool
265metrics_store_entry_is_histogram(const metrics_store_entry_t *entry)
266{
267 if (entry->type == METRICS_TYPE_HISTOGRAM) {
268 return true;
269 }
270
271 return false;
272}
273
274/** Return the total number of observations for the specified histogram. */
275uint64_t
276metrics_store_hist_entry_get_count(const metrics_store_entry_t *entry)
277{
278 tor_assert(entry);
279
280 if (BUG(entry->type != METRICS_TYPE_HISTOGRAM)) {
281 return 0;
282 }
283
284 return entry->u.histogram.count;
285}
286
287/** Return the sum of all observations for the specified histogram. */
288int64_t
289metrics_store_hist_entry_get_sum(const metrics_store_entry_t *entry)
290{
291 tor_assert(entry);
292
293 if (BUG(entry->type != METRICS_TYPE_HISTOGRAM)) {
294 return 0;
295 }
296
297 return entry->u.histogram.sum;
298}
const char * name
Definition: config.c:2462
Headers for util_malloc.c.
#define tor_free(p)
Definition: malloc.h:56
Header for lib/metrics/metrics_common.c.
metrics_type_t
uint64_t metrics_store_hist_entry_get_count(const metrics_store_entry_t *entry)
void metrics_store_entry_update(metrics_store_entry_t *entry, const int64_t value)
bool metrics_store_entry_is_histogram(const metrics_store_entry_t *entry)
uint64_t metrics_store_hist_entry_get_value(const metrics_store_entry_t *entry, const int64_t bucket)
void metrics_store_entry_add_label(metrics_store_entry_t *entry, const char *label)
int64_t metrics_store_hist_entry_get_sum(const metrics_store_entry_t *entry)
metrics_store_entry_t * metrics_store_entry_new(const metrics_type_t type, const char *name, const char *help, size_t bucket_count, const int64_t *buckets)
metrics_store_entry_t * metrics_store_find_entry_with_label(const smartlist_t *entries, const char *label)
void metrics_store_entry_free_(metrics_store_entry_t *entry)
void metrics_store_hist_entry_update(metrics_store_entry_t *entry, const int64_t value, const int64_t obs)
int64_t metrics_store_entry_get_value(const metrics_store_entry_t *entry)
void metrics_store_entry_reset(metrics_store_entry_t *entry)
bool metrics_store_entry_has_label(const metrics_store_entry_t *entry, const char *label)
Header for lib/metrics/metrics_store_entry.c.
int smartlist_contains_string(const smartlist_t *sl, const char *element)
Definition: smartlist.c:93
Header for smartlist.c.
smartlist_t * smartlist_new(void)
void smartlist_add(smartlist_t *sl, void *element)
#define SMARTLIST_FOREACH_BEGIN(sl, type, var)
#define SMARTLIST_FOREACH(sl, type, var, cmd)
Macros to manage assertions, fatal and non-fatal.
#define tor_assert(expr)
Definition: util_bug.h:103