Repository
Munin (master)
Last change
2018-08-07
Graph Categories
Family
auto
Capabilities
Language
Perl
License
GPL-2.0-only
Authors

squid

Name

squid - Multigraph-capable plugin to monitor Squid

Notes

This plugin will produce multiple graphs showing:

- the number of requests (replaces squid_requests);
- the traffic (replaces squid_traffic);
- the size of the cache (replaces squid_cache);
- the traffic to the ICP peers (replaces squid_icp);
- the mean size of stored objects (replaces squid_objectsize).

Configuration

The following configuration parameters are used by this plugin

[squid]
 env.host     - hostname to connect to
 env.port     - port number to connect to
 env.username - username used for authentication
 env.password - password used for authentication

Default Configuration

[squid]
 env.host 127.0.0.1
 env.port 3128

Wildcard Configuration

It’s possible to use the plugin in a virtual-node capacity, in which case the host configuration will default to the hostname following the underscore:

[squid_someserver]
 env.host someserver
 env.port 3128

Author

Copyright (C) 2013 Diego Elio Pettenò
Copyright (C) 2008 Bjorn Ruberg
Copyright (C) 2004 Audun Ytterdal
Copyright (C) 2004 Jimmy Olsen
Copyright (C) 2004 Tore Anderson

License

Gnu GPLv2

Magic Markers

#%# family=auto
#%# capabilities=autoconf

Pod Errors

Hey! The above document had some coding errors, which are explained below:

  • Around line 46:

    Non-ASCII character seen before =encoding in ‘Pettenò’. Assuming UTF-8

#!/usr/bin/perl -w

=head1 NAME

squid - Multigraph-capable plugin to monitor Squid

=head1 NOTES

This plugin will produce multiple graphs showing:

 - the number of requests (replaces squid_requests);
 - the traffic (replaces squid_traffic);
 - the size of the cache (replaces squid_cache);
 - the traffic to the ICP peers (replaces squid_icp);
 - the mean size of stored objects (replaces squid_objectsize).

=head1 CONFIGURATION

The following configuration parameters are used by this plugin

 [squid]
  env.host     - hostname to connect to
  env.port     - port number to connect to
  env.username - username used for authentication
  env.password - password used for authentication


=head2 DEFAULT CONFIGURATION

 [squid]
  env.host 127.0.0.1
  env.port 3128

=head2 WILDCARD CONFIGURATION

It's possible to use the plugin in a virtual-node capacity, in which
case the host configuration will default to the hostname following the
underscore:

 [squid_someserver]
  env.host someserver
  env.port 3128

=head1 AUTHOR

  Copyright (C) 2013 Diego Elio Pettenò
  Copyright (C) 2008 Bjorn Ruberg
  Copyright (C) 2004 Audun Ytterdal
  Copyright (C) 2004 Jimmy Olsen
  Copyright (C) 2004 Tore Anderson

=head1 LICENSE

Gnu GPLv2

=begin comment

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 dated June, 1991.

This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.

=end comment

=head1 MAGIC MARKERS

 #%# family=auto
 #%# capabilities=autoconf

=cut

use strict;
use Munin::Plugin;
use Munin::Plugin::Framework;
use IO::Socket::INET;


my $plugin = Munin::Plugin::Framework->new;

$plugin->{hostname} = $1 if $Munin::Plugin::me =~ /_([^_]+)$/;

my $peeraddr = $ENV{'host'} || $plugin->{hostname} || '127.0.0.1';
my $peerport = $ENV{'port'} || '3128';

my $username = $ENV{'username'};
my $password = $ENV{'password'};

my $requirements = undef;
if (! eval "require HTTP::Headers" or ! eval "require HTTP::Response" ) {
  $requirements = "HTTP::Message not found";
}

sub getobject {
  my $socket = IO::Socket::INET->new(PeerAddr => $peeraddr,
				     PeerPort => $peerport,
				     Proto => 'tcp',
				     Timeout => 25);
  if ( ! $socket ) {
    $requirements = $!;
    return undef;
  }

  my ($object) = @_;

  my $request_line = sprintf("GET cache_object://%s/%s HTTP/1.0\r\n",
			     $peeraddr, $object);
  my $headers = HTTP::Headers->new('Accept' => '*/*',
				   'User-Agent' => sprintf("munin/%s (squid)",
							   $Munin::Common::Defaults::MUNIN_VERSION)
				  );
  if ( $username and $password ) {
    $headers->authorization_basic($username, $password);
    $headers->proxy_authorization_basic($username, $password);
  }

  $socket->print($request_line . $headers->as_string("\r\n") . "\r\n");
  my $response = HTTP::Response->parse(join('', $socket->getlines));

  $socket->close();

  return $response;
}

sub get_icp {
  my $server_list = getobject('server_list');
  if ( not defined $server_list ) {
    return undef;
  }
  if ( $server_list->{content} =~ /There are no neighbors/ ) {
    return undef;
  }

  my @lines = split(/\r\n/, $server_list->{content});

  my $ret;
  my $id = "";
  for (my $i = 0; $i <= $#lines; $i++) {
    chomp $lines[$i];
    if ($lines[$i] =~ /Address[^:]+:\s*([\d\.]+)\s*$/) {
      my $host = $1;
      $id = "h" . $host;
      $id =~ s/\.//g;

      my $h;
      if ($h = Net::hostent::gethost ($host)) {
	$ret->{$id}->{host} = lc $h->name;
      } else {
	$ret->{$id}->{host} = $host;
      }
    } elsif ($lines[$i] =~ /FETCHES\s*:\s*(\d+)/) {
      $ret->{$id}->{fetches} = $1;
    }
  }
}

my $counters = getobject('counters');
my $storedir = getobject('storedir');
my $info     = getobject('info');
my $icp_data = get_icp;

if ( $requirements ) {
  $plugin->{autoconf} = "no ($requirements)";
} elsif ( !$counters->is_success ) {
  $plugin->{autoconf} = "no ($counters->status_line)";
  $plugin->{autoconf} =~ s/[\r\n]//g;
}

if ( defined $counters && $counters->{is_success} ) {
  my $hits =
    ($counters->content =~ /client_http\.hits = ([0-9]+)/) ? $1 : "U";
  my $errors =
    ($counters->content =~ /client_http\.errors = ([0-9]+)/) ? $1 : "U";
  my $requests =
    ($counters->content =~ /client_http\.requests = ([0-9]+)/) ? $1 : undef;
  my $misses = $requests ? ($requests - $errors - $hits) : "U";

  my $in =
    ($counters->content =~ /client_http\.kbytes_in = ([0-9]+)/) ? ($1 * 1024) : "U";
  my $out =
    ($counters->content =~ /client_http\.kbytes_out = ([0-9]+)/) ? ($1 * 1024) : "U";
  my $hits_out =
    ($counters->content =~ /client_http\.hit_kbytes_out = ([0-9]+)/) ? ($1 * 1024) : "U";

  $plugin->add_graphs
    (
     squid_requests =>
     {
      title => "Squid client requests",
      args => "--base 1000 -l 0",
      vlabel => "requests per \${graph_period}",
      order => "hits errors misses",
      total => "total",
      category => "network",
      fields =>
      {
       hits =>
       {
	type => "DERIVE",
	draw => "AREASTACK",
	min => 0,
	value => $hits,
       },
       errors =>
       {
	type => "DERIVE",
	draw => "AREASTACK",
	min => 0,
	value => $errors,
       },
       misses =>
       {
	type => "DERIVE",
	draw => "AREASTACK",
	min => 0,
	value => $misses,
       },
      },
     },
     "squid_traffic" =>
     {
      title => "Squid Traffic",
      args => "--base 1024 -l 0",
      vlabel => "bytes per \${graph_period}",
      order => "in out hits_out",
      fields =>
      {
       in =>
       {
	label => "received",
	type => "DERIVE",
	min => "0",
	value => $in,
       },
       out =>
       {
	label => "sent",
	type => "DERIVE",
	min => "0",
	value => $out,
       },
       hits_out =>
       {
	label => "sent from cache",
	type => "DERIVE",
	min => "0",
	value => $hits_out,
       },
      },
     },
    );
}

if ( defined $storedir && $storedir->is_success ) {
  my $max =
    ($storedir->content =~ /Maximum (?:Swap )?Size\s*:\s*([0-9]+) KB/) ? ($1 * 1024) : "U";
  my $current =
    ($storedir->content =~ /Current (?:Store Swap )?Size\s*:\s*([0-9]+) KB/) ? ($1 * 1024) : "U";

  $plugin->add_graphs
    (
     "squid_swap" =>
     {
      title => "Squid swap size",
      order => "max current",
      vlabel => "bytes",
      args => "--base 1024 -l 0",
      fields =>
      {
       max => { label => "Maximum Swap Size", value => $max },
       current => { label => "Current Store Swap Size", value => $current }
      }
     },
    );
}

if ( defined $info && $info->is_success ) {
  my $size = 'U';
  if ( $info->content =~ /Mean Object Size:\s*([0-9.]+) ([KMG])B/i ) {
    $size = $1;
    my $unit = $2;
    if ( $unit eq 'K' ) {
      $size *= 1024;
    } elsif ( $unit eq 'M' ) {
      $size *= (1024*1024);
    } elsif ( $unit eq 'G' ) {
      $size *= (1024*1024*1024);
    }
  }

  $plugin->add_graphs
    (
     "squid_objectsize" =>
     {
      title => "Squid object size",
      vlabel => "bytes",
      args => "--base 1024 -l 0",
      fields =>
      {
       size => { label => "Mean Object Size", value => $size }
      },
     }
    );
}

if ( $icp_data ) {
  $plugin->add_graphs
    (
     "squid_icp" =>
     {
      title => "Squid Relay Statistics",
      vlabel => "requests per \${graph_period}",
      args => "--base 1000 -l 0",
      total => "total",
      fields => {},
     },
    );

  foreach my $i (sort keys %{$icp_data}) {
    $plugin->{graphs}->{"squid_icp"}->{fields}->{$i} =
      {
       label => $icp_data->{$i}->{host},
       type => "DERIVE",
       min => 0,
       draw => "AREASTACK",
       value => $icp_data->{$i}->{fetches}
      };
  }
}

$plugin->run;