|
|
|
@ -1,4 +1,5 @@ |
|
|
|
#include <math.h> |
|
|
|
#include <stdarg.h> |
|
|
|
#include "call.h" |
|
|
|
#include "statistics.h" |
|
|
|
#include "graphite.h" |
|
|
|
@ -182,145 +183,113 @@ found:; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
#pragma GCC diagnostic ignored "-Wformat-zero-length" |
|
|
|
|
|
|
|
#define SM_PUSH(ret, m) \ |
|
|
|
do { \ |
|
|
|
struct stats_metric *last = NULL; \ |
|
|
|
for (GList *l_last = ret->tail; l_last; l_last = l_last->prev) { \ |
|
|
|
last = l_last->data; \ |
|
|
|
if (last->label) \ |
|
|
|
break; \ |
|
|
|
last = NULL; \ |
|
|
|
} \ |
|
|
|
if (!m->is_bracket && last) { \ |
|
|
|
if (!last->is_bracket || last->is_close_bracket) \ |
|
|
|
m->is_follow_up = 1; \ |
|
|
|
} \ |
|
|
|
else if (m->is_bracket && !m->is_close_bracket && last && last->is_close_bracket) \ |
|
|
|
m->is_follow_up = 1; \ |
|
|
|
g_queue_push_tail(ret, m); \ |
|
|
|
} while (0) |
|
|
|
|
|
|
|
#define PROM(name, type) \ |
|
|
|
do { \ |
|
|
|
struct stats_metric *last = g_queue_peek_tail(ret); \ |
|
|
|
last->prom_name = name; \ |
|
|
|
last->prom_type = type; \ |
|
|
|
} while (0) |
|
|
|
#define PROMLAB(fmt, ...) \ |
|
|
|
do { \ |
|
|
|
struct stats_metric *last = g_queue_peek_tail(ret); \ |
|
|
|
last->prom_label = g_strdup_printf(fmt, ## __VA_ARGS__); \ |
|
|
|
} while (0) |
|
|
|
|
|
|
|
#define METRICva(lb, dsc, fmt1, fmt2, ...) \ |
|
|
|
do { \ |
|
|
|
struct stats_metric *m = g_slice_alloc0(sizeof(*m)); \ |
|
|
|
m->label = g_strdup(lb); \ |
|
|
|
m->descr = g_strdup(dsc); \ |
|
|
|
if (fmt1) \ |
|
|
|
m->value_short = g_strdup_printf(fmt1, ## __VA_ARGS__); \ |
|
|
|
if (fmt2) \ |
|
|
|
m->value_long = g_strdup_printf(fmt2, ## __VA_ARGS__); \ |
|
|
|
SM_PUSH(ret, m); \ |
|
|
|
} while (0) |
|
|
|
|
|
|
|
#define METRIC(lb, dsc, fmt1, fmt2, arg) \ |
|
|
|
do { \ |
|
|
|
struct stats_metric *m = g_slice_alloc0(sizeof(*m)); \ |
|
|
|
m->label = g_strdup(lb); \ |
|
|
|
m->descr = g_strdup(dsc); \ |
|
|
|
if (fmt1) \ |
|
|
|
m->value_short = g_strdup_printf(fmt1, arg); \ |
|
|
|
if (fmt2) \ |
|
|
|
m->value_long = g_strdup_printf(fmt2, arg); \ |
|
|
|
if (fmt1 && fmt2 && !strcmp(fmt1, fmt2)) { \ |
|
|
|
if (!strcmp(fmt1, "%u") || \ |
|
|
|
!strcmp(fmt1, "%lu") || \ |
|
|
|
!strcmp(fmt1, "%llu") || \ |
|
|
|
!strcmp(fmt1, "%i") || \ |
|
|
|
!strcmp(fmt1, "%li") || \ |
|
|
|
!strcmp(fmt1, "%lli") || \ |
|
|
|
!strcmp(fmt1, "%d") || \ |
|
|
|
!strcmp(fmt1, "%ld") || \ |
|
|
|
!strcmp(fmt1, "%lld")) \ |
|
|
|
{ \ |
|
|
|
m->is_int = 1; \ |
|
|
|
m->int_value = arg; \ |
|
|
|
} \ |
|
|
|
} \ |
|
|
|
SM_PUSH(ret, m); \ |
|
|
|
} while (0) |
|
|
|
|
|
|
|
#define METRICl(dsc, fmt2, ...) \ |
|
|
|
do { \ |
|
|
|
struct stats_metric *m = g_slice_alloc0(sizeof(*m)); \ |
|
|
|
m->descr = g_strdup(dsc); \ |
|
|
|
m->value_long = g_strdup_printf(fmt2, ## __VA_ARGS__); \ |
|
|
|
SM_PUSH(ret, m); \ |
|
|
|
} while (0) |
|
|
|
|
|
|
|
#define METRICsva(lb, fmt1, ...) \ |
|
|
|
do { \ |
|
|
|
struct stats_metric *m = g_slice_alloc0(sizeof(*m)); \ |
|
|
|
m->label = g_strdup(lb); \ |
|
|
|
m->value_short = g_strdup_printf(fmt1, ## __VA_ARGS__); \ |
|
|
|
SM_PUSH(ret, m); \ |
|
|
|
} while (0) |
|
|
|
|
|
|
|
#define METRICs(lb, fmt1, arg) \ |
|
|
|
do { \ |
|
|
|
struct stats_metric *m = g_slice_alloc0(sizeof(*m)); \ |
|
|
|
m->label = g_strdup(lb); \ |
|
|
|
m->value_short = g_strdup_printf(fmt1, arg); \ |
|
|
|
if (fmt1) { \ |
|
|
|
if (!strcmp(fmt1, "%u") || \ |
|
|
|
!strcmp(fmt1, "%lu") || \ |
|
|
|
!strcmp(fmt1, "%llu") || \ |
|
|
|
!strcmp(fmt1, "%i") || \ |
|
|
|
!strcmp(fmt1, "%li") || \ |
|
|
|
!strcmp(fmt1, "%lli") || \ |
|
|
|
!strcmp(fmt1, "%d") || \ |
|
|
|
!strcmp(fmt1, "%ld") || \ |
|
|
|
!strcmp(fmt1, "%lld")) \ |
|
|
|
{ \ |
|
|
|
m->is_int = 1; \ |
|
|
|
m->int_value = arg; \ |
|
|
|
} \ |
|
|
|
} \ |
|
|
|
SM_PUSH(ret, m); \ |
|
|
|
} while (0) |
|
|
|
|
|
|
|
#define HEADER(fmt1, fmt2, ...) \ |
|
|
|
do { \ |
|
|
|
struct stats_metric *m = g_slice_alloc0(sizeof(*m)); \ |
|
|
|
if (fmt1) \ |
|
|
|
m->label = g_strdup_printf(fmt1, ## __VA_ARGS__); \ |
|
|
|
if (fmt2) \ |
|
|
|
m->descr = g_strdup_printf(fmt2, ## __VA_ARGS__); \ |
|
|
|
if (m->label && ( \ |
|
|
|
m->label[0] == '[' \ |
|
|
|
|| m->label[0] == '{' \ |
|
|
|
|| m->label[0] == '}' \ |
|
|
|
|| m->label[0] == ']') \ |
|
|
|
&& m->label[1] == 0) \ |
|
|
|
{ \ |
|
|
|
m->is_bracket = 1; \ |
|
|
|
if (m->label[0] == '}' || m->label[0] == ']') \ |
|
|
|
m->is_close_bracket = 1; \ |
|
|
|
if (m->label[0] == '{' || m->label[0] == '}') \ |
|
|
|
m->is_brace = 1; \ |
|
|
|
} \ |
|
|
|
SM_PUSH(ret, m); \ |
|
|
|
} while (0) |
|
|
|
|
|
|
|
#define HEADERl(fmt2, ...) \ |
|
|
|
do { \ |
|
|
|
struct stats_metric *m = g_slice_alloc0(sizeof(*m)); \ |
|
|
|
m->descr = g_strdup_printf(fmt2, ## __VA_ARGS__); \ |
|
|
|
SM_PUSH(ret, m); \ |
|
|
|
} while (0) |
|
|
|
|
|
|
|
INLINE void prom_metric(GQueue *ret, const char *name, const char *type) { |
|
|
|
struct stats_metric *last = g_queue_peek_tail(ret); |
|
|
|
last->prom_name = name; |
|
|
|
last->prom_type = type; |
|
|
|
} |
|
|
|
static void prom_label(GQueue *ret, const char *fmt, ...) { |
|
|
|
va_list ap; |
|
|
|
va_start(ap, fmt); |
|
|
|
struct stats_metric *last = g_queue_peek_tail(ret); |
|
|
|
last->prom_label = g_strdup_vprintf(fmt, ap); |
|
|
|
va_end(ap); |
|
|
|
} |
|
|
|
#define PROM(name, type) prom_metric(ret, name, type) |
|
|
|
#define PROMLAB(fmt, ...) prom_label(ret, fmt, ##__VA_ARGS__) |
|
|
|
|
|
|
|
INLINE void metric_push(GQueue *ret, struct stats_metric *m) { |
|
|
|
struct stats_metric *last = NULL; |
|
|
|
for (GList *l_last = ret->tail; l_last; l_last = l_last->prev) { |
|
|
|
last = l_last->data; |
|
|
|
if (last->label) |
|
|
|
break; |
|
|
|
last = NULL; |
|
|
|
} |
|
|
|
if (!m->is_bracket && last) { |
|
|
|
if (!last->is_bracket || last->is_close_bracket) |
|
|
|
m->is_follow_up = 1; |
|
|
|
} |
|
|
|
else if (m->is_bracket && !m->is_close_bracket && last && last->is_close_bracket) |
|
|
|
m->is_follow_up = 1; |
|
|
|
g_queue_push_tail(ret, m); |
|
|
|
} |
|
|
|
static void add_metric(GQueue *ret, const char *label, const char *desc, const char *fmt1, const char *fmt2, ...) { |
|
|
|
va_list ap; |
|
|
|
|
|
|
|
struct stats_metric *m = g_slice_alloc0(sizeof(*m)); |
|
|
|
if (label) |
|
|
|
m->label = g_strdup(label); |
|
|
|
if (desc) |
|
|
|
m->descr = g_strdup(desc); |
|
|
|
if (fmt1) { |
|
|
|
va_start(ap, fmt2); |
|
|
|
m->value_short = g_strdup_vprintf(fmt1, ap); |
|
|
|
va_end(ap); |
|
|
|
} |
|
|
|
if (fmt2) { |
|
|
|
va_start(ap, fmt2); |
|
|
|
m->value_long = g_strdup_vprintf(fmt2, ap); |
|
|
|
va_end(ap); |
|
|
|
} |
|
|
|
if (fmt1 && fmt1[0] == '%' && (!fmt2 || !strcmp(fmt1, fmt2))) { |
|
|
|
va_start(ap, fmt2); |
|
|
|
if (!strcmp(fmt1, "%u") || !strcmp(fmt1, "%i") || !strcmp(fmt1, "%d")) { |
|
|
|
m->is_int = 1; |
|
|
|
m->int_value = va_arg(ap, int); |
|
|
|
} |
|
|
|
else if (!strcmp(fmt1, "%lu") || !strcmp(fmt1, "%li") || !strcmp(fmt1, "%ld")) { |
|
|
|
m->is_int = 1; |
|
|
|
m->int_value = va_arg(ap, long); |
|
|
|
} |
|
|
|
else if ( !strcmp(fmt1, "%llu") || !strcmp(fmt1, "%lli") || !strcmp(fmt1, "%lld")) { |
|
|
|
m->is_int = 1; |
|
|
|
m->int_value = va_arg(ap, long long); |
|
|
|
} |
|
|
|
va_end(ap); |
|
|
|
} |
|
|
|
metric_push(ret, m); |
|
|
|
} |
|
|
|
static void add_header(GQueue *ret, const char *fmt1, const char *fmt2, ...) { |
|
|
|
va_list ap; |
|
|
|
|
|
|
|
struct stats_metric *m = g_slice_alloc0(sizeof(*m)); |
|
|
|
if (fmt1) { |
|
|
|
va_start(ap, fmt2); |
|
|
|
m->label = g_strdup_vprintf(fmt1, ap); |
|
|
|
va_end(ap); |
|
|
|
} |
|
|
|
if (fmt2) { |
|
|
|
va_start(ap, fmt2); |
|
|
|
m->descr = g_strdup_vprintf(fmt2, ap); |
|
|
|
va_end(ap); |
|
|
|
} |
|
|
|
if (m->label && ( |
|
|
|
m->label[0] == '[' |
|
|
|
|| m->label[0] == '{' |
|
|
|
|| m->label[0] == '}' |
|
|
|
|| m->label[0] == ']') |
|
|
|
&& m->label[1] == 0) |
|
|
|
{ |
|
|
|
m->is_bracket = 1; |
|
|
|
if (m->label[0] == '}' || m->label[0] == ']') |
|
|
|
m->is_close_bracket = 1; |
|
|
|
if (m->label[0] == '{' || m->label[0] == '}') |
|
|
|
m->is_brace = 1; |
|
|
|
} |
|
|
|
metric_push(ret, m); |
|
|
|
} |
|
|
|
|
|
|
|
#define METRIC(lb, dsc, fmt1, fmt2, ...) add_metric(ret, lb, dsc, fmt1, fmt2, ## __VA_ARGS__) |
|
|
|
#define METRICva METRIC |
|
|
|
#define METRICl(dsc, fmt2, ...) add_metric(ret, NULL, dsc, NULL, fmt2, ##__VA_ARGS__) |
|
|
|
#define METRICsva(lb, fmt1, ...) add_metric(ret, lb, NULL, fmt1, NULL, ##__VA_ARGS__) |
|
|
|
#define METRICs(lb, fmt1, arg) add_metric(ret, lb, NULL, fmt1, NULL, arg) |
|
|
|
|
|
|
|
#define HEADER(fmt1, fmt2, ...) add_header(ret, fmt1, fmt2, ##__VA_ARGS__) |
|
|
|
#define HEADERl(fmt2, ...) add_header(ret, NULL, fmt2, ##__VA_ARGS__) |
|
|
|
|
|
|
|
|
|
|
|
GQueue *statistics_gather_metrics(void) { |
|
|
|
GQueue *ret = g_queue_new(); |
|
|
|
|