From 6e5f7b4b3440a9fdce748d659dba6d6f1beb109b Mon Sep 17 00:00:00 2001 From: justme1968 Date: Mon, 18 Feb 2013 20:16:02 +0000 Subject: [PATCH] - allow less frequent updates for diskusage - allow remote monitoring by ssh git-svn-id: https://svn.fhem.de/fhem/trunk@2761 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/CHANGED | 2 + fhem/FHEM/32_SYSSTAT.pm | 148 ++++++++++++++++++++++++++++++++-------- 2 files changed, 121 insertions(+), 29 deletions(-) diff --git a/fhem/CHANGED b/fhem/CHANGED index 4b75658fe..858cc74b1 100644 --- a/fhem/CHANGED +++ b/fhem/CHANGED @@ -1,4 +1,6 @@ - SVN + - change: SYSSTAT: allow remote monitoring by ssh + - change: SYSSTAT: allow less frequent updates for diskusage - feature: new Module 32_SYSSTAT to monitor system load and disk usage on linux FHEM hosts (by justme1968) - feature: new Module 73_PRESENCE to make automatic presence detection of diff --git a/fhem/FHEM/32_SYSSTAT.pm b/fhem/FHEM/32_SYSSTAT.pm index 68d361f75..ab65ac451 100644 --- a/fhem/FHEM/32_SYSSTAT.pm +++ b/fhem/FHEM/32_SYSSTAT.pm @@ -3,7 +3,8 @@ package main; use strict; use warnings; -use Sys::Statistics::Linux; +use Sys::Statistics::Linux::LoadAVG; +use Sys::Statistics::Linux::DiskUsage; sub SYSSTAT_Initialize($) @@ -14,7 +15,7 @@ SYSSTAT_Initialize($) $hash->{UndefFn} = "SYSSTAT_Undefine"; $hash->{GetFn} = "SYSSTAT_Get"; $hash->{AttrFn} = "SYSSTAT_Attr"; - $hash->{AttrList} = "filesystems showpercent:1 useregex:1 loglevel:0,1,2,3,4,5,6 ". + $hash->{AttrList} = "filesystems showpercent:1 useregex:1 ssh_user loglevel:0,1,2,3,4,5,6 ". $readingFnAttributes; } @@ -27,21 +28,55 @@ SYSSTAT_Define($$) my @a = split("[ \t][ \t]*", $def); - return "Usage: define SYSSTAT [interval]" if(@a < 2); + return "Usage: define SYSSTAT [interval [interval_fs [host]]]" if(@a < 2); my $interval = 60; if(int(@a)>=3) { $interval = $a[2]; } if( $interval < 60 ) { $interval = 60; } + my $interval_fs = $interval * 60; + if(int(@a)>=4) { $interval_fs = $a[3]; } + if( $interval_fs < $interval ) { $interval_fs = $interval; } + if( $interval_fs == $interval ) { $interval_fs = undef; } + + my $host = $a[4] if(int(@a)>=5);; + + delete( $hash->{INTERVAL_FS} ); + delete( $hash->{HOST} ); + $hash->{STATE} = "Initialized"; $hash->{INTERVAL} = $interval; + $hash->{INTERVAL_FS} = $interval_fs if( defined( $interval_fs ) ); - $hash->{xls} = Sys::Statistics::Linux->new( loadavg => 1 ); + $hash->{HOST} = $host if( defined( $host ) ); + + $hash->{interval_fs} = $interval_fs; + SYSSTAT_InitSys( $hash ); InternalTimer(gettimeofday()+$hash->{INTERVAL}, "SYSSTAT_GetUpdate", $hash, 0); return undef; } +sub +SYSSTAT_InitSys( $ ) +{ + my ($hash) = @_; + + if( defined($hash->{HOST}) ) { + my $cmd = qx(which ssh); + chomp( $cmd ); + my $user = AttrVal($hash->{NAME}, "ssh_user", undef ); + $cmd .= ' '; + $cmd .= $user."\@" if( defined($user) ); + $cmd .= $hash->{HOST}." df -kP 2>/dev/null"; + $hash->{loadavg} = Sys::Statistics::Linux::LoadAVG->new; + $hash->{diskusage} = Sys::Statistics::Linux::DiskUsage->new( cmd => { path => '', + df => $cmd } ); + } else { + $hash->{loadavg} = Sys::Statistics::Linux::LoadAVG->new; + $hash->{diskusage} = Sys::Statistics::Linux::DiskUsage->new; + } +} sub SYSSTAT_Undefine($$) @@ -52,31 +87,30 @@ SYSSTAT_Undefine($$) return undef; } -sub +sub SYSSTAT_Get($@) -{ - my ($hash, @a) = @_; +{ + my ($hash, @a) = @_; my $name = $a[0]; return "$name: get needs at least one parameter" if(@a < 2); - + my $cmd= $a[1]; - + if($cmd eq "filesystems") { - my $sys = Sys::Statistics::Linux->new(diskusage => 1); - my $filesystems = $sys->get->{diskusage}; + my $filesystems = $hash->{diskusage}->get; my $ret; $ret .= " <= \n"; - foreach my $filesystem (keys %$filesystems ) { + foreach my $filesystem (keys %$filesystems ) { $ret .= $filesystem ." <= ". $filesystems->{$filesystem}->{mountpoint} ."\n"; } return $ret; } else { return "Unknown argument $cmd, choose one of filesystems"; - } -} + } +} sub SYSSTAT_Attr($$$) @@ -92,14 +126,10 @@ SYSSTAT_Attr($$$) my $hash = $defs{$name}; my @filesystems = split(",",$attrVal); @{$hash->{filesystems}} = @filesystems; - - if( $#filesystems >= 0 ) { - $hash->{xls}->set( loadavg => 1, - diskusage => 1 ); - } else { - $hash->{xls}->set( loadavg => 1, - diskusage => 0 ); - } + } elsif( $attrName eq "ssh_user") { + $attr{$name}{$attrName} = $attrVal; + my $hash = $defs{$name}; + SYSSTAT_InitSys( $hash ); } if( $cmd eq "set" ) { @@ -112,6 +142,7 @@ SYSSTAT_Attr($$$) return; } +sub SYSSTAT_getLoadAVG( $ ); sub SYSSTAT_GetUpdate($) { @@ -122,15 +153,28 @@ SYSSTAT_GetUpdate($) InternalTimer(gettimeofday()+$hash->{INTERVAL}, "SYSSTAT_GetUpdate", $hash, 1); } - my $stat = $hash->{xls}->get; - - my $load = $stat->{loadavg}; + my $load = $hash->{loadavg}->get; + my $load = SYSSTAT_getLoadAVG( $hash ); $hash->{STATE} = $load->{avg_1} . " " . $load->{avg_5} . " " . $load->{avg_15}; readingsSingleUpdate($hash,"load",$load->{avg_1},defined($hash->{LOCAL} ? 0 : 1)); - if( defined(my $usage = $stat->{diskusage}) ){ + my $do_diskusage = 1; + if( defined($hash->{INTERVAL_FS} ) ) { + $do_diskusage = 0; + $hash->{interval_fs} -= $hash->{INTERVAL}; + + if( $hash->{interval_fs} <= 0 ) { + $do_diskusage = 1; + $hash->{interval_fs} += $hash->{INTERVAL_FS}; + } + } + + if( $do_diskusage + && $#{$hash->{filesystems}} >= 0 ) { + + my $usage = $hash->{diskusage}->get; my $type = 'free'; if( AttrVal($hash->{NAME}, "showpercent", "") ne "" ) { @@ -155,6 +199,44 @@ SYSSTAT_GetUpdate($) } } +sub SYSSTAT_getLoadAVG( $ ) +{ + my ($hash) = @_; + + if( defined($hash->{HOST}) ) { + no strict; + no warnings 'redefine'; + local *Sys::Statistics::Linux::LoadAVG::get = sub { + my $self = shift; + my $class = ref $self; + my $file = $self->{files}; + my %lavg = (); + + my $cmd = qx(which ssh); + chomp( $cmd ); + my $user = AttrVal($hash->{NAME}, "ssh_user", undef ); + $cmd .= ' '; + $cmd .= $user."\@" if( defined($user) ); + $cmd .= $hash->{HOST}." cat /proc/loadavg 2>/dev/null"; + my $fh; + if( open($fh, "$cmd|" ) ) { + ( $lavg{avg_1} + , $lavg{avg_5} + , $lavg{avg_15} + ) = (split /\s+/, <$fh>)[0..2]; + + close($fh); + } + return \%lavg; + }; + + return $hash->{loadavg}->get; + } + + return $hash->{loadavg}->get; +} + + 1; =pod @@ -163,7 +245,7 @@ SYSSTAT_GetUpdate($)

SYSSTAT

    - Provides system statistics for the host FHEM runs on.

    + Provides system statistics for the host FHEM runs on or a remote Linux system that is reachable by preconfigured passwordless ssh access.

    Notes:
      @@ -171,6 +253,7 @@ SYSSTAT_GetUpdate($)
    • This module needs Sys::Statistics::Linux on Linux.
      It can be installed with 'cpan install Sys::Statistics::Linux'
      or on debian with 'apt-get install libsys-statistics-linux-perl'
    • +
    • To plot the load values the following code can be used:
         define sysstatlog FileLog /usr/local/FHEM/var/log/sysstat-%Y-%m.log sysstat
      @@ -184,17 +267,22 @@ SYSSTAT_GetUpdate($)
         
         Define
         
        - define <name> SYSSTAT [<interval>]
        + define <name> SYSSTAT [<interval> [<interval_fs>] [<host>]]

        Defines a SYSSTAT device.

        - The statistics are updated <interval> seconds. The default and minimum is 60.

        + The load is updated every <interval> seconds. The default and minimum is 60.

        + The diskusage is updated every <interval_fs> seconds. The default is <interval>*60 and the minimum is 60. + <interval_fs> is only aproximated and works best if <interval_fs> is an integral multiple of <interval>.

        + + If <host> is given it has to be accessible by ssh without the need for a password. Examples:
          define sysstat SYSSTAT
          define sysstat SYSSTAT 300
          + define sysstat SYSSTAT 60 600

      @@ -234,6 +322,8 @@ SYSSTAT_GetUpdate($) If set the usage is shown in percent. If not set the remaining free space in bytes is shown.
    • useregex
      If set the entries of the filesystems list are treated as regex.
    • +
    • ssh_user
      + The username for ssh remote access.