• Publicity: Public Only All

rrd-procs.tcl

RRD-procs - nx based monitoring and graphing

This file defines the following Objects and Classes: ::rrd::Graph[i], ::rrd::TrendLine[i], ::rrd::DataSource[i], ::rrd::DataLine[i], ::rrd::DataElement[i], ::rrd::Plugin[i], ::rrd::DataArea[i], ::rrd::VolatileObject[i], ::rrd::plugin::dbstats::pool3-statements[i], ::rrd::plugin::dbstats::pool2-statements[i], ::rrd::plugin::dbstats::pool2-gethandles[i], ::rrd::plugin::dbstats::pool2-waittime[i], ::rrd::plugin::dbstats::pool1-statements[i], ::rrd::plugin::users::authenticated[i], ::rrd::plugin::dbstats::pool1-gethandles[i], ::rrd::plugin::dbstats::pool1-waittime[i], ::rrd::plugin::memsize::rss[i], ::rrd::plugin::dbstats::pool3-waittime[i], ::rrd::plugin::dbstats::pool3-gethandles[i], ::rrd::plugin::dbstats::pool1-sqltime[i], ::rrd::plugin::memsize::vsize[i], ::rrd::plugin::dbstats::pool3-sqltime[i], ::rrd::plugin::dbstats::pool2-sqltime[i], ::rrd::plugin::responsetime::responsetime[i], ::rrd::plugin::users::anonymous[i], ::rrd::plugin::responsetime[i], ::rrd::plugin::memsize[i], ::rrd::plugin::users[i], ::rrd::plugin::dbstats[i], ::rrd::plugin::users[i], ::rrd::plugin::responsetime[i], ::rrd::plugin::memsize[i], ::rrd::Plugin[i], ::rrd::plugin::memsize[i], ::rrd::TrendLine[i], ::rrd::DataSource[i], ::rrd::plugin::dbstats[i], ::rrd::Plugin[i], ::rrd::plugin::users[i], ::rrd::Plugin[i], ::rrd::DataSource[i]

Location:
packages/rrd-tool/tcl/rrd-procs.tcl
Created:
2015-11-01
Author:
Gustaf Neumann
CVS Identification:
$Id: xowiki-procs.tcl,v 1.485.2.15 2015/10/22 08:28:42 gustafn Exp $

Procedures in this file

Detailed information

Class ::rrd::DataArea (public)

 ::nx::Class ::rrd::DataArea[i]

Testcases:
No testcase defined.

Class ::rrd::DataElement (public)

 ::nx::Class ::rrd::DataElement[i]

Testcases:
No testcase defined.

Class ::rrd::DataLine (public)

 ::nx::Class ::rrd::DataLine[i]

Testcases:
No testcase defined.

Class ::rrd::DataSource (public)

 ::nx::Class ::rrd::DataSource[i]

Testcases:
No testcase defined.

Class ::rrd::Graph (public)

 ::nx::Class ::rrd::Graph[i]

Testcases:
No testcase defined.

Class ::rrd::Plugin (public)

 ::nx::Class ::rrd::Plugin[i]

Testcases:
No testcase defined.

Class ::rrd::TrendLine (public)

 ::nx::Class ::rrd::TrendLine[i]

Testcases:
No testcase defined.

Class ::rrd::VolatileObject (public)

 ::nx::Class ::rrd::VolatileObject[i]

Testcases:
No testcase defined.

Object ::rrd::plugin::dbstats (public)

 ::rrd::Plugin ::rrd::plugin::dbstats[i]

Testcases:
No testcase defined.

rrd::DataArea method render (public)

 <instance of rrd::DataArea[i]> render

Testcases:
No testcase defined.

rrd::DataElement method render (public)

 <instance of rrd::DataElement[i]> render

Testcases:
No testcase defined.

rrd::DataLine method render (public)

 <instance of rrd::DataLine[i]> render

Testcases:
No testcase defined.

rrd::DataSource method deleteRRD (public)

 <instance of rrd::DataSource[i]> deleteRRD

Testcases:
No testcase defined.

rrd::DataSource method lastupdate (public)

 <instance of rrd::DataSource[i]> lastupdate

Testcases:
No testcase defined.

rrd::DataSource method requireRRD (public)

 <instance of rrd::DataSource[i]> requireRRD

Testcases:
No testcase defined.

rrd::DataSource method update (public)

 <instance of rrd::DataSource[i]> update [ -timestamp timestamp ] \
    value
Switches:
-timestamp (optional, defaults to "N")
Parameters:
value (required)

Testcases:
No testcase defined.

rrd::Graph method imgName (public)

 <instance of rrd::Graph[i]> imgName

Testcases:
No testcase defined.

rrd::Graph method render (public)

 <instance of rrd::Graph[i]> render

Testcases:
No testcase defined.

rrd::Plugin method baseResolution (public)

 <instance of rrd::Plugin[i]> baseResolution

Testcases:
No testcase defined.

rrd::Plugin method datasource (public)

 <instance of rrd::Plugin[i]> datasource varName
Parameters:
varName (required)

Testcases:
No testcase defined.

rrd::Plugin method datasources (public)

 <instance of rrd::Plugin[i]> datasources

Testcases:
No testcase defined.

rrd::Plugin method updateDataSource (public)

 <instance of rrd::Plugin[i]> updateDataSource varName value
Parameters:
varName (required)
value (required)

Testcases:
No testcase defined.

rrd::Plugin object method update (public)

 rrd::Plugin[i] update plugins
Parameters:
plugins (required)

Testcases:
No testcase defined.

rrd::TrendLine method render (public)

 <instance of rrd::TrendLine[i]> render

Testcases:
No testcase defined.

rrd::plugin::dbstats proc update (public)

 rrd::plugin::dbstats[i] update

Get db-statistics from [ns_db stats]

Testcases:
No testcase defined.

rrd::plugin::memsize proc update (public)

 rrd::plugin::memsize[i] update

Testcases:
No testcase defined.

rrd::plugin::responsetime proc update (public)

 rrd::plugin::responsetime[i] update

Testcases:
No testcase defined.

rrd::plugin::users proc update (public)

 rrd::plugin::users[i] update

Testcases:
No testcase defined.
[ hide source ] | [ make this the default ]

Content File Source

::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: