|
version 1.1.1.1, 2012/02/21 22:19:56
|
version 1.1.1.2, 2014/07/30 07:55:27
|
|
Line 1
|
Line 1
|
| /* |
/* |
| * out_ascii.c ASCII Output |
* out_ascii.c ASCII Output |
| * |
* |
| * Copyright (c) 2001-2005 Thomas Graf <tgraf@suug.ch> | * Copyright (c) 2001-2013 Thomas Graf <tgraf@suug.ch> |
| | * Copyright (c) 2013 Red Hat, Inc. |
| * |
* |
| * Permission is hereby granted, free of charge, to any person obtaining a |
* Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
* copy of this software and associated documentation files (the "Software"), |
|
Line 23
|
Line 24
|
| */ |
*/ |
| |
|
| #include <bmon/bmon.h> |
#include <bmon/bmon.h> |
| #include <bmon/graph.h> |
|
| #include <bmon/conf.h> |
#include <bmon/conf.h> |
| #include <bmon/output.h> |
#include <bmon/output.h> |
| #include <bmon/node.h> | #include <bmon/group.h> |
| | #include <bmon/element.h> |
| | #include <bmon/attr.h> |
| | #include <bmon/graph.h> |
| | #include <bmon/history.h> |
| #include <bmon/utils.h> |
#include <bmon/utils.h> |
| |
|
| typedef enum diagram_type_e { |
typedef enum diagram_type_e { |
|
Line 35 typedef enum diagram_type_e {
|
Line 39 typedef enum diagram_type_e {
|
| D_DETAILS |
D_DETAILS |
| } diagram_type_t; |
} diagram_type_t; |
| |
|
| static int c_print_header = INT_MAX; | static struct graph_cfg graph_cfg = { |
| | .gc_foreground = '*', |
| | .gc_background = ' ', |
| | .gc_noise = '.', |
| | .gc_unknown = '?', |
| | .gc_height = 6, |
| | }; |
| | |
| static diagram_type_t c_diagram_type = D_LIST; |
static diagram_type_t c_diagram_type = D_LIST; |
| static int c_graph_height = 6; | static char *c_hist = "second"; |
| static int c_quit_after = -1; |
static int c_quit_after = -1; |
| |
|
| static inline int get_print_header(void) | static void print_list(struct element *e) |
| { |
{ |
| static int hdr_rem; | char *rxu1 = "", *txu1 = "", *rxu2 = "", *txu2 = ""; |
| double rx1 = 0.0f, tx1 = 0.0f, rx2 = 0.0f, tx2 = 0.0f; |
| if (c_print_header) { | int rx1prec = 0, tx1prec = 0, rx2prec = 0, tx2prec = 0; |
| if (0 == hdr_rem) { | |
| hdr_rem = (c_print_header - 1); | |
| return 1; | |
| } | |
| |
| if (c_print_header != INT_MAX) | |
| hdr_rem--; | |
| } | |
| |
| return 0; | |
| } | |
| |
| static inline void set_diagram_type(const char *t) | |
| { | |
| if (tolower(*t) == 'l') | |
| c_diagram_type = D_LIST; | |
| else if (tolower(*t) == 'g') | |
| c_diagram_type = D_GRAPH; | |
| else if (tolower(*t) == 'd') | |
| c_diagram_type = D_DETAILS; | |
| else | |
| quit("Unknown diagram type '%s'\n", t); | |
| } | |
| |
| |
| static void print_item(item_t *i) | |
| { | |
| stat_attr_t *bytes, *packets; | |
| double rx, tx, rxp, txp; | |
| int rxprec, txprec, rxpprec, txpprec; | |
| char *rx_u, *tx_u, *rxp_u, *txp_u; | |
| char pad[IFNAMSIZ + 32]; |
char pad[IFNAMSIZ + 32]; |
| | struct attr *a; |
| if (get_print_header()) { | |
| printf("Name RX Rate # %%" \ | |
| " TX Rate # %%\n"); | |
| } | |
| |
|
| bytes = lookup_attr(i, i->i_major_attr); | if (e->e_key_attr[GT_MAJOR] && |
| packets = lookup_attr(i, i->i_minor_attr); | (a = attr_lookup(e, e->e_key_attr[GT_MAJOR]->ad_id))) |
| | attr_rate2float(a, &rx1, &rxu1, &rx1prec, |
| | &tx1, &txu1, &tx1prec); |
| |
|
| rx = cancel_down(attr_get_rx_rate(bytes), bytes->a_unit, &rx_u, &rxprec); | if (e->e_key_attr[GT_MINOR] && |
| tx = cancel_down(attr_get_tx_rate(bytes), bytes->a_unit, &tx_u, &txprec); | (a = attr_lookup(e, e->e_key_attr[GT_MINOR]->ad_id))) |
| | attr_rate2float(a, &rx2, &rxu2, &rx2prec, |
| | &tx2, &txu2, &tx2prec); |
| |
|
| rxp = cancel_down(attr_get_rx_rate(packets), packets->a_unit, &rxp_u, &rxpprec); |
|
| txp = cancel_down(attr_get_tx_rate(packets), packets->a_unit, &txp_u, &txpprec); |
|
| |
|
| memset(pad, 0, sizeof(pad)); |
memset(pad, 0, sizeof(pad)); |
| memset(pad, ' ', i->i_level < 15 ? i->i_level : 15); | memset(pad, ' ', e->e_level < 15 ? e->e_level : 15); |
| |
|
| strncat(pad, i->i_name, sizeof(pad) - strlen(pad) - 1); | strncat(pad, e->e_name, sizeof(pad) - strlen(pad) - 1); |
| |
|
| if (i->i_desc) { | if (e->e_description) { |
| strncat(pad, " (", sizeof(pad) - strlen(pad) - 1); |
strncat(pad, " (", sizeof(pad) - strlen(pad) - 1); |
| strncat(pad, i->i_desc, sizeof(pad) - strlen(pad) - 1); | strncat(pad, e->e_description, sizeof(pad) - strlen(pad) - 1); |
| strncat(pad, ")", sizeof(pad) - strlen(pad) - 1); |
strncat(pad, ")", sizeof(pad) - strlen(pad) - 1); |
| } |
} |
| |
|
| printf("%-22s %8.*f%s %8.*f%s ", pad, rxprec, rx, rx_u, rxpprec, rxp, rxp_u); | printf(" %-36s %8.*f%-3s %8.*f%-3s ", |
| if (i->i_rx_usage < 0) | pad, rx1prec, rx1, rxu1, rx2prec, rx2, rxu2); |
| printf(" "); | |
| else | |
| printf("%2d%%", i->i_rx_usage); | |
| |
|
| printf(" %8.*f%s %8.*f%s ", txprec, tx, tx_u, txpprec, txp, txp_u); | if (e->e_rx_usage == FLT_MAX) |
| if (i->i_tx_usage < 0) | |
| printf(" "); |
printf(" "); |
| else |
else |
| printf("%2d%%", i->i_tx_usage); | printf("%2.0f%%", e->e_rx_usage); |
| |
|
| printf("\n"); | printf(" %8.*f%-3s %8.*f%-3s ", tx1prec, tx1, txu1, tx2prec, tx2, txu2); |
| | |
| | if (e->e_tx_usage == FLT_MAX) |
| | printf(" \n"); |
| | else |
| | printf("%2.0f%%\n", e->e_tx_usage); |
| } |
} |
| |
|
| static void print_attr_detail(struct element *e, struct attr *a, void *arg) |
| static void handle_child(item_t *i, void *arg) | |
| { |
{ |
| node_t *node = arg; | char *rx_u, *tx_u; |
| | int rxprec, txprec; |
| |
|
| print_item(i); | double rx = unit_value2str(a->a_rx_rate.r_total, |
| foreach_child(node, i, handle_child, node); | a->a_def->ad_unit, |
| } | &rx_u, &rxprec); |
| | double tx = unit_value2str(a->a_tx_rate.r_total, |
| | a->a_def->ad_unit, |
| | &tx_u, &txprec); |
| |
|
| static void print_list(item_t *i, node_t *node) | printf(" %-36s %12.*f%-3s %12.*f%-3s\n", |
| { | a->a_def->ad_description, rxprec, rx, rx_u, txprec, tx, tx_u); |
| if (i->i_flags & ITEM_FLAG_IS_CHILD) | |
| return; | |
| | |
| print_item(i); | |
| foreach_child(node, i, handle_child, node); | |
| } |
} |
| |
|
| static void print_attr_detail(stat_attr_t *a, void *arg) | static void print_details(struct element *e) |
| { |
{ |
| char *rx_u, *tx_u; | printf(" %s", e->e_name); |
| int rxprec, txprec; | |
| double rx = cancel_down(attr_get_rx(a), a->a_unit, &rx_u, &rxprec); | |
| double tx = cancel_down(attr_get_tx(a), a->a_unit, &tx_u, &txprec); | |
| |
|
| printf(" %-14s %12.*f %s %12.*f %s\n", | if (e->e_id) |
| type2name(a->a_type), rxprec, rx, rx_u, txprec, tx, tx_u); | printf(" (%u)", e->e_id); |
| | |
| | printf("\n"); |
| | |
| | element_foreach_attr(e, print_attr_detail, NULL); |
| | |
| | printf("\n"); |
| } |
} |
| |
|
| static void print_details(item_t *i) | static void print_table(struct graph *g, struct graph_table *tbl, const char *hdr) |
| { |
{ |
| if (i->i_handle) | int i; |
| printf(" %s (%u)\n", i->i_name, i->i_handle); | |
| else | |
| printf(" %s\n", i->i_name); | |
| |
|
| foreach_attr(i, print_attr_detail, NULL); | if (!tbl->gt_table) |
| | return; |
| | |
| | printf("%s %s\n", hdr, tbl->gt_y_unit); |
| | |
| | for (i = (g->g_cfg.gc_height - 1); i >= 0; i--) |
| | printf("%8.2f %s\n", tbl->gt_scale[i], |
| | tbl->gt_table + (i * graph_row_size(&g->g_cfg))); |
| | |
| | printf(" 1 5 10 15 20 25 30 35 40 " \ |
| | "45 50 55 60\n"); |
| } |
} |
| |
|
| static void __print_graph(stat_attr_t *a, void *arg) | static void __print_graph(struct element *e, struct attr *a, void *arg) |
| { |
{ |
| item_t *i = (item_t *) arg; | struct history *h; |
| stat_attr_hist_t *h; | struct graph *g; |
| graph_t *g; | |
| int w; | |
| |
|
| if (!(a->a_flags & ATTR_FLAG_HISTORY)) | if (!(a->a_flags & ATTR_DOING_HISTORY)) |
| return; |
return; |
| |
|
| h = (stat_attr_hist_t *) a; | graph_cfg.gc_unit = a->a_def->ad_unit; |
| |
|
| g = create_configued_graph(&h->a_hist, c_graph_height, | list_for_each_entry(h, &a->a_history_list, h_list) { |
| h->a_unit, get_x_unit()); | if (strcasecmp(c_hist, h->h_definition->hd_name)) |
| | continue; |
| |
|
| printf("Item: %s\nAttribute: %s\n", i->i_name, type2desc(a->a_type)); | g = graph_alloc(h, &graph_cfg); |
| | graph_refill(g, h); |
| |
|
| printf("RX %s\n", g->g_rx.t_y_unit); | printf("Interface: %s\n", e->e_name); |
| | printf("Attribute: %s\n", a->a_def->ad_description); |
| for (w = (c_graph_height - 1); w >= 0; w--) | |
| printf("%8.2f %s\n", g->g_rx.t_y_scale[w], | |
| (char *) g->g_rx.t_data + (w * (HISTORY_SIZE + 1))); | |
| | |
| printf(" 1 5 10 15 20 25 30 35 40 " \ | |
| "45 50 55 60 %s\n", g->g_rx.t_x_unit); | |
| |
|
| printf("TX %s\n", g->g_tx.t_y_unit); | print_table(g, &g->g_rx, "RX"); |
| | print_table(g, &g->g_tx, "TX"); |
| for (w = (c_graph_height - 1); w >= 0; w--) | |
| printf("%8.2f %s\n", g->g_tx.t_y_scale[w], | |
| (char *) g->g_tx.t_data + (w * (HISTORY_SIZE + 1))); | |
| | |
| printf(" 1 5 10 15 20 25 30 35 40 " \ | |
| "45 50 55 60 %s\n", g->g_tx.t_x_unit); | |
| |
|
| free_graph(g); | graph_free(g); |
| | |
| | } |
| } |
} |
| |
|
| static void print_graph(item_t *i) | static void print_graph(struct element *e) |
| { |
{ |
| foreach_attr(i, &__print_graph, i); | element_foreach_attr(e, __print_graph, NULL); |
| } |
} |
| |
|
| static void ascii_draw_item(item_t *i, void *arg) | static void ascii_draw_element(struct element_group *g, struct element *e, |
| | void *arg) |
| { |
{ |
| node_t *node = arg; |
|
| |
|
| switch (c_diagram_type) { |
switch (c_diagram_type) { |
| case D_LIST: |
case D_LIST: |
| print_list(i, node); | print_list(e); |
| break; |
break; |
| |
|
| case D_DETAILS: |
case D_DETAILS: |
| print_details(i); | print_details(e); |
| break; |
break; |
| |
|
| case D_GRAPH: |
case D_GRAPH: |
| print_graph(i); | print_graph(e); |
| break; |
break; |
| } |
} |
| } |
} |
| |
|
| static void ascii_draw_node(node_t *n, void *arg) | static void ascii_draw_group(struct element_group *g, void *arg) |
| { |
{ |
| if (n->n_name) { | if (c_diagram_type == D_LIST) |
| if (get_nnodes() > 1) | printf("%-37s%10s %11s %%%10s %11s %%\n", |
| printf("%s:\n", n->n_name); | g->g_hdr->gh_title, |
| foreach_item(n, ascii_draw_item, n); | g->g_hdr->gh_column[0], |
| } | g->g_hdr->gh_column[1], |
| | g->g_hdr->gh_column[2], |
| | g->g_hdr->gh_column[3]); |
| | else |
| | printf("%s\n", g->g_hdr->gh_title); |
| | |
| | group_foreach_element(g, ascii_draw_element, NULL); |
| } |
} |
| |
|
| static void ascii_draw(void) |
static void ascii_draw(void) |
| { |
{ |
| foreach_node(ascii_draw_node, NULL); | group_foreach(ascii_draw_group, NULL); |
| |
|
| if (c_quit_after > 0) |
if (c_quit_after > 0) |
| if (--c_quit_after == 0) |
if (--c_quit_after == 0) |
| exit(0); |
exit(0); |
| } |
} |
| |
|
| static int ascii_probe(void) |
|
| { |
|
| return 1; |
|
| } |
|
| |
|
| static void print_help(void) |
static void print_help(void) |
| { |
{ |
| printf( |
printf( |
|
Line 249 static void print_help(void)
|
Line 225 static void print_help(void)
|
| "\n" \ |
"\n" \ |
| " Plain configurable ASCII output.\n" \ |
" Plain configurable ASCII output.\n" \ |
| "\n" \ |
"\n" \ |
| " vmstat like: (print header every 10 lines)\n" \ |
|
| " bmon -p eth0 -o ascii:header=10\n" \ |
|
| " scriptable: (output graph for eth1 10 times)\n" \ |
" scriptable: (output graph for eth1 10 times)\n" \ |
| " bmon -p eth1 -o 'ascii:diagram=graph;quitafter=10'\n" \ |
" bmon -p eth1 -o 'ascii:diagram=graph;quitafter=10'\n" \ |
| " show details for all ethernet interfaces:\n" \ |
" show details for all ethernet interfaces:\n" \ |
|
Line 267 static void print_help(void)
|
Line 241 static void print_help(void)
|
| " height=NUM Height of graph (default: 6)\n" \ |
" height=NUM Height of graph (default: 6)\n" \ |
| " xunit=UNIT X-Axis Unit (default: seconds)\n" \ |
" xunit=UNIT X-Axis Unit (default: seconds)\n" \ |
| " yunit=UNIT Y-Axis Unit (default: dynamic)\n" \ |
" yunit=UNIT Y-Axis Unit (default: dynamic)\n" \ |
| " header[=NUM] Print header every NUM lines\n" \ |
|
| " noheader Do not print a header\n" \ |
|
| " quitafter=NUM Quit bmon after NUM outputs\n"); |
" quitafter=NUM Quit bmon after NUM outputs\n"); |
| } |
} |
| |
|
| static void ascii_set_opts(tv_t *attrs) | static void ascii_parse_opt(const char *type, const char *value) |
| { |
{ |
| while (attrs) { | if (!strcasecmp(type, "diagram") && value) { |
| if (!strcasecmp(attrs->type, "diagram") && attrs->value) | if (tolower(*value) == 'l') |
| set_diagram_type(attrs->value); | c_diagram_type = D_LIST; |
| else if (!strcasecmp(attrs->type, "fgchar") && attrs->value) | else if (tolower(*value) == 'g') |
| set_fg_char(attrs->value[0]); | c_diagram_type = D_GRAPH; |
| else if (!strcasecmp(attrs->type, "bgchar") && attrs->value) | else if (tolower(*value) == 'd') |
| set_bg_char(attrs->value[0]); | c_diagram_type = D_DETAILS; |
| else if (!strcasecmp(attrs->type, "nchar") && attrs->value) | else |
| set_noise_char(attrs->value[0]); | quit("Unknown diagram type '%s'\n", value); |
| else if (!strcasecmp(attrs->type, "uchar") && attrs->value) | } else if (!strcasecmp(type, "fgchar") && value) |
| set_unk_char(attrs->value[0]); | graph_cfg.gc_foreground = value[0]; |
| else if (!strcasecmp(attrs->type, "xunit") && attrs->value) | else if (!strcasecmp(type, "bgchar") && value) |
| set_x_unit(attrs->value, 1); | graph_cfg.gc_background = value[0]; |
| else if (!strcasecmp(attrs->type, "yunit") && attrs->value) | else if (!strcasecmp(type, "nchar") && value) |
| set_y_unit(attrs->value); | graph_cfg.gc_noise = value[0]; |
| else if (!strcasecmp(attrs->type, "height") && attrs->value) | #if 0 |
| c_graph_height = strtol(attrs->value, NULL, 0); | else if (!strcasecmp(type, "uchar") && value) |
| else if (!strcasecmp(attrs->type, "header")) { | set_unk_char(value[0]); |
| if (attrs->value) | #endif |
| c_print_header = strtol(attrs->value, NULL, 0); | else if (!strcasecmp(type, "xunit") && value) |
| else | c_hist = strdup(value); |
| c_print_header = INT_MAX; | #if 0 |
| } else if (!strcasecmp(attrs->type, "noheader")) | else if (!strcasecmp(type, "yunit") && value) { |
| c_print_header = 0; | struct unit *u; |
| else if (!strcasecmp(attrs->type, "quitafter") && attrs->value) | |
| c_quit_after = strtol(attrs->value, NULL, 0); | if (!(u = unit_lookup(value))) |
| else if (!strcasecmp(attrs->type, "help")) { | quit("Unknown unit '%s'\n", value); |
| print_help(); | |
| exit(0); | graph_cfg.gc_unit = u; |
| } | #endif |
| | else if (!strcasecmp(type, "height") && value) |
| attrs = attrs->next; | graph_cfg.gc_height = strtol(value, NULL, 0); |
| } | else if (!strcasecmp(type, "quitafter") && value) |
| | c_quit_after = strtol(value, NULL, 0); |
| | else if (!strcasecmp(type, "help")) { |
| | print_help(); |
| | exit(0); |
| | } else |
| | quit("Unknown module option '%s'\n", type); |
| } |
} |
| |
|
| static struct output_module ascii_ops = { | static struct bmon_module ascii_ops = { |
| .om_name = "ascii", | .m_name = "ascii", |
| .om_draw = ascii_draw, | .m_do = ascii_draw, |
| .om_probe = ascii_probe, | .m_parse_opt = ascii_parse_opt, |
| .om_set_opts = ascii_set_opts, | |
| }; |
}; |
| |
|
| static void __init ascii_init(void) |
static void __init ascii_init(void) |
| { |
{ |
| register_output_module(&ascii_ops); | output_register(&ascii_ops); |
| } |
} |