added support for /proc/net/snmp
Costa Tsaousis (ktsaou) committed
Mar 30, 2014 at 18:08 UTC
0860f0df39761f14e536a5f081ec8b38dc5886cc
3 files changed
+213
-47
netdata.c
+167
-13
@@ -34,18 +34,21 @@
34
#define RRD_DIMENSION_ABSOLUTE 0
35
#define RRD_DIMENSION_INCREMENTAL 1
36
37
-#define RRD_TYPE_NET "net"
38
-#define RRD_TYPE_NET_LEN strlen(RRD_TYPE_NET)
37
+#define RRD_TYPE_NET "net"
38
+#define RRD_TYPE_NET_LEN strlen(RRD_TYPE_NET)
39
40
-#define RRD_TYPE_TC "tc"
41
-#define RRD_TYPE_TC_LEN strlen(RRD_TYPE_TC)
40
+#define RRD_TYPE_TC "tc"
41
+#define RRD_TYPE_TC_LEN strlen(RRD_TYPE_TC)
42
43
-#define RRD_TYPE_DISK "disk"
44
-#define RRD_TYPE_DISK_LEN strlen(RRD_TYPE_DISK)
43
+#define RRD_TYPE_DISK "disk"
44
+#define RRD_TYPE_DISK_LEN strlen(RRD_TYPE_DISK)
45
46
-#define WEB_PATH_FILE "file"
47
-#define WEB_PATH_DATA "data"
48
-#define WEB_PATH_GRAPH "graph"
46
+#define RRD_TYPE_NET_SNMP "ipv4"
47
+#define RRD_TYPE_NET_SNMP_LEN strlen(RRD_TYPE_NET_SNMP)
48
+
49
+#define WEB_PATH_FILE "file"
50
+#define WEB_PATH_DATA "data"
51
+#define WEB_PATH_GRAPH "graph"
52
53
// internal defaults
54
#define UPDATE_EVERY 1
@@ -102,6 +105,9 @@
105
#define MAX_PROC_DISKSTATS_LINE 4096
106
#define MAX_PROC_DISKSTATS_DISK_NAME 1024
107
108
+#define MAX_PROC_NET_SNMP_LINE 4096
109
+#define MAX_PROC_NET_SNMP_NAME 1024
110
+
111
112
int silent = 0;
113
int save_history = HISTORY;
@@ -1585,8 +1591,10 @@ void *new_client(void *ptr)
1591
debug(D_WEB_CLIENT, "%llu: Waiting...", w->id);
1592
retval = select(fdmax+1, &ifds, &ofds, &efds, &tv);
1593
1588
- if(retval == -1)
1589
- fatal("%llu: LISTENER: select() failed.", w->id);
1594
+ if(retval == -1) {
1595
+ error("%llu: LISTENER: select() failed.", w->id);
1596
+ continue;
1597
+ }
1598
else if(!retval) {
1599
// timeout
1600
w->obsolete = 1;
@@ -1664,8 +1672,10 @@ void *socket_listen_main(void *ptr)
1672
// debug(D_WEB_CLIENT, "LISTENER: Waiting...");
1673
retval = select(fdmax+1, &ifds, &ofds, &efds, &tv);
1674
1667
- if(retval == -1)
1668
- fatal("LISTENER: select() failed.");
1675
+ if(retval == -1) {
1676
+ error("LISTENER: select() failed.");
1677
+ continue;
1678
+ }
1679
else if(retval) {
1680
// check for new incoming connections
1681
if(FD_ISSET(listener, &ifds)) {
@@ -1939,6 +1949,148 @@ int do_proc_diskstats() {
1949
return 0;
1950
}
1951
1952
+// ----------------------------------------------------------------------------
1953
+// /proc/net/snmp processor
1954
+
1955
+int do_proc_net_snmp() {
1956
+ char buffer[MAX_PROC_NET_SNMP_LINE+1] = "";
1957
+
1958
+ FILE *fp = fopen("/proc/net/snmp", "r");
1959
+ if(!fp) {
1960
+ error("Cannot read /proc/net/snmp.");
1961
+ return 1;
1962
+ }
1963
+
1964
+ for(;1;) {
1965
+ char *p = fgets(buffer, MAX_PROC_NET_SNMP_LINE, fp);
1966
+ if(!p) break;
1967
+
1968
+ if(strncmp(p, "Ip: ", 4) == 0) {
1969
+ // skip the header line, read the data
1970
+ p = fgets(buffer, MAX_PROC_NET_SNMP_LINE, fp);
1971
+ if(!p) break;
1972
+
1973
+ if(strncmp(p, "Ip: ", 4) != 0) {
1974
+ error("Cannot read IP line from /proc/net/snmp.");
1975
+ break;
1976
+ }
1977
+
1978
+ // see also http://net-snmp.sourceforge.net/docs/mibs/ip.html
1979
+ unsigned long long Forwarding, DefaultTTL, InReceives, InHdrErrors, InAddrErrors, ForwDatagrams, InUnknownProtos, InDiscards, InDelivers,
1980
+ OutRequests, OutDiscards, OutNoRoutes, ReasmTimeout, ReasmReqds, ReasmOKs, ReasmFails, FragOKs, FragFails, FragCreates;
1981
+
1982
+ int r = sscanf(&buffer[4], "%llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
1983
+ &Forwarding, &DefaultTTL, &InReceives, &InHdrErrors, &InAddrErrors, &ForwDatagrams, &InUnknownProtos, &InDiscards, &InDelivers,
1984
+ &OutRequests, &OutDiscards, &OutNoRoutes, &ReasmTimeout, &ReasmReqds, &ReasmOKs, &ReasmFails, &FragOKs, &FragFails, &FragCreates);
1985
+
1986
+ if(r == EOF) break;
1987
+ if(r != 19) error("Cannot read /proc/net/snmp IP line. Expected 19 params, read %d.", r);
1988
+
1989
+ RRD_STATS *st = rrd_stats_find(RRD_TYPE_NET_SNMP ".ip");
1990
+ if(!st) {
1991
+ st = rrd_stats_create(RRD_TYPE_NET_SNMP ".ip", RRD_TYPE_NET_SNMP ".ip", save_history, "IPv4 Packets", "Packets/s", RRD_TYPE_NET_SNMP);
1992
+ if(!st) {
1993
+ error("Cannot create RRD_STATS for %s.", RRD_TYPE_NET_SNMP ".ip");
1994
+ continue;
1995
+ }
1996
+
1997
+ if(!rrd_stats_dimension_add(st, "forwarded", "forwarded", sizeof(unsigned long long), 1, 1, RRD_DIMENSION_INCREMENTAL))
1998
+ error("Cannot add RRD_STATS dimension %s.", "forwarded");
1999
+
2000
+ if(!rrd_stats_dimension_add(st, "sent", "sent", sizeof(unsigned long long), -1, 1, RRD_DIMENSION_INCREMENTAL))
2001
+ error("Cannot add RRD_STATS dimension %s.", "sent");
2002
+
2003
+ if(!rrd_stats_dimension_add(st, "received", "received", sizeof(unsigned long long), 1, 1, RRD_DIMENSION_INCREMENTAL))
2004
+ error("Cannot add RRD_STATS dimension %s.", "received");
2005
+
2006
+ }
2007
+ else rrd_stats_next(st);
2008
+
2009
+ rrd_stats_dimension_set(st, "sent", &OutRequests);
2010
+ rrd_stats_dimension_set(st, "received", &InReceives);
2011
+ rrd_stats_dimension_set(st, "forwarded", &ForwDatagrams);
2012
+ rrd_stats_done(st);
2013
+ }
2014
+ else if(strncmp(p, "Tcp: ", 5) == 0) {
2015
+ // skip the header line, read the data
2016
+ p = fgets(buffer, MAX_PROC_NET_SNMP_LINE, fp);
2017
+ if(!p) break;
2018
+
2019
+ if(strncmp(p, "Tcp: ", 5) != 0) {
2020
+ error("Cannot read TCP line from /proc/net/snmp.");
2021
+ break;
2022
+ }
2023
+
2024
+ unsigned long long RtoAlgorithm, RtoMin, RtoMax, MaxConn, ActiveOpens, PassiveOpens, AttemptFails, EstabResets, CurrEstab, InSegs, OutSegs, RetransSegs, InErrs, OutRsts;
2025
+
2026
+ int r = sscanf(&buffer[5], "%llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
2027
+ &RtoAlgorithm, &RtoMin, &RtoMax, &MaxConn, &ActiveOpens, &PassiveOpens, &AttemptFails, &EstabResets, &CurrEstab, &InSegs, &OutSegs, &RetransSegs, &InErrs, &OutRsts);
2028
+
2029
+ if(r == EOF) break;
2030
+ if(r != 14) error("Cannot read /proc/net/snmp TCP line. Expected 14 params, read %d.", r);
2031
+
2032
+ // see http://net-snmp.sourceforge.net/docs/mibs/tcp.html
2033
+ RRD_STATS *st = rrd_stats_find(RRD_TYPE_NET_SNMP ".tcp");
2034
+ if(!st) {
2035
+ st = rrd_stats_create(RRD_TYPE_NET_SNMP ".tcp", RRD_TYPE_NET_SNMP ".tcp", save_history, "IPv4 TCP Established Sockets", "Established Sockets", RRD_TYPE_NET_SNMP);
2036
+ if(!st) {
2037
+ error("Cannot create RRD_STATS for %s.", RRD_TYPE_NET_SNMP ".tcp");
2038
+ continue;
2039
+ }
2040
+
2041
+ if(!rrd_stats_dimension_add(st, "established", "established", sizeof(unsigned long long), 1, 1, RRD_DIMENSION_ABSOLUTE))
2042
+ error("Cannot add RRD_STATS dimension %s.", "established");
2043
+ }
2044
+ else rrd_stats_next(st);
2045
+
2046
+ rrd_stats_dimension_set(st, "established", &CurrEstab);
2047
+ rrd_stats_done(st);
2048
+ }
2049
+ else if(strncmp(p, "Udp: ", 5) == 0) {
2050
+ // skip the header line, read the data
2051
+ p = fgets(buffer, MAX_PROC_NET_SNMP_LINE, fp);
2052
+ if(!p) break;
2053
+
2054
+ if(strncmp(p, "Udp: ", 5) != 0) {
2055
+ error("Cannot read UDP line from /proc/net/snmp.");
2056
+ break;
2057
+ }
2058
+
2059
+ unsigned long long InDatagrams, NoPorts, InErrors, OutDatagrams, RcvbufErrors, SndbufErrors;
2060
+
2061
+ int r = sscanf(&buffer[5], "%llu %llu %llu %llu %llu %llu\n",
2062
+ &InDatagrams, &NoPorts, &InErrors, &OutDatagrams, &RcvbufErrors, &SndbufErrors);
2063
+
2064
+ if(r == EOF) break;
2065
+ if(r != 6) error("Cannot read /proc/net/snmp UDP line. Expected 6 params, read %d.", r);
2066
+
2067
+ // see http://net-snmp.sourceforge.net/docs/mibs/udp.html
2068
+ RRD_STATS *st = rrd_stats_find(RRD_TYPE_NET_SNMP ".udp");
2069
+ if(!st) {
2070
+ st = rrd_stats_create(RRD_TYPE_NET_SNMP ".udp", RRD_TYPE_NET_SNMP ".udp", save_history, "IPv4 UDP Packets", "Packets/s", RRD_TYPE_NET_SNMP);
2071
+ if(!st) {
2072
+ error("Cannot create RRD_STATS for %s.", RRD_TYPE_NET_SNMP ".udp");
2073
+ continue;
2074
+ }
2075
+
2076
+ if(!rrd_stats_dimension_add(st, "sent", "sent", sizeof(unsigned long long), -1, 1, RRD_DIMENSION_INCREMENTAL))
2077
+ error("Cannot add RRD_STATS dimension %s.", "sent");
2078
+
2079
+ if(!rrd_stats_dimension_add(st, "received", "received", sizeof(unsigned long long), 1, 1, RRD_DIMENSION_INCREMENTAL))
2080
+ error("Cannot add RRD_STATS dimension %s.", "received");
2081
+ }
2082
+ else rrd_stats_next(st);
2083
+
2084
+ rrd_stats_dimension_set(st, "received", &InDatagrams);
2085
+ rrd_stats_dimension_set(st, "sent", &OutDatagrams);
2086
+ rrd_stats_done(st);
2087
+ }
2088
+ }
2089
+
2090
+ fclose(fp);
2091
+ return 0;
2092
+}
2093
+
2094
// ----------------------------------------------------------------------------
2095
// /proc processor
2096
@@ -1960,6 +2112,7 @@ void *proc_main(void *ptr)
2112
// BEGIN -- the job to be done
2113
do_proc_net_dev(usec);
2114
do_proc_diskstats(usec);
2115
+ do_proc_net_snmp(usec);
2116
// END -- the job is done
2117
2118
// find the time to sleep in order to wait exactly update_every seconds
@@ -2288,6 +2441,7 @@ void become_daemon()
2441
2442
signal(SIGCHLD, SIG_IGN);
2443
signal(SIGHUP, SIG_IGN);
2444
+ signal(SIGWINCH, SIG_IGN);
2445
2446
// fork() again
2447
i = fork();
web/index.html
+14
-2
@@ -38,6 +38,8 @@
38
mainchart.chart = null;
39
mainchart.width = Math.round(((window.innerWidth * 0.95) - 50) / 1);
40
mainchart.height = window.innerHeight - 200;
41
+ if(mainchart.height < 300) mainchart.height = 300;
42
+
43
mainchart.thumbnail = false;
44
mainchart.group = 5;
45
mainchart.group_method = "max";
@@ -49,6 +51,10 @@
51
mainchart.group = 15;
52
mainchart.group_method = "average";
53
}
54
+ else if(mainchart.type == "ipv4") {
55
+ mainchart.group = 30;
56
+ mainchart.group_method = "max";
57
+ }
58
59
// calculate the time to refresh each chart
60
mainchart.chart_update_every = mainchart.group * 1000; // milliseconds
@@ -156,6 +162,11 @@
162
c.id == "net.lo")
163
c.enabled = false;
164
}
165
+ else if(c.type == "ipv4") {
166
+ c.category = "IPv4 connections"
167
+ c.group = 60;
168
+ c.group_method = "max";
169
+ }
170
else if(c.type == "disk") {
171
c.category = "Disk I/O"
172
c.group = 20;
@@ -199,10 +210,11 @@
210
$.each(categories, function(i, a) {
211
if(a.name == "net") a.priority = 1;
212
else if(a.name == "tc") a.priority = 2;
202
- else if(a.name == "disk") a.priority = 3;
213
+ else if(a.name == "ipv4") a.priority = 3;
214
+ else if(a.name == "disk") a.priority = 4;
215
else a.priority = 4;
216
205
- a.html = "<tr><td><ol class=\"breadcrumb graphs\"><li class=\"active\"><a id=\"" + a.type + "\" href=\"#" + a.type + "\"><b>" + a.title + "</b> " + a.description + " </a></li></ol></td></tr><tr><td><div class=\"thumbgraphs\">" + a.html + "</td></tr>";
217
+ a.html = "<tr><td><ol class=\"breadcrumb graphs\"><li class=\"active\"><a id=\"" + a.name + "\" href=\"#" + a.name + "\"><b>" + a.title + "</b> " + a.description + " </a></li></ol></td></tr><tr><td><div class=\"thumbgraphs\">" + a.html + "</td></tr>";
218
});
219
220
function categoriessort(a, b) {
web/netdata.js
+32
-32
@@ -29,45 +29,42 @@ function refreshChart(chart) {
29
// Create our data table out of JSON data loaded from server.
30
chart.datatable = new google.visualization.DataTable(chart.jsondata);
31
32
- var width = chart.width;
33
- var height = chart.height;
34
-
35
- var hAxisTitle = null;
36
- var vAxisTitle = null;
37
- if(height >= 200) hAxisTitle = "Time of Day";
38
- if(width >= 350) vAxisTitle = chart.vtitle;
39
-
40
- var title = chart.title;
41
-
42
- var isStacked = false;
43
- if(chart.name.substring(0, 3) == "tc.") {
44
- isStacked = true;
45
- title += " [stacked]";
46
- }
47
-
32
+ // setup the default options
33
var options = {
49
- width: width,
50
- height: height,
51
- title: title,
52
- isStacked: isStacked,
53
- hAxis: {title: hAxisTitle},
54
- vAxis: {title: vAxisTitle, minValue: 10},
34
+ width: chart.width,
35
+ height: chart.height,
36
+ title: chart.title,
37
+ hAxis: {title: "Time of Day"},
38
+ vAxis: {title: chart.vtitle, minValue: 10},
39
focusTarget: 'category',
56
- lineWidth: (isStacked)?1:2,
57
- areaOpacity: (isStacked)?1.0:0.3,
40
explorer: (chart.explorer)?true:false,
41
// animation: {duration: 1000, easing: 'inAndOut'},
42
};
43
62
- var thumb_options = {
63
- // legend: { position: 'none' },
64
- // tooltip: { trigger: 'none' },
65
- enableInteractivity: false,
66
- //chartArea: {left: 0, top: 0, width: chart.width, height: chart.height},
67
- };
68
- if(chart.thumbnail) $.extend(options, thumb_options);
44
+ // disable interactivity on thumbnails
45
+ if(chart.thumbnail) options.enableInteractivity = false;
46
+
47
+ // hide axis titles if too small
48
+ if(chart.height < 200) options.vAxis.title = null;
49
+ if(chart.width < 350) options.hAxis.title = null;
50
+
51
+ if(chart.name.substring(0, 5) == "ipv4.") {
52
+ options.lineWidth = 3;
53
+ options.curveType = 'function';
54
+ }
55
+ else if(chart.name.substring(0, 3) == "tc.") {
56
+ options.isStacked = true;
57
+ options.title += " [stacked]";
58
+ options.areaOpacity = 1.0;
59
+ options.lineWidth = 1;
60
+ }
61
+ else {
62
+ options.areaOpacity = 0.3;
63
+ options.lineWidth = 2;
64
+ }
65
66
// cleanup once every 100 updates
67
+ // we don't cleanup on every single, to avoid firefox flashing effect
68
if(chart.chart && chart.refreshCount > 100) {
69
chart.chart.clearChart();
70
chart.chart = null;
@@ -76,7 +73,10 @@ function refreshChart(chart) {
73
// Instantiate and draw our chart, passing in some options.
74
if(!chart.chart) {
75
console.log('Creating new chart for ' + chart.url);
79
- chart.chart = new google.visualization.AreaChart(document.getElementById(chart.div));
76
+ if(chart.name.substring(0, 5) == "ipv4.")
77
+ chart.chart = new google.visualization.LineChart(document.getElementById(chart.div));
78
+ else
79
+ chart.chart = new google.visualization.AreaChart(document.getElementById(chart.div));
80
}
81
82
if(chart.chart) chart.chart.draw(chart.datatable, options);