package Core::Memstat; use strict; use warnings; use base 'Resmon::Module'; use Resmon::ExtComm qw(run_command cache_command); my $osname = $^O; my $usekstat = 0; my $kstat; if ($osname eq 'solaris') { eval "use Sun::Solaris::Kstat"; unless ($@) { $usekstat = 1; $kstat = Sun::Solaris::Kstat->new(); } } =pod =head1 NAME Core::Memstat - Monitor memory statistics using vmstat =head1 SYNOPSIS Core::Memstat { local : noop } Core::Memstat { local : vmstat_path => /usr/sbin/vmstat } =head1 DESCRIPTION This module returns statistics on active and free memory. The type and number of metrics returned depend on the capabilities of each platform's respective vmstat command. =head1 CONFIGURATION =over =item check_name The check name is used for descriptive purposes only. It is not used for anything functional. =item vmstat_path Provide an alternate path to the vmstat command (optional). =back =head1 METRICS The metrics returned by this module vary by OS and method used: =head2 VMSTAT METRICS The default/fallback method used is vmstat, which returns the following metrics: =over =item actv_mem Active virtual pages. =item free_mem Free real memory. =back =head2 KSTAT METRICS Solaris provides an interface to numerous kernel statistics. If the Perl Sun::Solaris::Kstat library is locally available, this module will prefer that method first, bypassing vmstat collection. Otherwise, this module falls back on the standard vmstat collection method. =head2 PROC METRICS Linux configurations use /proc/meminfo for memory statistics. =head2 SYSCTL METRICS FreeBSD configurations use sysctl to extract the most common memory statistics. With the exception of hw.physmem, all metrics are pulled from the vm.stats.vm branch. =cut sub handler { my $self = shift; my $disk = $self->{'check_name'}; my $config = $self->{'config'}; my $vmstat_path = $config->{'vmstat_path'} || 'vmstat'; if ($osname eq 'solaris') { my $pagesize = run_command('pagesize'); if ($usekstat && $pagesize) { my %metrics; $kstat->update(); my $syspages = $kstat->{'unix'}->{0}->{'system_pages'}; foreach (keys %$syspages) { $metrics{"kstat_${_}"} = [int($syspages->{$_} * $pagesize / 1024), 'L'] unless ($_ eq 'class'); } if (exists $kstat->{'zfs'}) { $metrics{'kstat_cache_mem'} = [int($kstat->{'zfs'}->{0}->{'arcstats'}->{'size'} / 1024), 'L']; } return \%metrics; } else { my $output = run_command("$vmstat_path"); if ($output =~ /.*cs\s+us\s+sy\s+id\n\s+\d+\s+\d+\s+\d+\s+(\d+)\s+(\d+).*/) { return { 'actv_mem' => [$1, 'L'], 'free_mem' => [$2, 'L'] }; } else { die "Unable to extract statistics\n"; } } } elsif ($osname eq 'linux') { my %metrics; open(MEMINFO, '/proc/meminfo') || die "Unable to read proc: $!\n"; while (<MEMINFO>) { /(\w+)\:\s+(\d+).*/; next unless defined($1); $metrics{$1} = [$2, 'L']; } close(MEMINFO); $metrics{MemFreeBufCache} = [ ($metrics{MemFree}[0] + $metrics{Buffers}[0] + $metrics{Cached}[0]), "L"]; return \%metrics; } elsif ($osname eq 'freebsd') { my %metrics; open(SYSCTL, 'sysctl hw.physmem vm.stats.vm |') || die "Unable to read sysctl: $!\n"; while (<SYSCTL>) { /(.*)\:\s+(\d+).*/; $metrics{$1} = [$2, 'L']; } for my $page qw( cache inactive active wire free page ) { $metrics{"vm.stats.vm.v_${page}_count"}->[0] *= ($metrics{'vm.stats.vm.v_page_size'}->[0] / 1024); } close(SYSCTL); return \%metrics; } elsif ($osname eq 'openbsd') { my $output = run_command("$vmstat_path"); if ($output =~ /.*cs\s+us\s+sy\s+id\n\s+\d+\s+\d+\s+\d+\s+(\d+)\s+(\d+).*/) { return { 'actv_mem' => [$1, 'L'], 'free_mem' => [$2, 'L'] }; } else { die "Unable to extract statistics\n"; } } else { die "Unsupported platform: $osname\n"; } }; 1;