YAPC2007 Remote System Monitoring (w. Notes)

72
Remote System Monitoring Roland Giersig <[email protected]> Maintainer of Expect and IO::Tty on CPAN Sponsored by xion.at 

description

Tools & Techniques

Transcript of YAPC2007 Remote System Monitoring (w. Notes)

Page 1: YAPC2007 Remote System Monitoring (w. Notes)

Remote System Monitoring

Roland Giersig <[email protected]>

Maintainer of Expect and IO::Tty on CPAN

Sponsored by xion.at   

Page 2: YAPC2007 Remote System Monitoring (w. Notes)

System Monitoring

● What to monitor● How to monitor● Which kind of data to collect● When to use the collected data

Page 3: YAPC2007 Remote System Monitoring (w. Notes)

What to monitor

● Applications / Daemons● that provide Services● on one or more Ports● Running on one or more Machines.

Page 4: YAPC2007 Remote System Monitoring (w. Notes)

Remote vs. Local Checks

● Remote checks– Port­availability– Network– Dummy requests / Status servlet

● Local checks– Required processes running?– Networks available?– Error messages in Logfiles?– Application throughput?– System parameters OK?

Page 5: YAPC2007 Remote System Monitoring (w. Notes)

When to analyze

● Instant notification– Daily Operations– Boundaries/Limits checking

● Historical data– Problem determination and analysis– Statistics / Graphs

Page 6: YAPC2007 Remote System Monitoring (w. Notes)

How to collect

● Dedicated monitoring host– collects data from application machines– global data loss in case of network/monitoring failure

● Store data locally on each host– and backup/archive that data!

Page 7: YAPC2007 Remote System Monitoring (w. Notes)

Why History?

● For problem determination and analysis● Statistics / Graphs

– Show bottlenecks– Prove upgrade needs– Managers are loving it

Page 8: YAPC2007 Remote System Monitoring (w. Notes)

Ready­Made vs. Roll­your­own

– Deploying existing tools is fast– Gives you generic checks– Can be customized over time– Does it store monitoring data locally?– Recommendation: roll­your­own system 

monitoring

Page 9: YAPC2007 Remote System Monitoring (w. Notes)

Using NAGIOS

● http://www.nagios.org/● Network­ and Port­Checking● Needs plug­ins for remote checking● Use 'ssh' or NRPE● Think about security, 

use a non­privileged user.● 'sudo' is your friend.

Page 10: YAPC2007 Remote System Monitoring (w. Notes)

Data Format

● Should be simple, human­readable, parseable, flexible, grepable.

● YAML? Not grepable.● CSV? Not flexible.● Enhance CSV with infield header info:

ts=2007­08­28_11:50:00,task=YAPC::2007,\ status=attending

Page 11: YAPC2007 Remote System Monitoring (w. Notes)

Data Format (parsing)

● Easily parseable:@d = split(',', $_); # don't, use Text::CSV_XS%h = map {(split('=', $_, 2))} @d;

● use Text::CSV_XS

Page 12: YAPC2007 Remote System Monitoring (w. Notes)

Checking Logfiles

● How to count “matching log­lines per minute”?# in shelltail ­f access_log | grep " 200 " | wc ­l

# doesn't work :­(

● Use File::Tail (available from CPAN)

Page 13: YAPC2007 Remote System Monitoring (w. Notes)

Using File::Tail 

%patterns = (  '/var/logs/httpd/access_log' => [    {     regexp  => qr/ 200 /,     outfile => '/var/logs/monitoring/access_ok.last',     history => '/var/logs/monitoring/access_ok.log',     count => 0,    },    {     regexp  => qr/ 504 /,     outfile => '/var/logs/monitoring/access_gw_errors.last',     history => '/var/logs/monitoring/access_gw_errors.log',     count => 0,    },  ],);

Page 14: YAPC2007 Remote System Monitoring (w. Notes)

Using File::Tail (2)

my @tails = map {File::Tail­>new(name=>$_,                                 maxinterval=>10,                                 resetafter=>120,                                 reset_tail=>0,                                );                } keys %patterns;while (1) {  my ($nfound, $timeleft, @pending)=    File::Tail::select(undef, undef, undef, undef, @tails);  foreach my $f (@pending) {    my $line = $f­>read();    my $logfile = $f­>{input};    foreach my $p (@{$patterns{$logfile}}) {      $p­>{count}++        if ($line =~ m/$p­>{regexp}/);    }  }}

Page 15: YAPC2007 Remote System Monitoring (w. Notes)

Using File::Tail (3)$SIG{ALRM} = sub {  my $time = strftime("%Y­%m­%d_%H:%M:%S", localtime());  foreach my $p (map {@$_} values %patterns) { # expand list    $p­>{count} ||= 0; # be sure there is a num there

    open (STATFILE, ">$p­>{outfile}.$$")  # write to a temp file      or die "$0: ERROR opening stat file $p­>{outfile}: $!\n";    print STATFILE "$p­>{count}\n";    close STATFILE;    rename "$p­>{outfile}.$$" => $p­>{outfile}; # atomic update

    open (STATFILE, ">>$p­>{history}") # append to history      or die "$0: ERROR opening history file $p­>{history}: $!\n";    print STATFILE "ts=$time,cnt=$p­>{count}\n";    close STATFILE;        $p­>{count} = 0; # reset counter  }  alarm 60; # reset alarm};alarm 60; # upon alarm, write statistic files and reset counters

Page 16: YAPC2007 Remote System Monitoring (w. Notes)

'nmon'

● 'nmon' courtesy of IBM (unsupported)● Performance Data

– CPU utilization, Memory use, Kernel statistics and run queue– Disks I/O rates, transfers, and read/write ratios, File­systems size and free 

space, Disk adapters, Paging space and paging rates, User defined disk groups

– Network I/O rates, transfers, and read/write ratios– Machine details, CPU and OS specification, Top processors– Dynamic LPAR changes ­ AIX and Linux (on POWER hardware)

Page 17: YAPC2007 Remote System Monitoring (w. Notes)

'nmon' screenshot

──nmon­v10r c=CPU Host=was1prdA Refresh=2 secs 11:36.53─── ────────────── ─────── ─── ──┌─CPU­Utilisation­Small­View EntitledCPU=  0.40 UsedCPU=  0.384──────────── ──────┐│Logical                     0­­­­­­­­­­25­­­­­­­­­­­50­­­­­­­­­­75­­­­­­­­­­100││CPU User%  Sys% Wait% Idle% |           |            |           |            |│  │ 0  13.3   7.9   0.0  78.8 |UUUUUUsss         >                              |│  │ 1  17.7   0.5   0.5  81.3 |UUUUUUUU                 >                       |│  │ 2  10.1   1.0   0.0  88.9 |UUUUU>                                           |│  │ 3  19.4   1.9   0.5  78.2 |UUUUUUUUU>                                       |││Logical/Physical Averages   +­­­­­­­­­­­|­­­­­­­­­­­­|­­­­­­­­­­­|­­­­­­­­­­­­+││Log  15.2   2.8   0.2  81.8 |UUUUUUUs                                         |││Phy  74.5  16.9   0.0   8.6 |UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUssssssss    |││Entitlement Used= 96.0%     +­­­­­­­­­­­|­­­­­­­­­­­­|­­­­­­­­­­­|­­­­­­­­­­­­+│└──────────────────────────────────────────────────────────────────────────────┘┌─Memory­Use Paging Stats───────────────────── ──────────────────────── ───────────┐          │ Physical PagingSpace         pages/sec  In     Out   FileSystemCache ││% Used       98.6%      28.1%   to Paging Space   1.5    0.0   (numperm)  26.0%││% Free        1.4%      71.9%   to File System    0.0    3.0   Process    40.1%││MB Used    2020.0MB   1725.8MB  Page Scans        0.0          System     32.5%││MB Free      28.0MB   4418.2MB  Page Cycles       0.0          Free        1.4%││Total(MB)  2048.0MB   6144.0MB  Page Steals       0.0                    ­­­­­­│                                │ Page Faults     828.5          Total     100.0%││Min/Maxperm     386MB( 19%)  1543MB( 75%) note: % of memory                    ││Min/Maxfree     960   1088      Total  Virtual    8.0GB        User       61.0%││Min/Maxpgahead    2      8    Accessed Virtual    2.7GB 34.1%  Pinned     32.5%│└──────────────────────────────────────────────────────────────────────────────┘

Page 18: YAPC2007 Remote System Monitoring (w. Notes)

'nmon' screenshot

──nmon­v10r e=disk­ESS Host=db1prd3─── ───────── ────── Refresh=2 secs 11:44.57── ─── ──┌─Adapter­I/O­Statistics───────────────────────────────────────────────────────┐│Name          %busy     read    write        xfers Disks Adapter­Type          ││fscsi0         18.5  19547.9     26.0 KB/s   662.0 8     FC SCSI I/O Controller││fscsi1         16.5  20079.9     30.0 KB/s   673.0 8     FC SCSI I/O Controller││sisscsia0       1.0      4.0      0.0 KB/s     1.0 2     PCI­X Ultra320 SCSI Ad││TOTALS  3 adapters   39631.7     56.0 KB/s  1336.0 18    TOTAL(MB/s)=38.8      │└──────────────────────────────────────────────────────────────────────────────┘┌─Disk­Busy­Map Key(%): @=90 #=80 X=70 8=60 O=50 0=40 o=30 +=20 ­=10 .=5 _=0%─ ───┐│hdisks numbers­>           1         2         3         4                     │                 │ 01234567890123456789012345678901234567890123456789            ││hdisk0 to 49     __­__oX_.__.______                                            │└──────────────────────────────────────────────────────────────────────────────┘┌─Top­Processes Procs=267­mode=3­[1=Basic­2=CPU­3=Perf­4=Size­5=I/O]── ───────────┐  │ PID     %CPU  Size   Res   Res   Res  Char RAM      Paging       Command     │          │ Used    KB   Set  Text  Data   I/O  Use io other repage              │  │ 929812  30.6  8136  1076    16  1060  2047   0%  162 1242    0 db2sysc       │ │ 1528038  11.1  1200   268    16   252 32015K  0%  342  144    0 db2sysc       │ │ 1007782   2.5 12796  9688    16  9672     0   0%   19   27    0 db2sysc       │ │ 1503320   1.1  1200   232    16   216  2311K  0%   83   12    0 db2sysc       │  │ 503930   0.8 28404 25524    16 25508     0   1%    0    0    0 db2sysc       │ │ 1577164   0.5  5480  5600   252  5348  1172   0%    0    0    0 nmon          │  │ 729318   0.2  1936  2136   392  1744   525   0%    0    0    0 hats_nim      │└──────────────────────────────────────────────────────────────────────────────┘

Page 19: YAPC2007 Remote System Monitoring (w. Notes)

'nmon'

● Output– On screen (console, telnet, VNC, putty or X Windows) using curses for low CPU 

impact which is updated once every two seconds.– Save the data to a comma separated file for analysis and longer term data 

capture.– nmon Analyser Excel 2000 spreadsheet loads the nmon output file and 

automatically creates dozens of graphs.– Filter this data, add it to a rrd database

● See– http://www.ibm.com/developerworks/aix/library/au­analyze_aix/index.html– http://www­941.ibm.com/collaboration/wiki/display/WikiPtype/nmon

Page 20: YAPC2007 Remote System Monitoring (w. Notes)

Wrapping 'nmon'

my $LogDir = "/var/log/nmon";my $FifoFile = "$LogDir/nmon­stats.fifo";my $NmonCmd = "/usr/local/bin/nmon ­F $FifoFile ­pDET ­I 0 ­s 60 ­c 1440";

mkfifo($FifoFile, 0600);open(PIPE, "$NmonCmd|"); # will print PIDopen($readFH, $FifoFile)  or die "Cannot open $FifoFile: $!\n";$nmonPid = readline(*PIPE); # nmon writes PID in first line

close(PIPE);chomp $nmonPid;$nmonPid = $1 if ($nmonPid =~ m/(\d+)/); # untaint

my $selectFH = new IO::Select ($readFH);

Page 21: YAPC2007 Remote System Monitoring (w. Notes)

daemonize

sub go_background {  use POSIX qw(setsid);  my($pid, $sess_id, $i);

  ## Fork and exit parent  if ($pid = fork) { exit 0; }

  ## Detach ourselves from the terminal  die "Cannot detach from controlling terminal.\n"    unless setsid();

  ## Prevent possibility of acquiring a controling terminal  $SIG{'HUP'} = 'IGNORE';  if ($pid = fork) { exit 0; }

  ## Reopen stdin/out/err to /dev/null  open(STDIN,  "+>/dev/null");  open(STDOUT, "+>/dev/null");  open(STDERR, "+>/dev/null");}

Page 22: YAPC2007 Remote System Monitoring (w. Notes)

Writing to logfiles

# set new handlers$SIG{__WARN__} = sub { write_log($_[0]); };$SIG{__DIE__}  = sub { write_log($_[0]); CORE::die(@_); };

# all warnings and errors go to the log filesub write_log {  my $msg = shift;  use POSIX qw(strftime);  my $ts = "[".strftime('%Y­%m­%d_%H:%M:%S', localtime)."] ";

  $msg =~ s{^}{$ts}gm;  # insert at beginning of each line  $msg .= "\n" unless $msg =~ m/\n\Z/; # make sure it ends in a 

newline

  open(my $log, ">>$LogFile");  print $log $msg;  close $log;}

Page 23: YAPC2007 Remote System Monitoring (w. Notes)

Safely using 'ssh'

● .ssh/authorized_keys● command=”/path/to/script”● no­pty● no­port­forwarding● no­X11­forwarding● no­agent­forwarding● from=”10.1.1.1”command=”/path/to/script”,no­pty,no­port­forwarding \  ssh­dss AAAA...== comment

Page 24: YAPC2007 Remote System Monitoring (w. Notes)

Connecting 'ssh' to multiple sites

foreach my $host (@Hosts) {  if (not exists $HostInfo{$host}{pid}      and $now ­ $HostLastActive{$host} > $ReconnectDelay) {    $HostLastActive{$host} = time();    my ($rfh, $wfh, $efh) = (gensym, gensym, gensym);    my $pid;    eval { # open new connection      $pid = open3($wfh, $rfh, $efh,                   qw(/usr/bin/ssh ­T ­o BatchMode=yes ­l user),                   $host, "perl");    };    if ($@) {      warn "Cannot ssh to $host: $@\n";      if ($pid) { # cleanup child        kill TERM => $pid           and waitpid $pid, 0;      }      next; # retry later    }

Page 25: YAPC2007 Remote System Monitoring (w. Notes)

Connecting 'ssh' to multiple sites

  $SIG{PIPE} = sub { die "SIGPIPE: lost connection to $host\n" };

  eval { print $wfh script4host($host) }; # what's that? :­)

  $SIG{PIPE} = 'IGNORE';  if ($@) {    warn "Cannot push script to $host: $@\n";    if ($pid) { # cleanup child      kill TERM => $pid         and waitpid $pid, 0;    }    next; # retry later  }

Page 26: YAPC2007 Remote System Monitoring (w. Notes)

Connecting 'ssh' to multiple sites

    # add it to select list  $selectFHs­>add([$rfh, $host, 0]);  $selectFHs­>add([$efh, $host, 1]);  $HostInfo{$host}{stdin} = $wfh;  $HostInfo{$host}{stdout} = $rfh;  $HostInfo{$host}{stderr} = $efh;  $HostInfo{$host}{pid} = $pid;  warn "Connected to $host.\n";  $SIG{PIPE} = 'DEFAULT';}

Page 27: YAPC2007 Remote System Monitoring (w. Notes)

Pushing perl code to remote sites

● From within a perl script● Start a perl interpreter via 'ssh'● Feed it the script via stdin● Finish with __END__● Script will start to run● Script can use stdin/out to communicate

Page 28: YAPC2007 Remote System Monitoring (w. Notes)

Pushing modules

use File ::Tail; # just to get it into @INC

my $script;foreach my $m (qw(File/Tail.pm)) { # loop over needed modules  my $fn;  foreach my $prefix (@INC) { # find them in @INC    next if (ref($fn)); # skip code­refs    $fn = "$prefix/$m";    last if (­f $fn); # found it?     undef $fn;  }  die "Cannot find $m\n" if not $fn;

Page 29: YAPC2007 Remote System Monitoring (w. Notes)

Pushing modules (2)

  # read module file and append it to $script  open(my $fh, $fn)    or die "Cannot open $fn: $!\n";  $script .= "BEGIN { eval <<'__END_OF_MODULE__'\n";  local $/ = undef; # slurp mode  $script .= <$fh>;  $script .= "\n__END_OF_MODULE__\n}\n";  close $fh;}# now add monitoring script$script .= <<'__EOT__'...__EOT__

print PIPE_TO_REMOTE_PERL $script;

# for binary modules: PAR, the Perl Archive toolkit.# allows to package modules into one file that # can be eval'd by perl.

Page 30: YAPC2007 Remote System Monitoring (w. Notes)

RRDtool

● RRD = Round­Robin Database● (think ringbuffer)● RRDtool by Tobias Oetiker 

http://www.rrdtool.org/● Data logging and graphing system.● Used by BigSister, Cacti, NetMRG, webminstats● Perl bindings available:

use RRDs;

Page 31: YAPC2007 Remote System Monitoring (w. Notes)

Storing data into RRDs

use RRDs;

my @update = ("$RRDPathPrefix/$host.rrd",              "­­template" => join(":", @Datatags),              join(":", @data{@Datatags}),             );RRDs::update(@update);my $res = RRDs::error;warn $res if $res;

Page 32: YAPC2007 Remote System Monitoring (w. Notes)

Creating graphs with RRDtool

# files are named /rrdpath/hostname.rrdrrdtool graph drawing.png ­u 150 ­­rigid ­v “requests/min” \  ­t "Requests $host" ­­start ­86400 –end now \  ­­height 600 ­­width 1000 \  DEF:html=${host}.rrd:html:MAX \  DEF:xml=${host}.rrd:xml:MAX \  DEF:was=${host}.rrd:was:MAX \  DEF:soap=${host}.rrd:soap:MAX \  AREA:was#9F9F9F:"WAS Requests" \  LINE2:soap#F8B932:"SOAP Requests" \  LINE2:html#0000FF:"HTML Requests" \  LINE2:xml#00FF00:"XML Requests" \  STACK:html#FFFF00:"XML+HTML Requests" \  STACK:soap#000000:"SOAP+XML+HTML Requests" \

Page 33: YAPC2007 Remote System Monitoring (w. Notes)

Creating graphs with RRDtool

● Result:

Page 34: YAPC2007 Remote System Monitoring (w. Notes)

Creating graphs with 'drraw'

● A better, point­n­click way: use 'drraw'● http://web.taranis.org/drraw/● Installs as a CGI­app● Define graphs on­the­fly (somewhat WYSIWYG)● Turn graphs into templates that can be applied 

to selected .rrd files● Combine multiple templates into dashboards, 

letting you view all your data at once.

Page 35: YAPC2007 Remote System Monitoring (w. Notes)

'drraw' dashboard

Page 36: YAPC2007 Remote System Monitoring (w. Notes)

Have fun!

● Support Open­Source.● Be nice to your fellow people.● Pay it forward:

For each favor you receive, do three strangers a favor.http://www.payitforwardmovement.org/

● And have a great day!

Page 37: YAPC2007 Remote System Monitoring (w. Notes)

Remote System Monitoring

Roland Giersig <[email protected]>

Maintainer of Expect and IO::Tty on CPAN

Sponsored by xion.at   

Page 38: YAPC2007 Remote System Monitoring (w. Notes)

System Monitoring

● What to monitor● How to monitor● Which kind of data to collect● When to use the collected data

Page 39: YAPC2007 Remote System Monitoring (w. Notes)

What to monitor

● Applications / Daemons● that provide Services● on one or more Ports● Running on one or more Machines.

Some basic definitions:we are interested in monitoring applications, that is, programs that 

provide services on one or more ports, running on one or more machines. But of course these principles apply for just any program or daemon.

Page 40: YAPC2007 Remote System Monitoring (w. Notes)

Remote vs. Local Checks

● Remote checks– Port­availability– Network– Dummy requests / Status servlet

● Local checks– Required processes running?– Networks available?– Error messages in Logfiles?– Application throughput?– System parameters OK?

Check the application logfiles if there are some unusual messages in there. Check the logfiles for throughput. This is often the best and easiest check: let your users be your testers.

Count the user­generated requests and how many of them were OK. Then calculate a request rate and plot it. (I will show you later how to do that) Such a graph can be a tremendous help. Imagine getting a call from the helpdesk, that a user has reported that you application isn't working. (don't we all love such specific reports...) If you now have such a graph, you have to take only a glance at it to be able to tell the helpdesk: "Well, in the past hour, 3000 requests were processed and only 5 showed an error, so from my point, everything is running fine. Walk him through his configuration again..."

Page 41: YAPC2007 Remote System Monitoring (w. Notes)

When to analyze

● Instant notification– Daily Operations– Boundaries/Limits checking

● Historical data– Problem determination and analysis– Statistics / Graphs

For daily operations, you want to be notified as soon as possible if any problems turn up, if parameters are overstepping their boundaries.

For problem analysis you want all that data to be available at a later point in time in a way that is well­suited for searching.

Page 42: YAPC2007 Remote System Monitoring (w. Notes)

How to collect

● Dedicated monitoring host– collects data from application machines– global data loss in case of network/monitoring failure

● Store data locally on each host– and backup/archive that data!

Beware: monitoring host is a single point of failure.If there is a network problem or the monitoring software crashes or the 

monitoring host has a hardware­failure, ALL data is gone or doesn't get collected.

Page 43: YAPC2007 Remote System Monitoring (w. Notes)

Why History?

● For problem determination and analysis● Statistics / Graphs

– Show bottlenecks– Prove upgrade needs– Managers are loving it

Store the data locally on the machines.And archive those logs.Use backup/archiving mechanisms in place for your 

application and webserver logs.

Page 44: YAPC2007 Remote System Monitoring (w. Notes)

Ready­Made vs. Roll­your­own

– Deploying existing tools is fast– Gives you generic checks– Can be customized over time– Does it store monitoring data locally?– Recommendation: roll­your­own system 

monitoring

Page 45: YAPC2007 Remote System Monitoring (w. Notes)

Using NAGIOS

● http://www.nagios.org/● Network­ and Port­Checking● Needs plug­ins for remote checking● Use 'ssh' or NRPE● Think about security, 

use a non­privileged user.● 'sudo' is your friend.

Page 46: YAPC2007 Remote System Monitoring (w. Notes)

Data Format

● Should be simple, human­readable, parseable, flexible, grepable.

● YAML? Not grepable.● CSV? Not flexible.● Enhance CSV with infield header info:

ts=2007­08­28_11:50:00,task=YAPC::2007,\ status=attending

Page 47: YAPC2007 Remote System Monitoring (w. Notes)

Data Format (parsing)

● Easily parseable:@d = split(',', $_); # don't, use Text::CSV_XS%h = map {(split('=', $_, 2))} @d;

● use Text::CSV_XS

Page 48: YAPC2007 Remote System Monitoring (w. Notes)

Checking Logfiles

● How to count “matching log­lines per minute”?# in shelltail ­f access_log | grep " 200 " | wc ­l

# doesn't work :­(

● Use File::Tail (available from CPAN)

Page 49: YAPC2007 Remote System Monitoring (w. Notes)

Using File::Tail 

%patterns = (  '/var/logs/httpd/access_log' => [    {     regexp  => qr/ 200 /,     outfile => '/var/logs/monitoring/access_ok.last',     history => '/var/logs/monitoring/access_ok.log',     count => 0,    },    {     regexp  => qr/ 504 /,     outfile => '/var/logs/monitoring/access_gw_errors.last',     history => '/var/logs/monitoring/access_gw_errors.log',     count => 0,    },  ],);

For each logfile, count several matching regexps and store the counts into two files, outfile and history.

Page 50: YAPC2007 Remote System Monitoring (w. Notes)

Using File::Tail (2)

my @tails = map {File::Tail­>new(name=>$_,                                 maxinterval=>10,                                 resetafter=>120,                                 reset_tail=>0,                                );                } keys %patterns;while (1) {  my ($nfound, $timeleft, @pending)=    File::Tail::select(undef, undef, undef, undef, @tails);  foreach my $f (@pending) {    my $line = $f­>read();    my $logfile = $f­>{input};    foreach my $p (@{$patterns{$logfile}}) {      $p­>{count}++        if ($line =~ m/$p­>{regexp}/);    }  }}

In the script first generate all those File::Tail objects, each representing one logfile.

Wait for new lines to arrive via File::Tails select().Process list of objects that have new lines.For each line, run all the regexps for that logfile against it and increment 

the counter when matching.Periodically save the counts to files and reset the counters.

Page 51: YAPC2007 Remote System Monitoring (w. Notes)

Using File::Tail (3)$SIG{ALRM} = sub {  my $time = strftime("%Y­%m­%d_%H:%M:%S", localtime());  foreach my $p (map {@$_} values %patterns) { # expand list    $p­>{count} ||= 0; # be sure there is a num there

    open (STATFILE, ">$p­>{outfile}.$$")  # write to a temp file      or die "$0: ERROR opening stat file $p­>{outfile}: $!\n";    print STATFILE "$p­>{count}\n";    close STATFILE;    rename "$p­>{outfile}.$$" => $p­>{outfile}; # atomic update

    open (STATFILE, ">>$p­>{history}") # append to history      or die "$0: ERROR opening history file $p­>{history}: $!\n";    print STATFILE "ts=$time,cnt=$p­>{count}\n";    close STATFILE;        $p­>{count} = 0; # reset counter  }  alarm 60; # reset alarm};alarm 60; # upon alarm, write statistic files and reset counters

Use alarm() handler.Maybe keep track of the time by specifying a timeout to select() and 

periodically check the elapsed time.Go through all the regexps and counters and save the values to files.One history file with time information in it that can be used for plotting 

later­on and one file with just the value which can be used for the instant checks by NAGIOS.

Page 52: YAPC2007 Remote System Monitoring (w. Notes)

'nmon'

● 'nmon' courtesy of IBM (unsupported)● Performance Data

– CPU utilization, Memory use, Kernel statistics and run queue– Disks I/O rates, transfers, and read/write ratios, File­systems size and free 

space, Disk adapters, Paging space and paging rates, User defined disk groups

– Network I/O rates, transfers, and read/write ratios– Machine details, CPU and OS specification, Top processors– Dynamic LPAR changes ­ AIX and Linux (on POWER hardware)

'nmon' instead of standard command­line tools like 'ps', 'iostat' etc.Linux or AIX only.Similar to 'top' or 'topas', only on steroids.

Page 53: YAPC2007 Remote System Monitoring (w. Notes)

'nmon' screenshot

──nmon­v10r c=CPU Host=was1prdA Refresh=2 secs 11:36.53─── ────────────── ─────── ─── ──┌─CPU­Utilisation­Small­View EntitledCPU=  0.40 UsedCPU=  0.384──────────── ──────┐│Logical                     0­­­­­­­­­­25­­­­­­­­­­­50­­­­­­­­­­75­­­­­­­­­­100││CPU User%  Sys% Wait% Idle% |           |            |           |            |│  │ 0  13.3   7.9   0.0  78.8 |UUUUUUsss         >                              |│  │ 1  17.7   0.5   0.5  81.3 |UUUUUUUU                 >                       |│  │ 2  10.1   1.0   0.0  88.9 |UUUUU>                                           |│  │ 3  19.4   1.9   0.5  78.2 |UUUUUUUUU>                                       |│

│Logical/Physical Averages   +­­­­­­­­­­­|­­­­­­­­­­­­|­­­­­­­­­­­|­­­­­­­­­­­­+││Log  15.2   2.8   0.2  81.8 |UUUUUUUs                                         |││Phy  74.5  16.9   0.0   8.6 |UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUssssssss    |││Entitlement Used= 96.0%     +­­­­­­­­­­­|­­­­­­­­­­­­|­­­­­­­­­­­|­­­­­­­­­­­­+│└──────────────────────────────────────────────────────────────────────────────┘┌─Memory­Use Paging Stats───────────────────── ──────────────────────── ───────────┐          │ Physical PagingSpace         pages/sec  In     Out   FileSystemCache │

│% Used       98.6%      28.1%   to Paging Space   1.5    0.0   (numperm)  26.0%││% Free        1.4%      71.9%   to File System    0.0    3.0   Process    40.1%││MB Used    2020.0MB   1725.8MB  Page Scans        0.0          System     32.5%││MB Free      28.0MB   4418.2MB  Page Cycles       0.0          Free        1.4%││Total(MB)  2048.0MB   6144.0MB  Page Steals       0.0                    ­­­­­­│                                │ Page Faults     828.5          Total     100.0%│

│Min/Maxperm     386MB( 19%)  1543MB( 75%) note: % of memory                    ││Min/Maxfree     960   1088      Total  Virtual    8.0GB        User       61.0%││Min/Maxpgahead    2      8    Accessed Virtual    2.7GB 34.1%  Pinned     32.5%│└──────────────────────────────────────────────────────────────────────────────┘

Page 54: YAPC2007 Remote System Monitoring (w. Notes)

'nmon' screenshot

──nmon­v10r e=disk­ESS Host=db1prd3─── ───────── ────── Refresh=2 secs 11:44.57── ─── ──┌─Adapter­I/O­Statistics───────────────────────────────────────────────────────┐│Name          %busy     read    write        xfers Disks Adapter­Type          ││fscsi0         18.5  19547.9     26.0 KB/s   662.0 8     FC SCSI I/O Controller││fscsi1         16.5  20079.9     30.0 KB/s   673.0 8     FC SCSI I/O Controller││sisscsia0       1.0      4.0      0.0 KB/s     1.0 2     PCI­X Ultra320 SCSI Ad││TOTALS  3 adapters   39631.7     56.0 KB/s  1336.0 18    TOTAL(MB/s)=38.8      │└──────────────────────────────────────────────────────────────────────────────┘┌─Disk­Busy­Map Key(%): @=90 #=80 X=70 8=60 O=50 0=40 o=30 +=20 ­=10 .=5 _=0%─ ───┐│hdisks numbers­>           1         2         3         4                     │                 │ 01234567890123456789012345678901234567890123456789            │

│hdisk0 to 49     __­__oX_.__.______                                            │└──────────────────────────────────────────────────────────────────────────────┘┌─Top­Processes Procs=267­mode=3­[1=Basic­2=CPU­3=Perf­4=Size­5=I/O]── ───────────┐  │ PID     %CPU  Size   Res   Res   Res  Char RAM      Paging       Command     │          │ Used    KB   Set  Text  Data   I/O  Use io other repage              │  │ 929812  30.6  8136  1076    16  1060  2047   0%  162 1242    0 db2sysc       │ │ 1528038  11.1  1200   268    16   252 32015K  0%  342  144    0 db2sysc       │ │ 1007782   2.5 12796  9688    16  9672     0   0%   19   27    0 db2sysc       │ │ 1503320   1.1  1200   232    16   216  2311K  0%   83   12    0 db2sysc       │  │ 503930   0.8 28404 25524    16 25508     0   1%    0    0    0 db2sysc       │ │ 1577164   0.5  5480  5600   252  5348  1172   0%    0    0    0 nmon          │  │ 729318   0.2  1936  2136   392  1744   525   0%    0    0    0 hats_nim      │

└──────────────────────────────────────────────────────────────────────────────┘

The Disk­Busy­Map can be really helpful. 

[That can help finding out why the database doesn't perform well under high load. Might be that even though tablespaces are distributed across a lot of disks, most of the time it is only one disk that gets used and thus is the bottleneck.]

Page 55: YAPC2007 Remote System Monitoring (w. Notes)

'nmon'

● Output– On screen (console, telnet, VNC, putty or X Windows) using curses for low CPU 

impact which is updated once every two seconds.– Save the data to a comma separated file for analysis and longer term data 

capture.– nmon Analyser Excel 2000 spreadsheet loads the nmon output file and 

automatically creates dozens of graphs.– Filter this data, add it to a rrd database

● See– http://www.ibm.com/developerworks/aix/library/au­analyze_aix/index.html– http://www­941.ibm.com/collaboration/wiki/display/WikiPtype/nmon

'nmon' can collect all system information over a longer period and write it to a file.

Unfortunately, the output format is more geared to drop that data into a spreadsheet and analyze it there.

That's what Perl is for!

Page 56: YAPC2007 Remote System Monitoring (w. Notes)

Wrapping 'nmon'

my $LogDir = "/var/log/nmon";my $FifoFile = "$LogDir/nmon­stats.fifo";my $NmonCmd = "/usr/local/bin/nmon ­F $FifoFile ­pDET ­I 0 ­s 60 ­c 1440";

mkfifo($FifoFile, 0600);open(PIPE, "$NmonCmd|"); # will print PIDopen($readFH, $FifoFile)  or die "Cannot open $FifoFile: $!\n";$nmonPid = readline(*PIPE); # nmon writes PID in first line

close(PIPE);chomp $nmonPid;$nmonPid = $1 if ($nmonPid =~ m/(\d+)/); # untaint

my $selectFH = new IO::Select ($readFH);

Wrapper around 'nmon' that makes a useful data gathering daemon out of it. 

Use a named pipe aka fifo as an output file for 'nmon', so output can be processed as it happens. Also useful for other programs.

Page 57: YAPC2007 Remote System Monitoring (w. Notes)

daemonize

sub go_background {  use POSIX qw(setsid);  my($pid, $sess_id, $i);

  ## Fork and exit parent  if ($pid = fork) { exit 0; }

  ## Detach ourselves from the terminal  die "Cannot detach from controlling terminal.\n"    unless setsid();

  ## Prevent possibility of acquiring a controling terminal  $SIG{'HUP'} = 'IGNORE';  if ($pid = fork) { exit 0; }

  ## Reopen stdin/out/err to /dev/null  open(STDIN,  "+>/dev/null");  open(STDOUT, "+>/dev/null");  open(STDERR, "+>/dev/null");}

Run the script as a daemon in the background. Standard double­fork, exiting in between, end up having 

init as parent.Detach from the controlling terminal with setsid().Redirect stdin/out/err to /dev/null.But now all diagnostics must go to a logfile.

Page 58: YAPC2007 Remote System Monitoring (w. Notes)

Writing to logfiles

# set new handlers$SIG{__WARN__} = sub { write_log($_[0]); };$SIG{__DIE__}  = sub { write_log($_[0]); CORE::die(@_); };

# all warnings and errors go to the log filesub write_log {  my $msg = shift;  use POSIX qw(strftime);  my $ts = "[".strftime('%Y­%m­%d_%H:%M:%S', localtime)."] ";

  $msg =~ s{^}{$ts}gm;  # insert at beginning of each line  $msg .= "\n" unless $msg =~ m/\n\Z/; # make sure it ends in a 

newline

  open(my $log, ">>$LogFile");  print $log $msg;  close $log;}

Install handlers for warn() and die().Open and close the logfile for each logmessage.This makes logfile­rotation really easy (just rename).But shouldn't be used for high­volume logging.

Page 59: YAPC2007 Remote System Monitoring (w. Notes)

Safely using 'ssh'

● .ssh/authorized_keys● command=”/path/to/script”● no­pty● no­port­forwarding● no­X11­forwarding● no­agent­forwarding● from=”10.1.1.1”command=”/path/to/script”,no­pty,no­port­forwarding \  ssh­dss AAAA...== comment

'authorized_keys' file that allows connections from remote sites based on public­keys. Generate a key­pair on the monitoring machine and paste the public key into 'authorized_keys' on the monitored machine.  Then 'ssh' and 'scp' can be used without having to specify the password for that user.

Also specify which program or script to run if a certain key is used to login. This allows to have a remote user execute certain critical, privileged commands without giving him full shell­access.

Page 60: YAPC2007 Remote System Monitoring (w. Notes)

Connecting 'ssh' to multiple sites

foreach my $host (@Hosts) {  if (not exists $HostInfo{$host}{pid}      and $now ­ $HostLastActive{$host} > $ReconnectDelay) {    $HostLastActive{$host} = time();    my ($rfh, $wfh, $efh) = (gensym, gensym, gensym);    my $pid;    eval { # open new connection      $pid = open3($wfh, $rfh, $efh,                   qw(/usr/bin/ssh ­T ­o BatchMode=yes ­l user),                   $host, "perl");    };    if ($@) {      warn "Cannot ssh to $host: $@\n";      if ($pid) { # cleanup child        kill TERM => $pid           and waitpid $pid, 0;      }      next; # retry later    }

Kick off several ssh connections at once, using open3(). Spawn a perl interpreter at the remote side.Catch errors by handling EOF and by timeout, as we know that the 

logfiles that is tailed on are supposed to grow every minute or so.Cannot use the Net::Ssh* modules because we cannot select() on them (no 

fileno()).

Page 61: YAPC2007 Remote System Monitoring (w. Notes)

Connecting 'ssh' to multiple sites

  $SIG{PIPE} = sub { die "SIGPIPE: lost connection to $host\n" };

  eval { print $wfh script4host($host) }; # what's that? :­)

  $SIG{PIPE} = 'IGNORE';  if ($@) {    warn "Cannot push script to $host: $@\n";    if ($pid) { # cleanup child      kill TERM => $pid         and waitpid $pid, 0;    }    next; # retry later  }

Page 62: YAPC2007 Remote System Monitoring (w. Notes)

Connecting 'ssh' to multiple sites

    # add it to select list  $selectFHs­>add([$rfh, $host, 0]);  $selectFHs­>add([$efh, $host, 1]);  $HostInfo{$host}{stdin} = $wfh;  $HostInfo{$host}{stdout} = $rfh;  $HostInfo{$host}{stderr} = $efh;  $HostInfo{$host}{pid} = $pid;  warn "Connected to $host.\n";  $SIG{PIPE} = 'DEFAULT';}

Page 63: YAPC2007 Remote System Monitoring (w. Notes)

Pushing perl code to remote sites

● From within a perl script● Start a perl interpreter via 'ssh'● Feed it the script via stdin● Finish with __END__● Script will start to run● Script can use stdin/out to communicate

Don't install the perl scripts on the remote machines, simply push down the perl code to the interpreter via stdin.

Use File::Tail instead of 'tail ­f'Push down checking code for use with NAGIOS? Performance penalty. 

Maybe use persistent collecting daemon?

Page 64: YAPC2007 Remote System Monitoring (w. Notes)

Pushing modules

use File ::Tail; # just to get it into @INC

my $script;foreach my $m (qw(File/Tail.pm)) { # loop over needed modules  my $fn;  foreach my $prefix (@INC) { # find them in @INC    next if (ref($fn)); # skip code­refs    $fn = "$prefix/$m";    last if (­f $fn); # found it?     undef $fn;  }  die "Cannot find $m\n" if not $fn;

Push modules too!@INC contains the filepath to the loaded modules, so search it for the 

source file.

Page 65: YAPC2007 Remote System Monitoring (w. Notes)

Pushing modules (2)

  # read module file and append it to $script  open(my $fh, $fn)    or die "Cannot open $fn: $!\n";  $script .= "BEGIN { eval <<'__END_OF_MODULE__'\n";  local $/ = undef; # slurp mode  $script .= <$fh>;  $script .= "\n__END_OF_MODULE__\n}\n";  close $fh;}# now add monitoring script$script .= <<'__EOT__'...__EOT__

print PIPE_TO_REMOTE_PERL $script;

# for binary modules: PAR, the Perl Archive toolkit.# allows to package modules into one file that # can be eval'd by perl.

Slurp in the module source and wrap it with an eval so it gets its own namespace. 

Push it down along with check script.

Only works with pure­perl modules. For modules with binary libraries one could theoretically use PAR, the perl archive toolkit, which allows you to put all modules into one file that can be evaluated.

Need to pack a perl application into one executable?Remember PAR and pp, the Perl Packager. 

Page 66: YAPC2007 Remote System Monitoring (w. Notes)

RRDtool

● RRD = Round­Robin Database● (think ringbuffer)● RRDtool by Tobias Oetiker 

http://www.rrdtool.org/● Data logging and graphing system.● Used by BigSister, Cacti, NetMRG, webminstats● Perl bindings available:

use RRDs;

Store collected data in RRDs created by RRDtool.

RRD stands for Round­Robin Database, meaning that you simply drop your data points in there one at a time and the database keeps a certain timespan (for example the last 3 months) in its ringbuffer.

RRDtool can create graphs from the data in several ways and has a powerful data­manipulation machine built in.

RRDtool only plots time­like data and cannot be used to generate arbitrary graphs like pie­charts or x­y­scatter plots.

Page 67: YAPC2007 Remote System Monitoring (w. Notes)

Storing data into RRDs

use RRDs;

my @update = ("$RRDPathPrefix/$host.rrd",              "­­template" => join(":", @Datatags),              join(":", @data{@Datatags}),             );RRDs::update(@update);my $res = RRDs::error;warn $res if $res;

Easy to store data into an RR­database.­template tells RRDtool the names and order of the data points (similar to the header line of a CSV)Just store the data points in that order.

Page 68: YAPC2007 Remote System Monitoring (w. Notes)

Creating graphs with RRDtool

# files are named /rrdpath/hostname.rrdrrdtool graph drawing.png ­u 150 ­­rigid ­v “requests/min” \  ­t "Requests $host" ­­start ­86400 –end now \  ­­height 600 ­­width 1000 \  DEF:html=${host}.rrd:html:MAX \  DEF:xml=${host}.rrd:xml:MAX \  DEF:was=${host}.rrd:was:MAX \  DEF:soap=${host}.rrd:soap:MAX \  AREA:was#9F9F9F:"WAS Requests" \  LINE2:soap#F8B932:"SOAP Requests" \  LINE2:html#0000FF:"HTML Requests" \  LINE2:xml#00FF00:"XML Requests" \  STACK:html#FFFF00:"XML+HTML Requests" \  STACK:soap#000000:"SOAP+XML+HTML Requests" \

To create graphs from an RRDatabase use the command­line rrdtool with cron jobs.

Use the perl bindings for CGI scripts.

Specify the filename and the size of the graph, the time slot to plot and which and how the data points are to be drawn.

Page 69: YAPC2007 Remote System Monitoring (w. Notes)

Creating graphs with RRDtool

● Result:

Page 70: YAPC2007 Remote System Monitoring (w. Notes)

Creating graphs with 'drraw'

● A better, point­n­click way: use 'drraw'● http://web.taranis.org/drraw/● Installs as a CGI­app● Define graphs on­the­fly (somewhat WYSIWYG)● Turn graphs into templates that can be applied 

to selected .rrd files● Combine multiple templates into dashboards, 

letting you view all your data at once.

'drraw' has a more point­n­click or WYSIWYG approach. It's a CGI application that needs only minimal configuration. Just tell it where to find your .rrd files.

Just select which .rrd files to use and 'drraw' will show all data channels that are in the RRD. Assign colors, disable the unwanted data channels, set graph dimentions etc.

Store a finished graph as a template and use it with other RRDs that have the same structure.

Combine templates to form a dashboard that shows all available data at once.

Page 71: YAPC2007 Remote System Monitoring (w. Notes)

'drraw' dashboard

● Click to add an outline

Page 72: YAPC2007 Remote System Monitoring (w. Notes)

Have fun!

● Support Open­Source.● Be nice to your fellow people.● Pay it forward:

For each favor you receive, do three strangers a favor.http://www.payitforwardmovement.org/

● And have a great day!

Useful tools: NAGIOS, nmon, ssh, sudo, RRDtool and drraw.Perl modules: File ::Tail, Text::CSV_XS and PAR.