Annotation of embedaddon/bmon/src/out_html.c, revision 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>