Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New generic Resmon modules #21

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
196 changes: 196 additions & 0 deletions lib/Core/HTTPD.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
package Core::HTTPD;

use strict;
use warnings;

use base 'Resmon::Module';

use LWP::UserAgent;

=pod

=head1 NAME

Core::HTTPD - monitor HTTPD stats via mod_status

=head1 SYNOPSIS

Core::HTTPD {
local : url => http://server.example.com/path/to/mod_status/
}

Core::HTTPD {
local : url => http://server.example.com/path/to/mod_status/, username => username, password => password
}

=head1 DESCRIPTION

This module monitors HTTPD statistics via HTTP/HTTPS requests to mod_status.

=head1 CONFIGURATION

=over

=item check_name

Arbitrary name of the check.

=item url

The mod_status URL to connect to.

=item username

The basic authentication username to send when requesting statistics (required if password is specified).

=item password

The basic authentication password to send when requesting statistics (required if username is specified).

=back

=head1 METRICS

=over

=item total_hits

Total number of requests

=item total_bytes

Total number of bytes transfered

=item cpu_load

Current CPU load from the HTTPD processes.

=item busy_workers

Current count of busy workers/servers.

=item idle_workers

Current count of idle workers/servers.

=item threads_waiting

Current count of threads waiting for a connection.

=item threads_starting

Current count of threads starting up..

=item threads_reading

Current count of threads reading a request.

=item threads_writing

Current count of threads writing a response.

=item threads_keep_alive

Current count of threads idle in keep alive.

=item threads_dns_lookup

Current count of threads performing a DNS lookup.

=item threads_closing

Current count of threads closing a connection.

=item threads_logging

Current count of threads logging.

=item threads_stopping

Current count of threads gracefully finishing.

=item threads_idle

Current count of threads idle.

=item threads_available

Current count of thread slots with no current process.

=back

=cut


sub new {
my ($class, $check_name, $config) = @_;
my $self = $class->SUPER::new($check_name, $config);

$self->{'user_agent'} = LWP::UserAgent->new();
$self->{'user_agent'}->agent('Resmon');
$self->{'user_agent'}->timeout($config->{'check_timeout'} || 10);

$self->{'scoreboard_keys'} = {
'_' => 'threads_waiting',
'S' => 'threads_starting',
'R' => 'threads_reading',
'W' => 'threads_writing',
'K' => 'threads_keep_alive',
'D' => 'threads_dns_lookup',
'C' => 'threads_closing',
'L' => 'threads_logging',
'G' => 'threads_stopping',
'I' => 'threads_idle',
'.' => 'threads_available',
};

bless($self, $class);
return $self;
}

sub handler {
my $self = shift;
my $config = $self->{'config'};
my $url = $config->{'url'} || die "URL is required.\n";
my $username = $config->{'username'};
my $password = $config->{'password'};

my $user_agent = $self->{'user_agent'};
my $scoreboard_keys = $self->{'scoreboard_keys'};

my $request = HTTP::Request->new(GET => "$url?auto");
if($username && $password) {
$request->authorization_basic($username, $password);
}

my $response = $user_agent->request($request);
$response->is_success || die "HTTP GET failed to $url: " . $response->status_line . "\n";

my $content = $response->decoded_content();

my $result = { map { $_ => 0 } values %$scoreboard_keys };
foreach my $line (split(/\n/, $content)) {
my ($key, $val) = split(/: /, $line);

if ($key eq 'Total Accesses') {
$result->{'total_hits'} = [$val, 'n'];
} elsif ($key eq 'Total kBytes') {
$result->{'total_bytes'} = [$val * 1024, 'n'];
} elsif ($key eq 'CPULoad') {
$result->{'cpu_load'} = [$val, 'n'];
} elsif ($key =~ /^Busy/) {
$result->{'busy_workers'} = [$val, 'n'];
} elsif ($key =~ /^Idle/) {
$result->{'idle_workers'} = [$val, 'n'];
} elsif ($key eq 'Scoreboard') {
my @chars = split(//, $val);
foreach my $state (split(//, $val)) {
$result->{$scoreboard_keys->{$state}}++;
}
}
}

return $result;
}

1;
189 changes: 189 additions & 0 deletions lib/Core/JMX.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
package Core::JMX;

use strict;
use warnings;

use base 'Resmon::Module';

use JMX::Jmx4Perl;

=pod

=head1 NAME

Core::JMX - monitor JMX stats via Jmx4Perl/Jolokia

=head1 SYNOPSIS

Core::JMX {
memorypool : query => java.lang:type=MemoryPool\,name=*, attributes => Usage, metric_pattern => /^.*?=(.+?)\,.*_(.*)$/$1_$2/
}

Core::JMX {
memory : query => java.lang:type=Memory, attributes => HeapMemoryUsage,NonHeapMemoryUsage
}

=head1 DESCRIPTION

This module monitors arbitrary JMX statistics usage using jmx4perl/jolokia.

=head1 CONFIGURATION

=over

=item check_name

Arbitrary name of the check.

=item url

The Jolokia URL to connect to (optional; defaults to "http://localhost:8778/jolokia/").

=item username

The basic authentication username to send when requesting JMX statistics (required if password is specified).

=item password

The basic authentication password to send when requesting JMX statistics (required if username is specified).

=item query

The JMX query to perform (required if alias is not specified).

=item attributes

The JMX attributes to return, comma-separated (optional when query is specified, otherwise all attributes for query are returned).

=item alias

The name of a Jmx4Perl alias (required if query is not specified).

=item product

The name of a Jmx4Perl product (optional but recommended when using an alias; defaults to "unknown").

=item metric_pattern

A Perl regular expression used to transform the returned JMX names into friendlier metric names (recommended for most queries).

=back

=head1 METRICS

=over

=item *

Metrics as reported by JMX, and transformed by metric_pattern.

=back

=cut

sub new {
my ($class, $check_name, $config) = @_;
my $self = $class->SUPER::new($check_name, $config);

my $url = $config->{'url'} || 'http://localhost:8778/jolokia/';
my $username = $config->{'username'};
my $password = $config->{'password'};
my $product = $config->{'product'} || 'unknown';

if($username && $password) {
$self->{'jmx'} = new JMX::Jmx4Perl(url => $url, product => $product, user => $username, password => $password);
} else {
$self->{'jmx'} = new JMX::Jmx4Perl(url => $url, product => $product);
}

my $metric_pattern = $config->{'metric_pattern'};
if ($metric_pattern) {
$metric_pattern = trim_slashes($metric_pattern);
my ($metric_pattern_search, $metric_pattern_replace) = split(/(?<!\\)\//, $metric_pattern);
$self->{'metric_pattern_search'} = $metric_pattern_search;
$self->{'metric_pattern_replace'} = '"' . $metric_pattern_replace . '"';
}

bless($self, $class);
return $self;
}

sub trim_slashes {
my $string = shift;
$string =~ s/^\/?(.*?)\/?$/$1/;
return $string;
}

sub flatten_recursive {
my ($prefix, $in, $out) = @_;
for my $key (keys %$in) {
my $value = $in->{$key};
my $new_prefix = $prefix ? $prefix . '_' . $key : $key;
$new_prefix =~ s/\s+/_/g;
$new_prefix = lc($new_prefix);

if ( defined $value && ref $value eq 'HASH' ) {
flatten_recursive($new_prefix, $value, $out);
}
else {
$out->{$new_prefix} = [$value, 'n'];
}
}
}

sub handler {
my $self = shift;

my $jmx = $self->{'jmx'};
my $metric_pattern_search = $self->{'metric_pattern_search'};
my $metric_pattern_replace = $self->{'metric_pattern_replace'};
my $config = $self->{'config'};

my $alias = $config->{'alias'};
my $query = $config->{'query'};
my $attributes = $config->{'attributes'};

my $response;
if (defined $alias) {

# Use a pre-defined jmx4perl alias
$response = $jmx->get_attribute($alias);

} elsif (defined $query) {
if (defined $attributes)
{
# Get comma-separated list of attributes
my @array = split(/,/, $attributes);
$response = $jmx->get_attribute($query, \@array);

} else {

# Get all attributes
$response = $jmx->get_attribute($query, undef);

}
} else {

die "Either alias or query is required.";

}

my $flattened = {};
flatten_recursive('', $response, $flattened);

my $result;
if($metric_pattern_search && $metric_pattern_replace) {
my $transformed = {};
while( my ($key, $val) = each %$flattened ) {
$key =~ s/$metric_pattern_search/$metric_pattern_replace/ee;
$transformed->{$key} = $val;
}
$result = $transformed;
} else {
$result = $flattened;
}

return $result;
};

1;
Loading