#!/usr/bin/gawk -f # # netdrawmon -- 2007-12-13, last edit 2008-05-19 # # script to draw most recent month's daily totals chart, this script # is called from crontab at the top of each hour # # Copyright (C) 2007 Grant Coady GPLv2 # BEGIN { ARGV[ARGC++] = "/etc/netdraw.conf" # grab configuration file # option -v showdate="yyyy-mm-dd" if (show_date) { split(show_date, dt, "-") this_mon = dt[2] } else { this_mon = strftime("%m") } } /^$|^#/ { next } NR == FNR { conf[$1] = $2 if ($1 == "datafile") ARGV[ARGC++] = conf["datapath"] "/" $2 next } { split($1, dt, "[-.:]") year = dt[1] mon = dt[2] day = dt[3] hour = dt[4] min = dt[5] if (FNR > 1) { rx = $2 - old_rx # discover bytes transferred tx = $3 - old_tx if (rx < 0) rx = 0 # zero if reconnection if (tx < 0) tx = 0 trx += rx # accumulate totals ttx += tx if (hour == 23 && min == 59) { # last sample for the day if (mon == this_mon) { # transfer if this month dayrx[+day] = trx daytx[+day] = ttx } trx = ttx = 0 # clear daily totals # force selected date output for -v show_date if (show_date == year "-" mon "-" day) { # munge output filename split(conf["monimg"],dt,".") conf["monimg"] = dt[1] "-" show_date "." dt[2] nextfile } } } old_rx = $2; old_tx = $3 # save for next sample start } # create fly script for image generation END { if (!dayrx[+day]) dayrx[+day] = trx # get today's partial totals? if (!daytx[+day]) daytx[+day] = ttx # (+day converts string to number) for (i = 1; i <= day; i++) { # find max value for fs calibration if (dayrx[i] > max) max = dayrx[i] if (daytx[i] > max) max = daytx[i] } m = 400000 # select calibration interval if (max > 12000000) m = 4000000 if (max > 120000000) m = 40000000 if (max > 1200000000) m = 400000000 if (max > 12000000000) m = 4000000000 if (max > 120000000000) m = 40000000000 fullscale = m while (fullscale < max) # calibrate fullscale fullscale += m # create fullscale label text if (fullscale > 1000000000) fs_label = sprintf("%1.1fGB", fullscale / 1000000000) else fs_label = sprintf("%1.1fMB", fullscale / 1000000) # do chart scaling and prepare chart fs = fullscale / 80 # fullscale to 80px chart height fs2 = fullscale / 160 # half for integer rounding ox = 22 # left chart origin oy = 98 # baseline chart origin ot = 2 # origin for top label text ob = 115 # origin for bottom label text mx = 31 * 9 # chart width out = conf["monfly"] # fly script output file col_mix = set_col_mix() fly_chart(320, 132) # start chart fly script fly_scale(fs_label) # show vertical scale month = strftime("%B", mktime(year" "mon" "day" 12 0 0")) fly_date(month" "year) # show the date gsub(/_/, " ", conf["title"]) # paint title label fly_title(conf["title"]) # paint the chart gridlines and outline fly_line(ox, oy-80, ox, oy, conf["col_grid"]) # left fly_line(ox+mx, oy-80, ox+mx, oy, conf["col_grid"]) # right fly_line(ox-2, oy-81, ox+mx, oy-81, conf["col_grid"]) # top fly_dlin(ox, oy-61, ox+mx, oy-61, conf["col_grid"]) fly_dlin(ox, oy-41, ox+mx, oy-41, conf["col_grid"]) # mid fly_dlin(ox, oy-21, ox+mx, oy-21, conf["col_grid"]) fly_line(ox-2, oy, ox+mx, oy, conf["col_base"]) # base fly_fsquar(ox+mx-52, ot + 3, 7, conf["col_rx"]) # paint chart key fly_string(ox+mx-41, ot, "Rx", conf["col_text"]) fly_fsquar(ox+mx-21, ot + 3, 7, conf["col_tx"]) fly_string(ox+mx-11, ot, "Tx", conf["col_text"]) axis_x = conf["monaxisx"]; gsub(/_/, " ", axis_x) # paint axis labels axis_y = conf["monaxisy"]; gsub(/_/, " ", axis_y) fly_string(ox, ob , axis_x, conf["col_text"]) fly_strgup(ox-17, oy-2, axis_y, conf["col_text"]) fly_line(ox+x, oy+1, ox+x, oy+2, conf["col_base"]) # origin pip for (i = 1; i <= day; i++) { # paint pips and labels x = i * 9 fly_line(ox+x, oy+1, ox+x, oy+2, conf["col_base"]) fly_xlabel(ox+x-8, oy+14, i, conf["col_text"]) } x = day * 9; fly_line(ox+x, oy+1, ox+x, oy+2, conf["col_base"]) for (i = 1; i <= day; i++) { # paint data x1 = ox + ((i - 1) * 9) + 1 x2 = x1 + 7 rx = scale(dayrx[i]) tx = scale(daytx[i]) if (rx == tx) # equal? paint in mixed colour print "frect " x1 "," oy "," x2 "," oy-rx "," \ col_mix > out else if (rx > tx) { # paint smaller in mixed colour print "frect " x1 "," oy "," x2 "," oy-rx "," \ conf["col_rx"] > out print "frect " x1 "," oy "," x2 "," oy-tx "," \ col_mix > out } else { print "frect " x1 "," oy "," x2 "," oy-tx "," \ conf["col_tx"] > out print "frect " x1 "," oy "," x2 "," oy-rx "," \ col_mix > out } montrx += dayrx[i] # accumulate month's totals for 'ron monttx += daytx[i] } # paint baseline over chart zero data fly_line(ox, oy, ox+mx, oy, conf["col_base"]) # base fly_totals() # paint the totals # create the image file system("fly -q -i " out " -o " conf["htmlpath"] "/" conf["monimg"]) } function scale(s, t) { t = int((s + fs2) / fs) # to chart scale if (!t && s) t++ # don't lose near zero data return t } function set_col_mix( cr, ct, a, b, c) { split(conf["col_rx"], cr, ",") split(conf["col_tx"], ct, ",") a = (cr[1] + ct[1] + 1) / 2 b = (cr[2] + ct[2] + 1) / 2 c = (cr[3] + ct[3] + 1) / 2 return sprintf("%d,%d,%d", a, b, c) } function fly_chart(x, y) { print "# netdraw" > out print "new" > out print "size " x "," y > out print "type png" > out print "fill 1,1," conf["col_back"] > out } function fly_string(x, y, t, c) { print "string " conf["col_shdw"] "," x + 1 "," y ",small," t > out print "string " conf["col_shdw"] "," x + 1 "," y + 1 ",small," t > out print "string " c "," x "," y ",small," t > out } function fly_scale(s) { fly_string(ox, ot, s, conf["col_text"]) return } function fly_date(s, x) { x = ox + mx+1 - (length(s) * 6) # right justify fly_string(x, ob, s, conf["col_text"]) } function fly_title(s, x) { if (!s) return x = int(((length(s) * 6) / 2)) # get half pixel width of title x = ox + (mx/2) - x # centre it fly_string(x, ob, s, conf["col_text"]) } function fly_stringup(x, y, t, s, c) { print "stringup " conf["col_shdw"] "," x+1 "," y "," s "," t > out print "stringup " conf["col_shdw"] "," x+1 "," y+1 "," s "," t > out print "stringup " c "," x "," y "," s "," t > out } function fly_strgup(x, y, t, c) { fly_stringup(x, y, t, "small", c) } function fly_xlabel(x, y, n, c) { fly_stringup(x, y, sprintf("%2d",n), "tiny", c) } function fly_fsquar(x, y, s, c) { print "fsquare " x+1 "," y+1 "," s "," conf["col_shdw"] > out print "fsquare " x "," y "," s "," c > out } function fly_line(x1, y1, x2, y2, c) { print "line " x1 "," y1 "," x2 "," y2 "," c > out } function fly_dlin(x1, y1, x2, y2, c) { print "dline " x1 "," y1 "," x2 "," y2 "," c > out } function form_totals(n) { if (n > 1000000000 && conf["showtotGB"]) return sprintf("%1.2fGB", n / 1000000000) return sprintf("%1.2fMB", n / 1000000) } function fly_totals( s, x) { if (!conf["montotals"]) return s = form_totals(montrx) x = ox + mx/2 - ((length(s) + 1) * 6) fly_string(x, ot, s, conf["col_rx"]) s = form_totals(monttx) x = ox + mx/2 + 6 fly_string(x, ot, s, conf["col_tx"]) if (conf["title"]) return s = form_totals(montrx + monttx) x = ox + mx/2 - ((length(s) + 1) * 3) fly_string(x, ob, s, col_mix) } # end