diff --git a/plugins/other/srcds_cpu b/plugins/other/srcds_cpu new file mode 100755 index 00000000..56c32f8b --- /dev/null +++ b/plugins/other/srcds_cpu @@ -0,0 +1,146 @@ +#!/usr/bin/perl +# +# 2007-06-26 +# Written by Ghost +# +# 2008-04-16 +# Update: Wildcard version +# +# 2008-11-12 +# Update: Perl RCON system +# +# Configuration variables +# +# srcdspass - RCON password +# srcdssamples - Number of samples to take (optional, default: 5) +# +# Magic markers - optional - used by installation scripts and +# munin-config: +# +#%# family=contrib +#%# capabilities=autoconf + +use strict; + +# Set library path correctly +use File::Basename; +if (-l $0) { + push(@INC, dirname(readlink($0))); +} +push(@INC, dirname($0)); + +# Load Rcon module or exit with failuer message +if (!eval "require Rcon") { + print "Failed to load Rcon module. "; + print "Make sure Rcon.pm is copied to Munin plugins directory.\n"; + exit 1; +} + +# Parse hostname and port from the plugin filename +my ($HOST, $PORT) = $0 =~ m/.*_([^:]+)_(\d+)$/; +if (!defined($HOST) || !defined($PORT)) { + print "Could not parse server address from filename.\n"; + exit 1; +} + +# Load config variables or use default values +my $PASS = $ENV{srcdspass} || ""; +my $SAMPLES = $ENV{srcdssamples} || 5; + +# Print config or do plugin test if asked +my $arg = shift(); +if ($arg eq 'config') { + print_config(); +} elsif ($arg eq 'autoconf') { + test_service(); +} + + +# +# Main program starts here +# + +my $sock = Rcon::sock_connect($HOST, $PORT); +if (!$sock) { + print "Could not open socket to $HOST:$PORT.\n"; + exit 1; +} +if (!Rcon::rcon_auth($sock, $PASS)) { + print "Could not authenticate.\n"; + exit 1; +} + +my $cpu_avg = 0; +my @cpu_samples; + +for (my $i = 0; $i < $SAMPLES; $i++) { + my $reply = Rcon::rcon_command($sock, "stats"); + if (!defined($reply)) { + print "Did not receive reply from server (sample $i).\n"; + next; + } + my @reply = split(/\n/, $reply); + + foreach my $statline (@reply) { + next if ($statline !~ m/\s*[\w+\.]+\s+[\w+\.]+\s+[\w+\.]+\s+\d+\s+\d+\s+[\w+\.]+\s+\d+/); + my ($cpu, $in, $out, $uptime, $users, $fps, $players) = ($statline =~ m/^\s*([\w+\.]+)\s+([\w+\.]+)\s+([\w+\.]+)\s+(\d+)\s+(\d+)\s+([\w+\.]+)\s+(\d+)/); + + if (defined($cpu)) { + push(@cpu_samples, $cpu); + } + } + select(undef, undef, undef, 0.2); # Wait moment before next sample +} + +# MEAN +if (@cpu_samples) { + foreach (@cpu_samples) { + $cpu_avg += int($_); + } + $cpu_avg /= ($#cpu_samples+1); + $cpu_avg = int($cpu_avg); + print "cpu.value $cpu_avg\n"; +} + +# MEDIAN +#if (@cpu_samples) { +# @cpu_samples = sort {$a <=> $b} @cpu_samples; +# my $median = int($#cpu_samples / 2 + 0.5); +# $cpu_avg = $cpu_samples[$median]; +#} + + +sub print_config { + print("graph_title Server CPU usage at $HOST:$PORT\n", + "graph_args --base 1000\n", + "graph_vlabel CPU\n", + "graph_category SourceDS\n", + "graph_info The CPU usage of Source game server, such as HL2, CS:S and DoD:S.\n"); + + print ("cpu.label CPU\n", + "cpu.min 0\n", + "cpu.max 100\n", + "cpu.type GAUGE\n"); + + exit 0; +} + + +sub test_service { + my $sock = Rcon::sock_connect($HOST, $PORT); + if (!$sock) { + print "no (could not open socket to $HOST:$PORT)\n"; + exit 1; + } + if (!Rcon::rcon_auth($sock, $PASS)) { + print "no (could not authenticate)\n"; + exit 1; + } + if (!defined(Rcon::rcon_command($sock, "stats"))) { + print "no (did not receive reply from server)\n"; + exit 1; + } + + print "yes\n"; + exit 0; +}