#!/usr/bin/perl =head1 NAME acng - Graph activity for Apt-Cacher NG, request count and bytes =head1 APPLICABLE SYSTEMS Systems with "Apt-Cacher NG" installed and running. =head1 DESCRIPTION This plugin will add graphs for "bytes in and out" and "requests in and out" for systems with "Apt-Cacher NG" installed. =head1 CONFIGURATION The plugin must have permission to read the log of Apt-Cacher NG. (On Debian 8, this file is world readable by default). The path to the logfile can be set with the "logfile" environment variable. =head2 DEFAULT CONFIGURATION [acng] env.logfile /var/log/apt-cacher-ng/apt-cacher.log =head1 USAGE Link this plugin to /etc/munin/plugins/ and restart the munin-node. =head1 MAGIC MARKERS #%# family=contrib #%# capabilities=autoconf =head1 AUTHOR Stig Sandbeck Mathisen =head1 LICENSE GPLv3 =cut use strict; use warnings; use Munin::Plugin; use Storable qw(nfreeze thaw); use MIME::Base64; my $logfile = $ENV{'logfile'} ||= '/var/log/apt-cacher-ng/apt-cacher.log'; need_multigraph; # Read or initialize state used by the log tailer, and the plugin. sub read_state { my ($pos, $statsin) = restore_state; my $stats = thaw(decode_base64 $statsin) if $statsin; $pos = 0 unless defined $pos; $stats = {} unless defined $stats; return ($pos, $stats); } # Write state. # # "pos" is logfile position, and "stats" is a data structure with # counters used by the plugin. # # Note: Munin::Plugin::save_state has limited functionality, so the # data structure is serialized and converted to plain text. sub write_state { my ($pos, $stats) = @_; my $statsout = encode_base64 nfreeze($stats); save_state($pos, $statsout); } sub parse_logfile { my $logfile = shift; my ($pos, $stats) = read_state; my @keys = ( 'time', 'direction', 'size', 'client', 'file' ); # Open log my ( $fh, $reset ) = tail_open( $logfile, $pos ); die "Unable to open logfile\n" unless ($fh); while (<$fh>) { chomp; my @values = split( /\|/, $_ ); my %logentry; @logentry{@keys} = @values; $stats->{'bytes'}{ $logentry{'direction'} } += $logentry{'size'}; $stats->{'requests'}{ $logentry{'direction'} }++; } # Close log $pos = tail_close($fh); write_state($pos, $stats); return $stats; } sub print_autoconf{ my $logfile = shift; if ( open(my $fh, '<', $logfile) ) { print "yes\n"; } else { printf "no (could not open %s)\n", $logfile; } } sub print_config{ my $stats = shift; print << 'EOC'; multigraph acng_bytes echo "graph_category acng" graph_title Apt-Cacher NG bytes graph_order origin client graph_vlabel bytes per ${graph_period} graph_info Bytes transferred between origin, apt-cacher-ng and clients origin.info bytes transferred between origin and apt-cacher-ng origin.label origin origin.type DERIVE origin.min 0 client.info bytes transferred between apt-cacher-ng and clients client.label client client.type DERIVE client.min 0 EOC print << "EOV" if $ENV{'MUNIN_CAP_DIRTYCONFIG'}; origin.value $stats->{bytes}{I} client.value $stats->{bytes}{O} EOV print << 'EOC'; multigraph acng_requests echo "graph_category acng" graph_title Apt-Cacher NG requests graph_order origin client graph_vlabel requests per ${graph_period} graph_info Requests from clients to apt-cacher-ng, and from apt-cacher-ng to origin origin.info requests from apt-cacher-ng to origin origin.label origin origin.type DERIVE origin.min 0 client.info requests from clients to apt-cacher-ng client.label client client.type DERIVE client.min 0 EOC print << "EOV" if $ENV{'MUNIN_CAP_DIRTYCONFIG'}; origin.value $stats->{requests}{I} client.value $stats->{requests}{O} EOV } sub print_values{ my $stats = shift; print << "EOV"; multigraph acng_bytes origin.value $stats->{bytes}{I} client.value $stats->{bytes}{O} multigraph acng_requests origin.value $stats->{requests}{I} client.value $stats->{requests}{O} EOV } if ($ARGV[0] and $ARGV[0] eq 'autoconf') { print_autoconf($logfile); } elsif ($ARGV[0] and $ARGV[0] eq 'config') { my $stats = parse_logfile($logfile); print_config($stats); } else { my $stats = parse_logfile($logfile); print_values($stats); }