package req Rrd
set distinctFactor 10
proc getColor {index} {
}
proc rgbToHsv {red green blue} {
if {$red > $green} {
set max [expr {double($red)}]
set min [expr {double($green)}]
} else {
set max [expr {double($green)}]
set min [expr {double($red)}]
}
if {$blue > $max} {
set max [expr {double($blue)}]
} elseif {$blue < $min} {
set min [expr {double($blue)}]
}
set range [expr {$max-$min}]
if {$max == 0} {
set sat 0
} else {
set sat [expr {($max-$min)/$max}]
}
if {$sat == 0} {
set hue 0
} else {
set rc [expr {($max - $red)/$range}]
set gc [expr {($max - $green)/$range}]
set bc [expr {($max - $blue)/$range}]
if {$red == $max} {
set hue [expr {($bc - $gc)/6.0}]
} elseif {$green == $max} {
set hue [expr {(2 + $rc - $bc)/6.0}]
} else {
set hue [expr {(4 + $gc - $rc)/6.0}]
}
if {$hue < 0.0} {
set hue [expr {$hue + 1.0}]
}
}
return [list $hue $sat [expr {$max/65535}]]
}
proc hsvToRgb {hue sat value} {
set v [format %.0f [expr {65535.0*$value}]]
if {$sat == 0} {
return "$v $v $v"
} else {
set hue [expr {$hue*6.0}]
if {$hue >= 6.0} {
set hue 0.0
}
scan $hue. %d i
set f [expr {$hue-$i}]
set p [format %.0f [expr {65535.0*$value*(1 - $sat)}]]
set q [format %.0f [expr {65535.0*$value*(1 - ($sat*$f))}]]
set t [format %.0f [expr {65535.0*$value*(1 - ($sat*(1 - $f)))}]]
switch $i {
0 {return "$v $t $p"}
1 {return "$q $v $p"}
2 {return "$p $v $t"}
3 {return "$p $q $v"}
4 {return "$t $p $v"}
5 {return "$v $p $q"}
default {error "i value $i is out of range"}
}
}
}
set r [expr round(rand()*255)]
set g [expr round(rand()*255)]
set b [expr round(rand()*255)]
set r 250
set g 0
set b 0
set nrColors 12
set tables ""
set h1 ""
#set ::colors {8dd3c7 ffffb3 bebada fb8072 80b1d3 fdb462 b3de69 fccde5 d9d9d9 bc80bd ccebc5 ffed6f}
set ::colors {8dd3c7 ffdd00 bebada fb8072 80b1d3 fdb462 b3de69 fccde5 d9d9d9 bc80bd ccebc5 0000ff}
lassign [rgbToHsv $r $g $b] h s v
for {set c 0} {$c < $nrColors} {incr c} {
append ::_ "$c rgb $r $g $b hsv $h $s $v //$h1\n
"
append tables "
| [string repeat   10] |
\n"
namespace eval rrd {}
nx::Class create ::rrd::Object {
:method init {} {
:destroy_on_cleanup
}
}
nx::Class create rrd::Graph -superclass ::rrd::Object {
:property filename
:property -incremental {elements:0..n ""}
:property {period seconds}
# time range properties
:property start
:property end
:property step
# labels
:property title
:property vertical-label
# size
:property {width:integer 400}
:property {height:integer 175}
:property only-graph:switch
:property fill-size-mode:switch
# limits
:property upper-limit
:property lower-limit
:property rigid:switch
:property alt-autoscale:switch
:property alt-autoscale-min:switch
:property alt-autoscale-max:switch
:property no-gridfit:switch
# x-axis
:property x-grid
:property x-grid-none:switch
:property week-fmt
# y-axis
:property y-grid
:property y-grid-none:switch
:property left-axis-formatter
:property left-axis-format
:property alt-y-grid:switch
:property logarithmic:switch
:property units-exponent:integer
:property units-length:integer
# --units=si?
:property right-axis
:property right-axis-label
:property right-axis-formatter
:property right-axis-format
# legend
:property no-legend:switch
:property force-rules-legend:switch
:property legend-position
:property legend-direction
# misc
:property lazy:switch
:property daemon
:property imginfo
:property {color:0..n {FONT#666666 ARROW#CFD6F8}} ;# can be specified multiple times
:property grid-dash
:property border:integer
:property dynamic-labels:switch
:property zoom
:property {font:0..n {
"DEFAULT:0:DejaVuSans,DejaVu Sans,DejaVu LGC Sans,Bitstream Vera Sans"
LEGEND:7:monospace
TITLE:12
AXIS:8
UNIT:8
}}
:property font-render-mode
:property font-smoothing-threshold
:property pango-markup:switch
:property graph-render-mode
:property slope-mode:switch
:property imgformat
:property interlaced:switch
:property tabwidth:integer
:property {base:integer 1000}
:property {watermark "nx-rrd 0.1"}
:property use-nan-for-all-missing-data:swtich
:method init {} {
next
if {![info exists filename]} {
set :filename $::acs::rootdir/www/[namespace tail [self]].png
}
}
:public method render {} {
set defs [list ${:filename}]
foreach v [[current class] info variables] {
# append ::_ ".... " \
# [:info variable name $v] " /// " \
# [:info variable definition $v] " /// " \
# [:info variable parameter $v] " " \
# "
\n"
set varName [:info variable name $v]
if {$varName in {elements filename period}} {
continue
}
if {[info exists :$varName]} {
switch -glob -- [lindex [:info variable parameter $v] 0] {
*:boolean {
if {[set :$varName]} {lappend defs --$varName}
}
*:0..n {
foreach e [set :$varName] {
lappend defs --$varName $e
}
}
default { lappend defs --$varName [set :$varName]}
}
}
}
switch ${:period} {
day {set scale 34560}
hours {set scale 1440}
minutes {set scale 60}
seconds -
default {set scale 1}
}
foreach e ${:elements} { $e configure -scale $scale }
lappend defs "COMMENT: \t\t Cur\tMin\t Avg\t Max\\l"
foreach e ${:elements} {
lappend defs {*}[$e render]
}
#append ::_ "
GRAPH
[join $defs
\n]
\n"
return $defs
}
}
nx::Class create ::rrd::Data -superclass ::rrd::Object {
:property name:required
:property source:required
:property {ds-name 42}
:property {scale 1}
:object property {rrdPath /var/lib/munin/localdomain/localhost.localdomain}
:public method render {} {
set rrdFile [::rrd::Data cget -rrdPath]-${:source}_${:name}-d.rrd
regsub -all {[-]} ${:name} _ :name
lappend defs \
DEF:${:name}avg=${rrdFile}:${:ds-name}:AVERAGE \
DEF:${:name}cur=${rrdFile}:${:ds-name}:LAST \
DEF:${:name}min=${rrdFile}:${:ds-name}:MIN \
DEF:${:name}max=${rrdFile}:${:ds-name}:MAX \
CDEF:${:name}avgscaled=${:name}avg,${:scale},* \
CDEF:${:name}curscaled=${:name}cur,${:scale},* \
CDEF:${:name}minscaled=${:name}min,${:scale},* \
CDEF:${:name}maxscaled=${:name}max,${:scale},*
return $defs
}
}
nx::Class create ::rrd::Line -superclass ::rrd::Data {
:property {width 1}
:property color
:property legend
:public method render {} {
set defs [next]
if {[info exists :legend]} {
set legend "[format %-20s ${:legend}]\t"
} else {
set legend "[format %-20s ${:name}]\t"
}
lappend defs \
LINE${:width}:${:name}avgscaled#${:color}:$legend \
GPRINT:${:name}curscaled:LAST:%6.2lf%s\t \
GPRINT:${:name}minscaled:MIN:%6.2lf%s\t \
GPRINT:${:name}avgscaled:AVERAGE:%6.2lf%s\t \
GPRINT:${:name}maxscaled:MAX:%6.2lf%s\\l
#append ::_ "
[join $defs
\n]
\n"
return $defs
}
}
set plugin "naviserver_openacs_dbstats"
append ::_ "
\n"
append ::log "[join [$pool render]
\n]
\n"
}
foreach x {1} y {1 2 3} {puts "x=$x y=$y"}
set rrdTest /tmp/localhost.localdomain-naviserver_openacs_dbstats_pool1-statements-d.rrd
#file delete $rrdTest
if {![file exists $rrdTest]} {
set durations {
"5 min" "2 days"
"30 min" "9 days"
"2 hours" "45 days"
"1 day" "450 days"
}
set baseResolution [clock scan [lindex $durations 0] -timezone :UTC -base 0]
foreach duration $durations {
set d [clock scan $duration -timezone :UTC -base 0]
set multiple($duration) [expr {$d / $baseResolution}]
if {$multiple($duration) * $baseResolution != $d} {
error "duration '$duration' is not a multiple of the base resolution $baseResolution secs"
}
}
set RRA {}
foreach {res duration} $durations {
set m [expr {$multiple($duration)/$multiple($res)}]
if {$m * $multiple($res) != $multiple($duration)} {
error "duration '$duration' is not a multiple of the resolution $res"
}
puts stderr "$multiple($res) [expr {$multiple($duration)/$multiple($res)}]"
lappend RRA \
"RRA:AVERAGE:0.5:$multiple($res):$m" \
"RRA:MIN:0.5:$multiple($res):$m" \
"RRA:MAX:0.5:$multiple($res):$m"
}
Rrd::create $rrdTest --step $baseResolution "DS:42:DERIVE:10m:0:U" {*}$RRA
}
set pairs [ns_db stats]
foreach {p values} $pairs {
if {$p ne "pool1"} continue
foreach {key value} $values {
if {$key ne "statements"} continue
if {![string is integer -strict $value]} {
# assume floating point number in secs, compute ms
set value [expr {round ($value*1000)}]
}
break
}
}
append ::_ "
$pairs
Rrd::update $rrdTest N:$value
\n"
Rrd::update $rrdTest N:$value
ns_return 200 text/html $::_