Annotation of embedaddon/bmon/src/out_html.c, revision 1.1.1.1
1.1 misho 1: /*
2: * out_html.c HTML Output
3: *
4: * Copyright (c) 2001-2005 Thomas Graf <tgraf@suug.ch>
5: *
6: * Permission is hereby granted, free of charge, to any person obtaining a
7: * copy of this software and associated documentation files (the "Software"),
8: * to deal in the Software without restriction, including without limitation
9: * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10: * and/or sell copies of the Software, and to permit persons to whom the
11: * Software is furnished to do so, subject to the following conditions:
12: *
13: * The above copyright notice and this permission notice shall be included
14: * in all copies or substantial portions of the Software.
15: *
16: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17: * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21: * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22: * DEALINGS IN THE SOFTWARE.
23: */
24:
25: #include <bmon/bmon.h>
26: #include <bmon/node.h>
27: #include <bmon/output.h>
28: #include <bmon/graph.h>
29: #include <bmon/utils.h>
30:
31: static const char *c_path;
32: static int c_graph_height = 6;
33: static int c_update_interval = 1;
34: static int c_rowspan = 1;
35: static int c_hide_item = 0;
36: static char *c_title = "Traffic Rate Estimation and Monitoring";
37:
38: static FILE * open_file(const char *p)
39: {
40: FILE *fd;
41:
42: if (!(fd = fopen(p, "w")))
43: quit("fopen(%s) failed: %s\n", p, strerror(errno));
44:
45: return fd;
46: }
47:
48: static void write_css(const char *path)
49: {
50: char ofile[FILENAME_MAX];
51: FILE *f;
52:
53: snprintf(ofile, sizeof(ofile), "%s/layout.css", path);
54:
55: /* do not overwrite an existing .css */
56: if (!access(ofile, R_OK))
57: return;
58:
59: f = open_file(ofile);
60: fprintf(f,
61: "/*\n" \
62: " * Generated by %s\n" \
63: " */\n" \
64: "\n" \
65: "body {\n" \
66: " background: #f7f7f7;\n" \
67: " margin-top: 20px;\n" \
68: "}\n" \
69: "\n" \
70: "p, b, td {\n" \
71: " color: #000000;\n" \
72: " font-family: Verdana, Arial, Helvetica, sans-serif;\n" \
73: " font-size: 10pt;\n" \
74: "}\n" \
75: "\n" \
76: "a:link,a:visited,a:hover {\n" \
77: " color: #4E7AAF;\n" \
78: " text-decoration: underline;\n" \
79: "}\n" \
80: "\n" \
81: "p.banner {\n" \
82: " margin-top: 8px;\n" \
83: " margin-bottom: 8px;\n" \
84: " text-align: center;\n" \
85: " font-size: 18pt;\n" \
86: " font-weight: bold;\n" \
87: "}\n" \
88: "\n" \
89: "p.node_title {\n" \
90: " text-align: center;\n" \
91: " margin: 0pt;\n" \
92: " margin-bottom: 10px;\n" \
93: " font-weight: bold;\n" \
94: " font-size: 18pt;\n" \
95: "}\n" \
96: "\n" \
97: "p.title {\n" \
98: " margin: 0pt;\n" \
99: " margin-top: 5px;\n" \
100: " text-align: center;\n" \
101: " font-weight: bold;\n" \
102: " font-size: 14pt;\n" \
103: "}\n" \
104: "\n" \
105: "a.a_node_link:link,a.a_node_link:visited,a.a_node_link:hover {\n" \
106: " color: #000;\n" \
107: " font-weight: bold;\n" \
108: " text-decoration: none;\n" \
109: "}\n" \
110: "\n" \
111: "a.a_node_link:hover {\n" \
112: " font-weight: bold;\n" \
113: " text-decoration: underline;\n" \
114: "}\n" \
115: "\n" \
116: "a.a_intf_link:link,a.a_intf_link:visited,a.a_intf_link:hover {\n" \
117: " color: #000;\n" \
118: " text-decoration: none;\n" \
119: "}\n" \
120: "\n" \
121: "a.a_intf_link:hover {\n" \
122: " text-decoration: underline;\n" \
123: "}\n" \
124: "\n" \
125: "p.selection {\n" \
126: " text-align: center;\n" \
127: " margin: 0pt;\n" \
128: "}\n" \
129: "\n" \
130: "table.intf_list {\n" \
131: " border: 1px solid #cdcdcd;\n" \
132: " width: 100%%;\n" \
133: " border-spacing: 1px;\n" \
134: " background: #f8f8f8;\n" \
135: " margin-bottom: 10px;\n" \
136: "}\n" \
137: "\n" \
138: "tr.intf_list_hdr {\n" \
139: " font-weight: bold;\n" \
140: "}\n" \
141: "\n" \
142: "th.intf_list_hdr_name {\n" \
143: " text-align: left;\n" \
144: " padding-left: 5px;\n" \
145: "}\n" \
146: "\n" \
147: "td.intf_list_nr {\n" \
148: " border-top: 1px dashed #cdcdcd;\n" \
149: " text-align: center;\n" \
150: "}\n" \
151: "\n" \
152: "td.intf_list_name {\n" \
153: " border-top: 1px dashed #cdcdcd;\n" \
154: " border-left: 1px dashed #cdcdcd;\n" \
155: " text-align: left;\n" \
156: " padding-left: 5px;\n" \
157: "}\n" \
158: "\n" \
159: "td.intf_list_rx {\n" \
160: " border-top: 1px dashed #cdcdcd;\n" \
161: " border-left: 1px dashed #cdcdcd;\n" \
162: " text-align: center;\n" \
163: "}\n" \
164: "\n" \
165: "td.intf_list_rxp {\n" \
166: " border-top: 1px dashed #cdcdcd;\n" \
167: " border-left: 1px dashed #cdcdcd;\n" \
168: " text-align: center;\n" \
169: "}\n" \
170: "\n" \
171: "td.intf_list_tx {\n" \
172: " border-top: 1px dashed #cdcdcd;\n" \
173: " border-left: 1px dashed #cdcdcd;\n" \
174: " text-align: center;\n" \
175: "}\n" \
176: "\n" \
177: "td.intf_list_txp {\n" \
178: " border-top: 1px dashed #cdcdcd;\n" \
179: " border-left: 1px dashed #cdcdcd;\n" \
180: " text-align: center;\n" \
181: "}\n" \
182: " \n" \
183: "table.details {\n" \
184: " border: 1px solid #cdcdcd;\n" \
185: " width: 100%%;\n" \
186: " border-spacing: 1px;\n" \
187: " background: #f8f8f8;\n" \
188: " margin-top: 10px;\n" \
189: "}\n" \
190: "\n" \
191: "tr.details_hdr {\n" \
192: " font-weight: bold;\n" \
193: "}\n" \
194: "\n" \
195: "th.details_hdr_name {\n" \
196: " text-align: left;\n" \
197: " padding-left: 20px;\n" \
198: "}\n" \
199: "\n" \
200: "td.details_name {\n" \
201: " border-top: 1px dashed #cdcdcd;\n" \
202: " padding-left: 20px;\n" \
203: "}\n" \
204: "\n" \
205: "td.details_rx {\n" \
206: " border-top: 1px dashed #cdcdcd;\n" \
207: " border-left: 1px dashed #cdcdcd;\n" \
208: " text-align: center;\n" \
209: "}\n" \
210: "\n" \
211: "td.details_tx {\n" \
212: " border-top: 1px dashed #cdcdcd;\n" \
213: " border-left: 1px dashed #cdcdcd;\n" \
214: " text-align: center;\n" \
215: "}\n" \
216: "\n" \
217: "table.overall {\n" \
218: " width: 750px;\n" \
219: " border-spacing: 0px;\n" \
220: "}\n" \
221: "\n" \
222: "td.header {\n" \
223: " background: #b8c4db;\n" \
224: " text-align: center;\n" \
225: " border: 1px solid #000;\n" \
226: "}\n" \
227: "\n" \
228: "td.left_col {\n" \
229: " background: #eeeeee;\n" \
230: " padding-left: 10px;\n" \
231: " border-left: 1px solid #cdcdcd;\n" \
232: " border-right: 1px solid #cdcdcd;\n" \
233: " border-bottom: 1px solid #cdcdcd;\n" \
234: " vertical-align: top;\n" \
235: " width: 130px;\n" \
236: "}\n" \
237: "\n" \
238: "td.right_col {\n" \
239: " background: #fff;\n" \
240: " padding: 20px;\n" \
241: " padding-top: 10px;\n" \
242: " border-bottom: 1px solid #cdcdcd;\n" \
243: " border-right: 1px solid #cdcdcd;\n" \
244: " vertical-align: top;\n" \
245: "}\n" \
246: "\n" \
247: "td.fg {\n" \
248: " background: #6a94b7;\n" \
249: "}\n" \
250: "\n" \
251: "td.noise {\n" \
252: " background: #9fc5db;\n" \
253: "}\n" \
254: "\n" \
255: "td.bg {\n" \
256: " background: #eeeeee;\n" \
257: "}\n" \
258: "\n" \
259: "td.unknown {\n" \
260: " background: #f69191;\n" \
261: "}\n" \
262: "\n" \
263: "table.graph {\n" \
264: " border: 1px solid #cdcdcd;\n" \
265: " width: 100%%;\n" \
266: " border-spacing: 1px;\n" \
267: " background: #f8f8f8;\n" \
268: " margin-top: 10px;\n" \
269: " table-layout: fixed;\n" \
270: " empty-cells: show;\n" \
271: " padding-right: 5px;\n" \
272: " padding-bottom: 5px;\n" \
273: "}\n" \
274: "\n" \
275: "th.graph_hdr {\n" \
276: "}\n" \
277: "\n" \
278: "th.scale_hdr {\n" \
279: " text-align: right;\n" \
280: " width: 60px;\n" \
281: "}\n" \
282: "\n" \
283: "td.scale {\n" \
284: " text-align: right;\n" \
285: " vertical-align: top;\n" \
286: "}\n" \
287: "\n" \
288: "tr.graph_row {\n" \
289: " line-height: 7px;\n" \
290: "}\n" \
291: "\n" \
292: "ul.node_list {\n" \
293: " padding-left: 15px;\n" \
294: "}\n" \
295: "\n" \
296: "ul.node_intf_list {\n" \
297: " padding-left: 8px;\n" \
298: "}\n" \
299: "\n" \
300: "ul.sub_intf {\n" \
301: " padding-left: 8px;\n" \
302: "}\n" \
303: "\n" \
304: "tr.legend {\n" \
305: " line-height: 10px;\n" \
306: "}\n" \
307: "\n" \
308: "td.legend {\n" \
309: " font-size: 8pt;\n" \
310: "}\n", PACKAGE_STRING);
311: fclose(f);
312: }
313:
314: struct bxd {
315: FILE *fd;
316: node_t *node;
317: int clevel;
318: };
319:
320: static void list_add_child(item_t *it, void *arg)
321: {
322: struct bxd *x = (struct bxd *) arg;
323:
324: fprintf(x->fd, "<li><a class=\"a_intf_link\" href=\"%s.%d.bytes.s.html\">%s</a>\n",
325: x->node->n_name, it->i_index, it->i_name);
326:
327: if (it->i_flags & ITEM_FLAG_HAS_CHILDS) {
328: fprintf(x->fd, "<ul class=\"sub_intf\">");
329: foreach_child(x->node, it, list_add_child, arg);
330: fprintf(x->fd, "</ul>\n");
331: }
332:
333: fprintf(x->fd, "</li>\n");
334: }
335:
336: static void list_add_item(item_t *it, void *arg)
337: {
338: struct bxd *x = (struct bxd *) arg;
339:
340: if (it->i_flags & ITEM_FLAG_IS_CHILD)
341: return;
342:
343: fprintf(x->fd, "<li><a class=\"a_intf_link\" href=\"%s.%d.bytes.s.html\">%s</a>\n",
344: x->node->n_name, it->i_index, it->i_name);
345:
346: if (it->i_flags & ITEM_FLAG_HAS_CHILDS) {
347: fprintf(x->fd, "<ul class=\"sub_intf\">");
348: foreach_child(x->node, it, list_add_child, arg);
349: fprintf(x->fd, "</ul>\n");
350: }
351:
352: fprintf(x->fd, "</li>\n");
353: }
354:
355: static void list_add(node_t *node, void *arg)
356: {
357: FILE *fd = (FILE *) arg;
358: struct bxd x = {
359: .fd = fd,
360: .node = node,
361: };
362:
363: fprintf(fd, "<li><a class=\"a_node_link\" href=\"%s.html\">%s%s</a>\n",
364: node->n_name, node->n_name, !c_hide_item ? ":" : "");
365:
366: if (!c_hide_item) {
367: fprintf(fd, "<ul class=\"node_intf_list\">\n");
368: foreach_item(node, list_add_item, &x);
369: fprintf(fd, "</ul>\n");
370: }
371:
372: fprintf(fd, "</li>\n");
373: }
374:
375: static void write_header(FILE *fd, const char *title)
376: {
377: fprintf(fd,
378: "<!DOCTYPE html PUBLIC \"-//W3c/DTD XHTML 1.0 Strict//EN\" \n" \
379: " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n" \
380: "<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"en\"\n" \
381: " xml:lang=\"en\">\n" \
382: "<head>\n" \
383: "<title>%s</title>\n" \
384: "<link rel=\"stylesheet\" type=\"text/css\" href=\"layout.css\" />\n" \
385: "</head>\n" \
386: "<body>\n" \
387: "<table class=\"overall\" align=\"center\">\n" \
388: "<tr>\n" \
389: "<td colspan=\"2\" class=\"header\">\n" \
390: "<p class=\"banner\">%s</p>\n" \
391: "</td>\n" \
392: "</tr><tr>\n" \
393: "<td class=\"left_col\">\n" \
394: "<ul class=\"node_list\">\n",
395: title, c_title);
396:
397: foreach_node(list_add, fd);
398:
399: fprintf(fd,
400: "</ul></td>\n" \
401: "<td class=\"right_col\">\n");
402: }
403:
404: static void write_footer(FILE *fd)
405: {
406: time_t now = time(0);
407:
408: fprintf(fd,
409: "</td>\n" \
410: "</tr>\n" \
411: "<tr>\n" \
412: "<td colspan=\"2\" class=\"footer\">\n" \
413: "<p class=\"p_footer\">Updated: %s</p>\n" \
414: "</td>\n" \
415: "</tr>\n" \
416: "</table>\n" \
417: "</body>\n" \
418: "</html>\n",
419: asctime(localtime(&now)));
420: }
421:
422: struct html_xdata {
423: FILE *fd;
424: node_t *node;
425: };
426:
427: static void write_interface_entry(FILE *fd, item_t *intf, node_t *node)
428: {
429: stat_attr_t *bytes, *packets;
430: int i, rxprec, txprec;
431: double rx, tx;
432: char *rx_u, *tx_u;
433:
434: bytes = lookup_attr(intf, intf->i_major_attr);
435: packets = lookup_attr(intf, intf->i_minor_attr);
436:
437: if (!bytes || !packets)
438: return;
439:
440: rx = cancel_down(attr_get_rx_rate(bytes), bytes->a_unit, &rx_u, &rxprec);
441: tx = cancel_down(attr_get_tx_rate(bytes), bytes->a_unit, &tx_u, &txprec);
442:
443: fprintf(fd,
444: "<tr class=\"intf_list_row\">\n" \
445: "<td class=\"intf_list_nr\">%d</td>\n" \
446: "<td class=\"intf_list_name\">",
447: intf->i_index);
448:
449: for (i = 0; i < intf->i_level; i++)
450: fprintf(fd, " ");
451:
452: fprintf(fd,
453: "<a class=\"a_intf\" href=\"%s.%d.bytes.s.html\">%s</a></td>\n" \
454: "<td class=\"intf_list_rx\">%.*f %s</td>\n" \
455: "<td class=\"intf_list_rxp\">%u</td>\n" \
456: "<td class=\"intf_list_tx\">%.*f %s</td>\n" \
457: "<td class=\"intf_list_txp\">%u</td>\n" \
458: "</tr>\n",
459: node->n_name, intf->i_index, intf->i_name,
460: rxprec, rx, rx_u, attr_get_rx_rate(packets),
461: txprec, tx, tx_u, attr_get_tx_rate(packets));
462: }
463:
464: static void handle_child(item_t *intf, void *arg)
465: {
466: struct html_xdata *x = arg;
467:
468: write_interface_entry(x->fd, intf, x->node);
469: foreach_child(x->node, intf, handle_child, x);
470: }
471:
472: static void add_to_interace_list(FILE *fd, node_t *node, item_t *intf)
473: {
474: struct html_xdata x = {
475: .fd = fd,
476: .node = node,
477: };
478:
479: if (intf->i_parent)
480: return;
481:
482: write_interface_entry(fd, intf, node);
483: foreach_child(node, intf, handle_child, &x);
484: }
485:
486: static void write_interface_list(FILE *fd, node_t *node)
487: {
488: int i;
489:
490: fprintf(fd,
491: "<p class=\"node_title\">%s</p>\n" \
492: "<table class=\"intf_list\">\n" \
493: "<tr class=\"intf_list_hdr\">\n" \
494: "<th class=\"intf_list_hdr_classx\">#</th>\n" \
495: "<th class=\"intf_list_hdr_name\">Name</th>\n" \
496: "<th class=\"intf_list_hdr_rx\">RX</th>\n" \
497: "<th class=\"intf_list_hdr_rxp\">#</th>\n" \
498: "<th class=\"intf_list_hdr_tx\">TX</th>\n" \
499: "<th class=\"intf_list_hdr_txp\">#</th>\n" \
500: "</tr>",
501: node->n_name);
502:
503: for (i = 0; i < node->n_nitems; i++)
504: if (node->n_items[i].i_name[0])
505: add_to_interace_list(fd, node, &node->n_items[i]);
506:
507: fprintf(fd,
508: "</table>\n");
509: }
510:
511: static void write_graph(FILE *fd, node_t *node, item_t *intf,
512: stat_attr_hist_t *h, hist_elem_t *e, const char *x_unit)
513: {
514: int i, w, rem;
515: graph_t *g = create_graph(e, c_graph_height, h->a_unit);
516:
517: fprintf(fd,
518: "<p class=\"selection\">");
519:
520: for (i = 0; i < ATTR_HASH_MAX; i++) {
521: stat_attr_t *a;
522: for (a = intf->i_attrs[i]; a; a = a->a_next) {
523: if (!(a->a_flags & ATTR_FLAG_HISTORY))
524: continue;
525: fprintf(fd,
526: "[<a class=\"a_selection\" href=\"%s.%d.%s.s.html\">%s</a>] ",
527: node->n_name, intf->i_index, type2name(a->a_type),
528: type2desc(a->a_type));
529: }
530: }
531:
532: fprintf(fd,
533: "</p><p class=\"selection\">[");
534:
535: if (get_read_interval() != 1.0f)
536: fprintf(fd,
537: "<a class=\"a_selection\" href=\"%s.%d.%s.r.html\">Read interval</a> ] [",
538: node->n_name, intf->i_index, type2name(h->a_type));
539:
540: fprintf(fd,
541: "<a class=\"a_selection\" href=\"%s.%d.%s.s.html\">Seconds</a>] [" \
542: "<a class=\"a_selection\" href=\"%s.%d.%s.m.html\">Minutes</a>] [" \
543: "<a class=\"a_selection\" href=\"%s.%d.%s.h.html\">Hours</a>] [" \
544: "<a class=\"a_selection\" href=\"%s.%d.%s.d.html\">Days</a>]</p>\n",
545: node->n_name, intf->i_index, type2name(h->a_type),
546: node->n_name, intf->i_index, type2name(h->a_type),
547: node->n_name, intf->i_index, type2name(h->a_type),
548: node->n_name, intf->i_index, type2name(h->a_type));
549:
550:
551:
552: fprintf(fd, "<table class=\"graph\">\n");
553:
554: fprintf(fd, "<tr><th class=\"scale_hdr\">%s</th>" \
555: "<th class=\"graph_hdr\" colspan=\"61\">RX %s</th></tr>\n",
556: g->g_tx.t_y_unit, type2desc(h->a_type));
557:
558: for (rem = 1, w = (c_graph_height - 1); w >= 0; w--) {
559: char *p;
560: fprintf(fd, "<tr class=\"graph_row\">\n");
561:
562: if (--rem == 0) {
563: fprintf(fd, "<td class=\"scale\" rowspan=\"%d\">%8.2f</td>",
564: c_rowspan, g->g_rx.t_y_scale[w]);
565: rem = c_rowspan;
566: }
567:
568: for (p = (char *) (g->g_rx.t_data + (w * (HISTORY_SIZE + 1))); *p; p++) {
569: if (*p == get_fg_char())
570: fprintf(fd, "<td class=\"fg\"></td>");
571: else if (*p == get_noise_char())
572: fprintf(fd, "<td class=\"noise\"></td>");
573: else if (*p == get_unk_char())
574: fprintf(fd, "<td class=\"unknown\"></td>");
575: else
576: fprintf(fd, "<td class=\"bg\"></td>");
577: }
578: fprintf(fd, "<td> </td></tr>");
579: }
580:
581: fprintf(fd, "<tr><td> </td>" \
582: "<td colspan=\"5\">1</td>" \
583: "<td colspan=\"5\">5</td>" \
584: "<td colspan=\"5\">10</td>" \
585: "<td colspan=\"5\">15</td>" \
586: "<td colspan=\"5\">20</td>" \
587: "<td colspan=\"5\">25</td>" \
588: "<td colspan=\"5\">30</td>" \
589: "<td colspan=\"5\">35</td>" \
590: "<td colspan=\"5\">40</td>" \
591: "<td colspan=\"5\">45</td>" \
592: "<td colspan=\"5\">50</td>" \
593: "<td colspan=\"5\">55</td>" \
594: "<td>%s</td></tr>\n" \
595: " <tr class=\"legend\">\n" \
596: " <td colspan=\"7\"></td>\n" \
597: " <td colspan=\"2\" class=\"fg\"> </td>\n" \
598: " <td colspan=\"15\" class=\"legend\">Consumed</td>\n" \
599: " <td colspan=\"2\" class=\"noise\"> </td>\n" \
600: " <td colspan=\"15\" class=\"legend\">Noise</td>\n" \
601: " <td colspan=\"2\" class=\"unknown\"> </td>\n" \
602: " <td colspan=\"15\" class=\"legend\">No input data</td>\n" \
603: " <td colspan=\"4\"></td>\n" \
604: " </tr>\n" \
605: "</table>\n", x_unit);
606:
607: fprintf(fd, "<table class=\"graph\">\n");
608: fprintf(fd, "<tr><th class=\"scale_hdr\">%s</th>" \
609: "<th class=\"graph_hdr\" colspan=\"61\">TX %s</th></tr>\n",
610: g->g_tx.t_y_unit, type2desc(h->a_type));
611:
612: for (rem = 1, w = (c_graph_height - 1); w >= 0; w--) {
613: char *p;
614: fprintf(fd, "<tr class=\"graph_row\">\n");
615:
616: if (--rem == 0) {
617: fprintf(fd, "<td class=\"scale\" rowspan=\"%d\">%8.2f</td>",
618: c_rowspan, g->g_tx.t_y_scale[w]);
619: rem = c_rowspan;
620: }
621: for (p = (char *) (g->g_tx.t_data + (w * (HISTORY_SIZE + 1))); *p; p++) {
622: if (*p == get_fg_char())
623: fprintf(fd, "<td class=\"fg\"></td>");
624: else if (*p == get_noise_char())
625: fprintf(fd, "<td class=\"noise\"></td>");
626: else
627: fprintf(fd, "<td class=\"bg\"></td>");
628: }
629: fprintf(fd, "<td> </td></tr>");
630: }
631: fprintf(fd, "<tr><td> </td>" \
632: "<td colspan=\"5\">1</td>" \
633: "<td colspan=\"5\">5</td>" \
634: "<td colspan=\"5\">10</td>" \
635: "<td colspan=\"5\">15</td>" \
636: "<td colspan=\"5\">20</td>" \
637: "<td colspan=\"5\">25</td>" \
638: "<td colspan=\"5\">30</td>" \
639: "<td colspan=\"5\">35</td>" \
640: "<td colspan=\"5\">40</td>" \
641: "<td colspan=\"5\">45</td>" \
642: "<td colspan=\"5\">50</td>" \
643: "<td colspan=\"5\">55</td>" \
644: "<td>%s</td></tr>\n" \
645: " <tr class=\"legend\">\n" \
646: " <td colspan=\"7\"></td>\n" \
647: " <td colspan=\"2\" class=\"fg\"> </td>\n" \
648: " <td colspan=\"15\" class=\"legend\">Consumed</td>\n" \
649: " <td colspan=\"2\" class=\"noise\"> </td>\n" \
650: " <td colspan=\"15\" class=\"legend\">Noise</td>\n" \
651: " <td colspan=\"2\" class=\"unknown\"> </td>\n" \
652: " <td colspan=\"15\" class=\"legend\">No input data</td>\n" \
653: " <td colspan=\"4\"></td>\n" \
654: " </tr>\n" \
655: "</table>\n", x_unit);
656:
657: free_graph(g);
658: }
659:
660: static void print_attr_detail(stat_attr_t *a, void *arg)
661: {
662: double rx, tx;
663: char *rx_u, *tx_u;
664: int rxprec, txprec;
665: FILE *fd = (FILE *) arg;
666:
667: rx = cancel_down(attr_get_rx(a), a->a_unit, &rx_u, &rxprec);
668: tx = cancel_down(attr_get_tx(a), a->a_unit, &tx_u, &txprec);
669:
670: fprintf(fd,
671: "<tr class=\"details\">\n" \
672: "<td class=\"details_name\">%s</td>\n" \
673: "<td class=\"details_rx\">%.*f %s</td>\n" \
674: "<td class=\"details_tx\">%.*f %s</td>\n" \
675: "</tr>\n",
676: type2desc(a->a_type), rxprec, rx, rx_u, txprec, tx, tx_u);
677: }
678:
679: static void write_details(FILE *fd, item_t *intf)
680: {
681:
682: fprintf(fd,
683: "<table class=\"details\">\n" \
684: "<tr class=\"details_hdr\">\n" \
685: "<th class=\"details_hdr_name\">Details</th>\n" \
686: "<th class=\"details_hdr_rx\">RX</th>\n" \
687: "<th class=\"details_hdr_tx\">TX</th>\n" \
688: "</tr>\n");
689:
690: foreach_attr(intf, print_attr_detail, (void *) fd);
691:
692: fprintf(fd, "</table>\n");
693: }
694:
695: static void __write_per_item(item_t *intf, node_t *node, stat_attr_hist_t *h,
696: hist_elem_t *e, char *x_unit)
697: {
698: char outf[FILENAME_MAX];
699: char title[256];
700: FILE *fd;
701:
702: snprintf(outf, sizeof(outf), "%s/%s.%d.%s.%s.html",
703: c_path, node->n_name, intf->i_index, type2name(h->a_type), x_unit);
704: snprintf(title, sizeof(title), "%s on %s - %s/%s",
705: intf->i_name, node->n_name, type2desc(h->a_type), x_unit);
706: fd = open_file(outf);
707: write_header(fd, title);
708:
709: write_interface_list(fd, node);
710: fprintf(fd, "<p class=\"title\">%s</p>\n", intf->i_name);
711: write_graph(fd, node, intf, h, e, x_unit);
712: write_details(fd, intf);
713:
714: write_footer(fd);
715: fclose(fd);
716: }
717:
718: struct xdata {
719: item_t *i;
720: node_t *n;
721: };
722:
723: static void write_attr_graph(stat_attr_t *a, void *arg)
724: {
725: node_t *node = ((struct xdata *) arg)->n;
726: item_t *intf = ((struct xdata *) arg)->i;
727: stat_attr_hist_t *h = (stat_attr_hist_t *) a;
728:
729: if (!(a->a_flags & ATTR_FLAG_HISTORY))
730: return;
731:
732: if (get_read_interval() != 1.0f)
733: __write_per_item(intf, node, h, &h->a_hist.h_read, "r");
734: __write_per_item(intf, node, h, &h->a_hist.h_sec, "s");
735: __write_per_item(intf, node, h, &h->a_hist.h_min, "m");
736: __write_per_item(intf, node, h, &h->a_hist.h_hour, "h");
737: __write_per_item(intf, node, h, &h->a_hist.h_day, "d");
738: }
739:
740: static void write_per_item(item_t *intf, void *arg)
741: {
742: struct xdata x = {
743: .i = intf,
744: .n = (node_t *) arg
745: };
746:
747: foreach_attr(intf, &write_attr_graph, &x);
748: }
749:
750: static void write_per_node(node_t *node, void *arg)
751: {
752: char outf[FILENAME_MAX];
753: FILE *fd;
754:
755: snprintf(outf, sizeof(outf), "%s/%s.html", c_path, node->n_name);
756: fd = open_file(outf);
757: write_header(fd, node->n_name);
758: write_interface_list(fd, node);
759: write_footer(fd);
760: fclose(fd);
761:
762: foreach_item(node, write_per_item, (void *) node);
763: }
764:
765: void html_draw(void)
766: {
767: static int rem = 1;
768: char outf[FILENAME_MAX];
769: FILE *fd;
770:
771: if (--rem)
772: return;
773: else
774: rem = c_update_interval;
775:
776: umask(0133);
777: write_css(c_path);
778:
779: foreach_node(write_per_node, NULL);
780:
781: snprintf(outf, sizeof(outf), "%s/index.html", c_path);
782: fd = open_file(outf);
783: write_header(fd, c_title);
784: write_footer(fd);
785: fclose(fd);
786: }
787:
788: static void print_module_help(void)
789: {
790: printf(
791: "HTML - HTML Output\n" \
792: "\n" \
793: " Lightweight HTML output with CSS configuration.\n" \
794: " Author: Thomas Graf <tgraf@suug.ch>\n" \
795: "\n" \
796: " Options:\n" \
797: " path=PATH Output directory\n" \
798: " interval=SEC Update interval in seconds (default: 1)\n" \
799: " rowspan=NUM Summarize NUM rows into into a single scale step\n" \
800: " height=NUM Height of graphical statistics (default: 6)\n" \
801: " hideitems Hide interfaces in node list\n" \
802: " title=STRING Title of output\n");
803: }
804:
805: static void html_set_opts(tv_t *attrs)
806: {
807: while (attrs) {
808: if (!strcasecmp(attrs->type, "path") && attrs->value)
809: c_path = attrs->value;
810: else if (!strcasecmp(attrs->type, "height") && attrs->value)
811: c_graph_height = strtol(attrs->value, NULL, 0);
812: else if (!strcasecmp(attrs->type, "interval") && attrs->value)
813: c_update_interval = strtol(attrs->value, NULL, 0);
814: else if (!strcasecmp(attrs->type, "rowspan") && attrs->value)
815: c_rowspan = strtol(attrs->value, NULL, 0);
816: else if (!strcasecmp(attrs->type, "title") && attrs->value)
817: c_title = attrs->value;
818: else if (!strcasecmp(attrs->type, "hideitems"))
819: c_hide_item = 1;
820: else if (!strcasecmp(attrs->type, "help")) {
821: print_module_help();
822: exit(0);
823: }
824:
825: attrs = attrs->next;
826: }
827: }
828:
829: static int html_probe(void)
830: {
831: if (NULL == c_path)
832: quit("You must specify a path (-O html:path=DIR)\n");
833:
834: return 1;
835: }
836:
837: static struct output_module html_ops = {
838: .om_name = "html",
839: .om_draw = html_draw,
840: .om_set_opts = html_set_opts,
841: .om_probe = html_probe,
842: };
843:
844: static void __init html_init(void)
845: {
846: register_secondary_output_module(&html_ops);
847: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>