@cryptotaxi247 / netdata-1 / commits / 608d937b4

first commit

Costa Tsaousis committed Jun 17, 2013 at 21:45 UTC 608d937b4a31e8c2dc984aadf1168710b91fbf78
1 file changed +244
netdata.c new
+244
@@ -0,0 +1,244 @@
1 +#include <stdio.h>
2 +#include <stdlib.h>
3 +#include <string.h>
4 +#include <time.h>
5 +#include <unistd.h>
6 +#include <sys/types.h>
7 +
8 +// internal defaults
9 +#define UPDATE_EVERY 1
10 +#define HISTORY 3600
11 +#define SAVE_PATH "/tmp"
12 +
13 +// configuration
14 +#define MAX_IFACE_NAME 1024
15 +char save_path[FILENAME_MAX+1] = SAVE_PATH;
16 +int update_every = UPDATE_EVERY;
17 +int save_history = 60;
18 +
19 +struct iface_history {
20 + time_t time;
21 + unsigned long long rbytes;
22 + unsigned long long tbytes;
23 +};
24 +
25 +struct iface_stats {
26 + char name[MAX_IFACE_NAME + 1];
27 +
28 + int last_history_id;
29 + struct iface_history history[HISTORY];
30 +
31 + struct iface_stats *next;
32 +} *interfaces = NULL;
33 +
34 +void update_iface_history(char *name, unsigned long long rbytes, unsigned long long tbytes) {
35 + struct iface_stats *iface = NULL;
36 +
37 + for(iface = interfaces; iface != NULL; iface = iface->next)
38 + if(strcmp(iface->name, name) == 0) break;
39 +
40 + if(!iface) {
41 + int i;
42 +
43 + // printf("Creating new interface for %s\n", name);
44 +
45 + iface = malloc(sizeof(struct iface_stats));
46 + if(!iface) return;
47 +
48 + iface->last_history_id = HISTORY + 1;
49 +
50 + // link it to beginning
51 + iface->next = interfaces;
52 + interfaces = iface;
53 +
54 + for(i = 0; i < HISTORY ;i++) {
55 + iface->history[i].time = time(NULL) - HISTORY + (i * update_every);
56 + iface->history[i].rbytes = rbytes;
57 + iface->history[i].tbytes = tbytes;
58 + }
59 + }
60 +
61 + iface->last_history_id++;
62 + if(iface->last_history_id >= HISTORY) iface->last_history_id = 0;
63 +
64 + // printf("Updating values for interface %s at position %d, rbytes = %llu, tbytes = %llu\n", iface->name, iface->last_history_id, rbytes, tbytes);
65 +
66 + strcpy(iface->name, name);
67 + iface->history[iface->last_history_id].time = time(NULL);
68 + iface->history[iface->last_history_id].rbytes = rbytes;
69 + iface->history[iface->last_history_id].tbytes = tbytes;
70 +}
71 +
72 +void save_stats() {
73 + struct iface_stats *iface = NULL;
74 +
75 + for(iface = interfaces; iface != NULL; iface = iface->next) {
76 + char tmp[FILENAME_MAX+1];
77 + char filename[FILENAME_MAX+1];
78 + FILE *fp;
79 + int i, ld;
80 +
81 + sprintf(tmp, "%s/%s.json.tmp.%d", save_path, iface->name, getpid());
82 + sprintf(filename, "%s/%s.json", save_path, iface->name);
83 + fp = fopen(tmp, "w");
84 + if(!fp) {
85 + perror(filename);
86 + return;
87 + }
88 +
89 +
90 + fprintf(fp, "{\n \"cols\":\n [\n");
91 + fprintf(fp, " {\"id\":\"\",\"label\":\"time\",\"pattern\":\"\",\"type\":\"timeofday\"},\n");
92 + fprintf(fp, " {\"id\":\"\",\"label\":\"received\",\"pattern\":\"\",\"type\":\"number\"},\n");
93 + fprintf(fp, " {\"id\":\"\",\"label\":\"sent\",\"pattern\":\"\",\"type\":\"number\"}\n");
94 + fprintf(fp, " ],\n \"rows\":\n [\n");
95 +
96 + ld = iface->last_history_id;
97 + for(i = 1; i < save_history ; i++) {
98 + int dt, s, d;
99 + long long rb, tb;
100 + struct tm *tm;
101 + char dtm[1025];
102 +
103 + d = iface->last_history_id - i;
104 + if(d < 0) d += HISTORY;
105 +
106 + dt = iface->history[ld].time - iface->history[d].time;
107 + if(dt == 0) dt = 1;
108 + rb = (iface->history[ld].rbytes - iface->history[d].rbytes) * 8 / dt / 1024;
109 + tb = (iface->history[ld].tbytes - iface->history[d].tbytes) * 8 / dt / 1024;
110 +
111 + s = time(NULL) - iface->history[ld].time;
112 +
113 + tm = localtime(&iface->history[d].time);
114 + if(!tm) { perror("localtime"); continue; }
115 + // strftime(dtm, 1024, "%T", tm);
116 + // strftime(dtm, 1024, "%H:%M %B %d, %Y %z", tm);
117 + // strftime(dtm, 1024, "new Date(\"%B %d, %Y %T\")", tm);
118 + strftime(dtm, 1024, "[%H, %M, %S, 0]", tm);
119 +
120 + // fprintf(fp, " {\"c\":[{\"v\":\"%ds\",\"f\":null},{\"v\":%llu,\"f\":\"%llu\"},{\"v\":%llu,\"f\":\"%llu\"}]}", -s, rb, rb, tb, tb);
121 + // fprintf(fp, " {\"c\":[{\"v\":%s,\"f\":null},{\"v\":%lld,\"f\":null},{\"v\":%lld,\"f\":null}]}", dtm, rb, tb);
122 + fprintf(fp, " {\"c\":[{\"v\":%s},{\"v\":%lld},{\"v\":%lld}]}", dtm, rb, tb);
123 + if(i == save_history - 1) fprintf(fp, "\n");
124 + else fprintf(fp, ",\n");
125 +
126 + ld = d;
127 + }
128 + fprintf(fp, " ]\n}\n");
129 + fclose(fp);
130 + unlink(filename);
131 + link(tmp, filename);
132 + unlink(tmp);
133 + }
134 +}
135 +
136 +int main(int argc, char **argv) {
137 + char iface[MAX_IFACE_NAME + 1] = "";
138 + unsigned long long rbytes, rpackets, rerrors, rdrops, rfifo, rframe, rcompressed, rmulticast;
139 + unsigned long long tbytes, tpackets, terrors, tdrops, tfifo, tcollisions, tcarrier, tcompressed;
140 + int i;
141 + int daemon = 0;
142 +
143 + // parse the arguments
144 + for(i = 1; i < argc ; i++) {
145 + if(strcmp(argv[i], "-l") == 0 && (i+1) < argc) {
146 + save_history = atoi(argv[i+1]);
147 + if(save_history <= 0 || save_history > HISTORY) {
148 + fprintf(stderr, "Invalid save lines %d given. Defaulting to %d.\n", save_history, HISTORY);
149 + save_history = HISTORY;
150 + }
151 + else {
152 + fprintf(stderr, "save lines set to %d.\n", save_history);
153 + }
154 + i++;
155 + }
156 + else if(strcmp(argv[i], "-u") == 0 && (i+1) < argc) {
157 + update_every = atoi(argv[i+1]);
158 + if(update_every <= 0 || update_every > 600) {
159 + fprintf(stderr, "Invalid update timer %d given. Defaulting to %d.\n", update_every, UPDATE_EVERY);
160 + update_every = UPDATE_EVERY;
161 + }
162 + else {
163 + fprintf(stderr, "update timer set to %d.\n", update_every);
164 + }
165 + i++;
166 + }
167 + else if(strcmp(argv[i], "-o") == 0 && (i+1) < argc) {
168 + strncpy(save_path, argv[i+1], FILENAME_MAX);
169 + save_path[FILENAME_MAX]='\0';
170 + fprintf(stderr, "Saving files to '%s'.\n", save_path);
171 + i++;
172 + }
173 + else if(strcmp(argv[i], "-d") == 0) {
174 + daemon = 1;
175 + fprintf(stderr, "Enabled daemon mode.\n");
176 + }
177 + else {
178 + fprintf(stderr, "Cannot understand option '%s'.\n", argv[i]);
179 + fprintf(stderr, "\nUSAGE: %s [-d] [-l LINES_TO_SAVE] [-u UPDATE_TIMER] [-o PATH_TO_SAVE_FILES].\n\n", argv[0]);
180 + fprintf(stderr, " -d enabled daemon mode.\n");
181 + fprintf(stderr, " -l LINES_TO_SAVE can be from 0 to %d lines in JSON data. Default: %d.\n", HISTORY, save_history);
182 + fprintf(stderr, " -u UPDATE_TIMER can be from 1 to %d seconds. Default: %d.\n", 600, update_every);
183 + fprintf(stderr, " -o PATH_TO_SAVE_FILES is a directory to place the JSON files. Default: '%s'.\n", save_path);
184 + exit(1);
185 + }
186 + }
187 +
188 + if(daemon) {
189 + i = fork();
190 + if(i == -1) {
191 + perror("cannot fork");
192 + exit(1);
193 + }
194 + if(i != 0) exit(0); // the parent
195 + close(0);
196 + close(1);
197 + close(2);
198 + }
199 +
200 + for(;1;) {
201 + FILE *fp = fopen("/proc/net/dev", "r");
202 + int r;
203 +
204 + if(!fp) {
205 + perror("/proc/net/dev");
206 + sleep(1);
207 + continue;
208 + }
209 +
210 + // skip the first two lines
211 + fgets(iface, MAX_IFACE_NAME, fp);
212 + fgets(iface, MAX_IFACE_NAME, fp);
213 +
214 + // read the rest of the lines
215 + for(;1;) {
216 + r = fscanf(fp, "%s\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\n",
217 + iface,
218 + &rbytes, &rpackets, &rerrors, &rdrops, &rfifo, &rframe, &rcompressed, &rmulticast,
219 + &tbytes, &tpackets, &terrors, &tdrops, &tfifo, &tcollisions, &tcarrier, &tcompressed);
220 + if(r == EOF) break;
221 + if(r != 17) printf("Cannot read line\n");
222 + else {
223 + // printf("Read %d items\n", r);
224 +
225 + // remove the ':' from the end of the name
226 + int l = strlen(iface);
227 + if(l > 0) iface[l-1] = '\0';
228 +
229 + // update our data
230 + update_iface_history(iface, rbytes, tbytes);
231 + }
232 + }
233 +
234 + // done reading, close it
235 + fclose(fp);
236 +
237 + // save statistics
238 + save_stats();
239 +
240 + // printf("Received bytes = %llu, Transmit bytes = %llu\n", rbytes, tbytes);
241 + sleep(update_every);
242 + }
243 +}
244 +