mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-27 13:53:31 +01:00
metrics: Add support for histograms.
This will enable us to add e.g. circuit build metrics (#40717). Signed-off-by: Gabriela Moldovan <gabi@torproject.org>
This commit is contained in:
parent
3fa08dc9a7
commit
d1264d11c3
3
changes/ticket40757
Normal file
3
changes/ticket40757
Normal file
@ -0,0 +1,3 @@
|
||||
o Minor features (metrics):
|
||||
- Add support for histograms.
|
||||
Part of ticket 40757.
|
@ -76,7 +76,8 @@ add_metric_with_labels(hs_service_t *service, hs_metrics_key_t metric,
|
||||
if (!num_error_reasons) {
|
||||
metrics_store_entry_t *entry = metrics_store_add(
|
||||
store, base_metrics[metric].type, base_metrics[metric].name,
|
||||
base_metrics[metric].help);
|
||||
base_metrics[metric].help, base_metrics[metric].bucket_count,
|
||||
base_metrics[metric].buckets);
|
||||
|
||||
metrics_store_entry_add_label(entry,
|
||||
metrics_format_label("onion", service->onion_address));
|
||||
@ -97,7 +98,9 @@ add_metric_with_labels(hs_service_t *service, hs_metrics_key_t metric,
|
||||
metrics_store_entry_t *entry =
|
||||
metrics_store_add(store, base_metrics[metric].type,
|
||||
base_metrics[metric].name,
|
||||
base_metrics[metric].help);
|
||||
base_metrics[metric].help,
|
||||
base_metrics[metric].bucket_count,
|
||||
base_metrics[metric].buckets);
|
||||
/* Add labels to the entry. */
|
||||
metrics_store_entry_add_label(entry,
|
||||
metrics_format_label("onion", service->onion_address));
|
||||
|
@ -70,6 +70,10 @@ typedef struct hs_metrics_entry_t {
|
||||
const char *name;
|
||||
/* Metrics output help comment. */
|
||||
const char *help;
|
||||
/* The buckets, if the metric type is METRICS_TYPE_HISTOGRAM. */
|
||||
const int64_t *buckets;
|
||||
/* The number of buckets, if the metric type is METRICS_TYPE_HISTOGRAM. */
|
||||
size_t bucket_count;
|
||||
/* True iff a port label should be added to the metrics entry. */
|
||||
bool port_as_label;
|
||||
} hs_metrics_entry_t;
|
||||
|
@ -222,8 +222,8 @@ fill_circuits_values(void)
|
||||
{
|
||||
const relay_metrics_entry_t *rentry =
|
||||
&base_metrics[RELAY_METRICS_NUM_CIRCUITS];
|
||||
metrics_store_entry_t *sentry =
|
||||
metrics_store_add(the_store, rentry->type, rentry->name, rentry->help);
|
||||
metrics_store_entry_t *sentry = metrics_store_add(
|
||||
the_store, rentry->type, rentry->name, rentry->help, 0, NULL);
|
||||
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("state", "opened"));
|
||||
@ -255,57 +255,57 @@ fill_relay_flags(void)
|
||||
|
||||
const relay_metrics_entry_t *rentry =
|
||||
&base_metrics[RELAY_METRICS_RELAY_FLAGS];
|
||||
metrics_store_entry_t *sentry =
|
||||
metrics_store_add(the_store, rentry->type, rentry->name, rentry->help);
|
||||
metrics_store_entry_t *sentry = metrics_store_add(
|
||||
the_store, rentry->type, rentry->name, rentry->help, 0, NULL);
|
||||
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("type", "Fast"));
|
||||
metrics_store_entry_update(sentry, is_fast);
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("type", "Exit"));
|
||||
metrics_store_entry_update(sentry, is_exit);
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("type", "Authority"));
|
||||
metrics_store_entry_update(sentry, is_authority);
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("type", "Stable"));
|
||||
metrics_store_entry_update(sentry, is_stable);
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("type", "HSDir"));
|
||||
metrics_store_entry_update(sentry, is_hs_dir);
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("type", "Running"));
|
||||
metrics_store_entry_update(sentry, is_running);
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("type", "V2Dir"));
|
||||
metrics_store_entry_update(sentry, is_v2_dir);
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("type", "Sybil"));
|
||||
metrics_store_entry_update(sentry, is_sybil);
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("type", "Guard"));
|
||||
metrics_store_entry_update(sentry, is_guard);
|
||||
@ -317,15 +317,15 @@ fill_traffic_values(void)
|
||||
{
|
||||
const relay_metrics_entry_t *rentry =
|
||||
&base_metrics[RELAY_METRICS_NUM_TRAFFIC];
|
||||
metrics_store_entry_t *sentry =
|
||||
metrics_store_add(the_store, rentry->type, rentry->name, rentry->help);
|
||||
metrics_store_entry_t *sentry = metrics_store_add(
|
||||
the_store, rentry->type, rentry->name, rentry->help, 0, NULL);
|
||||
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("direction", "read"));
|
||||
metrics_store_entry_update(sentry, get_bytes_read());
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("direction", "written"));
|
||||
metrics_store_entry_update(sentry, get_bytes_written());
|
||||
@ -336,57 +336,57 @@ static void
|
||||
fill_dos_values(void)
|
||||
{
|
||||
const relay_metrics_entry_t *rentry = &base_metrics[RELAY_METRICS_NUM_DOS];
|
||||
metrics_store_entry_t *sentry =
|
||||
metrics_store_add(the_store, rentry->type, rentry->name, rentry->help);
|
||||
metrics_store_entry_t *sentry = metrics_store_add(
|
||||
the_store, rentry->type, rentry->name, rentry->help, 0, NULL);
|
||||
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("type", "circuit_rejected"));
|
||||
metrics_store_entry_update(sentry, dos_get_num_cc_rejected());
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("type", "circuit_killed_max_cell"));
|
||||
metrics_store_entry_update(sentry, stats_n_circ_max_cell_reached);
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("type", "circuit_killed_max_cell_outq"));
|
||||
metrics_store_entry_update(sentry, stats_n_circ_max_cell_outq_reached);
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("type", "marked_address"));
|
||||
metrics_store_entry_update(sentry, dos_get_num_cc_marked_addr());
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("type", "marked_address_maxq"));
|
||||
metrics_store_entry_update(sentry, dos_get_num_cc_marked_addr_maxq());
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("type", "conn_rejected"));
|
||||
metrics_store_entry_update(sentry, dos_get_num_conn_addr_connect_rejected());
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("type", "concurrent_conn_rejected"));
|
||||
metrics_store_entry_update(sentry, dos_get_num_conn_addr_rejected());
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("type", "single_hop_refused"));
|
||||
metrics_store_entry_update(sentry, dos_get_num_single_hop_refused());
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("type", "introduce2_rejected"));
|
||||
metrics_store_entry_update(sentry, hs_dos_get_intro2_rejected_count());
|
||||
@ -399,8 +399,8 @@ fill_cc_counters_values(void)
|
||||
const relay_metrics_entry_t *rentry =
|
||||
&base_metrics[RELAY_METRICS_CC_COUNTERS];
|
||||
|
||||
metrics_store_entry_t *sentry =
|
||||
metrics_store_add(the_store, rentry->type, rentry->name, rentry->help);
|
||||
metrics_store_entry_t *sentry = metrics_store_add(
|
||||
the_store, rentry->type, rentry->name, rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("state", "starvation"));
|
||||
metrics_store_entry_add_label(sentry,
|
||||
@ -408,7 +408,7 @@ fill_cc_counters_values(void)
|
||||
metrics_store_entry_update(sentry, congestion_control_get_num_rtt_reset());
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("state", "clock_stalls"));
|
||||
metrics_store_entry_add_label(sentry,
|
||||
@ -417,7 +417,7 @@ fill_cc_counters_values(void)
|
||||
congestion_control_get_num_clock_stalls());
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("state", "flow_control"));
|
||||
metrics_store_entry_add_label(sentry,
|
||||
@ -426,7 +426,7 @@ fill_cc_counters_values(void)
|
||||
cc_stats_flow_num_xoff_sent);
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("state", "flow_control"));
|
||||
metrics_store_entry_add_label(sentry,
|
||||
@ -435,7 +435,7 @@ fill_cc_counters_values(void)
|
||||
cc_stats_flow_num_xon_sent);
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("state", "cc_limits"));
|
||||
metrics_store_entry_add_label(sentry,
|
||||
@ -443,7 +443,7 @@ fill_cc_counters_values(void)
|
||||
metrics_store_entry_update(sentry, cc_stats_vegas_above_delta);
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("state", "cc_limits"));
|
||||
metrics_store_entry_add_label(sentry,
|
||||
@ -451,7 +451,7 @@ fill_cc_counters_values(void)
|
||||
metrics_store_entry_update(sentry, cc_stats_vegas_above_ss_cwnd_max);
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("state", "cc_limits"));
|
||||
metrics_store_entry_add_label(sentry,
|
||||
@ -459,7 +459,7 @@ fill_cc_counters_values(void)
|
||||
metrics_store_entry_update(sentry, cc_stats_vegas_below_ss_inc_floor);
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("state", "cc_circuits"));
|
||||
metrics_store_entry_add_label(sentry,
|
||||
@ -467,7 +467,7 @@ fill_cc_counters_values(void)
|
||||
metrics_store_entry_update(sentry, cc_stats_circs_created);
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("state", "cc_circuits"));
|
||||
metrics_store_entry_add_label(sentry,
|
||||
@ -475,7 +475,7 @@ fill_cc_counters_values(void)
|
||||
metrics_store_entry_update(sentry, cc_stats_circs_closed);
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("state", "cc_circuits"));
|
||||
metrics_store_entry_add_label(sentry,
|
||||
@ -490,8 +490,8 @@ fill_cc_gauges_values(void)
|
||||
const relay_metrics_entry_t *rentry =
|
||||
&base_metrics[RELAY_METRICS_CC_GAUGES];
|
||||
|
||||
metrics_store_entry_t *sentry =
|
||||
metrics_store_add(the_store, rentry->type, rentry->name, rentry->help);
|
||||
metrics_store_entry_t *sentry = metrics_store_add(
|
||||
the_store, rentry->type, rentry->name, rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("state", "slow_start_exit"));
|
||||
metrics_store_entry_add_label(sentry,
|
||||
@ -500,7 +500,7 @@ fill_cc_gauges_values(void)
|
||||
tor_llround(cc_stats_vegas_exit_ss_cwnd_ma));
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("state", "slow_start_exit"));
|
||||
metrics_store_entry_add_label(sentry,
|
||||
@ -509,7 +509,7 @@ fill_cc_gauges_values(void)
|
||||
tor_llround(cc_stats_vegas_exit_ss_bdp_ma));
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("state", "slow_start_exit"));
|
||||
metrics_store_entry_add_label(sentry,
|
||||
@ -518,7 +518,7 @@ fill_cc_gauges_values(void)
|
||||
tor_llround(cc_stats_vegas_exit_ss_inc_ma));
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("state", "on_circ_close"));
|
||||
metrics_store_entry_add_label(sentry,
|
||||
@ -527,7 +527,7 @@ fill_cc_gauges_values(void)
|
||||
tor_llround(cc_stats_circ_close_cwnd_ma));
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("state", "on_circ_close"));
|
||||
metrics_store_entry_add_label(sentry,
|
||||
@ -536,7 +536,7 @@ fill_cc_gauges_values(void)
|
||||
tor_llround(cc_stats_circ_close_ss_cwnd_ma));
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("state", "buffers"));
|
||||
metrics_store_entry_add_label(sentry,
|
||||
@ -545,7 +545,7 @@ fill_cc_gauges_values(void)
|
||||
tor_llround(cc_stats_flow_xon_outbuf_ma));
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("state", "buffers"));
|
||||
metrics_store_entry_add_label(sentry,
|
||||
@ -554,7 +554,7 @@ fill_cc_gauges_values(void)
|
||||
tor_llround(cc_stats_flow_xoff_outbuf_ma));
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("state", "cc_backoff"));
|
||||
metrics_store_entry_add_label(sentry,
|
||||
@ -563,7 +563,7 @@ fill_cc_gauges_values(void)
|
||||
tor_llround(cc_stats_vegas_csig_blocked_ma));
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("state", "cc_backoff"));
|
||||
metrics_store_entry_add_label(sentry,
|
||||
@ -572,7 +572,7 @@ fill_cc_gauges_values(void)
|
||||
tor_llround(cc_stats_vegas_gamma_drop_ma));
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("state", "cc_backoff"));
|
||||
metrics_store_entry_add_label(sentry,
|
||||
@ -581,7 +581,7 @@ fill_cc_gauges_values(void)
|
||||
tor_llround(cc_stats_vegas_delta_drop_ma));
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("state", "cc_backoff"));
|
||||
metrics_store_entry_add_label(sentry,
|
||||
@ -590,7 +590,7 @@ fill_cc_gauges_values(void)
|
||||
tor_llround(cc_stats_vegas_ss_csig_blocked_ma));
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("state", "cc_cwnd_update"));
|
||||
metrics_store_entry_add_label(sentry,
|
||||
@ -599,7 +599,7 @@ fill_cc_gauges_values(void)
|
||||
tor_llround(cc_stats_vegas_csig_alpha_ma));
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("state", "cc_cwnd_update"));
|
||||
metrics_store_entry_add_label(sentry,
|
||||
@ -608,7 +608,7 @@ fill_cc_gauges_values(void)
|
||||
tor_llround(cc_stats_vegas_csig_beta_ma));
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("state", "cc_cwnd_update"));
|
||||
metrics_store_entry_add_label(sentry,
|
||||
@ -617,7 +617,7 @@ fill_cc_gauges_values(void)
|
||||
tor_llround(cc_stats_vegas_csig_delta_ma));
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("state", "cc_estimates"));
|
||||
metrics_store_entry_add_label(sentry,
|
||||
@ -626,7 +626,7 @@ fill_cc_gauges_values(void)
|
||||
tor_llround(cc_stats_vegas_ss_queue_ma));
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("state", "cc_estimates"));
|
||||
metrics_store_entry_add_label(sentry,
|
||||
@ -635,7 +635,7 @@ fill_cc_gauges_values(void)
|
||||
tor_llround(cc_stats_vegas_queue_ma));
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("state", "cc_estimates"));
|
||||
metrics_store_entry_add_label(sentry,
|
||||
@ -659,16 +659,16 @@ fill_streams_values(void)
|
||||
{
|
||||
const relay_metrics_entry_t *rentry =
|
||||
&base_metrics[RELAY_METRICS_NUM_STREAMS];
|
||||
metrics_store_entry_t *sentry =
|
||||
metrics_store_add(the_store, rentry->type, rentry->name, rentry->help);
|
||||
metrics_store_entry_t *sentry = metrics_store_add(
|
||||
the_store, rentry->type, rentry->name, rentry->help, 0, NULL);
|
||||
fill_single_stream_value(sentry, RELAY_COMMAND_BEGIN);
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
fill_single_stream_value(sentry, RELAY_COMMAND_BEGIN_DIR);
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
fill_single_stream_value(sentry, RELAY_COMMAND_RESOLVE);
|
||||
}
|
||||
|
||||
@ -704,31 +704,31 @@ fill_conn_counter_values(void)
|
||||
if (i == 10) {
|
||||
continue;
|
||||
}
|
||||
metrics_store_entry_t *sentry =
|
||||
metrics_store_add(the_store, rentry->type, rentry->name, rentry->help);
|
||||
metrics_store_entry_t *sentry = metrics_store_add(
|
||||
the_store, rentry->type, rentry->name, rentry->help, 0, NULL);
|
||||
fill_single_connection_value(sentry, i, "initiated", "created", AF_INET,
|
||||
rep_hist_get_conn_created(false, i, AF_INET));
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
fill_single_connection_value(sentry, i, "initiated", "created", AF_INET6,
|
||||
rep_hist_get_conn_created(false, i,
|
||||
AF_INET6));
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
fill_single_connection_value(sentry, i, "received", "created", AF_INET,
|
||||
rep_hist_get_conn_created(true, i, AF_INET));
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
fill_single_connection_value(sentry, i, "received", "created", AF_INET6,
|
||||
rep_hist_get_conn_created(true, i, AF_INET6));
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
fill_single_connection_value(sentry, i, "received", "rejected", AF_INET,
|
||||
rep_hist_get_conn_rejected(i, AF_INET));
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
fill_single_connection_value(sentry, i, "received", "rejected", AF_INET6,
|
||||
rep_hist_get_conn_rejected(i, AF_INET6));
|
||||
|
||||
@ -748,21 +748,21 @@ fill_conn_gauge_values(void)
|
||||
if (i == 10) {
|
||||
continue;
|
||||
}
|
||||
metrics_store_entry_t *sentry =
|
||||
metrics_store_add(the_store, rentry->type, rentry->name, rentry->help);
|
||||
metrics_store_entry_t *sentry = metrics_store_add(
|
||||
the_store, rentry->type, rentry->name, rentry->help, 0, NULL);
|
||||
fill_single_connection_value(sentry, i, "initiated", "opened", AF_INET,
|
||||
rep_hist_get_conn_opened(false, i, AF_INET));
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
fill_single_connection_value(sentry, i, "initiated", "opened", AF_INET6,
|
||||
rep_hist_get_conn_opened(false, i, AF_INET6));
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
fill_single_connection_value(sentry, i, "received", "opened", AF_INET,
|
||||
rep_hist_get_conn_opened(true, i, AF_INET));
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
fill_single_connection_value(sentry, i, "received", "opened", AF_INET6,
|
||||
rep_hist_get_conn_opened(true, i, AF_INET6));
|
||||
}
|
||||
@ -777,7 +777,7 @@ fill_tcp_exhaustion_values(void)
|
||||
&base_metrics[RELAY_METRICS_NUM_TCP_EXHAUSTION];
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_update(sentry, rep_hist_get_n_tcp_exhaustion());
|
||||
}
|
||||
|
||||
@ -835,7 +835,7 @@ fill_dns_error_values(void)
|
||||
|
||||
for (size_t j = 0; j < num_errors; j++) {
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry, record_label);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("reason", errors[j].name));
|
||||
@ -849,7 +849,7 @@ fill_dns_error_values(void)
|
||||
/* Put in the DNS errors, unfortunately not per-type for now. */
|
||||
for (size_t j = 0; j < num_errors; j++) {
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("reason", errors[j].name));
|
||||
metrics_store_entry_update(sentry,
|
||||
@ -873,7 +873,7 @@ fill_dns_query_values(void)
|
||||
char *record_label =
|
||||
tor_strdup(metrics_format_label("record", dns_types[i].name));
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry, record_label);
|
||||
metrics_store_entry_update(sentry,
|
||||
rep_hist_get_n_dns_request(dns_types[i].type));
|
||||
@ -882,7 +882,7 @@ fill_dns_query_values(void)
|
||||
#endif
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_update(sentry, rep_hist_get_n_dns_request(0));
|
||||
}
|
||||
|
||||
@ -895,13 +895,13 @@ fill_global_bw_limit_values(void)
|
||||
&base_metrics[RELAY_METRICS_NUM_GLOBAL_RW_LIMIT];
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("side", "read"));
|
||||
metrics_store_entry_update(sentry, rep_hist_get_n_read_limit_reached());
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("side", "write"));
|
||||
metrics_store_entry_update(sentry, rep_hist_get_n_write_limit_reached());
|
||||
@ -916,13 +916,13 @@ fill_socket_values(void)
|
||||
&base_metrics[RELAY_METRICS_NUM_SOCKETS];
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("state", "opened"));
|
||||
metrics_store_entry_update(sentry, get_n_open_sockets());
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_update(sentry, get_max_sockets());
|
||||
}
|
||||
|
||||
@ -940,7 +940,7 @@ fill_onionskins_values(void)
|
||||
char *type_label =
|
||||
tor_strdup(metrics_format_label("type", handshake_type_to_str(t)));
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry, type_label);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("action", "processed"));
|
||||
@ -948,7 +948,7 @@ fill_onionskins_values(void)
|
||||
rep_hist_get_circuit_n_handshake_assigned(t));
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry, type_label);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("action", "dropped"));
|
||||
@ -967,25 +967,25 @@ fill_oom_values(void)
|
||||
&base_metrics[RELAY_METRICS_NUM_OOM_BYTES];
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("subsys", "cell"));
|
||||
metrics_store_entry_update(sentry, oom_stats_n_bytes_removed_cell);
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("subsys", "dns"));
|
||||
metrics_store_entry_update(sentry, oom_stats_n_bytes_removed_dns);
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("subsys", "geoip"));
|
||||
metrics_store_entry_update(sentry, oom_stats_n_bytes_removed_geoip);
|
||||
|
||||
sentry = metrics_store_add(the_store, rentry->type, rentry->name,
|
||||
rentry->help);
|
||||
rentry->help, 0, NULL);
|
||||
metrics_store_entry_add_label(sentry,
|
||||
metrics_format_label("subsys", "hsdir"));
|
||||
metrics_store_entry_update(sentry, oom_stats_n_bytes_removed_hsdir);
|
||||
|
@ -24,6 +24,8 @@ metrics_type_to_str(const metrics_type_t type)
|
||||
return "counter";
|
||||
case METRICS_TYPE_GAUGE:
|
||||
return "gauge";
|
||||
case METRICS_TYPE_HISTOGRAM:
|
||||
return "histogram";
|
||||
default:
|
||||
tor_assert_unreached();
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
#define TOR_LIB_METRICS_METRICS_COMMON_H
|
||||
|
||||
#include "lib/cc/torint.h"
|
||||
#include "lib/container/smartlist.h"
|
||||
|
||||
/** Helper macro that must be used to construct the right namespaced metrics
|
||||
* name. A name is a string so stringify the result. */
|
||||
@ -28,8 +29,18 @@ typedef enum {
|
||||
METRICS_TYPE_COUNTER,
|
||||
/* Can go up or down. */
|
||||
METRICS_TYPE_GAUGE,
|
||||
/* Cumulative counters for multiple observation buckets. */
|
||||
METRICS_TYPE_HISTOGRAM,
|
||||
} metrics_type_t;
|
||||
|
||||
typedef struct metrics_histogram_bucket_t {
|
||||
/* The value of the counter of this bucket. */
|
||||
uint64_t value;
|
||||
/* Technically, this should be a floating point value, but in practice, we
|
||||
* can make do with integer buckets. */
|
||||
int64_t bucket;
|
||||
} metrics_histogram_bucket_t;
|
||||
|
||||
/** Metric counter object (METRICS_TYPE_COUNTER). */
|
||||
typedef struct metrics_counter_t {
|
||||
uint64_t value;
|
||||
@ -40,6 +51,18 @@ typedef struct metrics_gauge_t {
|
||||
int64_t value;
|
||||
} metrics_gauge_t;
|
||||
|
||||
/** Metric histogram object (METRICS_TYPE_HISTOGRAM). */
|
||||
typedef struct metrics_histogram_t {
|
||||
/* The observation buckets. */
|
||||
metrics_histogram_bucket_t *buckets;
|
||||
/* The number of observation buckets. */
|
||||
size_t bucket_count;
|
||||
/* The sum of all observations */
|
||||
int64_t sum;
|
||||
/* The total number of observations */
|
||||
uint64_t count;
|
||||
} metrics_histogram_t;
|
||||
|
||||
const char *metrics_type_to_str(const metrics_type_t type);
|
||||
|
||||
/* Helpers. */
|
||||
|
@ -107,7 +107,9 @@ metrics_store_get_all(const metrics_store_t *store, const char *name)
|
||||
* 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)
|
||||
const char *name, const char *help, size_t bucket_count,
|
||||
const int64_t *buckets)
|
||||
|
||||
{
|
||||
smartlist_t *entries;
|
||||
metrics_store_entry_t *entry;
|
||||
@ -120,7 +122,7 @@ metrics_store_add(metrics_store_t *store, metrics_type_t type,
|
||||
entries = smartlist_new();
|
||||
strmap_set(store->entries, name, entries);
|
||||
}
|
||||
entry = metrics_store_entry_new(type, name, help);
|
||||
entry = metrics_store_entry_new(type, name, help, bucket_count, buckets);
|
||||
smartlist_add(entries, entry);
|
||||
|
||||
return entry;
|
||||
|
@ -26,8 +26,10 @@ metrics_store_t *metrics_store_new(void);
|
||||
|
||||
/* Modifiers. */
|
||||
metrics_store_entry_t *metrics_store_add(metrics_store_t *store,
|
||||
metrics_type_t type,
|
||||
const char *name, const char *help);
|
||||
metrics_type_t type, const char *name,
|
||||
const char *help, size_t bucket_count,
|
||||
const int64_t *buckets);
|
||||
|
||||
void metrics_store_reset(metrics_store_t *store);
|
||||
|
||||
/* Accessors. */
|
||||
|
@ -6,6 +6,7 @@
|
||||
* @brief Metrics store entry which contains the gathered data.
|
||||
**/
|
||||
|
||||
#include "metrics_common.h"
|
||||
#define METRICS_STORE_ENTRY_PRIVATE
|
||||
|
||||
#include <string.h>
|
||||
@ -22,10 +23,11 @@
|
||||
* Public API.
|
||||
*/
|
||||
|
||||
/** Return newly allocated store entry of type COUNTER. */
|
||||
/** Return newly allocated store entry of the specified type. */
|
||||
metrics_store_entry_t *
|
||||
metrics_store_entry_new(const metrics_type_t type, const char *name,
|
||||
const char *help)
|
||||
const char *help, size_t bucket_count,
|
||||
const int64_t *buckets)
|
||||
{
|
||||
metrics_store_entry_t *entry = tor_malloc_zero(sizeof(*entry));
|
||||
|
||||
@ -38,6 +40,18 @@ metrics_store_entry_new(const metrics_type_t type, const char *name,
|
||||
entry->help = tor_strdup(help);
|
||||
}
|
||||
|
||||
if (type == METRICS_TYPE_HISTOGRAM && bucket_count > 0) {
|
||||
tor_assert(buckets);
|
||||
|
||||
entry->u.histogram.bucket_count = bucket_count;
|
||||
entry->u.histogram.buckets =
|
||||
tor_malloc_zero(sizeof(metrics_histogram_bucket_t) * bucket_count);
|
||||
|
||||
for (size_t i = 0; i < bucket_count; ++i) {
|
||||
entry->u.histogram.buckets[i].bucket = buckets[i];
|
||||
}
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
@ -52,6 +66,11 @@ metrics_store_entry_free_(metrics_store_entry_t *entry)
|
||||
smartlist_free(entry->labels);
|
||||
tor_free(entry->name);
|
||||
tor_free(entry->help);
|
||||
|
||||
if (entry->type == METRICS_TYPE_HISTOGRAM) {
|
||||
tor_free(entry->u.histogram.buckets);
|
||||
}
|
||||
|
||||
tor_free(entry);
|
||||
}
|
||||
|
||||
@ -61,6 +80,11 @@ metrics_store_entry_update(metrics_store_entry_t *entry, const int64_t value)
|
||||
{
|
||||
tor_assert(entry);
|
||||
|
||||
/* Histogram values are updated using metrics_store_hist_entry_update */
|
||||
if (BUG(entry->type == METRICS_TYPE_HISTOGRAM)) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (entry->type) {
|
||||
case METRICS_TYPE_COUNTER:
|
||||
/* Counter can ONLY be positive. */
|
||||
@ -73,6 +97,43 @@ metrics_store_entry_update(metrics_store_entry_t *entry, const int64_t value)
|
||||
/* Gauge can increment or decrement. And can be positive or negative. */
|
||||
entry->u.gauge.value += value;
|
||||
break;
|
||||
case METRICS_TYPE_HISTOGRAM:
|
||||
tor_assert_unreached();
|
||||
}
|
||||
}
|
||||
|
||||
/** Update a store entry with value for the specified observation obs.
|
||||
*
|
||||
* Note: entry **must** be a histogram. */
|
||||
void
|
||||
metrics_store_hist_entry_update(metrics_store_entry_t *entry,
|
||||
const int64_t value, const int64_t obs)
|
||||
{
|
||||
if (BUG(entry->type != METRICS_TYPE_HISTOGRAM)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Counter can ONLY be positive for histograms. */
|
||||
if (BUG(value < 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* If we're about to overflow or underflow the sum, reset all counters back
|
||||
* to 0 before recording the observation. */
|
||||
if (PREDICT_UNLIKELY(
|
||||
(obs > 0 && entry->u.histogram.sum > INT64_MAX - obs) ||
|
||||
(obs < 0 && entry->u.histogram.sum < INT64_MIN - obs))) {
|
||||
metrics_store_entry_reset(entry);
|
||||
}
|
||||
|
||||
entry->u.histogram.count += value;
|
||||
entry->u.histogram.sum += obs;
|
||||
|
||||
for (size_t i = 0; i < entry->u.histogram.bucket_count; ++i) {
|
||||
metrics_histogram_bucket_t *hb = &entry->u.histogram.buckets[i];
|
||||
if (obs <= hb->bucket) {
|
||||
hb->value += value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -81,8 +142,22 @@ void
|
||||
metrics_store_entry_reset(metrics_store_entry_t *entry)
|
||||
{
|
||||
tor_assert(entry);
|
||||
/* Everything back to 0. */
|
||||
memset(&entry->u, 0, sizeof(entry->u));
|
||||
|
||||
switch (entry->type) {
|
||||
case METRICS_TYPE_COUNTER: FALLTHROUGH;
|
||||
case METRICS_TYPE_GAUGE:
|
||||
/* Everything back to 0. */
|
||||
memset(&entry->u, 0, sizeof(entry->u));
|
||||
break;
|
||||
case METRICS_TYPE_HISTOGRAM:
|
||||
for (size_t i = 0; i < entry->u.histogram.bucket_count; ++i) {
|
||||
metrics_histogram_bucket_t *hb = &entry->u.histogram.buckets[i];
|
||||
hb->value = 0;
|
||||
}
|
||||
entry->u.histogram.sum = 0;
|
||||
entry->u.histogram.count = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** Return store entry value. */
|
||||
@ -91,6 +166,11 @@ metrics_store_entry_get_value(const metrics_store_entry_t *entry)
|
||||
{
|
||||
tor_assert(entry);
|
||||
|
||||
/* Histogram values are accessed using metrics_store_hist_entry_get_value. */
|
||||
if (BUG(entry->type == METRICS_TYPE_HISTOGRAM)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (entry->type) {
|
||||
case METRICS_TYPE_COUNTER:
|
||||
if (entry->u.counter.value > INT64_MAX) {
|
||||
@ -99,6 +179,9 @@ metrics_store_entry_get_value(const metrics_store_entry_t *entry)
|
||||
return entry->u.counter.value;
|
||||
case METRICS_TYPE_GAUGE:
|
||||
return entry->u.gauge.value;
|
||||
case METRICS_TYPE_HISTOGRAM:
|
||||
tor_assert_unreached();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// LCOV_EXCL_START
|
||||
@ -106,6 +189,35 @@ metrics_store_entry_get_value(const metrics_store_entry_t *entry)
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
/** Return store entry value for the specified bucket.
|
||||
*
|
||||
* Note: entry **must** be a histogram. */
|
||||
uint64_t
|
||||
metrics_store_hist_entry_get_value(const metrics_store_entry_t *entry,
|
||||
const int64_t bucket)
|
||||
{
|
||||
tor_assert(entry);
|
||||
|
||||
if (BUG(entry->type != METRICS_TYPE_HISTOGRAM)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i <= entry->u.histogram.bucket_count; ++i) {
|
||||
metrics_histogram_bucket_t hb = entry->u.histogram.buckets[i];
|
||||
if (bucket == hb.bucket) {
|
||||
if (hb.value > INT64_MAX) {
|
||||
return INT64_MAX;
|
||||
} else {
|
||||
return hb.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tor_assertf_nonfatal(false, "attempted to get the value of non-existent "
|
||||
"bucket %" PRId64, bucket);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Add a label into the given entry.*/
|
||||
void
|
||||
metrics_store_entry_add_label(metrics_store_entry_t *entry,
|
||||
@ -147,3 +259,40 @@ metrics_store_find_entry_with_label(const smartlist_t *entries,
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Return true iff the specified entry is a histogram. */
|
||||
bool
|
||||
metrics_store_entry_is_histogram(const metrics_store_entry_t *entry)
|
||||
{
|
||||
if (entry->type == METRICS_TYPE_HISTOGRAM) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Return the total number of observations for the specified histogram. */
|
||||
uint64_t
|
||||
metrics_store_hist_entry_get_count(const metrics_store_entry_t *entry)
|
||||
{
|
||||
tor_assert(entry);
|
||||
|
||||
if (BUG(entry->type != METRICS_TYPE_HISTOGRAM)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return entry->u.histogram.count;
|
||||
}
|
||||
|
||||
/** Return the sum of all observations for the specified histogram. */
|
||||
int64_t
|
||||
metrics_store_hist_entry_get_sum(const metrics_store_entry_t *entry)
|
||||
{
|
||||
tor_assert(entry);
|
||||
|
||||
if (BUG(entry->type != METRICS_TYPE_HISTOGRAM)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return entry->u.histogram.sum;
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ struct metrics_store_entry_t {
|
||||
union {
|
||||
metrics_counter_t counter;
|
||||
metrics_gauge_t gauge;
|
||||
metrics_histogram_t histogram;
|
||||
} u;
|
||||
};
|
||||
|
||||
@ -48,7 +49,9 @@ typedef struct metrics_store_entry_t metrics_store_entry_t;
|
||||
/* Allocators. */
|
||||
metrics_store_entry_t *metrics_store_entry_new(const metrics_type_t type,
|
||||
const char *name,
|
||||
const char *help);
|
||||
const char *help,
|
||||
size_t bucket_count,
|
||||
const int64_t *buckets);
|
||||
|
||||
void metrics_store_entry_free_(metrics_store_entry_t *entry);
|
||||
#define metrics_store_entry_free(entry) \
|
||||
@ -56,10 +59,16 @@ void metrics_store_entry_free_(metrics_store_entry_t *entry);
|
||||
|
||||
/* Accessors. */
|
||||
int64_t metrics_store_entry_get_value(const metrics_store_entry_t *entry);
|
||||
uint64_t metrics_store_hist_entry_get_value(const metrics_store_entry_t *entry,
|
||||
const int64_t bucket);
|
||||
bool metrics_store_entry_has_label(const metrics_store_entry_t *entry,
|
||||
const char *label);
|
||||
metrics_store_entry_t *metrics_store_find_entry_with_label(
|
||||
const smartlist_t *entries, const char *label);
|
||||
bool metrics_store_entry_is_histogram(const metrics_store_entry_t *entry);
|
||||
uint64_t metrics_store_hist_entry_get_count(
|
||||
const metrics_store_entry_t *entry);
|
||||
int64_t metrics_store_hist_entry_get_sum(const metrics_store_entry_t *entry);
|
||||
|
||||
/* Modifiers. */
|
||||
void metrics_store_entry_add_label(metrics_store_entry_t *entry,
|
||||
@ -67,5 +76,7 @@ void metrics_store_entry_add_label(metrics_store_entry_t *entry,
|
||||
void metrics_store_entry_reset(metrics_store_entry_t *entry);
|
||||
void metrics_store_entry_update(metrics_store_entry_t *entry,
|
||||
const int64_t value);
|
||||
void metrics_store_hist_entry_update(metrics_store_entry_t *entry,
|
||||
const int64_t value, const int64_t obs);
|
||||
|
||||
#endif /* !defined(TOR_LIB_METRICS_METRICS_STORE_ENTRY_H) */
|
||||
|
@ -17,6 +17,8 @@
|
||||
|
||||
#include "lib/metrics/prometheus.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/** Return a static buffer containing all the labels properly formatted
|
||||
* for the output as a string.
|
||||
*
|
||||
@ -33,13 +35,54 @@ format_labels(smartlist_t *labels)
|
||||
}
|
||||
|
||||
line = smartlist_join_strings(labels, ",", 0, NULL);
|
||||
tor_snprintf(buf, sizeof(buf), "{%s}", line);
|
||||
tor_snprintf(buf, sizeof(buf), "%s", line);
|
||||
|
||||
end:
|
||||
tor_free(line);
|
||||
return buf;
|
||||
}
|
||||
|
||||
/** Write the string representation of the histogram entry to the specified
|
||||
* buffer.
|
||||
*
|
||||
* Note: entry **must** be a histogram.
|
||||
*/
|
||||
static void
|
||||
format_histogram(const metrics_store_entry_t *entry, buf_t *data)
|
||||
{
|
||||
tor_assert(entry->type == METRICS_TYPE_HISTOGRAM);
|
||||
|
||||
const char *labels = format_labels(entry->labels);
|
||||
|
||||
for (size_t i = 0; i < entry->u.histogram.bucket_count; ++i) {
|
||||
metrics_histogram_bucket_t hb = entry->u.histogram.buckets[i];
|
||||
if (strlen(labels) > 0) {
|
||||
buf_add_printf(data, "%s_bucket{%s,le=\"%.2f\"} %" PRIi64 "\n",
|
||||
entry->name, labels, (double)hb.bucket, hb.value);
|
||||
} else {
|
||||
buf_add_printf(data, "%s_bucket{le=\"%.2f\"} %" PRIi64 "\n",
|
||||
entry->name, (double)hb.bucket, hb.value);
|
||||
}
|
||||
}
|
||||
|
||||
if (strlen(labels) > 0) {
|
||||
buf_add_printf(data, "%s_bucket{%s,le=\"+Inf\"} %" PRIi64 "\n",
|
||||
entry->name, labels,
|
||||
metrics_store_hist_entry_get_count(entry));
|
||||
buf_add_printf(data, "%s_sum{%s} %" PRIi64 "\n", entry->name, labels,
|
||||
metrics_store_hist_entry_get_sum(entry));
|
||||
buf_add_printf(data, "%s_count{%s} %" PRIi64 "\n", entry->name, labels,
|
||||
metrics_store_hist_entry_get_count(entry));
|
||||
} else {
|
||||
buf_add_printf(data, "%s_bucket{le=\"+Inf\"} %" PRIi64 "\n", entry->name,
|
||||
metrics_store_hist_entry_get_count(entry));
|
||||
buf_add_printf(data, "%s_sum %" PRIi64 "\n", entry->name,
|
||||
metrics_store_hist_entry_get_sum(entry));
|
||||
buf_add_printf(data, "%s_count %" PRIi64 "\n", entry->name,
|
||||
metrics_store_hist_entry_get_count(entry));
|
||||
}
|
||||
}
|
||||
|
||||
/** Format the given entry in to the buffer data. */
|
||||
void
|
||||
prometheus_format_store_entry(const metrics_store_entry_t *entry, buf_t *data,
|
||||
@ -53,7 +96,26 @@ prometheus_format_store_entry(const metrics_store_entry_t *entry, buf_t *data,
|
||||
buf_add_printf(data, "# TYPE %s %s\n", entry->name,
|
||||
metrics_type_to_str(entry->type));
|
||||
}
|
||||
buf_add_printf(data, "%s%s %" PRIi64 "\n", entry->name,
|
||||
format_labels(entry->labels),
|
||||
metrics_store_entry_get_value(entry));
|
||||
|
||||
switch (entry->type) {
|
||||
case METRICS_TYPE_COUNTER: FALLTHROUGH;
|
||||
case METRICS_TYPE_GAUGE:
|
||||
{
|
||||
const char *labels = format_labels(entry->labels);
|
||||
if (strlen(labels) > 0) {
|
||||
buf_add_printf(data, "%s{%s} %" PRIi64 "\n", entry->name,
|
||||
labels,
|
||||
metrics_store_entry_get_value(entry));
|
||||
} else {
|
||||
buf_add_printf(data, "%s %" PRIi64 "\n", entry->name,
|
||||
metrics_store_entry_get_value(entry));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case METRICS_TYPE_HISTOGRAM:
|
||||
format_histogram(entry, data);
|
||||
break;
|
||||
default:
|
||||
tor_assert_unreached();
|
||||
}
|
||||
}
|
||||
|
@ -28,11 +28,16 @@
|
||||
#include "lib/encoding/confline.h"
|
||||
#include "lib/metrics/metrics_store.h"
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#define TEST_METRICS_ENTRY_NAME "entryA"
|
||||
#define TEST_METRICS_ENTRY_HELP "Description of entryA"
|
||||
#define TEST_METRICS_ENTRY_LABEL_1 "label=\"farfadet\""
|
||||
#define TEST_METRICS_ENTRY_LABEL_2 "label=\"ponki\""
|
||||
|
||||
#define TEST_METRICS_HIST_ENTRY_NAME "test_hist_entry"
|
||||
#define TEST_METRICS_HIST_ENTRY_HELP "Description of test_hist_entry"
|
||||
|
||||
static void
|
||||
set_metrics_port(or_options_t *options)
|
||||
{
|
||||
@ -189,7 +194,8 @@ test_prometheus(void *arg)
|
||||
/* Add entry and validate its content. */
|
||||
entry = metrics_store_add(store, METRICS_TYPE_COUNTER,
|
||||
TEST_METRICS_ENTRY_NAME,
|
||||
TEST_METRICS_ENTRY_HELP);
|
||||
TEST_METRICS_ENTRY_HELP,
|
||||
0, NULL);
|
||||
tt_assert(entry);
|
||||
metrics_store_entry_add_label(entry, TEST_METRICS_ENTRY_LABEL_1);
|
||||
|
||||
@ -208,11 +214,61 @@ test_prometheus(void *arg)
|
||||
metrics_store_free(store);
|
||||
}
|
||||
|
||||
static void
|
||||
test_prometheus_histogram(void *arg)
|
||||
{
|
||||
metrics_store_t *store = NULL;
|
||||
metrics_store_entry_t *entry = NULL;
|
||||
buf_t *buf = buf_new();
|
||||
char *output = NULL;
|
||||
const int64_t buckets[] = { 10, 20, 3000 };
|
||||
|
||||
(void) arg;
|
||||
|
||||
/* Fresh new store. No entries. */
|
||||
store = metrics_store_new();
|
||||
tt_assert(store);
|
||||
|
||||
/* Add a histogram entry and validate its content. */
|
||||
entry = metrics_store_add(store, METRICS_TYPE_HISTOGRAM,
|
||||
TEST_METRICS_HIST_ENTRY_NAME,
|
||||
TEST_METRICS_HIST_ENTRY_HELP,
|
||||
ARRAY_LENGTH(buckets), buckets);
|
||||
tt_assert(entry);
|
||||
metrics_store_entry_add_label(entry, TEST_METRICS_ENTRY_LABEL_1);
|
||||
|
||||
static const char *expected =
|
||||
"# HELP " TEST_METRICS_HIST_ENTRY_NAME " "
|
||||
TEST_METRICS_HIST_ENTRY_HELP "\n"
|
||||
"# TYPE " TEST_METRICS_HIST_ENTRY_NAME " histogram\n"
|
||||
TEST_METRICS_HIST_ENTRY_NAME "_bucket{"
|
||||
TEST_METRICS_ENTRY_LABEL_1 ",le=\"10.00\"} 0\n"
|
||||
TEST_METRICS_HIST_ENTRY_NAME "_bucket{"
|
||||
TEST_METRICS_ENTRY_LABEL_1 ",le=\"20.00\"} 0\n"
|
||||
TEST_METRICS_HIST_ENTRY_NAME "_bucket{"
|
||||
TEST_METRICS_ENTRY_LABEL_1 ",le=\"3000.00\"} 0\n"
|
||||
TEST_METRICS_HIST_ENTRY_NAME "_bucket{"
|
||||
TEST_METRICS_ENTRY_LABEL_1 ",le=\"+Inf\"} 0\n"
|
||||
TEST_METRICS_HIST_ENTRY_NAME "_sum{" TEST_METRICS_ENTRY_LABEL_1 "} 0\n"
|
||||
TEST_METRICS_HIST_ENTRY_NAME "_count{" TEST_METRICS_ENTRY_LABEL_1 "} 0\n";
|
||||
|
||||
metrics_store_get_output(METRICS_FORMAT_PROMETHEUS, store, buf);
|
||||
output = buf_extract(buf, NULL);
|
||||
tt_str_op(expected, OP_EQ, output);
|
||||
|
||||
done:
|
||||
buf_free(buf);
|
||||
tor_free(output);
|
||||
metrics_store_free(store);
|
||||
}
|
||||
|
||||
static void
|
||||
test_store(void *arg)
|
||||
{
|
||||
metrics_store_t *store = NULL;
|
||||
metrics_store_entry_t *entry = NULL;
|
||||
const int64_t buckets[] = { 10, 20, 3000 };
|
||||
const size_t bucket_count = ARRAY_LENGTH(buckets);
|
||||
|
||||
(void) arg;
|
||||
|
||||
@ -224,7 +280,7 @@ test_store(void *arg)
|
||||
/* Add entry and validate its content. */
|
||||
entry = metrics_store_add(store, METRICS_TYPE_COUNTER,
|
||||
TEST_METRICS_ENTRY_NAME,
|
||||
TEST_METRICS_ENTRY_HELP);
|
||||
TEST_METRICS_ENTRY_HELP, 0, NULL);
|
||||
tt_assert(entry);
|
||||
tt_int_op(entry->type, OP_EQ, METRICS_TYPE_COUNTER);
|
||||
tt_str_op(entry->name, OP_EQ, TEST_METRICS_ENTRY_NAME);
|
||||
@ -251,7 +307,7 @@ test_store(void *arg)
|
||||
/* Add entry and validate its content. */
|
||||
entry = metrics_store_add(store, METRICS_TYPE_COUNTER,
|
||||
TEST_METRICS_ENTRY_NAME,
|
||||
TEST_METRICS_ENTRY_HELP);
|
||||
TEST_METRICS_ENTRY_HELP, 0, NULL);
|
||||
tt_assert(entry);
|
||||
metrics_store_entry_add_label(entry, TEST_METRICS_ENTRY_LABEL_2);
|
||||
|
||||
@ -261,6 +317,89 @@ test_store(void *arg)
|
||||
tt_assert(entries);
|
||||
tt_int_op(smartlist_len(entries), OP_EQ, 2);
|
||||
|
||||
/* Add a histogram entry and validate its content. */
|
||||
entry = metrics_store_add(store, METRICS_TYPE_HISTOGRAM,
|
||||
TEST_METRICS_HIST_ENTRY_NAME,
|
||||
TEST_METRICS_HIST_ENTRY_HELP,
|
||||
bucket_count, buckets);
|
||||
|
||||
tt_assert(entry);
|
||||
tt_int_op(entry->type, OP_EQ, METRICS_TYPE_HISTOGRAM);
|
||||
tt_str_op(entry->name, OP_EQ, TEST_METRICS_HIST_ENTRY_NAME);
|
||||
tt_str_op(entry->help, OP_EQ, TEST_METRICS_HIST_ENTRY_HELP);
|
||||
tt_uint_op(entry->u.histogram.bucket_count, OP_EQ, bucket_count);
|
||||
|
||||
for (size_t i = 0; i < bucket_count; ++i) {
|
||||
tt_uint_op(entry->u.histogram.buckets[i].bucket, OP_EQ, buckets[i]);
|
||||
tt_uint_op(entry->u.histogram.buckets[i].value, OP_EQ, 0);
|
||||
}
|
||||
|
||||
/* Access the entry. */
|
||||
tt_assert(metrics_store_get_all(store, TEST_METRICS_HIST_ENTRY_NAME));
|
||||
|
||||
/* Record various observations. */
|
||||
metrics_store_hist_entry_update(entry, 3, 11);
|
||||
tt_int_op(metrics_store_hist_entry_get_value(entry, 10), OP_EQ, 0);
|
||||
tt_int_op(metrics_store_hist_entry_get_value(entry, 20), OP_EQ, 3);
|
||||
tt_int_op(metrics_store_hist_entry_get_value(entry, 3000), OP_EQ, 3);
|
||||
tt_int_op(metrics_store_hist_entry_get_value(entry, 3000), OP_EQ, 3);
|
||||
tt_int_op(metrics_store_hist_entry_get_count(entry), OP_EQ, 3);
|
||||
tt_int_op(metrics_store_hist_entry_get_sum(entry), OP_EQ, 11);
|
||||
|
||||
metrics_store_hist_entry_update(entry, 1, 42);
|
||||
tt_int_op(metrics_store_hist_entry_get_value(entry, 10), OP_EQ, 0);
|
||||
tt_int_op(metrics_store_hist_entry_get_value(entry, 20), OP_EQ, 3);
|
||||
tt_int_op(metrics_store_hist_entry_get_value(entry, 3000), OP_EQ, 4);
|
||||
tt_int_op(metrics_store_hist_entry_get_value(entry, 3000), OP_EQ, 4);
|
||||
tt_int_op(metrics_store_hist_entry_get_count(entry), OP_EQ, 4);
|
||||
tt_int_op(metrics_store_hist_entry_get_sum(entry), OP_EQ, 53);
|
||||
|
||||
/* Ensure this resets all buckets back to 0. */
|
||||
metrics_store_entry_reset(entry);
|
||||
for (size_t i = 0; i < bucket_count; ++i) {
|
||||
tt_uint_op(entry->u.histogram.buckets[i].bucket, OP_EQ, buckets[i]);
|
||||
tt_uint_op(entry->u.histogram.buckets[i].value, OP_EQ, 0);
|
||||
}
|
||||
|
||||
/* tt_int_op assigns the third argument to a variable of type long, which
|
||||
* overflows on some platforms (e.g. on some 32-bit systems). We disable
|
||||
* these checks for those platforms. */
|
||||
#if LONG_MAX >= INT64_MAX
|
||||
metrics_store_hist_entry_update(entry, 1, INT64_MAX - 13);
|
||||
tt_int_op(metrics_store_hist_entry_get_sum(entry), OP_EQ, INT64_MAX - 13);
|
||||
metrics_store_hist_entry_update(entry, 1, 13);
|
||||
tt_int_op(metrics_store_hist_entry_get_sum(entry), OP_EQ, INT64_MAX);
|
||||
/* Uh-oh, the sum of all observations is now greater than INT64_MAX. Make
|
||||
* sure we reset the entry instead of overflowing the sum. */
|
||||
metrics_store_hist_entry_update(entry, 1, 1);
|
||||
tt_int_op(metrics_store_hist_entry_get_value(entry, 10), OP_EQ, 1);
|
||||
tt_int_op(metrics_store_hist_entry_get_value(entry, 20), OP_EQ, 1);
|
||||
tt_int_op(metrics_store_hist_entry_get_value(entry, 3000), OP_EQ, 1);
|
||||
tt_int_op(metrics_store_hist_entry_get_value(entry, 3000), OP_EQ, 1);
|
||||
tt_int_op(metrics_store_hist_entry_get_count(entry), OP_EQ, 1);
|
||||
tt_int_op(metrics_store_hist_entry_get_sum(entry), OP_EQ, 1);
|
||||
#endif
|
||||
|
||||
#if LONG_MIN <= INT64_MIN
|
||||
metrics_store_entry_reset(entry);
|
||||
/* In practice, we're not going to have negative observations (as we only use
|
||||
* histograms for timings, which are always positive), but technically
|
||||
* prometheus _does_ support negative observations. */
|
||||
metrics_store_hist_entry_update(entry, 1, INT64_MIN + 13);
|
||||
tt_int_op(metrics_store_hist_entry_get_sum(entry), OP_EQ, INT64_MIN + 13);
|
||||
metrics_store_hist_entry_update(entry, 1, -13);
|
||||
tt_int_op(metrics_store_hist_entry_get_sum(entry), OP_EQ, INT64_MIN);
|
||||
/* Uh-oh, the sum of all observations is now less than INT64_MIN. Make
|
||||
* sure we reset the entry instead of underflowing the sum. */
|
||||
metrics_store_hist_entry_update(entry, 1, -1);
|
||||
tt_int_op(metrics_store_hist_entry_get_value(entry, 10), OP_EQ, 1);
|
||||
tt_int_op(metrics_store_hist_entry_get_value(entry, 20), OP_EQ, 1);
|
||||
tt_int_op(metrics_store_hist_entry_get_value(entry, 3000), OP_EQ, 1);
|
||||
tt_int_op(metrics_store_hist_entry_get_value(entry, 3000), OP_EQ, 1);
|
||||
tt_int_op(metrics_store_hist_entry_get_count(entry), OP_EQ, 1);
|
||||
tt_int_op(metrics_store_hist_entry_get_sum(entry), OP_EQ, -1);
|
||||
#endif
|
||||
|
||||
done:
|
||||
metrics_store_free(store);
|
||||
}
|
||||
@ -270,6 +409,7 @@ struct testcase_t metrics_tests[] = {
|
||||
{ "config", test_config, TT_FORK, NULL, NULL },
|
||||
{ "connection", test_connection, TT_FORK, NULL, NULL },
|
||||
{ "prometheus", test_prometheus, TT_FORK, NULL, NULL },
|
||||
{ "prometheus_histogram", test_prometheus_histogram, TT_FORK, NULL, NULL },
|
||||
{ "store", test_store, TT_FORK, NULL, NULL },
|
||||
|
||||
END_OF_TESTCASES
|
||||
|
Loading…
Reference in New Issue
Block a user