Software Engineer

monitoring squid proxy servers via snmp from nagios

· by jsnby · Read in about 2 min · (369 Words)

I recently built a small squid proxy cluster. I wanted to see how the proxies were performing. Squid has a built in snmp service with all sorts of checks available. We have pnp4nagios configured to graph the performance data from any nagios checks, so all I needed to do was write a script to query the oid’s and report the results. Unfortunately, the items I wanted to report on (cacheProtoClientHttpRequests, cacheHttpInKb, cacheHttpOutKb, etc.) were counters….reading them at any one point in time doesn’t do a whole lot for you.

Ideally, you would read them once, store the data, read them again at some point in the future and determine the change in the value over the change in time (so you could get average http requests per second). I wrote a little script to do this:


use strict;
use warnings;
use Getopt::Std;
use Net::SNMP;

my %options=();

my %oids;
$oids{'cacheProtoClientHttpRequests'} = '.';
$oids{'cacheHttpInKb'}                = '.';
$oids{'cacheHttpOutKb'}               = '.';
$oids{'cacheDnsRequests'}             = '.';

my $oid;

my $host = defined($options{h}) ? $options{h}: die("no host (-h) passed in");

if(!defined($options{p}) || !defined($oids{$options{p}})) {
    print "No parameter (-p) specified or no oid found for given param";
    exit(3); # exit with unknown status
} else {
    $oid = $oids{$options{p}};

my $cache_file = "/tmp/squid_snmp_${host}_" . $options{p};
my %cache = loadCache($cache_file);

# requires a hostname and a community string as its arguments
my ($session,$error) = Net::SNMP->session(
                            Hostname  => $host,
                            Community => 'public',
                            Port      => 3401

if(!$session) {
    print "unable to establish SNMP session - $error";

my $result = $session->get_request($oid);

if(!defined($result)) {
    print "request error: " . $session->error;

my $data = $result->{$oid};
my $time = time();
my $value;

# compute the amount per second
if(defined($cache{'timestamp'}) && defined($cache{'data'})) {
    my $dt = $time - $cache{'timestamp'};
    my $dv = $data - $cache{'data'};

    $value = $dv / $dt;
} else {
    $value = 0;

$cache{'data'} = $data;
$cache{'timestamp'} = $time;
saveCache($cache_file, %cache);

printf('%s | %s=%d', $options{p}, $options{p}, $value);

# Keep a cache of values on disk - a simple tab-delimited file with key-value pairs, one per line.
sub loadCache {
    my ($file) = @_;
    my %cache;
    if(-e $file) {
        open IN, "<$file" or die("Cache file exists ($file), but can't open for reading\n\n");
        while(my $line=<IN>) {
            my @linesplit=split(/\t/, $line, 2);
            $cache{$linesplit[0]} = $linesplit[1];
        close IN;
    return %cache;

# If necessary, save out the cache file to disk
sub saveCache {
    my ($file, %cache) = @_;

    open OUT, ">$file" or die("Can't open file ($file) for output.\n\n");
    foreach my $key(sort keys %cache) {
        printf OUT ("%s\t%s\n", $key, $cache{$key});
    close OUT;

sub setCacheValue {
    my ($key, $value) = @_;
    $cache{$key} = $value;

To enable snmp in squid, I added this to my squid.conf file:

acl snmppublic snmp_community public
snmp_port 3401
snmp_access allow all

Since my machines are behind a firewall, I didn’t have to worry about configuring the acl to only allow certain addresses or anything of that sort.

If server was running a squid proxy, you could query it like this:

./ -h -p cacheProtoClientHttpRequests

The first time you run it, it will say 0…that’s because it’s seeding the cache. Subsequent requests will show you the actual requests/second:

cacheProtoClientHttpRequests | cacheProtoClientHttpRequests=59

You could then define a command for nagios:

define command {
    command_name  check_squid_http_requests
    command_line  /path/to/script/ -h $HOSTADDRESS$ -p cacheProtoClientHttpRequests

I didn’t put any warning or critical thresholds in my script as the goal of this particular check was simply data to graph. You may need to adjust this script to fit your particular needs and/or environment.