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" lappend ::colors [format %.2x%.2x%.2x $r $g $b] set h1 [expr {$h + (($c + 1.0) / $nrColors)}] if {$h1 > 1} {set h1 [expr {$h1 - 1.0}]} lassign [hsvToRgb $h1 $s $v] r g b } append ::_ $tables \n set ::colorCount -1 proc getColor {} { return [lindex $::colors [incr ::colorCount]] } set rrdPath /var/lib/munin/localdomain/localhost.localdomain set pugin naviserver_openacs_threadcpu set lines {sum-g time_conns-d time_drivers-d time_logwriter-d time_main-d time_others-d time_scheds-d time_tcl_bgdelivery-d time_tcl_throttle-d time_writers-d} # /var/lib/munin/localdomain/localhost.localdomain-naviserver_openacs_dbstats_pool2-gethandles-d.rrd # /var/lib/munin/localdomain/localhost.localdomain-naviserver_openacs_dbstats_pool2-sqltime-d.rrd # /var/lib/munin/localdomain/localhost.localdomain-naviserver_openacs_dbstats_pool2-statements-d.rrd # /var/lib/munin/localdomain/localhost.localdomain-naviserver_openacs_dbstats_pool2-waittime-d.rrd set rrdPath /var/lib/munin/localdomain/localhost.localdomain set plugin naviserver_openacs_dbstats set pools {pool1 pool2 pool3} set vars {gethandles-d sqltime-d statements-d waittime-d} set lines "" set defs {} lappend defs "COMMENT: \t\t Cur\t\tMin\t Avg\t Max\\l" set vdefs "" foreach pool $pools { foreach var $vars { set rrdFile ${rrdPath}-${plugin}_${pool}-${var}.rrd append ::_ "[file exists $rrdFile] $rrdFile
\n" if {[file exists $rrdFile]} { set vn ${pool}_${var} regsub {[-][a-z]$} $vn "" vn lappend defs "DEF:$vn=${rrdFile}:42:AVERAGE" lappend defs VDEF:${vn}cur=$vn,LAST lappend defs VDEF:${vn}min=$vn,MINIMUM lappend defs VDEF:${vn}avg=$vn,AVERAGE lappend defs VDEF:${vn}max=$vn,MAXIMUM lappend defs "LINE2:$vn#[getColor]:[format %-20s $vn]\t" lappend defs "GPRINT:${vn}cur:%6.2lf%s\t" lappend defs "GPRINT:${vn}min:%6.2lf%s\t" lappend defs "GPRINT:${vn}avg:%6.2lf%s\t" lappend defs "GPRINT:${vn}max:%6.2lf%s\\l" } } } set root $::acs::rootdir/www set fn /gaga.png set cmd [list Rrd::graph ${root}$fn --width 400 --height 180 --logarithmic --font LEGEND:7:monospace --title "gaga"] lappend cmd {*}$defs append ::_ [join $defs \n
]
[join $lines \n
]
[join $vdefs \n
] {*}$cmd append ::_ "

\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 ::_ "

Graphs from $plugin

" foreach pool {pool1 pool2 pool3} { rrd::Graph create $pool \ -title "DB Statistics of openacs.org from Pool $pool" \ -logarithmic \ -vertical-label "Operations or ms spent per minute" \ -start -2000m \ -slope-mode \ -period minutes foreach var {gethandles statements sqltime waittime} color {00aaaa 00ff00 ffdd00 fdb462} { if {$var eq ""} break $pool elements add [rrd::Line new -source $plugin -name $pool-$var -legend $var -color $color] } Rrd::graph {*}[$pool render] 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 $::_