metrics: Add number of opened circuits to MetricsPort
[tor.git] / src / feature / relay / relay_metrics.c
blob7fcbb72d75658904ad4fd793ee84093952e6a9bc
1 /* Copyright (c) 2021, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
4 /**
5 * @file relay_metrics.c
6 * @brief Relay metrics exposed through the MetricsPort
7 **/
9 #define RELAY_METRICS_ENTRY_PRIVATE
11 #include "orconfig.h"
13 #include "core/or/or.h"
14 #include "core/mainloop/connection.h"
15 #include "core/mainloop/mainloop.h"
16 #include "core/or/congestion_control_common.h"
17 #include "core/or/circuitlist.h"
18 #include "core/or/dos.h"
19 #include "core/or/relay.h"
21 #include "app/config/config.h"
23 #include "lib/malloc/malloc.h"
24 #include "lib/container/smartlist.h"
25 #include "lib/metrics/metrics_store.h"
26 #include "lib/log/util_bug.h"
28 #include "feature/hs/hs_dos.h"
29 #include "feature/nodelist/nodelist.h"
30 #include "feature/nodelist/node_st.h"
31 #include "feature/nodelist/routerstatus_st.h"
32 #include "feature/relay/relay_metrics.h"
33 #include "feature/relay/router.h"
34 #include "feature/stats/rephist.h"
36 #include <event2/dns.h>
38 /** Declarations of each fill function for metrics defined in base_metrics. */
39 static void fill_cc_values(void);
40 static void fill_circuits_values(void);
41 static void fill_connections_values(void);
42 static void fill_dns_error_values(void);
43 static void fill_dns_query_values(void);
44 static void fill_dos_values(void);
45 static void fill_global_bw_limit_values(void);
46 static void fill_socket_values(void);
47 static void fill_onionskins_values(void);
48 static void fill_oom_values(void);
49 static void fill_streams_values(void);
50 static void fill_relay_flags(void);
51 static void fill_tcp_exhaustion_values(void);
52 static void fill_traffic_values(void);
54 /** The base metrics that is a static array of metrics added to the metrics
55 * store.
57 * The key member MUST be also the index of the entry in the array. */
58 static const relay_metrics_entry_t base_metrics[] =
61 .key = RELAY_METRICS_NUM_OOM_BYTES,
62 .type = METRICS_TYPE_COUNTER,
63 .name = METRICS_NAME(relay_load_oom_bytes_total),
64 .help = "Total number of bytes the OOM has freed by subsystem",
65 .fill_fn = fill_oom_values,
68 .key = RELAY_METRICS_NUM_ONIONSKINS,
69 .type = METRICS_TYPE_COUNTER,
70 .name = METRICS_NAME(relay_load_onionskins_total),
71 .help = "Total number of onionskins handled",
72 .fill_fn = fill_onionskins_values,
75 .key = RELAY_METRICS_NUM_SOCKETS,
76 .type = METRICS_TYPE_GAUGE,
77 .name = METRICS_NAME(relay_load_socket_total),
78 .help = "Total number of sockets",
79 .fill_fn = fill_socket_values,
82 .key = RELAY_METRICS_NUM_GLOBAL_RW_LIMIT,
83 .type = METRICS_TYPE_COUNTER,
84 .name = METRICS_NAME(relay_load_global_rate_limit_reached_total),
85 .help = "Total number of global connection bucket limit reached",
86 .fill_fn = fill_global_bw_limit_values,
89 .key = RELAY_METRICS_NUM_DNS,
90 .type = METRICS_TYPE_COUNTER,
91 .name = METRICS_NAME(relay_exit_dns_query_total),
92 .help = "Total number of DNS queries done by this relay",
93 .fill_fn = fill_dns_query_values,
96 .key = RELAY_METRICS_NUM_DNS_ERRORS,
97 .type = METRICS_TYPE_COUNTER,
98 .name = METRICS_NAME(relay_exit_dns_error_total),
99 .help = "Total number of DNS errors encountered by this relay",
100 .fill_fn = fill_dns_error_values,
103 .key = RELAY_METRICS_NUM_TCP_EXHAUSTION,
104 .type = METRICS_TYPE_COUNTER,
105 .name = METRICS_NAME(relay_load_tcp_exhaustion_total),
106 .help = "Total number of times we ran out of TCP ports",
107 .fill_fn = fill_tcp_exhaustion_values,
110 .key = RELAY_METRICS_NUM_CONNECTIONS,
111 .type = METRICS_TYPE_COUNTER,
112 .name = METRICS_NAME(relay_connections_total),
113 .help = "Total number of connections",
114 .fill_fn = fill_connections_values,
117 .key = RELAY_METRICS_NUM_STREAMS,
118 .type = METRICS_TYPE_COUNTER,
119 .name = METRICS_NAME(relay_streams_total),
120 .help = "Total number of streams",
121 .fill_fn = fill_streams_values,
124 .key = RELAY_METRICS_NUM_CC,
125 .type = METRICS_TYPE_COUNTER,
126 .name = METRICS_NAME(relay_congestion_control_total),
127 .help = "Congestion control related counters",
128 .fill_fn = fill_cc_values,
131 .key = RELAY_METRICS_NUM_DOS,
132 .type = METRICS_TYPE_COUNTER,
133 .name = METRICS_NAME(relay_dos_total),
134 .help = "Denial of Service defenses related counters",
135 .fill_fn = fill_dos_values,
138 .key = RELAY_METRICS_NUM_TRAFFIC,
139 .type = METRICS_TYPE_COUNTER,
140 .name = METRICS_NAME(relay_traffic_bytes),
141 .help = "Traffic related counters",
142 .fill_fn = fill_traffic_values,
145 .key = RELAY_METRICS_RELAY_FLAGS,
146 .type = METRICS_TYPE_GAUGE,
147 .name = METRICS_NAME(relay_flag),
148 .help = "Relay flags from consensus",
149 .fill_fn = fill_relay_flags,
152 .key = RELAY_METRICS_NUM_CIRCUITS,
153 .type = METRICS_TYPE_GAUGE,
154 .name = METRICS_NAME(relay_circuits_total),
155 .help = "Total number of circuits",
156 .fill_fn = fill_circuits_values,
159 static const size_t num_base_metrics = ARRAY_LENGTH(base_metrics);
161 /** The only and single store of all the relay metrics. */
162 static metrics_store_t *the_store;
164 /** Helper function to convert an handshake type into a string. */
165 static inline const char *
166 handshake_type_to_str(const uint16_t type)
168 switch (type) {
169 case ONION_HANDSHAKE_TYPE_TAP:
170 return "tap";
171 case ONION_HANDSHAKE_TYPE_FAST:
172 return "fast";
173 case ONION_HANDSHAKE_TYPE_NTOR:
174 return "ntor";
175 case ONION_HANDSHAKE_TYPE_NTOR_V3:
176 return "ntor_v3";
177 default:
178 // LCOV_EXCL_START
179 tor_assert_unreached();
180 // LCOV_EXCL_STOP
184 /** Fill function for the RELAY_METRICS_NUM_CIRCUITS metric. */
185 static void
186 fill_circuits_values(void)
188 const relay_metrics_entry_t *rentry =
189 &base_metrics[RELAY_METRICS_NUM_CIRCUITS];
190 metrics_store_entry_t *sentry =
191 metrics_store_add(the_store, rentry->type, rentry->name, rentry->help);
193 metrics_store_entry_add_label(sentry,
194 metrics_format_label("state", "opened"));
195 metrics_store_entry_update(sentry,
196 smartlist_len(circuit_get_global_list()));
199 /** Fill function for the RELAY_METRICS_RELAY_FLAGS metric. */
200 static void
201 fill_relay_flags(void)
203 uint8_t is_fast = 0, is_exit = 0, is_authority = 0, is_stable = 0;
204 uint8_t is_running = 0, is_v2_dir = 0, is_guard = 0, is_sybil = 0;
205 uint8_t is_hs_dir = 0;
207 const node_t *me =
208 node_get_by_id((const char *) router_get_my_id_digest());
209 if (me && me->rs) {
210 is_fast = me->rs->is_fast;
211 is_exit = me->rs->is_exit;
212 is_authority = me->rs->is_authority;
213 is_stable = me->rs->is_stable;
214 is_running = me->rs->is_flagged_running;
215 is_v2_dir = me->rs->is_v2_dir;
216 is_guard = me->rs->is_possible_guard;
217 is_sybil = me->rs->is_sybil;
218 is_hs_dir = me->rs->is_hs_dir;
221 const relay_metrics_entry_t *rentry =
222 &base_metrics[RELAY_METRICS_RELAY_FLAGS];
223 metrics_store_entry_t *sentry =
224 metrics_store_add(the_store, rentry->type, rentry->name, rentry->help);
226 metrics_store_entry_add_label(sentry,
227 metrics_format_label("type", "Fast"));
228 metrics_store_entry_update(sentry, is_fast);
230 sentry = metrics_store_add(the_store, rentry->type, rentry->name,
231 rentry->help);
232 metrics_store_entry_add_label(sentry,
233 metrics_format_label("type", "Exit"));
234 metrics_store_entry_update(sentry, is_exit);
236 sentry = metrics_store_add(the_store, rentry->type, rentry->name,
237 rentry->help);
238 metrics_store_entry_add_label(sentry,
239 metrics_format_label("type", "Authority"));
240 metrics_store_entry_update(sentry, is_authority);
242 sentry = metrics_store_add(the_store, rentry->type, rentry->name,
243 rentry->help);
244 metrics_store_entry_add_label(sentry,
245 metrics_format_label("type", "Stable"));
246 metrics_store_entry_update(sentry, is_stable);
248 sentry = metrics_store_add(the_store, rentry->type, rentry->name,
249 rentry->help);
250 metrics_store_entry_add_label(sentry,
251 metrics_format_label("type", "HSDir"));
252 metrics_store_entry_update(sentry, is_hs_dir);
254 sentry = metrics_store_add(the_store, rentry->type, rentry->name,
255 rentry->help);
256 metrics_store_entry_add_label(sentry,
257 metrics_format_label("type", "Running"));
258 metrics_store_entry_update(sentry, is_running);
260 sentry = metrics_store_add(the_store, rentry->type, rentry->name,
261 rentry->help);
262 metrics_store_entry_add_label(sentry,
263 metrics_format_label("type", "V2Dir"));
264 metrics_store_entry_update(sentry, is_v2_dir);
266 sentry = metrics_store_add(the_store, rentry->type, rentry->name,
267 rentry->help);
268 metrics_store_entry_add_label(sentry,
269 metrics_format_label("type", "Sybil"));
270 metrics_store_entry_update(sentry, is_sybil);
272 sentry = metrics_store_add(the_store, rentry->type, rentry->name,
273 rentry->help);
274 metrics_store_entry_add_label(sentry,
275 metrics_format_label("type", "Guard"));
276 metrics_store_entry_update(sentry, is_guard);
279 /** Fill function for the RELAY_METRICS_NUM_TRAFFIC metric. */
280 static void
281 fill_traffic_values(void)
283 const relay_metrics_entry_t *rentry =
284 &base_metrics[RELAY_METRICS_NUM_TRAFFIC];
285 metrics_store_entry_t *sentry =
286 metrics_store_add(the_store, rentry->type, rentry->name, rentry->help);
288 metrics_store_entry_add_label(sentry,
289 metrics_format_label("direction", "read"));
290 metrics_store_entry_update(sentry, get_bytes_read());
292 sentry = metrics_store_add(the_store, rentry->type, rentry->name,
293 rentry->help);
294 metrics_store_entry_add_label(sentry,
295 metrics_format_label("direction", "written"));
296 metrics_store_entry_update(sentry, get_bytes_written());
299 /** Fill function for the RELAY_METRICS_NUM_DOS metric. */
300 static void
301 fill_dos_values(void)
303 const relay_metrics_entry_t *rentry = &base_metrics[RELAY_METRICS_NUM_DOS];
304 metrics_store_entry_t *sentry =
305 metrics_store_add(the_store, rentry->type, rentry->name, rentry->help);
307 metrics_store_entry_add_label(sentry,
308 metrics_format_label("type", "circuit_rejected"));
309 metrics_store_entry_update(sentry, dos_get_num_cc_rejected());
311 sentry = metrics_store_add(the_store, rentry->type, rentry->name,
312 rentry->help);
313 metrics_store_entry_add_label(sentry,
314 metrics_format_label("type", "circuit_killed_max_cell"));
315 metrics_store_entry_update(sentry, stats_n_circ_max_cell_reached);
317 sentry = metrics_store_add(the_store, rentry->type, rentry->name,
318 rentry->help);
319 metrics_store_entry_add_label(sentry,
320 metrics_format_label("type", "marked_address"));
321 metrics_store_entry_update(sentry, dos_get_num_cc_marked_addr());
323 sentry = metrics_store_add(the_store, rentry->type, rentry->name,
324 rentry->help);
325 metrics_store_entry_add_label(sentry,
326 metrics_format_label("type", "marked_address_maxq"));
327 metrics_store_entry_update(sentry, dos_get_num_cc_marked_addr_maxq());
329 sentry = metrics_store_add(the_store, rentry->type, rentry->name,
330 rentry->help);
331 metrics_store_entry_add_label(sentry,
332 metrics_format_label("type", "conn_rejected"));
333 metrics_store_entry_update(sentry, dos_get_num_conn_addr_connect_rejected());
335 sentry = metrics_store_add(the_store, rentry->type, rentry->name,
336 rentry->help);
337 metrics_store_entry_add_label(sentry,
338 metrics_format_label("type", "concurrent_conn_rejected"));
339 metrics_store_entry_update(sentry, dos_get_num_conn_addr_rejected());
341 sentry = metrics_store_add(the_store, rentry->type, rentry->name,
342 rentry->help);
343 metrics_store_entry_add_label(sentry,
344 metrics_format_label("type", "single_hop_refused"));
345 metrics_store_entry_update(sentry, dos_get_num_single_hop_refused());
347 sentry = metrics_store_add(the_store, rentry->type, rentry->name,
348 rentry->help);
349 metrics_store_entry_add_label(sentry,
350 metrics_format_label("type", "introduce2_rejected"));
351 metrics_store_entry_update(sentry, hs_dos_get_intro2_rejected_count());
354 /** Fill function for the RELAY_METRICS_NUM_CC metric. */
355 static void
356 fill_cc_values(void)
358 const relay_metrics_entry_t *rentry = &base_metrics[RELAY_METRICS_NUM_CC];
359 metrics_store_entry_t *sentry =
360 metrics_store_add(the_store, rentry->type, rentry->name, rentry->help);
362 metrics_store_entry_add_label(sentry,
363 metrics_format_label("state", "starvation"));
364 metrics_store_entry_add_label(sentry,
365 metrics_format_label("action", "rtt_reset"));
366 metrics_store_entry_update(sentry, congestion_control_get_num_rtt_reset());
369 /** Helper: Fill in single stream metrics output. */
370 static void
371 fill_single_stream_value(metrics_store_entry_t *sentry, uint8_t cmd)
373 metrics_store_entry_add_label(sentry,
374 metrics_format_label("type", relay_command_to_string(cmd)));
375 metrics_store_entry_update(sentry, rep_hist_get_exit_stream_seen(cmd));
378 /** Fill function for the RELAY_METRICS_NUM_STREAMS metric. */
379 static void
380 fill_streams_values(void)
382 const relay_metrics_entry_t *rentry =
383 &base_metrics[RELAY_METRICS_NUM_STREAMS];
384 metrics_store_entry_t *sentry =
385 metrics_store_add(the_store, rentry->type, rentry->name, rentry->help);
386 fill_single_stream_value(sentry, RELAY_COMMAND_BEGIN);
388 sentry = metrics_store_add(the_store, rentry->type, rentry->name,
389 rentry->help);
390 fill_single_stream_value(sentry, RELAY_COMMAND_BEGIN_DIR);
392 sentry = metrics_store_add(the_store, rentry->type, rentry->name,
393 rentry->help);
394 fill_single_stream_value(sentry, RELAY_COMMAND_RESOLVE);
397 /** Helper: Fill in single connection metrics output. */
398 static void
399 fill_single_connection_value(metrics_store_entry_t *sentry,
400 unsigned int conn_type,
401 const char* direction,
402 const char* state,
403 uint64_t value)
405 metrics_store_entry_add_label(sentry,
406 metrics_format_label("type", conn_type_to_string(conn_type)));
407 metrics_store_entry_add_label(sentry,
408 metrics_format_label("direction", direction));
409 metrics_store_entry_add_label(sentry,
410 metrics_format_label("state", state));
411 metrics_store_entry_update(sentry, value);
414 /** Fill function for the RELAY_METRICS_NUM_CONNECTIONS metric. */
415 static void
416 fill_connections_values(void)
418 const relay_metrics_entry_t *rentry =
419 &base_metrics[RELAY_METRICS_NUM_CONNECTIONS];
421 for (unsigned int i = CONN_TYPE_MIN_; i < CONN_TYPE_MAX_ ; i++) {
422 /* Type is unused. Ugly but else we clobber the output. */
423 if (i == 10) {
424 continue;
426 metrics_store_entry_t *sentry =
427 metrics_store_add(the_store, rentry->type, rentry->name, rentry->help);
428 fill_single_connection_value(sentry, i, "initiated", "created",
429 rep_hist_get_conn_created(false, i));
431 sentry = metrics_store_add(the_store, rentry->type, rentry->name,
432 rentry->help);
433 fill_single_connection_value(sentry, i, "received", "created",
434 rep_hist_get_conn_created(true, i));
436 sentry = metrics_store_add(the_store, rentry->type, rentry->name,
437 rentry->help);
438 fill_single_connection_value(sentry, i, "initiated", "opened",
439 rep_hist_get_conn_opened(false, i));
441 sentry = metrics_store_add(the_store, rentry->type, rentry->name,
442 rentry->help);
443 fill_single_connection_value(sentry, i, "received", "opened",
444 rep_hist_get_conn_opened(true, i));
446 sentry = metrics_store_add(the_store, rentry->type, rentry->name,
447 rentry->help);
448 fill_single_connection_value(sentry, i, "received", "rejected",
449 rep_hist_get_conn_rejected(i));
453 /** Fill function for the RELAY_METRICS_NUM_DNS metrics. */
454 static void
455 fill_tcp_exhaustion_values(void)
457 metrics_store_entry_t *sentry;
458 const relay_metrics_entry_t *rentry =
459 &base_metrics[RELAY_METRICS_NUM_TCP_EXHAUSTION];
461 sentry = metrics_store_add(the_store, rentry->type, rentry->name,
462 rentry->help);
463 metrics_store_entry_update(sentry, rep_hist_get_n_tcp_exhaustion());
466 /* NOTE: Disable the record type label until libevent is fixed. */
467 #if 0
468 /** Helper array containing mapping for the name of the different DNS records
469 * and their corresponding libevent values. */
470 static struct dns_type {
471 const char *name;
472 uint8_t type;
473 } dns_types[] = {
474 { .name = "A", .type = DNS_IPv4_A },
475 { .name = "PTR", .type = DNS_PTR },
476 { .name = "AAAA", .type = DNS_IPv6_AAAA },
478 static const size_t num_dns_types = ARRAY_LENGTH(dns_types);
479 #endif
481 /** Fill function for the RELAY_METRICS_NUM_DNS_ERRORS metrics. */
482 static void
483 fill_dns_error_values(void)
485 metrics_store_entry_t *sentry;
486 const relay_metrics_entry_t *rentry =
487 &base_metrics[RELAY_METRICS_NUM_DNS_ERRORS];
489 /* Helper array to map libeven DNS errors to their names and so we can
490 * iterate over this array to add all metrics. */
491 static struct dns_error {
492 const char *name;
493 uint8_t key;
494 } errors[] = {
495 { .name = "success", .key = DNS_ERR_NONE },
496 { .name = "format", .key = DNS_ERR_FORMAT },
497 { .name = "serverfailed", .key = DNS_ERR_SERVERFAILED },
498 { .name = "notexist", .key = DNS_ERR_NOTEXIST },
499 { .name = "notimpl", .key = DNS_ERR_NOTIMPL },
500 { .name = "refused", .key = DNS_ERR_REFUSED },
501 { .name = "truncated", .key = DNS_ERR_TRUNCATED },
502 { .name = "unknown", .key = DNS_ERR_UNKNOWN },
503 { .name = "tor_timeout", .key = DNS_ERR_TIMEOUT },
504 { .name = "shutdown", .key = DNS_ERR_SHUTDOWN },
505 { .name = "cancel", .key = DNS_ERR_CANCEL },
506 { .name = "nodata", .key = DNS_ERR_NODATA },
508 static const size_t num_errors = ARRAY_LENGTH(errors);
510 /* NOTE: Disable the record type label until libevent is fixed. */
511 #if 0
512 for (size_t i = 0; i < num_dns_types; i++) {
513 /* Dup the label because metrics_format_label() returns a pointer to a
514 * string on the stack and we need that label for all metrics. */
515 char *record_label =
516 tor_strdup(metrics_format_label("record", dns_types[i].name));
518 for (size_t j = 0; j < num_errors; j++) {
519 sentry = metrics_store_add(the_store, rentry->type, rentry->name,
520 rentry->help);
521 metrics_store_entry_add_label(sentry, record_label);
522 metrics_store_entry_add_label(sentry,
523 metrics_format_label("reason", errors[j].name));
524 metrics_store_entry_update(sentry,
525 rep_hist_get_n_dns_error(dns_types[i].type, errors[j].key));
527 tor_free(record_label);
529 #endif
531 /* Put in the DNS errors, unfortunately not per-type for now. */
532 for (size_t j = 0; j < num_errors; j++) {
533 sentry = metrics_store_add(the_store, rentry->type, rentry->name,
534 rentry->help);
535 metrics_store_entry_add_label(sentry,
536 metrics_format_label("reason", errors[j].name));
537 metrics_store_entry_update(sentry,
538 rep_hist_get_n_dns_error(0, errors[j].key));
542 /** Fill function for the RELAY_METRICS_NUM_DNS metrics. */
543 static void
544 fill_dns_query_values(void)
546 metrics_store_entry_t *sentry;
547 const relay_metrics_entry_t *rentry =
548 &base_metrics[RELAY_METRICS_NUM_DNS];
550 /* NOTE: Disable the record type label until libevent is fixed (#40490). */
551 #if 0
552 for (size_t i = 0; i < num_dns_types; i++) {
553 /* Dup the label because metrics_format_label() returns a pointer to a
554 * string on the stack and we need that label for all metrics. */
555 char *record_label =
556 tor_strdup(metrics_format_label("record", dns_types[i].name));
557 sentry = metrics_store_add(the_store, rentry->type, rentry->name,
558 rentry->help);
559 metrics_store_entry_add_label(sentry, record_label);
560 metrics_store_entry_update(sentry,
561 rep_hist_get_n_dns_request(dns_types[i].type));
562 tor_free(record_label);
564 #endif
566 sentry = metrics_store_add(the_store, rentry->type, rentry->name,
567 rentry->help);
568 metrics_store_entry_update(sentry, rep_hist_get_n_dns_request(0));
571 /** Fill function for the RELAY_METRICS_NUM_GLOBAL_RW_LIMIT metrics. */
572 static void
573 fill_global_bw_limit_values(void)
575 metrics_store_entry_t *sentry;
576 const relay_metrics_entry_t *rentry =
577 &base_metrics[RELAY_METRICS_NUM_GLOBAL_RW_LIMIT];
579 sentry = metrics_store_add(the_store, rentry->type, rentry->name,
580 rentry->help);
581 metrics_store_entry_add_label(sentry,
582 metrics_format_label("side", "read"));
583 metrics_store_entry_update(sentry, rep_hist_get_n_read_limit_reached());
585 sentry = metrics_store_add(the_store, rentry->type, rentry->name,
586 rentry->help);
587 metrics_store_entry_add_label(sentry,
588 metrics_format_label("side", "write"));
589 metrics_store_entry_update(sentry, rep_hist_get_n_write_limit_reached());
592 /** Fill function for the RELAY_METRICS_NUM_SOCKETS metrics. */
593 static void
594 fill_socket_values(void)
596 metrics_store_entry_t *sentry;
597 const relay_metrics_entry_t *rentry =
598 &base_metrics[RELAY_METRICS_NUM_SOCKETS];
600 sentry = metrics_store_add(the_store, rentry->type, rentry->name,
601 rentry->help);
602 metrics_store_entry_add_label(sentry,
603 metrics_format_label("state", "opened"));
604 metrics_store_entry_update(sentry, get_n_open_sockets());
606 sentry = metrics_store_add(the_store, rentry->type, rentry->name,
607 rentry->help);
608 metrics_store_entry_update(sentry, get_max_sockets());
611 /** Fill function for the RELAY_METRICS_NUM_ONIONSKINS metrics. */
612 static void
613 fill_onionskins_values(void)
615 metrics_store_entry_t *sentry;
616 const relay_metrics_entry_t *rentry =
617 &base_metrics[RELAY_METRICS_NUM_ONIONSKINS];
619 for (uint16_t t = 0; t <= MAX_ONION_HANDSHAKE_TYPE; t++) {
620 /* Dup the label because metrics_format_label() returns a pointer to a
621 * string on the stack and we need that label for all metrics. */
622 char *type_label =
623 tor_strdup(metrics_format_label("type", handshake_type_to_str(t)));
624 sentry = metrics_store_add(the_store, rentry->type, rentry->name,
625 rentry->help);
626 metrics_store_entry_add_label(sentry, type_label);
627 metrics_store_entry_add_label(sentry,
628 metrics_format_label("action", "processed"));
629 metrics_store_entry_update(sentry,
630 rep_hist_get_circuit_n_handshake_assigned(t));
632 sentry = metrics_store_add(the_store, rentry->type, rentry->name,
633 rentry->help);
634 metrics_store_entry_add_label(sentry, type_label);
635 metrics_store_entry_add_label(sentry,
636 metrics_format_label("action", "dropped"));
637 metrics_store_entry_update(sentry,
638 rep_hist_get_circuit_n_handshake_dropped(t));
639 tor_free(type_label);
643 /** Fill function for the RELAY_METRICS_NUM_OOM_BYTES metrics. */
644 static void
645 fill_oom_values(void)
647 metrics_store_entry_t *sentry;
648 const relay_metrics_entry_t *rentry =
649 &base_metrics[RELAY_METRICS_NUM_OOM_BYTES];
651 sentry = metrics_store_add(the_store, rentry->type, rentry->name,
652 rentry->help);
653 metrics_store_entry_add_label(sentry,
654 metrics_format_label("subsys", "cell"));
655 metrics_store_entry_update(sentry, oom_stats_n_bytes_removed_cell);
657 sentry = metrics_store_add(the_store, rentry->type, rentry->name,
658 rentry->help);
659 metrics_store_entry_add_label(sentry,
660 metrics_format_label("subsys", "dns"));
661 metrics_store_entry_update(sentry, oom_stats_n_bytes_removed_dns);
663 sentry = metrics_store_add(the_store, rentry->type, rentry->name,
664 rentry->help);
665 metrics_store_entry_add_label(sentry,
666 metrics_format_label("subsys", "geoip"));
667 metrics_store_entry_update(sentry, oom_stats_n_bytes_removed_geoip);
669 sentry = metrics_store_add(the_store, rentry->type, rentry->name,
670 rentry->help);
671 metrics_store_entry_add_label(sentry,
672 metrics_format_label("subsys", "hsdir"));
673 metrics_store_entry_update(sentry, oom_stats_n_bytes_removed_hsdir);
676 /** Reset the global store and fill it with all the metrics from base_metrics
677 * and their associated values.
679 * To pull this off, every metrics has a "fill" function that is called and in
680 * charge of adding the metrics to the store, appropriate labels and finally
681 * updating the value to report. */
682 static void
683 fill_store(void)
685 /* Reset the current store, we are about to fill it with all the things. */
686 metrics_store_reset(the_store);
688 /* Call the fill function for each metrics. */
689 for (size_t i = 0; i < num_base_metrics; i++) {
690 if (BUG(!base_metrics[i].fill_fn)) {
691 continue;
693 base_metrics[i].fill_fn();
697 /** Return a list of all the relay metrics stores. This is the
698 * function attached to the .get_metrics() member of the subsys_t. */
699 const smartlist_t *
700 relay_metrics_get_stores(void)
702 /* We can't have the caller to free the returned list so keep it static,
703 * simply update it. */
704 static smartlist_t *stores_list = NULL;
706 /* We dynamically fill the store with all the metrics upon a request. The
707 * reason for this is because the exposed metrics of a relay are often
708 * internal counters in the fast path and thus we fetch the value when a
709 * metrics port request arrives instead of keeping a local metrics store of
710 * those values. */
711 fill_store();
713 if (!stores_list) {
714 stores_list = smartlist_new();
715 smartlist_add(stores_list, the_store);
718 return stores_list;
721 /** Initialize the relay metrics. */
722 void
723 relay_metrics_init(void)
725 if (BUG(the_store)) {
726 return;
728 the_store = metrics_store_new();
731 /** Free the relay metrics. */
732 void
733 relay_metrics_free(void)
735 if (!the_store) {
736 return;
738 /* NULL is set with this call. */
739 metrics_store_free(the_store);