Skip to content

Commit aaaee2f

Browse files
committed
in_node_exporter_metrics: collect TcpExt and IpExt counters on netstat
Signed-off-by: Hiroshi Hatake <hiroshi@chronosphere.io>
1 parent 11c1171 commit aaaee2f

2 files changed

Lines changed: 290 additions & 14 deletions

File tree

plugins/in_node_exporter_metrics/ne.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ struct flb_ne {
192192
struct cmt_counter *netstat_Udp_InErrors;
193193
struct cmt_counter *netstat_Udp_OutDatagrams;
194194
struct cmt_counter *netstat_Udp_NoPorts;
195+
struct mk_list netstat_dynamic_metrics;
195196

196197
/* time */
197198
struct cmt_gauge *time;

plugins/in_node_exporter_metrics/ne_netstat_linux.c

Lines changed: 289 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,100 @@
3030
#define NETSTAT_PROTO_NONE 0
3131
#define NETSTAT_PROTO_TCP 1
3232
#define NETSTAT_PROTO_UDP 2
33+
#define NETSTAT_PROTO_TCPEXT 3
34+
#define NETSTAT_PROTO_IPEXT 4
35+
36+
struct netstat_dynamic_metric {
37+
char *name;
38+
struct cmt_gauge *gauge;
39+
struct mk_list _head;
40+
};
41+
42+
static void netstat_dynamic_metrics_destroy(struct flb_ne *ctx)
43+
{
44+
struct mk_list *tmp;
45+
struct mk_list *head;
46+
struct netstat_dynamic_metric *entry;
47+
48+
mk_list_foreach_safe(head, tmp, &ctx->netstat_dynamic_metrics) {
49+
entry = mk_list_entry(head, struct netstat_dynamic_metric, _head);
50+
mk_list_del(&entry->_head);
51+
if (entry->name != NULL) {
52+
flb_free(entry->name);
53+
}
54+
flb_free(entry);
55+
}
56+
}
57+
58+
static int netstat_is_static_metric(const char *name)
59+
{
60+
if (strcmp(name, "Tcp_CurrEstab") == 0 ||
61+
strcmp(name, "Tcp_ActiveOpens") == 0 ||
62+
strcmp(name, "Tcp_PassiveOpens") == 0 ||
63+
strcmp(name, "Tcp_RetransSegs") == 0 ||
64+
strcmp(name, "Udp_InDatagrams") == 0 ||
65+
strcmp(name, "Udp_NoPorts") == 0 ||
66+
strcmp(name, "Udp_InErrors") == 0 ||
67+
strcmp(name, "Udp_OutDatagrams") == 0) {
68+
return FLB_TRUE;
69+
}
70+
71+
return FLB_FALSE;
72+
}
73+
74+
static struct cmt_gauge *netstat_dynamic_metric_get(struct flb_ne *ctx, const char *name)
75+
{
76+
int ret;
77+
size_t name_len;
78+
char *metric_name;
79+
struct mk_list *head;
80+
struct netstat_dynamic_metric *entry;
81+
82+
mk_list_foreach(head, &ctx->netstat_dynamic_metrics) {
83+
entry = mk_list_entry(head, struct netstat_dynamic_metric, _head);
84+
if (strcmp(entry->name, name) == 0) {
85+
return entry->gauge;
86+
}
87+
}
88+
89+
entry = flb_calloc(1, sizeof(struct netstat_dynamic_metric));
90+
if (entry == NULL) {
91+
return NULL;
92+
}
93+
94+
name_len = strlen(name);
95+
metric_name = flb_malloc(name_len + 1);
96+
if (metric_name == NULL) {
97+
flb_free(entry);
98+
return NULL;
99+
}
100+
101+
ret = snprintf(metric_name, name_len + 1, "%s", name);
102+
if (ret < 0 || ret >= (int) (name_len + 1)) {
103+
flb_free(metric_name);
104+
flb_free(entry);
105+
return NULL;
106+
}
107+
108+
entry->gauge = cmt_gauge_create(ctx->cmt, "node", "netstat", metric_name,
109+
"Network statistics from /proc/net/netstat.",
110+
0, NULL);
111+
if (entry->gauge == NULL) {
112+
flb_free(metric_name);
113+
flb_free(entry);
114+
return NULL;
115+
}
116+
117+
entry->name = metric_name;
118+
mk_list_add(&entry->_head, &ctx->netstat_dynamic_metrics);
119+
120+
return entry->gauge;
121+
}
33122

34123
static int netstat_configure(struct flb_ne *ctx)
35124
{
125+
mk_list_init(&ctx->netstat_dynamic_metrics);
126+
36127
ctx->netstat_Tcp_CurrEstab =
37128
cmt_gauge_create(ctx->cmt, "node", "netstat", "Tcp_CurrEstab",
38129
"Number of TCP connections in ESTABLISHED or CLOSE-WAIT state.",
@@ -198,6 +289,80 @@ static void netstat_process_pair(struct flb_ne *ctx,
198289
else if (proto == NETSTAT_PROTO_UDP) {
199290
netstat_process_udp(ctx, &headers, headers_count, &values, values_count, ts);
200291
}
292+
else if (proto == NETSTAT_PROTO_TCPEXT || proto == NETSTAT_PROTO_IPEXT) {
293+
int idx;
294+
double d_val;
295+
struct cmt_gauge *metric;
296+
char metric_name[256];
297+
struct flb_slist_entry *key;
298+
struct flb_slist_entry *val;
299+
300+
for (idx = 1; idx < headers_count && idx < values_count; idx++) {
301+
key = flb_slist_entry_get(&headers, idx);
302+
val = flb_slist_entry_get(&values, idx);
303+
304+
if (key == NULL || val == NULL) {
305+
continue;
306+
}
307+
308+
if (ne_utils_str_to_double(val->str, &d_val) != 0) {
309+
continue;
310+
}
311+
312+
if (proto == NETSTAT_PROTO_TCPEXT) {
313+
snprintf(metric_name, sizeof(metric_name) - 1, "TcpExt_%s", key->str);
314+
}
315+
else {
316+
snprintf(metric_name, sizeof(metric_name) - 1, "IpExt_%s", key->str);
317+
}
318+
metric_name[sizeof(metric_name) - 1] = '\0';
319+
320+
metric = netstat_dynamic_metric_get(ctx, metric_name);
321+
if (metric != NULL) {
322+
cmt_gauge_set(metric, ts, d_val, 0, NULL);
323+
}
324+
}
325+
}
326+
else {
327+
int idx;
328+
double d_val;
329+
struct cmt_gauge *metric;
330+
char metric_name[256];
331+
struct flb_slist_entry *proto_name;
332+
struct flb_slist_entry *key;
333+
struct flb_slist_entry *val;
334+
335+
proto_name = flb_slist_entry_get(&headers, 0);
336+
if (proto_name != NULL && strlen(proto_name->str) > 1) {
337+
proto_name->str[strlen(proto_name->str) - 1] = '\0';
338+
}
339+
340+
for (idx = 1; idx < headers_count && idx < values_count; idx++) {
341+
key = flb_slist_entry_get(&headers, idx);
342+
val = flb_slist_entry_get(&values, idx);
343+
344+
if (key == NULL || val == NULL || proto_name == NULL) {
345+
continue;
346+
}
347+
348+
if (ne_utils_str_to_double(val->str, &d_val) != 0) {
349+
continue;
350+
}
351+
352+
snprintf(metric_name, sizeof(metric_name) - 1, "%s_%s",
353+
proto_name->str, key->str);
354+
metric_name[sizeof(metric_name) - 1] = '\0';
355+
356+
if (netstat_is_static_metric(metric_name) == FLB_TRUE) {
357+
continue;
358+
}
359+
360+
metric = netstat_dynamic_metric_get(ctx, metric_name);
361+
if (metric != NULL) {
362+
cmt_gauge_set(metric, ts, d_val, 0, NULL);
363+
}
364+
}
365+
}
201366
}
202367

203368
flb_slist_destroy(&headers);
@@ -222,40 +387,142 @@ static int netstat_update(struct flb_ne *ctx)
222387

223388
ts = cfl_time_now();
224389
prev_line = NULL;
225-
prev_proto = NETSTAT_PROTO_NONE;
226390

227391
mk_list_foreach(head, &list) {
228392
line = mk_list_entry(head, struct flb_slist_entry, _head);
229393

230-
if (prev_proto != NETSTAT_PROTO_NONE) {
231-
if (prev_proto == NETSTAT_PROTO_TCP && strncmp(line->str, "Tcp:", 4) == 0) {
394+
if (prev_line != NULL) {
395+
if (strncmp(prev_line, "Tcp:", 4) == 0 && strncmp(line->str, "Tcp:", 4) == 0) {
232396
netstat_process_pair(ctx, prev_line, line->str, NETSTAT_PROTO_TCP, ts);
233-
prev_proto = NETSTAT_PROTO_NONE;
397+
netstat_process_pair(ctx, prev_line, line->str, NETSTAT_PROTO_NONE, ts);
234398
prev_line = NULL;
235399
continue;
236400
}
237-
else if (prev_proto == NETSTAT_PROTO_UDP && strncmp(line->str, "Udp:", 4) == 0) {
401+
else if (strncmp(prev_line, "Udp:", 4) == 0 && strncmp(line->str, "Udp:", 4) == 0) {
238402
netstat_process_pair(ctx, prev_line, line->str, NETSTAT_PROTO_UDP, ts);
239-
prev_proto = NETSTAT_PROTO_NONE;
403+
netstat_process_pair(ctx, prev_line, line->str, NETSTAT_PROTO_NONE, ts);
404+
prev_line = NULL;
405+
continue;
406+
}
407+
else if ((strncmp(prev_line, "Ip:", 3) == 0 && strncmp(line->str, "Ip:", 3) == 0) ||
408+
(strncmp(prev_line, "Icmp:", 5) == 0 && strncmp(line->str, "Icmp:", 5) == 0) ||
409+
(strncmp(prev_line, "IcmpMsg:", 8) == 0 && strncmp(line->str, "IcmpMsg:", 8) == 0) ||
410+
(strncmp(prev_line, "UdpLite:", 8) == 0 && strncmp(line->str, "UdpLite:", 8) == 0)) {
411+
netstat_process_pair(ctx, prev_line, line->str, NETSTAT_PROTO_NONE, ts);
240412
prev_line = NULL;
241413
continue;
242414
}
243415

244-
prev_proto = NETSTAT_PROTO_NONE;
245416
prev_line = NULL;
246417
}
247418

248-
if (strncmp(line->str, "Tcp:", 4) == 0) {
419+
if (strchr(line->str, ':') != NULL) {
249420
prev_line = line->str;
250-
prev_proto = NETSTAT_PROTO_TCP;
251421
}
252-
else if (strncmp(line->str, "Udp:", 4) == 0) {
253-
prev_line = line->str;
254-
prev_proto = NETSTAT_PROTO_UDP;
422+
}
423+
424+
flb_slist_destroy(&list);
425+
426+
mk_list_init(&list);
427+
ret = ne_utils_file_read_lines(ctx->path_procfs, "/net/netstat", &list);
428+
if (ret == 0) {
429+
prev_line = NULL;
430+
prev_proto = NETSTAT_PROTO_NONE;
431+
432+
mk_list_foreach(head, &list) {
433+
line = mk_list_entry(head, struct flb_slist_entry, _head);
434+
435+
if (prev_proto != NETSTAT_PROTO_NONE) {
436+
if (prev_proto == NETSTAT_PROTO_TCPEXT && strncmp(line->str, "TcpExt:", 7) == 0) {
437+
netstat_process_pair(ctx, prev_line, line->str, NETSTAT_PROTO_TCPEXT, ts);
438+
prev_proto = NETSTAT_PROTO_NONE;
439+
prev_line = NULL;
440+
continue;
441+
}
442+
else if (prev_proto == NETSTAT_PROTO_IPEXT && strncmp(line->str, "IpExt:", 6) == 0) {
443+
netstat_process_pair(ctx, prev_line, line->str, NETSTAT_PROTO_IPEXT, ts);
444+
prev_proto = NETSTAT_PROTO_NONE;
445+
prev_line = NULL;
446+
continue;
447+
}
448+
449+
prev_proto = NETSTAT_PROTO_NONE;
450+
prev_line = NULL;
451+
}
452+
453+
if (strncmp(line->str, "TcpExt:", 7) == 0) {
454+
prev_line = line->str;
455+
prev_proto = NETSTAT_PROTO_TCPEXT;
456+
}
457+
else if (strncmp(line->str, "IpExt:", 6) == 0) {
458+
prev_line = line->str;
459+
prev_proto = NETSTAT_PROTO_IPEXT;
460+
}
255461
}
256462
}
257463

258464
flb_slist_destroy(&list);
465+
466+
mk_list_init(&list);
467+
ret = ne_utils_file_read_lines(ctx->path_procfs, "/net/snmp6", &list);
468+
if (ret == 0) {
469+
mk_list_foreach(head, &list) {
470+
int i;
471+
int six_index;
472+
int metric_name_len;
473+
double d_val;
474+
char metric_name[256];
475+
char value[128];
476+
char raw_name[128];
477+
char proto_name[64];
478+
char field_name[64];
479+
struct cmt_gauge *metric;
480+
481+
line = mk_list_entry(head, struct flb_slist_entry, _head);
482+
if (sscanf(line->str, "%127s %127s", raw_name, value) != 2) {
483+
continue;
484+
}
485+
486+
six_index = -1;
487+
i = 0;
488+
while (raw_name[i] != '\0') {
489+
if (raw_name[i] == '6') {
490+
six_index = i;
491+
break;
492+
}
493+
i++;
494+
}
495+
if (six_index == -1 || six_index == 0 || raw_name[six_index + 1] == '\0') {
496+
continue;
497+
}
498+
499+
snprintf(proto_name, sizeof(proto_name) - 1, "%.*s",
500+
six_index + 1, raw_name);
501+
proto_name[sizeof(proto_name) - 1] = '\0';
502+
503+
snprintf(field_name, sizeof(field_name) - 1, "%s",
504+
raw_name + six_index + 1);
505+
field_name[sizeof(field_name) - 1] = '\0';
506+
507+
metric_name_len = snprintf(metric_name, sizeof(metric_name) - 1, "%s_%s",
508+
proto_name, field_name);
509+
if (metric_name_len < 0) {
510+
continue;
511+
}
512+
metric_name[sizeof(metric_name) - 1] = '\0';
513+
514+
if (ne_utils_str_to_double(value, &d_val) != 0) {
515+
continue;
516+
}
517+
518+
metric = netstat_dynamic_metric_get(ctx, metric_name);
519+
if (metric != NULL) {
520+
cmt_gauge_set(metric, ts, d_val, 0, NULL);
521+
}
522+
}
523+
flb_slist_destroy(&list);
524+
}
525+
259526
return 0;
260527
}
261528

@@ -273,10 +540,18 @@ static int ne_netstat_update(struct flb_input_instance *ins,
273540
return 0;
274541
}
275542

543+
static int ne_netstat_exit(struct flb_ne *ctx)
544+
{
545+
if (ctx != NULL) {
546+
netstat_dynamic_metrics_destroy(ctx);
547+
}
548+
549+
return 0;
550+
}
551+
276552
struct flb_ne_collector netstat_collector = {
277553
.name = "netstat",
278554
.cb_init = ne_netstat_init,
279555
.cb_update = ne_netstat_update,
280-
.cb_exit = NULL
556+
.cb_exit = ne_netstat_exit
281557
};
282-

0 commit comments

Comments
 (0)