added nfacct charts (disabled for the moment - they must be made an external plugin since nfacct requires root access); fixed a rounding problem in long double values by linking with the math library
Costa Tsaousis (ktsaou) committed
Mar 19, 2015 at 01:54 UTC
b5462c8c6d4a6b8d7a8c2fda68d4cf2569e164a3
10 files changed
+180
-91
src/Makefile
+10
-1
@@ -27,6 +27,15 @@ CC = gcc
27
28
proc_sources = proc_net_dev.c proc_net_ip_vs_stats.c proc_diskstats.c proc_meminfo.c proc_net_netstat.c proc_net_snmp.c proc_net_stat_conntrack.c proc_stat.c proc_vmstat.c proc_net_rpc_nfsd.c
29
sources = procfile.c common.c log.c popen.c url.c config.c web_buffer.c storage_number.c web_client.c global_statistics.c rrd.c rrd2json.c web_server.c plugins_d.c daemon.c plugin_tc.c plugin_checks.c plugin_idlejitter.c plugin_proc.c unit_test.c main.c
30
+libs = -pthread -lz -lm
31
+
32
+# nfacct requires root access, so we prefer it as a plugin.d external plugin
33
+ifdef INTERNAL_PLUGIN_NFACCT
34
+CFLAGS += -DINTERNAL_PLUGIN_NFACCT=1
35
+sources += plugin_nfacct.c
36
+libs += -lmnl -lnetfilter_acct
37
+endif
38
+
39
headers = $(patsubst %.c,%.h,$(sources))
40
objects = $(patsubst %.c,%.o,$(sources) $(proc_sources))
41
@@ -38,7 +47,7 @@ all: options netdata plugins
47
48
netdata: $(objects)
49
@echo " $(CC) netdata"
41
- @$(CC) -o netdata $(objects) -pthread -lz
50
+ @$(CC) -o netdata $(objects) $(libs)
51
52
.PHONY: plugins
53
plugins:
src/log.h
+1
@@ -19,6 +19,7 @@
19
#define D_CHILDS 0x00001000
20
#define D_EXIT 0x00002000
21
#define D_CHECKS 0x00004000
22
+#define D_NFACCT_LOOP 0x00008000
23
24
#define DEBUG (D_WEB_CLIENT_ACCESS|D_LISTENER|D_RRD_STATS)
25
//#define DEBUG 0xffffffff
src/main.c
+35
-18
@@ -25,6 +25,7 @@
25
#include "plugin_tc.h"
26
#include "plugin_checks.h"
27
#include "plugin_proc.h"
28
+#include "plugin_nfacct.h"
29
30
#include "main.h"
31
@@ -37,17 +38,26 @@ struct netdata_static_thread {
38
int enabled;
39
40
pthread_t *thread;
41
+
42
+ void (*init_routine) (void);
43
void *(*start_routine) (void *);
44
};
45
46
struct netdata_static_thread static_threads[] = {
44
- {"tc", "plugins", "tc", 1, NULL, tc_main},
45
- {"idlejitter", "plugins", "idlejitter", 1, NULL, cpuidlejitter_main},
46
- {"proc", "plugins", "proc", 1, NULL, proc_main},
47
- {"plugins.d", NULL, NULL, 1, NULL, pluginsd_main},
48
- {"check", "plugins", "checks", 0, NULL, checks_main},
49
- {"web", NULL, NULL, 1, NULL, socket_listen_main},
50
- {NULL, NULL, NULL, 0, NULL, NULL}
47
+ {"tc", "plugins", "tc", 1, NULL, NULL, tc_main},
48
+ {"idlejitter", "plugins", "idlejitter", 1, NULL, NULL, cpuidlejitter_main},
49
+ {"proc", "plugins", "proc", 1, NULL, NULL, proc_main},
50
+
51
+#ifdef INTERNAL_PLUGIN_NFACCT
52
+ // nfacct requires root access
53
+ // so, we build it as an external plugin with setuid to root
54
+ {"nfacct", "plugins", "nfacct", 1, NULL, NULL, nfacct_main},
55
+#endif
56
+
57
+ {"plugins.d", NULL, NULL, 1, NULL, NULL, pluginsd_main},
58
+ {"check", "plugins", "checks", 0, NULL, NULL, checks_main},
59
+ {"web", NULL, NULL, 1, NULL, NULL, socket_listen_main},
60
+ {NULL, NULL, NULL, 0, NULL, NULL, NULL}
61
};
62
63
void kill_childs()
@@ -231,6 +241,24 @@ int main(int argc, char **argv)
241
242
// --------------------------------------------------------------------
243
244
+ update_every = config_get_number("global", "update every", UPDATE_EVERY);
245
+ if(update_every < 1 || update_every > 600) {
246
+ fprintf(stderr, "Invalid update timer %d given. Defaulting to %d.\n", update_every, UPDATE_EVERY_MAX);
247
+ update_every = UPDATE_EVERY;
248
+ }
249
+ else debug(D_OPTIONS, "update timer set to %d.", update_every);
250
+
251
+ // --------------------------------------------------------------------
252
+
253
+ for (i = 0; static_threads[i].name != NULL ; i++) {
254
+ struct netdata_static_thread *st = &static_threads[i];
255
+
256
+ if(st->config_name) st->enabled = config_get_boolean(st->config_section, st->config_name, st->enabled);
257
+ if(st->enabled && st->init_routine) st->init_routine();
258
+ }
259
+
260
+ // --------------------------------------------------------------------
261
+
262
prepare_rundir();
263
char *user = config_get("global", "run as user", (getuid() == 0)?"nobody":"");
264
if(*user) {
@@ -243,15 +271,6 @@ int main(int argc, char **argv)
271
272
// --------------------------------------------------------------------
273
246
- update_every = config_get_number("global", "update every", UPDATE_EVERY);
247
- if(update_every < 1 || update_every > 600) {
248
- fprintf(stderr, "Invalid update timer %d given. Defaulting to %d.\n", update_every, UPDATE_EVERY_MAX);
249
- update_every = UPDATE_EVERY;
250
- }
251
- else debug(D_OPTIONS, "update timer set to %d.", update_every);
252
-
253
- // --------------------------------------------------------------------
254
-
274
listen_port = config_get_number("global", "port", LISTEN_PORT);
275
if(listen_port < 1 || listen_port > 65535) {
276
fprintf(stderr, "Invalid listen port %d given. Defaulting to %d.\n", listen_port, LISTEN_PORT);
@@ -285,8 +304,6 @@ int main(int argc, char **argv)
304
for (i = 0; static_threads[i].name != NULL ; i++) {
305
struct netdata_static_thread *st = &static_threads[i];
306
288
- if(st->config_name) st->enabled = config_get_boolean(st->config_section, st->config_name, st->enabled);
289
-
307
if(st->enabled) {
308
st->thread = malloc(sizeof(pthread_t));
309
src/proc_net_stat_conntrack.c
+9
-9
@@ -9,7 +9,7 @@
9
#include "rrd.h"
10
#include "plugin_proc.h"
11
12
-#define RRD_TYPE_NET_STAT_CONNTRACK "conntrack"
12
+#define RRD_TYPE_NET_STAT_CONNTRACK "netfilter"
13
#define RRD_TYPE_NET_STAT_CONNTRACK_LEN strlen(RRD_TYPE_NET_STAT_CONNTRACK)
14
15
int do_proc_net_stat_conntrack(int update_every, unsigned long long dt) {
@@ -67,16 +67,16 @@ int do_proc_net_stat_conntrack(int update_every, unsigned long long dt) {
67
if(!aentries) aentries = tentries;
68
69
// sum all the cpus together
70
- asearched += tsearched; // conntrack.search
71
- afound += tfound; // conntrack.search
72
- anew += tnew; // conntrack.new
73
- ainvalid += tinvalid; // conntrack.new
74
- aignore += tignore; // conntrack.new
75
- adelete += tdelete; // conntrack.changes
70
+ asearched += tsearched; // conntrack.search
71
+ afound += tfound; // conntrack.search
72
+ anew += tnew; // conntrack.new
73
+ ainvalid += tinvalid; // conntrack.new
74
+ aignore += tignore; // conntrack.new
75
+ adelete += tdelete; // conntrack.changes
76
adelete_list += tdelete_list; // conntrack.changes
77
- ainsert += tinsert; // conntrack.changes
77
+ ainsert += tinsert; // conntrack.changes
78
ainsert_failed += tinsert_failed; // conntrack.errors
79
- adrop += tdrop; // conntrack.errors
79
+ adrop += tdrop; // conntrack.errors
80
aearly_drop += tearly_drop; // conntrack.errors
81
aicmp_error += ticmp_error; // conntrack.errors
82
aexpect_new += texpect_new; // conntrack.expect
src/rrd.c
+1
-1
@@ -582,7 +582,7 @@ void rrd_stats_dimension_set_by_pointer(RRD_STATS *st, RRD_DIMENSION *rd, collec
582
rd->collected_value = value;
583
}
584
585
-int rrd_stats_dimension_set(RRD_STATS *st, char *id, collected_number value)
585
+int rrd_stats_dimension_set(RRD_STATS *st, const char *id, collected_number value)
586
{
587
RRD_DIMENSION *rd = rrd_stats_dimension_find(st, id);
588
if(!rd) {
src/rrd.h
+45
-45
@@ -74,77 +74,77 @@ extern const char *algorithm_name(int chart_type);
74
75
struct rrd_dimension {
76
char magic[sizeof(RRD_DIMENSION_MAGIC) + 1]; // our magic
77
- char id[RRD_STATS_NAME_MAX + 1]; // the id of this dimension (for internal identification)
78
- char *name; // the name of this dimension (as presented to user)
77
+ char id[RRD_STATS_NAME_MAX + 1]; // the id of this dimension (for internal identification)
78
+ char *name; // the name of this dimension (as presented to user)
79
char cache_file[FILENAME_MAX+1];
80
81
- unsigned long hash; // a simple hash on the id, to speed up searching
82
- // we first compare hashes, and only if the hashes are equal we do string comparisons
81
+ unsigned long hash; // a simple hash on the id, to speed up searching
82
+ // we first compare hashes, and only if the hashes are equal we do string comparisons
83
84
- long entries; // how many entries this dimension has
85
- // this should be the same to the entries of the data set
84
+ long entries; // how many entries this dimension has
85
+ // this should be the same to the entries of the data set
86
87
- long current_entry; // the entry that is currently being updated
88
- int update_every; // every how many seconds is this updated?
87
+ long current_entry; // the entry that is currently being updated
88
+ int update_every; // every how many seconds is this updated?
89
90
- int hidden; // if set to non zero, this dimension will not be sent to the client
91
- int mapped; // 1 if the file is mapped
92
- unsigned long memsize; // the memory allocated for this dimension
90
+ int hidden; // if set to non zero, this dimension will not be sent to the client
91
+ int mapped; // 1 if the file is mapped
92
+ unsigned long memsize; // the memory allocated for this dimension
93
94
int algorithm;
95
long multiplier;
96
long divisor;
97
98
- struct timeval last_collected_time; // when was this dimension last updated
99
- // this is only used to detect un-updated dimensions
100
- // which are removed after some time
98
+ struct timeval last_collected_time; // when was this dimension last updated
99
+ // this is only used to detect un-updated dimensions
100
+ // which are removed after some time
101
102
calculated_number calculated_value;
103
calculated_number last_calculated_value;
104
105
- collected_number collected_value; // the value collected at this round
106
- collected_number last_collected_value; // the value that was collected at the last round
105
+ collected_number collected_value; // the value collected at this round
106
+ collected_number last_collected_value; // the value that was collected at the last round
107
108
- struct rrd_dimension *next; // linking of dimensions within the same data set
108
+ struct rrd_dimension *next; // linking of dimensions within the same data set
109
110
- storage_number values[]; // the array of values - THIS HAS TO BE THE LAST MEMBER
110
+ storage_number values[]; // the array of values - THIS HAS TO BE THE LAST MEMBER
111
};
112
typedef struct rrd_dimension RRD_DIMENSION;
113
114
struct rrd_stats {
115
- char magic[sizeof(RRD_STATS_MAGIC) + 1]; // our magic
115
+ char magic[sizeof(RRD_STATS_MAGIC) + 1]; // our magic
116
117
- char id[RRD_STATS_NAME_MAX + 1]; // id of the data set
118
- char *name; // name of the data set
119
- char *cache_dir; // the directory to store dimension maps
117
+ char id[RRD_STATS_NAME_MAX + 1]; // id of the data set
118
+ char *name; // name of the data set
119
+ char *cache_dir; // the directory to store dimension maps
120
char cache_file[FILENAME_MAX+1];
121
122
- char *type; // the type of graph RRD_TYPE_* (a category, for determining graphing options)
123
- char *family; // the family of this data set (for grouping them together)
124
- char *title; // title shown to user
125
- char *units; // units of measurement
122
+ char *type; // the type of graph RRD_TYPE_* (a category, for determining graphing options)
123
+ char *family; // the family of this data set (for grouping them together)
124
+ char *title; // title shown to user
125
+ char *units; // units of measurement
126
127
pthread_rwlock_t rwlock;
128
- unsigned long counter; // the number of times we added values to this rrd
129
- unsigned long counter_done; // the number of times we added values to this rrd
128
+ unsigned long counter; // the number of times we added values to this rrd
129
+ unsigned long counter_done; // the number of times we added values to this rrd
130
131
- int mapped; // if set to 1, this is memory mapped
132
- unsigned long memsize; // how much mem we have allocated for this (without dimensions)
131
+ int mapped; // if set to 1, this is memory mapped
132
+ unsigned long memsize; // how much mem we have allocated for this (without dimensions)
133
134
- unsigned long hash_name; // a simple hash on the name
135
- unsigned long hash; // a simple hash on the id, to speed up searching
136
- // we first compare hashes, and only if the hashes are equal we do string comparisons
134
+ unsigned long hash_name; // a simple hash on the name
135
+ unsigned long hash; // a simple hash on the id, to speed up searching
136
+ // we first compare hashes, and only if the hashes are equal we do string comparisons
137
138
long priority;
139
140
- long entries; // total number of entries in the data set
141
- long current_entry; // the entry that is currently being updated
142
- // it goes around in a round-robin fashion
140
+ long entries; // total number of entries in the data set
141
+ long current_entry; // the entry that is currently being updated
142
+ // it goes around in a round-robin fashion
143
144
- int update_every; // every how many seconds is this updated?
145
- unsigned long long first_entry_t; // the timestamp (in microseconds) of the oldest entry in the db
146
- struct timeval last_updated; // when this data set was last updated (updated every time the rrd_stats_done() function)
147
- struct timeval last_collected_time; //
144
+ int update_every; // every how many seconds is this updated?
145
+ unsigned long long first_entry_t; // the timestamp (in microseconds) of the oldest entry in the db
146
+ struct timeval last_updated; // when this data set was last updated (updated every time the rrd_stats_done() function)
147
+ struct timeval last_collected_time; //
148
unsigned long long usec_since_last_update;
149
150
total_number collected_total;
@@ -153,12 +153,12 @@ struct rrd_stats {
153
int chart_type;
154
int debug;
155
int enabled;
156
- int isdetail; // if set, the data set should be considered as a detail of another
157
- // (the master data set should be the one that has the same family and is not detail)
156
+ int isdetail; // if set, the data set should be considered as a detail of another
157
+ // (the master data set should be the one that has the same family and is not detail)
158
159
- RRD_DIMENSION *dimensions; // the actual data for every dimension
159
+ RRD_DIMENSION *dimensions; // the actual data for every dimension
160
161
- struct rrd_stats *next; // linking of rrd stats
161
+ struct rrd_stats *next; // linking of rrd stats
162
};
163
typedef struct rrd_stats RRD_STATS;
164
@@ -191,7 +191,7 @@ extern RRD_DIMENSION *rrd_stats_dimension_find(RRD_STATS *st, const char *id);
191
extern int rrd_stats_dimension_hide(RRD_STATS *st, const char *id);
192
193
extern void rrd_stats_dimension_set_by_pointer(RRD_STATS *st, RRD_DIMENSION *rd, collected_number value);
194
-extern int rrd_stats_dimension_set(RRD_STATS *st, char *id, collected_number value);
194
+extern int rrd_stats_dimension_set(RRD_STATS *st, const char *id, collected_number value);
195
196
extern void rrd_stats_next_usec(RRD_STATS *st, unsigned long long microseconds);
197
extern void rrd_stats_next(RRD_STATS *st);
src/storage_number.c
+5
@@ -1,3 +1,4 @@
1
+#include <math.h>
2
3
#include "log.h"
4
#include "storage_number.h"
@@ -44,6 +45,10 @@ storage_number pack_storage_number(calculated_number value)
45
46
mul = m;
47
48
+ // without this there are rounding problems
49
+ // example: 0.9 becomes 0.89
50
+ n = lrint(n);
51
+
52
r = (sign << 31) + (exp << 30) + (mul << 27) + n;
53
// fprintf(stderr, "PACK: %08X, sign = %d, exp = %d, mul = %d, n = " CALCULATED_NUMBER_FORMAT "\n", r, sign, exp, mul, n);
54
src/unit_test.c
+33
-6
@@ -1,4 +1,5 @@
1
#include <stdio.h>
2
+#include <stdlib.h>
3
4
#include "storage_number.h"
5
#include "rrd.h"
@@ -7,9 +8,9 @@
8
9
int unit_test_storage()
10
{
10
- char buffer[100];
11
+ char buffer[100], *msg;
12
storage_number s;
12
- calculated_number c, a = 0, d, f;
13
+ calculated_number c, a = 0, d, ddiff, dcdiff, f, p, pdiff, pcdiff, maxddiff = 0, maxpdiff = 0;
14
int i, j, g, r = 0, l;
15
16
for(g = -1; g <= 1 ; g++) {
@@ -21,24 +22,50 @@ int unit_test_storage()
22
a += 0.0000001;
23
c = a * g;
24
for(i = 0; i < 21 ;i++, c *= 10) {
25
+ if(c > 0 && c < 0.00001) continue;
26
+ if(c < 0 && c > -0.00001) continue;
27
+
28
s = pack_storage_number(c);
29
d = unpack_storage_number(s);
30
31
+ ddiff = d - c;
32
+ dcdiff = ddiff * 100.0 / c;
33
+ if(dcdiff < 0) dcdiff = -dcdiff;
34
+ if(dcdiff > maxddiff) maxddiff = dcdiff;
35
+
36
f = d / c;
37
38
l = print_calculated_number(buffer, d);
39
+ p = strtold(buffer, NULL);
40
+ pdiff = c - p;
41
+ pcdiff = pdiff * 100.0 / c;
42
+ if(pcdiff < 0) pcdiff = -pcdiff;
43
+ if(pcdiff > maxpdiff) maxpdiff = pcdiff;
44
45
if(f < 0.99999 || f > 1.00001) {
32
- fprintf(stderr, "\nERROR\n" CALCULATED_NUMBER_FORMAT " original\n" CALCULATED_NUMBER_FORMAT " unpacked, (stored as 0x%08X)\n%s printed as %d bytes\n", c, d, s, buffer, l);
46
+ msg = "ERROR";
47
r++;
48
}
35
- else {
36
- fprintf(stderr, "\nOK\n" CALCULATED_NUMBER_FORMAT " original\n" CALCULATED_NUMBER_FORMAT " unpacked, (stored as 0x%08X)\n%s printed as %d bytes\n", c, d, s, buffer, l);
37
- }
49
+ else msg = "OK";
50
+
51
+ fprintf(stderr, "%s\n"
52
+ CALCULATED_NUMBER_FORMAT " original\n"
53
+ CALCULATED_NUMBER_FORMAT " unpacked, (stored as 0x%08X, diff " CALCULATED_NUMBER_FORMAT ", " CALCULATED_NUMBER_FORMAT "%%)\n"
54
+ "%s printed (%d bytes)\n"
55
+ CALCULATED_NUMBER_FORMAT " re-parsed with diff " CALCULATED_NUMBER_FORMAT ", " CALCULATED_NUMBER_FORMAT "%%\n\n",
56
+ msg,
57
+ c,
58
+ d, s, ddiff, dcdiff,
59
+ buffer,
60
+ l, p, pdiff, pcdiff
61
+ );
62
}
63
}
64
}
65
66
+ fprintf(stderr, "Worst accuracy loss on unpacked numbers: " CALCULATED_NUMBER_FORMAT "%%\n", maxddiff);
67
+ fprintf(stderr, "Worst accuracy loss on printed numbers: " CALCULATED_NUMBER_FORMAT "%%\n", maxpdiff);
68
+
69
return r;
70
}
71
src/web_buffer.c
+24
-8
@@ -1,4 +1,5 @@
1
#include <stdlib.h>
2
+#include <math.h>
3
4
#include "web_buffer.h"
5
@@ -20,35 +21,50 @@ int print_calculated_number(char *str, calculated_number value)
21
{
22
char *wstr = str;
23
23
- // make sure it is unsigned
24
- unsigned long long uvalue = (unsigned long long)(((value < 0) ? -value : value) * (calculated_number)10000);
24
+ int sign = (value < 0) ? 1 : 0;
25
+ if(sign) value = -value;
26
+
27
+ // without llrint() there are rounding problems
28
+ // for example 0.9 becomes 0.89
29
+ unsigned long long uvalue = llrint(value * (calculated_number)100000);
30
31
// print each digit
32
do *wstr++ = (char)(48 + (uvalue % 10)); while(uvalue /= 10);
33
29
- // make sure we have 8 bytes at least
30
- while((wstr - str) < 5) *wstr++ = '0';
34
+ // make sure we have 6 bytes at least
35
+ while((wstr - str) < 6) *wstr++ = '0';
36
37
// put the sign back
33
- if (value < 0) *wstr++ = '-';
38
+ if(sign) *wstr++ = '-';
39
40
// reverse it
41
wstr--;
42
strreverse(str, wstr);
43
44
+ // remove trailing zeros
45
+ int decimal = 5;
46
+ while(decimal > 0 && *wstr == '0') {
47
+ *wstr-- = '\0';
48
+ decimal--;
49
+ }
50
+
51
// terminate it, one position to the right
52
// to let space for a dot
53
wstr[2] = '\0';
54
55
+ // make space for the dot
56
int i;
44
- for(i = 0; i < 4 ;i++) {
57
+ for(i = 0; i < decimal ;i++) {
58
wstr[1] = wstr[0];
59
wstr--;
60
}
48
- wstr[1] = '.';
61
+
62
+ // put the dot
63
+ if(wstr[2] == '\0') { wstr[1] = '\0'; decimal--; }
64
+ else wstr[1] = '.';
65
66
// return the buffer length
51
- return ( (wstr - str) + 6 );
67
+ return ( (wstr - str) + 2 + decimal );
68
}
69
70
void web_buffer_rrd_value(struct web_buffer *wb, calculated_number value)
web/netdata.js
+17
-3
@@ -317,20 +317,20 @@ function loadCharts(base_url, doNext) {
317
break;
318
319
case "tc":
320
- json.charts[i].category = "QoS";
320
+ json.charts[i].category = "Quality of Service";
321
json.charts[i].categoryPriority = 30;
322
json.charts[i].glyphicon = "glyphicon-random";
323
json.charts[i].group = 15;
324
break;
325
326
case "ipvs":
327
- json.charts[i].category = "IPVS";
327
+ json.charts[i].category = "IP Virtual Server";
328
json.charts[i].categoryPriority = 40;
329
json.charts[i].glyphicon = "glyphicon-sort";
330
json.charts[i].group = 5;
331
break;
332
333
- case "conntrack":
333
+ case "netfilter":
334
json.charts[i].category = "Netfilter";
335
json.charts[i].categoryPriority = 50;
336
json.charts[i].glyphicon = "glyphicon-cloud";
@@ -370,6 +370,20 @@ function loadCharts(base_url, doNext) {
370
json.charts[i].group = 5;
371
break;
372
373
+ case "nfsd":
374
+ json.charts[i].category = "NFS Server";
375
+ json.charts[i].categoryPriority = 100;
376
+ json.charts[i].glyphicon = "glyphicon-hdd";
377
+ json.charts[i].group = 5;
378
+ break;
379
+
380
+ case "nut":
381
+ json.charts[i].category = "UPS";
382
+ json.charts[i].categoryPriority = 110;
383
+ json.charts[i].glyphicon = "glyphicon-dashboard";
384
+ json.charts[i].group = 5;
385
+ break;
386
+
387
case "netdata":
388
json.charts[i].category = "NetData";
389
json.charts[i].categoryPriority = 3000;