diff --git a/plugins/djabberd/djabberd_ b/plugins/djabberd/djabberd_ new file mode 100644 index 00000000..247af90c --- /dev/null +++ b/plugins/djabberd/djabberd_ @@ -0,0 +1,285 @@ +#!/usr/bin/perl -w +# +# Copyright (C) 2012 Dominik Schulz +# +# 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. +# +# Script to monitor DJabberd servers. +# Mostly an adaptation of Guillaume Blairon's mogliefsd_activity script. +# +# Usage: +# ln -s /usr/share/munin/plugins/djabberd_ \ +# /etc/munin/plugins/djabberd_{connections,memory,latency,counters} +# +# Configuration variables: +# +# host (default: '127.0.0.1') +# port (default: '5200') +# +# Parameters: +# +# config (required) +# autoconf (optional - only used by munin-config) +# +#%# family=auto +#%# capabilities=autoconf + +use strict; +use warnings; +use IO::Socket; + +my $djabberd_host = $ENV{host} || "127.0.0.1"; +my $djabberd_port = $ENV{port} || 5200; +my $mode = undef; +my $mode_name = undef; + +# mapping mode to command from which we get the information +my $mode_ref = { + 'connections' => { + 'cmd' => 'stats', + 'title' => 'DJabberd Connections', + 'vlabel' => 'connections', + 'fields' => { + 'connections' => { + 'key' => 'connections', + 'label' => 'Connections', + 'description' => 'Number of current connections', + 'draw' => 'LINE1', + 'type' => 'GAUGE', + }, + 'users' => { + 'key' => 'users', + 'label' => 'Users', + 'description' => 'Number of connected users', + 'draw' => 'LINE1', + 'type' => 'GAUGE', + }, + }, + }, + 'memory' => { + 'cmd' => 'stats', + 'title' => 'DJabberd Memory Statistics', + 'vlabel' => 'Bytes', + 'fields' => { + 'mem_total' => { + 'key' => 'mem_total', + 'label' => '', + 'description' => 'Total memory used by DJabberd', + 'draw' => 'LINE1', + 'type' => 'GAUGE', + 'filter' => \&kb2bytes, + }, + 'mem_connections' => { + 'key' => 'mem_connections', + 'label' => '', + 'description' => 'Memory used for handling connections', + 'draw' => 'LINE1', + 'type' => 'GAUGE', + 'filter' => \&kb2bytes, + }, + 'mem_per_connection' => { + 'key' => 'mem_per_connection', + 'label' => '', + 'description' => 'Memory used per connection', + 'draw' => 'LINE1', + 'type' => 'GAUGE', + 'filter' => \&kb2bytes, + }, + } + }, + 'latency' => { + 'cmd' => 'latency', + 'title' => 'DJabberd Latency Statistics', + 'vlabel' => 'reqs.', + 'fields' => { + 'dotzerozerozerofive' => { + 'key' => '-0.0005', + 'label' => 'lt. 0.0005', + 'description' => 'Requests handled in lt. 0.0005s', + 'draw' => 'AREA', + 'type' => 'COUNTER', + }, + 'dotzerozeroone' => { + 'key' => '-0.001', + 'label' => 'lt. 0.001', + 'description' => 'Requests handled int lt. 0.001s', + 'draw' => 'STACK', + 'type' => 'COUNTER', + }, + 'dotzerozerotwo' => { + 'key' => '-0.002', + 'label' => 'lt. 0.002', + 'description' => 'Requests handled int lt. 0.002s', + 'draw' => 'STACK', + 'type' => 'COUNTER', + }, + 'dotzerozerofive' => { + 'key' => '-0.005', + 'label' => 'lt. 0.005', + 'description' => 'Requests handled int lt. 0.005s', + 'draw' => 'STACK', + 'type' => 'COUNTER', + }, + 'dotzeroone' => { + 'key' => '-0.01', + 'label' => 'lt. 0.01', + 'description' => 'Requests handled int lt. 0.01s', + 'draw' => 'STACK', + 'type' => 'COUNTER', + }, + 'dotzerotwo' => { + 'key' => '-0.02', + 'label' => 'lt. 0.02', + 'description' => 'Requests handled int lt. 0.02s', + 'draw' => 'STACK', + 'type' => 'COUNTER', + }, + } + }, + 'counters' => { + 'cmd' => 'counters', + 'title' => 'DJabberd Counters', + 'vlabel' => 'msgs.', + 'fields' => { + 'clientin_djabberd_iq' => { 'key' => 'ClientIn:DJabberd::IQ', 'type' => 'COUNTER', }, + 'clientin_djabberd_message' => { 'key' => 'ClientIn:DJabberd::Message', 'type' => 'COUNTER', }, + 'clientin_djabberd_presence' => { 'key' => 'ClientIn:DJabberd::Presence', 'type' => 'COUNTER', }, + 'clientin_djabberd_stanza_sasl' => { 'key' => 'ClientIn:DJabberd::Stanza::SASL', 'type' => 'COUNTER', }, + 'clientin_djabberd_stanza_starttls' => { 'key' => 'ClientIn:DJabberd::Stanza::StartTLS', 'type' => 'COUNTER', }, + 'iniq_get_info_query' => { 'key' => 'InIQ:get-{http://jabber.org/protocol/disco#info}query', 'type' => 'COUNTER', }, + 'iniq_get_items_query' => { 'key' => 'InIQ:get-{http://jabber.org/protocol/disco#items}query', 'type' => 'COUNTER', }, + 'iniq_get_roster_query' => { 'key' => 'InIQ:get-{jabber:iq:roster}query', 'type' => 'COUNTER', }, + 'iniq_get_bind' => { 'key' => 'InIQ:set-{urn:ietf:params:xml:ns:xmpp-bind}bind', 'type' => 'COUNTER', }, + 'iniq_get_session' => { 'key' => 'InIQ:set-{urn:ietf:params:xml:ns:xmpp-session}session', 'type' => 'COUNTER', }, + 'serverin_djabberd_stanza_dialback_result' => { 'key' => 'ServerIn:DJabberd::Stanza::DialbackResult', 'type' => 'COUNTER', }, + 'serverin_djabberd_stanza_dialback_verify' => { 'key' => 'ServerIn:DJabberd::Stanza::DialbackVerify', 'type' => 'COUNTER', }, + 'auth_success' => { 'key' => 'auth_success', 'type' => 'COUNTER', }, + 'c2s_message' => { 'key' => 'c2s-Message', 'type' => 'COUNTER', }, + 'c2s_presence' => { 'key' => 'c2s-Presence', 'type' => 'COUNTER', }, + 'connect' => { 'key' => 'connect', 'type' => 'COUNTER', }, + 'deliver_local' => { 'key' => 'deliver_local', 'type' => 'COUNTER', }, + 'deliver_s2s' => { 'key' => 'deliver_s2s', 'type' => 'COUNTER', }, + 'disconnect' => { 'key' => 'disconnect', 'type' => 'COUNTER', }, + }, + }, +}; + +if ( $0 =~ m/djabberd_(.*)$/ && $mode_ref->{$1} ) { + $mode_name = $1; + $mode = $mode_ref->{$mode_name}; +} +else { + print STDERR "ERROR: Unknown mode '$mode'. Exiting.\n"; + exit -1; +} + +if ( $ARGV[0] && $ARGV[0] eq 'suggest' ) { + print join( "\n", keys %$mode_ref ); + + exit 0; +} +elsif ( $ARGV[0] && $ARGV[0] eq "autoconf" ) { + my $result_ref = &query_djabberd( $djabberd_host, $djabberd_port, $mode ); + + if ($result_ref) { + print "yes\n"; + } + else { + print "no\n"; + } + + exit 0; +} +elsif ( $ARGV[0] and $ARGV[0] eq "config" ) { + print "graph_title " . $mode->{'title'} . "\n"; + print "graph_vlabel " . $mode->{'vlabel'} . "\n"; + print "graph_args -l 0\n"; + print "graph_category DJabberd\n"; + foreach my $field_name ( keys %{ $mode->{'fields'} } ) { + my $label = $mode->{'fields'}->{$field_name}->{'label'} || $field_name; + my $desc = $mode->{'fields'}->{$field_name}->{'description'} || $mode->{'fields'}->{$field_name}->{'key'}; + my $draw = $mode->{'fields'}->{$field_name}->{'draw'} || 'LINE1'; + my $type = $mode->{'fields'}->{$field_name}->{'type'} || 'COUNTER'; + + print $field_name. '.label ' . $label . "\n"; + print $field_name. '.description ' . $desc . "\n"; + print $field_name. '.draw ' . $draw . "\n"; + print $field_name. '.type ' . $type . "\n"; + } + + exit 0; +} +else { + my $result_ref = &query_djabberd( $djabberd_host, $djabberd_port, $mode ); + + foreach my $field_name ( keys %{ $mode->{'fields'} } ) { + my $key = $mode->{'fields'}->{$field_name}->{'key'}; + if ( defined( $result_ref->{$key} ) ) { # check for definedness, may well be zero (false for perl) + my $value = $result_ref->{$key}; + + # if there is a filter defined for this key apply it now + if ( exists( $mode->{'fields'}->{$field_name}->{'filter'} ) && ref( $mode->{'fields'}->{$field_name}->{'filter'} ) eq 'CODE' ) { + $value = &{ $mode->{'fields'}->{$field_name}->{'filter'} }($value); + } + print $field_name. ".value " . $value . "\n"; + } + } +} + +sub query_djabberd { + my ( $host, $port, $mode ) = @_; + + my $conn = IO::Socket::INET::->new( + PeerAddr => $host, + PeerPort => $port, + Proto => 'tcp', + Timeout => 5, + ) or die($!); + + my $request = $mode->{'cmd'} . "\n"; + + $conn->syswrite( $request, length($request) ); + + my @lines = (); + while ( my $line = $conn->getline() ) { + if ( $line =~ /^\./ ) { + last; + } + push( @lines, $line ); + } + close($conn); + + my $result_ref = {}; + foreach my $line (@lines) { + my ( $key, $value, $unit ) = split /\s+/, $line; + if ( $key && $value ) { + $result_ref->{$key} = $value; + } + } + + return $result_ref; +} + +# transform kb => bytes +sub kb2bytes { + + my $num = shift; + + if ( $num && $num =~ m/^\d+$/ ) { + $num *= 1024; + } + + return $num; +}