rrd-procs.tcl
Does not contain a contract.
- Location:
- /packages/rrd-tool/tcl/rrd-procs.tcl
Related Files
[ hide source ] | [ make this the default ]
File Contents
::xo::library doc { RRD-procs - nx based monitoring and graphing @creation-date 2015-11-01 @author Gustaf Neumann @cvs-id $Id: xowiki-procs.tcl,v 1.485.2.15 2015/10/22 08:28:42 gustafn Exp $ } if {[catch { package require Rrd } errorMsg]} { ns_log warning "Can't load Tcl package Rrd: $errorMsg" namespace eval ::Rrd { proc ::Rrd::create {args} {ns_log warning "Would call Rrd::create $args"} proc ::Rrd::update {args} {ns_log warning "Would call Rrd::update $args"} proc ::Rrd::lastupdate {args} {ns_log warning "Would call Rrd::lastupdate $args"} } #return } namespace eval rrd { # # ::rrd::VolatileObject # # Graphical Object, we want auto-cleanup # nx::Class create ::rrd::VolatileObject { :method init {} { :destroy_on_cleanup } } # # rrd:Graph # nx::Class create ::rrd::Graph -superclass ::rrd::VolatileObject { :property filename :property name :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 PNG} :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 name]} { set :name [namespace tail [self]] } if {![info exists filename]} { set :imgname ${:name}.[string tolower ${:imgformat}] set :filename $::acs::rootdir/www/${:imgname} } } :public method imgName {} { return ${:imgname} } :public method render {} { set defs [list ${:filename}] foreach v [[current class] info variables] { set varName [:info variable name $v] # # the following four varnames are NOT from rrd, so don't pass # these as is to rrd. # if {$varName in {elements filename name period}} { continue } # # These are configuration variables from rrd # 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] } # get the lastupdate from the last element lassign [[$e cget -datasource] lastupdate] ds secs value regsub -all {:} [clock format [string trimright $secs :]] {\:} ts lappend defs "COMMENT:Last update\\: $ts\\r" #append ::_ "<p>GRAPH<br>[join $defs <br>\n]<br>\n" return $defs } } # # Graphical elements # nx::Class create ::rrd::Element -superclass ::rrd::VolatileObject { } # # ::rrd::DataElement # # Graphical elements with attached data # nx::Class create ::rrd::DataElement -superclass ::rrd::Element { :property name :property datasource:required :property {ds-name 42} :property {scale 1} :method init {} { next if {![info exists :name]} { set :name [${:datasource} cget -name] } } :public method render {} { set rrdFile [${:datasource} cget -rrdFile] 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 } :method gprintLegend {} { return [list \ 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 ] } } # # ::rrd::DataLine # # Line with some data attached # nx::Class create ::rrd::DataLine -superclass ::rrd::DataElement { :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 \ {*}[:gprintLegend] return $defs } } # # ::rrd::TrendLine # # TrendLine, based on scaled avg data # nx::Class create ::rrd::TrendLine -superclass ::rrd::DataElement { :property {width 1} :property color :property {legend ""} :property {window 1800} :public method render {} { if {[info exists :legend]} { set legend "[format %-20s ${:legend}]\t" } else { set legend "[format %-20s ${:name}]\t" } lappend defs \ CDEF:${:name}trend=${:name}avgscaled,${:window},TREND \ LINE${:width}:${:name}trend#${:color} return $defs } } # # ::rrd::DataArea # # Area with some data attached # nx::Class create ::rrd::DataArea -superclass ::rrd::DataElement { :property color :property color2 :property legend :property {gradheight 50} :public method render {} { set defs [next] if {[info exists :legend]} { set legend "[format %-20s ${:legend}]\t" } else { set legend "[format %-20s ${:name}]\t" } set colors ${:color} if {[info exists :color2]} {append colors \#${:color2}} lappend defs \ AREA:${:name}avgscaled#${colors}:$legend:gradheight=${:gradheight} \ {*}[:gprintLegend] return $defs } } # # ::rrd::DataSource # nx::Class create ::rrd::DataSource { :property name :property baseResolution :property rrdFile :property {type DERIVE} :method createRRDfile {} { set durations [[:info parent] cget -durations] 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" } #ns_log notice "$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" } ns_log notice "try to create: Rrd::create ${:rrdFile} --step ${:baseResolution} DS:42:DERIVE:10m:0:U {*}$RRA" Rrd::create ${:rrdFile} --step ${:baseResolution} "DS:42:${:type}:10m:0:U" {*}$RRA } :public method update {{-timestamp N} value} { ns_log notice "Rrd::update ${:rrdFile} ${timestamp}:$value" Rrd::update ${:rrdFile} ${timestamp}:$value } :public method lastupdate {} { return [Rrd::lastupdate ${:rrdFile}] } :public method requireRRD {} { if {![file exists ${:rrdFile}]} { :createRRDfile } } :public method deleteRRD {} { if {[file exists ${:rrdFile}]} { file delete ${:rrdFile} } } :method init {} { next if {![info exists :name]} { set :name [namespace tail [self]] } set :rrdFile [[:info parent] cget -rrdPath]_${:name}-d.rrd append ::log "rrdFile of [self] is ${:rrdFile}<br>\n" :requireRRD } } # # ::rrd::Plugin # nx::Class create ::rrd::Plugin { :property vars :property name :property {rrdRoot /var/lib/munin/localdomain/localhost.localdomain} :property rrdPath :property {type DERIVE} :property {durations { "5 min" "2 days" "30 min" "9 days" "2 hours" "45 days" "1 day" "450 days" }} :public object method update {plugins} { foreach p $plugins { if {[info commands $p] eq ""} { ns_log warning "::rrd::Plugin: $p is not a command, ignore update" continue } $p update } } :method init {} { next if {![info exists :name]} { set :name [namespace tail [self]]} set :rrdPath ${:rrdRoot}_${:name} set :baseResolution [clock scan [lindex ${:durations} 0] -timezone :UTC -base 0] foreach varName ${:vars} { ::rrd::DataSource create [self]::$varName -baseResolution ${:baseResolution} -type ${:type} } } :public method baseResolution {} { return ${:baseResolution} } :public method datasource {varName} { if {[info commands [self]::$varName] ne ""} { return [self]::$varName } else { error "no data source $varName exists for plugin ${:name}" } } :public method datasources {} { return [:info children -type ::rrd::DataSource] } :public method updateDataSource {varName value} { [self]::$varName update $value } } } ::xo::library source_dependent # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: