Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Add munin monitoring plugin

This commit adds a plugin for the munin monitoring tool.
  • Loading branch information...
commit 77625b0eb3fa8a50956dcd2f77e84207b6036174 1 parent 518782c
@dominikschulz authored
Showing with 283 additions and 0 deletions.
  1. +283 −0 contrib/monitoring/munin/djabberd_
View
283 contrib/monitoring/munin/djabberd_
@@ -0,0 +1,283 @@
+#!/usr/bin/perl -w
+#
+# Copyright (C) 2012 Dominik Schulz <dominik.schulz@gauner.org>
+#
+# 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/
+#
+# 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(
@yannk
yannk added a note

unnecessary trailing ::

also, it's probably not going to work if djabberd is configuring for IPv6 per your other change.

@dominikschulz Owner

Sorry for the trailing ::. But it's going to work with IPv6 if the server binds the admin port to '::'. This creates a dual-stack socket on most (if not all) OS. But I think I should change that to INET6 anyway. If the server was bound to an ipv6-only socket than it wouldn't work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ 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 {
@yannk
yannk added a note

indentation of this is poor

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+
+ my $num = shift;
+
+ if($num && $num =~ m/^\d+$/) {
+ $num *= 1024;
+ }
+
+ return $num;
+ }

2 comments on commit 77625b0

@yannk

I'm confused by the naming scheme this requires. I'm not familiar with munin, why is the mode encoded in the filename rather than coming from argv or env?

@dominikschulz

Munin Plugins are usually placed somewhere in the filesystem, e.g. /usr/local/share/munin/plugins. Those which should be active are then symlinked to /etc/munin/plugins. The munin agent (munin-node) scans /etc/munin/plugins on startup and allows those plugins to be queried. Since you'll usually symlink the plugins anyway and you can't (easily) pass command line args to the plugins many plugin authors have begun to bundle common code in one script file and determine the output based on the name of the symlink.

Future munin releases will allow for multiple chunks (graphs) per plugin, but this isn't available in all major distros, yet.

Munin may not be the most sophisticated monitoring framework, but it's dead easy and can complement major monitoring frameworks like Nagios or Zabbix very well.

Please sign in to comment.
Something went wrong with that request. Please try again.