@cryptotaxi247 / netdata-1 / commits / b5462c8c6

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;