Repository
Munin (contrib)
Last change
2020-10-24
Graph Categories
Capabilities
Keywords
Language
Perl
License
GPL-2.0-only
Authors

nn_

Name

nn_ - Munin plugin to display misc newznab stats.

Configuration

This script is used to generate data for several graphs. To generate data for one specific graph, you need to create a symbolic link with a name like nn_ to this script.

To get a graph over numbers of users use nn_users

Applicable Systems

Any MySQL platform, tested by the author on MySQL 5.1.29 and 5.0.51

Configuration

This script is used to generate data for several graphs. To generate data for one specific graph, you need to create a symbolic link with a name like nn_ to this script.

connection parameters - use this in your plugin configuration file.

[nn_*]
env.mysqlconnection DBI:mysql:<yourdatabase>;host=127.0.0.1;port=3306
env.mysqluser <user>
env.mysqlpassword <password>

Dependencies

  • DBD::mysql

Thanks

A special thanks to Kjell-Magne Øierud for the mysql_ plugin in munin which gave me the inspiration and reusable code to create this plugin.

License

Copyright (C) 2012 Jan Astrup (cryzeck@synIRC)

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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

SPDX-License-Identifier: GPL-2.0-only

#!/usr/bin/perl

=encoding utf8

=head1 NAME

nn_ - Munin plugin to display misc newznab stats.


=head1 CONFIGURATION

This script is used to generate data for several graphs. To generate
data for one specific graph, you need to create a symbolic link with a
name like nn_<GRAPH> to this script.

To get a graph over numbers of users use nn_users


=head1 APPLICABLE SYSTEMS

Any MySQL platform, tested by the author on MySQL 5.1.29 and 5.0.51


=head1 CONFIGURATION

This script is used to generate data for several graphs. To generate
data for one specific graph, you need to create a symbolic link with a
name like nn_<GRAPH> to this script.

connection parameters - use this in your plugin configuration file.

 [nn_*]
 env.mysqlconnection DBI:mysql:<yourdatabase>;host=127.0.0.1;port=3306
 env.mysqluser <user>
 env.mysqlpassword <password>


=head1 DEPENDENCIES

=over

=item DBD::mysql

=back


=head1 THANKS

A special thanks to Kjell-Magne Øierud for the mysql_ plugin in munin which
gave me the inspiration and reusable code to create this plugin.


=head1 LICENSE

Copyright (C) 2012 Jan Astrup (cryzeck@synIRC)

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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
USA.

SPDX-License-Identifier: GPL-2.0-only

=cut

use warnings;
use strict;
use utf8;

use DBI;
use Data::Dumper;
use File::Basename;

use Munin::Plugin;

#-- CONFIG --#

my %config = (
    'dsn'        => $ENV{'mysqlconnection'} || 'dbi:mysql:newznab',
    'user'       => $ENV{'mysqluser'}       || 'test1',
    'password'   => $ENV{'mysqlpassword'}   || 'test',
);

my %defaults = (
	global_attrs => {
		args   => '--base 1000 -l 0',
		scale  => 'no',
	},
	data_source_attrs => {
		draw  => 'AREA',
	},
);

my %graphs = ();

$graphs{releases} = {
	config => {
		global_attrs => {
			title 	=> 'Releases',
			vlabel	=> 'Releases',
		},
		data_source_attrs => {
			min   => '0',

		},
	},
	data_sources => [
		{name => 'releases',		label => 'Releases'},
	],
};
$graphs{category} = {
	config => {
		global_attrs => {
			title 	=> 'Releases by category',
			vlabel	=> 'Releases by category',
		},
		data_source_attrs => {
			min   => '0',
			draw  => 'LINE2',
			type  => 'GAUGE',
		},
	},
	data_sources => [
		{name => '1000', label => 'Console'},
		{name => '1010', label => 'Console - NDS'},
		{name => '1020', label => 'Console - PSP'},
		{name => '1030', label => 'Console - Wii'},
		{name => '1040', label => 'Console - Xbox'},
		{name => '1050', label => 'Console - Xbox 360'},
		{name => '1060', label => 'Console - WiiWare/VC'},
		{name => '1070', label => 'Console - XBOX 360 DLC'},
		{name => '1080', label => 'Console - PS3'},
		{name => '2000', label => 'Movies'},
		{name => '2010', label => 'Movies - Foreign'},
		{name => '2020', label => 'Movies - Other'},
		{name => '2030', label => 'Movies - SD'},
		{name => '2040', label => 'Movies - HD'},
		{name => '2050', label => 'Movies - BluRay'},
		{name => '2060', label => 'Movies - 3D'},
		{name => '3000', label => 'Audio'},
		{name => '3010', label => 'Audio - MP3'},
		{name => '3020', label => 'Audio - Video'},
		{name => '3030', label => 'Audio - Audiobook'},
		{name => '3040', label => 'Audio - Lossless'},
		{name => '4000', label => 'PC'},
		{name => '4010', label => 'PC - 0day'},
		{name => '4020', label => 'PC - ISO'},
		{name => '4030', label => 'PC - Mac'},
		{name => '4040', label => 'PC - Mobile-Other'},
		{name => '4050', label => 'PC - Games'},
		{name => '4060', label => 'PC - Mobile-iOS'},
		{name => '4070', label => 'PC - Mobile-Android'},
		{name => '5000', label => 'TV'},
		{name => '5020', label => 'TV - Foreign'},
		{name => '5030', label => 'TV - SD'},
		{name => '5040', label => 'TV - HD'},
		{name => '5050', label => 'TV - Other'},
		{name => '5060', label => 'TV - Sport'},
		{name => '5070', label => 'TV - Anime'},
		{name => '5080', label => 'TV - Documentary'},
		{name => '6000', label => 'XXX'},
		{name => '6010', label => 'XXX - DVD'},
		{name => '6020', label => 'XXX - WMV'},
		{name => '6030', label => 'XXX - XviD'},
		{name => '6040', label => 'XXX - x264'},
		{name => '6050', label => 'XXX - Pack'},
		{name => '6060', label => 'XXX - ImgSet'},
		{name => '7000', label => 'Other'},
		{name => '7010', label => 'Other - Magazines'},
		{name => '7020', label => 'Other - Ebook'},
		{name => '7030', label => 'Other - Comics'},
		{name => '8010', label => 'Other - Misc'},
		{name => '7900', label => 'Unknown'},
	],
};

$graphs{api} = {
	config => {
		global_attrs => {
			title 	=> 'API Requests / Downloads',
			vlabel	=> 'API / DOWNLOAD',
		},
		data_source_attrs => {
			min   	=> '0',
			draw	=> 'LINE1',
			type	=> 'GAUGE',
		},
	},
	data_sources => [
		{name => 'request',		label => 'API Requests'},
		{name => 'download',		label => 'Downloads'},
	],
};

$graphs{users} = {
	config => {
		global_attrs => {
			title 	=> 'Registered Users',
			vlabel	=> 'Usercount',
		},
		data_source_attrs => {
			min   => '0',
		},
	},
	data_sources => [
		{name => 'users',		label => 'Users'},
	],
};
our $data;
sub config {
    my $graph_name = shift;
    die 'Unknown graph ' . ($graph_name ? $graph_name : '')
	unless $graphs{$graph_name};

    my $graph = $graphs{$graph_name};

    my %conf = (%{$defaults{global_attrs}}, %{$graph->{config}{global_attrs}});
    while (my ($k, $v) = each %conf) {
	print "graph_$k $v\n";
    }
    print "graph_category search\n";

    my $i = 0;
    for my $ds (@{$graph->{data_sources}}) {
	my %ds_spec = (
	    %{$defaults{data_source_attrs}},
	    %{$graph->{config}{data_source_attrs}},
	    %$ds,
	);
	while (my ($k, $v) = each %ds_spec) {
	    # 'name' is only used internally in this script, not
	    # understood by munin.
	    next if ($k eq 'name');

	    if ($k eq 'draw' && $v eq 'AREASTACK') {
		printf("%s.%s %s\n",
		       clean_fieldname($ds->{label}), $k, ($i ? 'STACK' : 'AREA'));
	    }
	    else {
		printf("%s.%s %s\n", clean_fieldname($ds->{label}), $k, $v);
	    }
	    $i++;
	}
    }

    return 0;
}

sub main {
	my $graph = substr(basename($0), length('nn_'));
	my $command = $ARGV[0] || 'show';

	my %commands = (
		'config'	=>	\&config,
		'show'		=>	\&show,
	);

	die "Unknown command: $command" unless exists $commands{$command};
	return $commands{$command}->($graph);
}

sub show {
	my $graph_name = shift;
	die 'Unknown graph ' . ($graph_name ? $graph_name : '')
		unless $graphs{$graph_name};

	my $graph = $graphs{$graph_name};
	run_queries($graph_name);
	for my $ds (@{$graph->{data_sources}}) {
		printf "%s.value %s\n", clean_fieldname($ds->{label}), ($data->{$ds->{name}} ? $data->{$ds->{name}} : '0');
	}
	return 0;
}

sub db_connect {
	my $dsn = "$config{dsn};mysql_connect_timeout=5";

	return DBI->connect($dsn, $config{user}, $config{password}, {
		RaiseError       => 1,
		PrintError       => 0,
		FetchHashKeyName => 'NAME_lc',
	});

}

sub run_queries {
	my $updater = shift;
	$data = {};
	my $dbh = db_connect();
	my %updaters = (
		'releases'			=> \&update_releases,
		'users'				=> \&update_users,
		'api'				=> \&update_requests,
		'category'			=> \&update_category,
	);
	die "Unknown updater: $updater" unless exists $updaters{$updater};
	$updaters{$updater}->($dbh);
}

sub update_requests {
	my ($dbh) = @_;
	my %queries = (
		request => 'select count(*) as requests from userrequests where timestamp > now() - INTERVAL 5 MINUTE;',
		download => 'select count(*) as downloads from userdownloads where timestamp > now() - INTERVAL 5 MINUTE;',
	);
	for my $name ( qw(request download) ) {
		my $query = $queries{$name};
		my $sth = $dbh->prepare($query);
		$sth->execute();
		while (my $row = $sth->fetch) {
			$data->{$name} = $row->[0];
		}
		$sth->finish();
	}
}

sub update_category {
	my ($dbh) = @_;
	my $sth = $dbh->prepare('select count(*) as releases, category.title, category.id from releases LEFT JOIN category ON releases.categoryID = category.ID group by releases.categoryID');
	$sth->execute();
	if ($@) { die $@; }
	while (my $row = $sth->fetch) {
	$data->{$row->[2]} = $row->[0];
	}

}
sub update_releases {
	my ($dbh) = @_;
	my $sth = $dbh->prepare('SELECT count(*) as releases from releases');
	eval {
		$sth->execute();
	};
	if ($@) { die $@; }
	my $row = $sth->fetchrow_hashref();
	$data->{releases} = $row->{'releases'};
	$sth->finish();
}

sub update_users {
	my ($dbh) = @_;
	my $sth = $dbh->prepare('SELECT count(*) as users from users');
	eval {
		$sth->execute();
	};
	if ($@) { die $@; }
	my $row = $sth->fetchrow_hashref();
	$data->{users} = $row->{'users'};
	$sth->finish();
}

exit main() unless caller;


1;