prometheus.c (3637B)
1 /* Copyright (c) 2020-2021, The Tor Project, Inc. */ 2 /* See LICENSE for licensing information */ 3 4 /** 5 * @file prometheus.c 6 * @brief Metrics format driver for Prometheus data model. 7 **/ 8 9 #define METRICS_STORE_ENTRY_PRIVATE 10 11 #include "orconfig.h" 12 13 #include "lib/container/smartlist.h" 14 #include "lib/log/util_bug.h" 15 #include "lib/malloc/malloc.h" 16 #include "lib/string/printf.h" 17 18 #include "lib/metrics/prometheus.h" 19 20 #include <string.h> 21 22 /** Return a static buffer containing all the labels properly formatted 23 * for the output as a string. 24 * 25 * Subsequent calls to this invalidates the previous result. */ 26 static const char * 27 format_labels(smartlist_t *labels) 28 { 29 static char buf[1024]; 30 char *line = NULL; 31 32 if (smartlist_len(labels) == 0) { 33 buf[0] = '\0'; 34 goto end; 35 } 36 37 line = smartlist_join_strings(labels, ",", 0, NULL); 38 tor_snprintf(buf, sizeof(buf), "%s", line); 39 40 end: 41 tor_free(line); 42 return buf; 43 } 44 45 /** Write the string representation of the histogram entry to the specified 46 * buffer. 47 * 48 * Note: entry **must** be a histogram. 49 */ 50 static void 51 format_histogram(const metrics_store_entry_t *entry, buf_t *data) 52 { 53 tor_assert(entry->type == METRICS_TYPE_HISTOGRAM); 54 55 const char *labels = format_labels(entry->labels); 56 57 for (size_t i = 0; i < entry->u.histogram.bucket_count; ++i) { 58 metrics_histogram_bucket_t hb = entry->u.histogram.buckets[i]; 59 if (strlen(labels) > 0) { 60 buf_add_printf(data, "%s_bucket{%s,le=\"%.2f\"} %" PRIi64 "\n", 61 entry->name, labels, (double)hb.bucket, hb.value); 62 } else { 63 buf_add_printf(data, "%s_bucket{le=\"%.2f\"} %" PRIi64 "\n", 64 entry->name, (double)hb.bucket, hb.value); 65 } 66 } 67 68 if (strlen(labels) > 0) { 69 buf_add_printf(data, "%s_bucket{%s,le=\"+Inf\"} %" PRIi64 "\n", 70 entry->name, labels, 71 metrics_store_hist_entry_get_count(entry)); 72 buf_add_printf(data, "%s_sum{%s} %" PRIi64 "\n", entry->name, labels, 73 metrics_store_hist_entry_get_sum(entry)); 74 buf_add_printf(data, "%s_count{%s} %" PRIi64 "\n", entry->name, labels, 75 metrics_store_hist_entry_get_count(entry)); 76 } else { 77 buf_add_printf(data, "%s_bucket{le=\"+Inf\"} %" PRIi64 "\n", entry->name, 78 metrics_store_hist_entry_get_count(entry)); 79 buf_add_printf(data, "%s_sum %" PRIi64 "\n", entry->name, 80 metrics_store_hist_entry_get_sum(entry)); 81 buf_add_printf(data, "%s_count %" PRIi64 "\n", entry->name, 82 metrics_store_hist_entry_get_count(entry)); 83 } 84 } 85 86 /** Format the given entry in to the buffer data. */ 87 void 88 prometheus_format_store_entry(const metrics_store_entry_t *entry, buf_t *data, 89 bool no_comment) 90 { 91 tor_assert(entry); 92 tor_assert(data); 93 94 if (!no_comment) { 95 buf_add_printf(data, "# HELP %s %s\n", entry->name, entry->help); 96 buf_add_printf(data, "# TYPE %s %s\n", entry->name, 97 metrics_type_to_str(entry->type)); 98 } 99 100 switch (entry->type) { 101 case METRICS_TYPE_COUNTER: FALLTHROUGH; 102 case METRICS_TYPE_GAUGE: 103 { 104 const char *labels = format_labels(entry->labels); 105 if (strlen(labels) > 0) { 106 buf_add_printf(data, "%s{%s} %" PRIi64 "\n", entry->name, 107 labels, 108 metrics_store_entry_get_value(entry)); 109 } else { 110 buf_add_printf(data, "%s %" PRIi64 "\n", entry->name, 111 metrics_store_entry_get_value(entry)); 112 } 113 break; 114 } 115 case METRICS_TYPE_HISTOGRAM: 116 format_histogram(entry, data); 117 break; 118 default: 119 tor_assert_unreached(); 120 } 121 }