added netdata info at the footer, added cpu.netdata chart, added memory consumption info all.json
Costa Tsaousis (ktsaou) committed
Apr 26, 2014 at 01:05 UTC
9d7f917378d208d26095484b7d3bf247006dd8da
4 files changed
+134
-38
netdata.c
+100
-20
@@ -108,6 +108,9 @@
108
//#define DEBUG 0xffffffff
109
//#define DEBUG (0)
110
111
+#define HOSTNAME_MAX 1024
112
+char hostname[HOSTNAME_MAX + 1];
113
+
114
unsigned long long debug_flags = DEBUG;
115
char *debug_log = NULL;
116
int debug_fd = -1;
@@ -390,8 +393,6 @@ struct rrd_stats {
393
char envtitle[RRD_STATS_NAME_MAX + 1]; // the variable name for taking the title
394
char envpriority[RRD_STATS_NAME_MAX + 1]; // the variable name for taking the priority
395
393
- char hostname[RRD_STATS_NAME_MAX + 1]; // the host this data set belongs to
394
-
396
size_t entries; // total number of entries in the data set
397
size_t current_entry; // the entry that is currently being updated
398
// it goes around in a round-robin fashion
@@ -484,9 +485,6 @@ RRD_STATS *rrd_stats_create(const char *type, const char *id, const char *name,
485
if(p) strncpy(st->userpriority, p, RRD_STATS_NAME_MAX);
486
else strncpy(st->userpriority, st->name, RRD_STATS_NAME_MAX);
487
487
- if(gethostname(st->hostname, RRD_STATS_NAME_MAX) == -1)
488
- error("Cannot get hostname.");
489
-
488
st->entries = entries;
489
st->current_entry = 0;
490
// st->last_entry = 0;
@@ -965,7 +963,7 @@ size_t rrd_stats_first_entry(RRD_STATS *st)
963
return first_entry;
964
}
965
968
-void rrd_stats_one_json(RRD_STATS *st, char *options, struct web_buffer *wb)
966
+unsigned long rrd_stats_one_json(RRD_STATS *st, char *options, struct web_buffer *wb)
967
{
968
web_buffer_increase(wb, 16384);
969
@@ -987,22 +985,70 @@ void rrd_stats_one_json(RRD_STATS *st, char *options, struct web_buffer *wb)
985
wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"usertitle\" : \"%s %s (%s)\",\n", st->title, st->usertitle, st->name);
986
987
wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"userpriority\" : \"%s\",\n", st->userpriority);
990
- wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"envtitle\" : \"%s\",\n", st->envtitle);
991
- wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"envpriority\" : \"%s\",\n", st->envpriority);
992
- wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"hostname\" : \"%s\",\n", st->hostname);
988
+ //wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"envtitle\" : \"%s\",\n", st->envtitle);
989
+ //wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"envpriority\" : \"%s\",\n", st->envpriority);
990
wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"units\" : \"%s\",\n", st->units);
991
wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"url\" : \"/data/%s/%s\",\n", st->name, options?options:"");
992
wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"entries\" : %ld,\n", st->entries);
996
- wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"first_entry\" : %ld,\n", first_entry);
993
+ //wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"first_entry\" : %ld,\n", first_entry);
994
wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"first_entry_t\" : %ld,\n", first_entry_t);
998
- wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"last_entry\" : %ld,\n", st->current_entry);
995
+ //wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"last_entry\" : %ld,\n", st->current_entry);
996
wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"last_entry_t\" : %lu,\n", st->last_updated);
1000
- wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"last_entry_secs_ago\" : %lu,\n", time(NULL) - st->last_updated);
997
+ //wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"last_entry_secs_ago\" : %lu,\n", time(NULL) - st->last_updated);
998
wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"update_every\" : %d,\n", update_every);
1002
- wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"isdetail\" : %d\n", st->isdetail);
999
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"isdetail\" : %d,\n", st->isdetail);
1000
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"dimensions\" : [\n");
1001
+
1002
+ unsigned long memory = sizeof(RRD_STATS) + (sizeof(struct timeval) * st->entries);
1003
+
1004
+ RRD_DIMENSION *rd;
1005
+ for(rd = st->dimensions; rd ; rd = rd->next) {
1006
+ unsigned long rdmem = sizeof(RRD_DIMENSION) + (rd->bytes * rd->entries);
1007
+ memory += rdmem;
1008
+
1009
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\t{\n");
1010
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\t\t\"id\" : \"%s\",\n", rd->id);
1011
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\t\t\"name\" : \"%s\",\n", rd->name);
1012
+ //wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\t\t\"bytes\" : %ld,\n", rd->bytes);
1013
+ //wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\t\t\"entries\" : %ld,\n", rd->entries);
1014
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\t\t\"isSigned\" : %d,\n", rd->issigned);
1015
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\t\t\"isHidden\" : %d,\n", rd->hidden);
1016
+
1017
+ switch(rd->type) {
1018
+ case RRD_DIMENSION_INCREMENTAL:
1019
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\t\t\"type\" : \"%s\",\n", "incremental");
1020
+ break;
1021
+
1022
+ case RRD_DIMENSION_ABSOLUTE:
1023
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\t\t\"type\" : \"%s\",\n", "absolute");
1024
+ break;
1025
+
1026
+ case RRD_DIMENSION_PCENT_OVER_DIFF_TOTAL:
1027
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\t\t\"type\" : \"%s\",\n", "percent on incremental total");
1028
+ break;
1029
+
1030
+ case RRD_DIMENSION_PCENT_OVER_ROW_TOTAL:
1031
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\t\t\"type\" : \"%s\",\n", "percent on absolute total");
1032
+ break;
1033
+
1034
+ default:
1035
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\t\t\"type\" : %d,\n", rd->type);
1036
+ break;
1037
+ }
1038
+
1039
+ //wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\t\t\"multiplier\" : %ld,\n", rd->multiplier);
1040
+ //wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\t\t\"divisor\" : %ld,\n", rd->divisor);
1041
+ //wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\t\t\"last_entry_t\" : %lu,\n", rd->last_updated);
1042
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\t\t\"memory\" : %lu\n", rdmem);
1043
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\t}%s\n", rd->next?",":"");
1044
+ }
1045
+
1046
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t],\n");
1047
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"memory\" : %lu\n", memory);
1048
wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t}");
1049
1050
pthread_mutex_unlock(&st->mutex);
1051
+ return memory;
1052
}
1053
1054
#define RRD_GRAPH_JSON_HEADER "{\n\t\"charts\": [\n"
@@ -1019,8 +1065,9 @@ void rrd_stats_graph_json(RRD_STATS *st, char *options, struct web_buffer *wb)
1065
1066
void rrd_stats_all_json(struct web_buffer *wb)
1067
{
1022
- web_buffer_increase(wb, 16384);
1068
+ web_buffer_increase(wb, 150000);
1069
1070
+ unsigned long memory = 0;
1071
size_t c;
1072
RRD_STATS *st;
1073
@@ -1028,10 +1075,15 @@ void rrd_stats_all_json(struct web_buffer *wb)
1075
1076
for(st = root, c = 0; st ; st = st->next, c++) {
1077
if(c) wb->bytes += sprintf(&wb->buffer[wb->bytes], "%s", ",\n");
1031
- rrd_stats_one_json(st, NULL, wb);
1078
+ memory += rrd_stats_one_json(st, NULL, wb);
1079
}
1080
1034
- wb->bytes += sprintf(&wb->buffer[wb->bytes], RRD_GRAPH_JSON_FOOTER);
1081
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\n\t],\n");
1082
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\"hostname\": \"%s\",\n", hostname);
1083
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\"update_every\": %d,\n", update_every);
1084
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\"history\": %d,\n", save_history);
1085
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\"memory\": %lu\n", memory);
1086
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "}\n");
1087
}
1088
1089
long double rrd_stats_dimension_get(RRD_DIMENSION *rd, size_t position)
@@ -4074,7 +4126,7 @@ int do_proc_vmstat() {
4126
st->isdetail = 1;
4127
4128
rrd_stats_dimension_add(st, "minor", NULL, sizeof(unsigned long long), 0, 1, 1, RRD_DIMENSION_INCREMENTAL, NULL);
4077
- rrd_stats_dimension_add(st, "major", NULL, sizeof(unsigned long long), 0, 1, 1, RRD_DIMENSION_INCREMENTAL, NULL);
4129
+ rrd_stats_dimension_add(st, "major", NULL, sizeof(unsigned long long), 0, -1, 1, RRD_DIMENSION_INCREMENTAL, NULL);
4130
}
4131
else rrd_stats_next(st);
4132
@@ -4090,6 +4142,7 @@ int do_proc_vmstat() {
4142
4143
void *proc_main(void *ptr)
4144
{
4145
+ struct rusage me, me_last;
4146
struct timeval last, now;
4147
4148
gettimeofday(&last, NULL);
@@ -4106,7 +4159,11 @@ void *proc_main(void *ptr)
4159
int vdo_proc_meminfo = 0;
4160
int vdo_proc_vmstat = 0;
4161
4162
+ RRD_STATS *stcpu = NULL;
4163
+
4164
gettimeofday(&last, NULL);
4165
+ getrusage(RUSAGE_SELF, &me_last);
4166
+
4167
unsigned long long usec = 0, susec = 0;
4168
for(;1;) {
4169
@@ -4122,6 +4179,8 @@ void *proc_main(void *ptr)
4179
if(!vdo_proc_vmstat) vdo_proc_vmstat = do_proc_vmstat(usec);
4180
// END -- the job is done
4181
4182
+ getrusage(RUSAGE_SELF, &me);
4183
+
4184
// find the time to sleep in order to wait exactly update_every seconds
4185
gettimeofday(&now, NULL);
4186
usec = usecdiff(&now, &last) - susec;
@@ -4133,11 +4192,29 @@ void *proc_main(void *ptr)
4192
// make sure we will wait at least 100ms
4193
if(susec < 100000) susec = 100000;
4194
4195
+ // --------------------------------------------------------------------
4196
+
4197
+ unsigned long long cpuuser = usecdiff(&me.ru_utime, &me_last.ru_utime) * (usec + susec) / (update_every * 1000000);
4198
+ unsigned long long cpusyst = usecdiff(&me.ru_stime, &me_last.ru_stime) * (usec + susec) / (update_every * 1000000);
4199
+
4200
+ if(!stcpu) stcpu = rrd_stats_find("cpu.netdata");
4201
+ if(!stcpu) {
4202
+ stcpu = rrd_stats_create("cpu", "netdata", NULL, "cpu", "NetData CPU usage", "milliseconds/s", save_history);
4203
+
4204
+ rrd_stats_dimension_add(stcpu, "user", NULL, sizeof(unsigned long long), 0, 1, 1000, RRD_DIMENSION_ABSOLUTE, NULL);
4205
+ rrd_stats_dimension_add(stcpu, "system", NULL, sizeof(unsigned long long), 0, 1, 1000, RRD_DIMENSION_ABSOLUTE, NULL);
4206
+ }
4207
+ else rrd_stats_next(stcpu);
4208
+
4209
+ rrd_stats_dimension_set(stcpu, "user", &cpuuser, NULL);
4210
+ rrd_stats_dimension_set(stcpu, "system", &cpusyst, NULL);
4211
+ rrd_stats_done(stcpu);
4212
+
4213
usleep(susec);
4214
4138
- // copy now to last
4139
- last.tv_sec = now.tv_sec;
4140
- last.tv_usec = now.tv_usec;
4215
+ // copy current to last
4216
+ bcopy(&me, &me_last, sizeof(struct rusage));
4217
+ bcopy(&now, &last, sizeof(struct timeval));
4218
}
4219
4220
return NULL;
@@ -4665,6 +4742,9 @@ int main(int argc, char **argv)
4742
}
4743
}
4744
4745
+ if(gethostname(hostname, HOSTNAME_MAX) == -1)
4746
+ error("WARNING: Cannot get machine hostname.");
4747
+
4748
// never become a problem
4749
if(nice(20) == -1) {
4750
fprintf(stderr, "Cannot lower my CPU priority. Error: %s.\n", strerror(errno));
web/index.html
+3
-1
@@ -139,7 +139,9 @@
139
Distributed under GPL.
140
<p/>
141
(c) 2014 Costa Tsaousis <a href="mailto:costa@tsaousis.gr">costa@tsaousis.gr</a>
142
- </div>
142
+ <p/>
143
+ <div id="server_summary_id"></div>
144
+ </div>
145
146
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
147
<script type='text/javascript'>
web/index.js
+8
-11
@@ -32,13 +32,6 @@ var mainmenu = "";
32
// ------------------------------------------------------------------------
33
// common HTML generation
34
35
-function chartIsLoadingHTML(name, width, height) { return "<table><tr><td align=\"center\" width=\"" + width + "\" height=\"" + height + "\" style=\"vertical-align:middle\"><h4><span class=\"glyphicon glyphicon-refresh\"></span><br/><br/>loading " + name + "<br/><br/><span class=\"label label-default\">Please wait...</span></h4></td></tr></table>"; }
36
-
37
-function showChartIsLoading(id, name, width, height) {
38
- //mylog('adding loading chart html in div with id ' + id);
39
- document.getElementById(id).innerHTML = chartIsLoadingHTML(name, width, height);
40
-}
41
-
35
function thumbChartActions(i, c, nogroup) {
36
var name = c.name;
37
if(!nogroup) name = c.group_tag;
@@ -841,8 +834,8 @@ function initCharts() {
834
var width = thumbWidth();
835
var height = TARGET_THUMB_GRAPH_HEIGHT;
836
844
- loadCharts(null, function(c) {
845
- mycharts = c;
837
+ loadCharts(null, function(all) {
838
+ mycharts = all.charts;
839
840
if(mycharts == null || mycharts.length == 0) {
841
alert("Cannot load data from server.");
@@ -857,12 +850,14 @@ function initCharts() {
850
851
mycharts.sort(chartssort);
852
860
- document.getElementById('hostname_id').innerHTML = mycharts[0].hostname;
861
- document.title = mycharts[0].hostname;
853
+ document.getElementById('hostname_id').innerHTML = all.hostname;
854
+ document.title = all.hostname;
855
856
// create an array for grouping all same-type graphs together
857
+ var dimensions = 0;
858
var categories = new Array();
859
$.each(mycharts, function(i, c) {
860
+ dimensions += c.dimensions.length;
861
c.chartOptions.width = width;
862
c.chartOptions.height = height;
863
@@ -893,6 +888,8 @@ function initCharts() {
888
}
889
});
890
891
+ document.getElementById('server_summary_id').innerHTML = "<small>NetData server at <b>" + all.hostname + "</b> is maintaining <b>" + mycharts.length + "</b> charts, having <b>" + dimensions + "</b> dimensions of <b>" + all.history + "</b> entries each, which are updated every <b>" + all.update_every + "s</b>, using a total of <b>" + (Math.round(all.memory * 10 / 1024 / 1024) / 10) + " MB</b> for the round robbin database.</small>";
892
+
893
$.each(categories, function(i, a) {
894
if(a.name == "system") a.priority = 1;
895
else if(a.name == "net") a.priority = 2;
web/netdata.js
+23
-6
@@ -80,6 +80,14 @@ function refreshChart(chart, doNext) {
80
}
81
else console.log('Cannot create chart for ' + chart.url);
82
})
83
+ .fail(function() {
84
+ // to avoid an infinite loop, let's assume it was refreshed
85
+ if(chart.chart) chart.chart.clearChart();
86
+ chart.chart = null;
87
+ chart.refreshCount = 0;
88
+ showChartIsLoading(chart.div, chart.name, chart.chartOptions.width, chart.chartOptions.height, "failed to refresh");
89
+ chart.last_updated = new Date().getTime();
90
+ })
91
.always(function() {
92
if(typeof doNext == "function") doNext();
93
});
@@ -87,6 +95,14 @@ function refreshChart(chart, doNext) {
95
return true;
96
}
97
98
+function chartIsLoadingHTML(name, width, height, message)
99
+{
100
+ return "<table><tr><td align=\"center\" width=\"" + width + "\" height=\"" + height + "\" style=\"vertical-align:middle\"><h4><span class=\"glyphicon glyphicon-refresh\"></span><br/><br/>loading " + name + "<br/><br/><span class=\"label label-default\">" + (message?message:"Please wait...") + "</span></h4></td></tr></table>";
101
+}
102
+
103
+function showChartIsLoading(id, name, width, height, message) {
104
+ document.getElementById(id).innerHTML = chartIsLoadingHTML(name, width, height, message);
105
+}
106
107
// calculateChartPointsToShow
108
// calculate the chart group and point to show properties.
@@ -245,6 +261,7 @@ function loadCharts(base_url, doNext) {
261
|| json.charts[i].name == 'system.swap'
262
|| json.charts[i].name == 'mem.slab'
263
|| json.charts[i].name == 'mem.kernel'
264
+ || json.charts[i].name == 'cpu.netdata'
265
) {
266
267
// default for all stacked AreaChart
@@ -252,7 +269,7 @@ function loadCharts(base_url, doNext) {
269
json.charts[i].chartOptions.isStacked = true;
270
json.charts[i].chartOptions.areaOpacity = 0.85;
271
json.charts[i].chartOptions.lineWidth = 1;
255
- json.charts[i].chartOptions.vAxis.viewWindowMode = 'maximized';
272
+ //json.charts[i].chartOptions.vAxis.viewWindowMode = 'maximized';
273
274
json.charts[i].group_method = "average";
275
}
@@ -278,8 +295,8 @@ function loadCharts(base_url, doNext) {
295
json.charts[i].chartOptions.lineWidth = 2;
296
json.charts[i].chartOptions.curveType = 'function';
297
281
- json.charts[i].chartOptions.vAxis.minValue = -10;
282
- json.charts[i].chartOptions.vAxis.maxValue = 10;
298
+ json.charts[i].chartOptions.vAxis.minValue = -0.1;
299
+ json.charts[i].chartOptions.vAxis.maxValue = 0.1;
300
}
301
302
// the category name, and other options, per type
@@ -294,8 +311,8 @@ function loadCharts(base_url, doNext) {
311
json.charts[i].chartOptions.vAxis.maxValue = 100;
312
}
313
else {
297
- json.charts[i].chartOptions.vAxis.minValue = -10;
298
- json.charts[i].chartOptions.vAxis.maxValue = 10;
314
+ json.charts[i].chartOptions.vAxis.minValue = -0.1;
315
+ json.charts[i].chartOptions.vAxis.maxValue = 0.1;
316
}
317
break;
318
@@ -365,7 +382,7 @@ function loadCharts(base_url, doNext) {
382
}
383
});
384
368
- if(typeof doNext == "function") doNext(json.charts);
385
+ if(typeof doNext == "function") doNext(json);
386
})
387
.fail(function() {
388
if(typeof doNext == "function") doNext();