250 lines
7.4 KiB
Python
Executable file
250 lines
7.4 KiB
Python
Executable file
#!/usr/bin/python -Wignore::DeprecationWarning
|
|
# -*- coding: utf-8 -*-
|
|
#
|
|
# Wildcard-plugin to monitor spectrum transport usage through an XMPP-connection
|
|
# sending Statistics Gathering (XEP-0039 [1]) packets. Depending on the suffix,
|
|
# the plugin monitors one specific characteristic of one or more spectrum
|
|
# instances.
|
|
#
|
|
# Current suffixes are:
|
|
# spectrum_uptime (monitor uptime of transports)
|
|
# spectrum_registered (how many users are registered to the transport)
|
|
# spectrum_online (how many users are online)
|
|
# spectarm_contacts_registered
|
|
# spectrum_contacts_online (same as above, only for the legacy network)
|
|
# spectrum_messages (how many messages have been sent over this transport)
|
|
# spectrum_memory (how much memory the transport consumes)
|
|
#
|
|
# Configuration:
|
|
# You need to configure this plugin (just like any other plugin) in
|
|
# plugin-conf.d/munin-node.
|
|
# You have to configure the plugin to run as user and group "spectrum".
|
|
#
|
|
# By default, the plugin monitors all instances configured in a config-file
|
|
# in /etc/spectrum2/transports. If you do not want to monitor all instances,
|
|
# you can give an explicit listing of the corresponding instances
|
|
# with the environment variable "jids".
|
|
#
|
|
# Here is an example of a configuration. Note again that you can ommit both
|
|
# env.cfgs and env.base:
|
|
#
|
|
# [spectrum_*]
|
|
# user spectrum
|
|
# group spectrum
|
|
# env.jids xmpp.example.com,irc.example.com
|
|
#
|
|
# Author:
|
|
# Mathias Ertl <mati@fsinf.at>
|
|
#
|
|
# Changelog:
|
|
# 2.0: Port to config_interface local socket
|
|
# 1.1: Suffixes that aggregate multiple values no longer show the individual
|
|
# values by default. This can be overridden by setting the "verbose"
|
|
# env-variable to any non-empty string.
|
|
# 1.0: Initial version
|
|
#
|
|
# [1] http://xmpp.org/extensions/xep-0039.html
|
|
#
|
|
# Copyright (c) 2009 Mathias Ertl.
|
|
#
|
|
# Permission to use, copy, and modify this software with or without fee
|
|
# is hereby granted, provided that this entire notice is included in
|
|
# all source code copies of any software which is or includes a copy or
|
|
# modification of this software.
|
|
#
|
|
# THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
|
|
# IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
|
|
# REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
|
|
# MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
|
|
# PURPOSE.
|
|
#
|
|
# Magic markers
|
|
#%# family=auto
|
|
#%# capabilities=autoconf suggest
|
|
|
|
import sys
|
|
from subprocess import *
|
|
|
|
# autoconf and suggest handling:
|
|
if len( sys.argv ) > 1:
|
|
if sys.argv[1] == 'autoconf':
|
|
print( 'yes' )
|
|
sys.exit( 0 )
|
|
elif sys.argv[1] == 'suggest':
|
|
print( """uptime
|
|
registered
|
|
online
|
|
contacts_total
|
|
contacts_online
|
|
messages
|
|
messages_sec
|
|
memory""" )
|
|
sys.exit(0)
|
|
|
|
import os, re
|
|
|
|
# filter forbidden characters for munin fieldnames
|
|
def handle_field( string ):
|
|
for regexp in [ '^[^A-Za-z_]', '[^A-Za-z0-9_]' ]:
|
|
string = re.compile( regexp ).sub( '_', string )
|
|
return string
|
|
|
|
# get runtime variables
|
|
suffix = sys.argv[0].partition('_')[2]
|
|
verbose = os.environ.get( 'verbose' )
|
|
|
|
jids = []
|
|
|
|
base = os.environ.get( 'base', '/etc/spectrum' )
|
|
if 'jids' in os.environ.keys():
|
|
jids = os.environ.get( 'jids' ).split(',')
|
|
else:
|
|
proc = Popen(['spectrum2_manager', 'list'], stdout=PIPE, stderr=PIPE)
|
|
out, err = proc.communicate()
|
|
jids = out.split('\n')[:-1]
|
|
|
|
# set variables based on wildcard
|
|
if suffix == 'uptime':
|
|
stat = { 'uptime': None }
|
|
title = "Uptime"
|
|
vlabel = "days"
|
|
info = ''
|
|
transformer = lambda value: float(value)/60.0/60.0/24.0
|
|
elif suffix == 'backends_count':
|
|
stat = { "backends_count": None }
|
|
title = "Backends count"
|
|
vlabel = "backends"
|
|
info = 'Total number of backends.'
|
|
elif suffix == 'crashed_backends_count':
|
|
stat = { "crashed_backends_count": None }
|
|
title = "Crashed backends count"
|
|
vlabel = "backends"
|
|
info = 'Total number of backends.'
|
|
elif suffix == 'online':
|
|
stat = { 'online_users_count': None }
|
|
title = "Online users"
|
|
vlabel = "users"
|
|
info = 'Number of users that currently use the spectrum transports.'
|
|
elif suffix == 'messages':
|
|
stat = { 'messages_from_xmpp': 'from_xmpp', 'messages_to_xmpp': 'to_xmpp' }
|
|
title = "Messages send over transport"
|
|
vlabel = "messages"
|
|
info = 'Total messages send over spectrum since the last restart.'
|
|
elif suffix == 'messages_sec':
|
|
stat = { 'messages_from_xmpp': 'from_xmpp', 'messages_to_xmpp': 'to_xmpp' }
|
|
title = "Messages send over transport per second"
|
|
vlabel = "messages/sec"
|
|
info = 'Messages send per second over spectrum transports.'
|
|
elif suffix == 'memory':
|
|
stat = { 'used_memory': None }
|
|
title = "Memory usage of transports"
|
|
vlabel = "megabytes"
|
|
transformer = lambda value: float(value)/1024.0
|
|
info = 'Memory usage of spectrum transports.'
|
|
elif suffix == 'average_memory_per_user':
|
|
stat = { 'average_memory_per_user': None }
|
|
title = "Average memory usage per user"
|
|
vlabel = "kilobytes"
|
|
#transformer = lambda value: float(value)/1024.0
|
|
info = 'Memory usage of spectrum transports.'
|
|
|
|
# handle config
|
|
if len( sys.argv ) > 1 and sys.argv[1] == 'config':
|
|
print( """graph_title %s
|
|
graph_args --base 1000 -l 0
|
|
graph_scale no
|
|
graph_vlabel %s
|
|
graph_category spectrum2
|
|
graph_info %s""" %(title, vlabel, info) )
|
|
for jid in jids:
|
|
if len(stat) > 1:
|
|
# plugin monitors more than one field
|
|
label = jid + ' total'
|
|
fieldname = handle_field( label )
|
|
print( '%s.label %s' %(fieldname, label) )
|
|
if suffix == 'messages_sec':
|
|
print( '%s.type DERIVE' %(fieldname) )
|
|
print( '%s.min 0' %(fieldname) )
|
|
|
|
# to not print individual fields if verbose is not set:
|
|
if not verbose:
|
|
continue
|
|
|
|
for name, field_suffix in stat.iteritems():
|
|
label = jid
|
|
if field_suffix:
|
|
label += ' ' + field_suffix
|
|
fieldname = handle_field( label )
|
|
print( '%s.label %s' %(fieldname, label) )
|
|
if suffix == 'messages_sec':
|
|
print( '%s.type DERIVE' %(fieldname) )
|
|
print( '%s.min 0' %(fieldname) )
|
|
sys.exit(0)
|
|
|
|
# callback to handle incoming packets
|
|
def handler_fetch( packet ):
|
|
jid = str( packet.getFrom() )
|
|
total = None
|
|
|
|
for child in packet.getChildren()[0].getChildren():
|
|
label = jid
|
|
value = child.getAttr( 'value' )
|
|
if len( stat ) > 1:
|
|
if total == None:
|
|
total = int( value )
|
|
else:
|
|
total += int( value )
|
|
if not verbose:
|
|
continue
|
|
|
|
field_suffix = stat[ child.getAttr( 'name' ) ]
|
|
if field_suffix:
|
|
label += ' ' + field_suffix
|
|
fieldname = handle_field( label )
|
|
if 'transformer' in globals():
|
|
value = transformer(value)
|
|
|
|
print( '%s.value %s' %(fieldname, value) )
|
|
|
|
if total != None:
|
|
fieldname = handle_field( jid + ' total' )
|
|
if 'transformer' in globals():
|
|
total = transformer( total )
|
|
print( '%s.value %s' %(fieldname, total) )
|
|
|
|
for jid in jids:
|
|
total = None
|
|
label = jid
|
|
for name in stat.keys():
|
|
proc = Popen(['spectrum2_manager', jid, name], stdout=PIPE, stderr=PIPE)
|
|
out, err = proc.communicate()
|
|
out = out.replace('\n', '')
|
|
value = 0
|
|
try:
|
|
value = int(out)
|
|
except:
|
|
print( "Error: %s" % (value))
|
|
continue
|
|
|
|
if len( stat ) > 1:
|
|
if total == None:
|
|
total = int( value )
|
|
else:
|
|
total += int( value )
|
|
if not verbose:
|
|
continue
|
|
|
|
field_suffix = stat[ name ]
|
|
if field_suffix:
|
|
label += ' ' + field_suffix
|
|
fieldname = handle_field( label )
|
|
if 'transformer' in globals():
|
|
value = transformer(value)
|
|
|
|
print( '%s.value %s' %(fieldname, value) )
|
|
|
|
if total != None:
|
|
fieldname = handle_field( jid + ' total' )
|
|
if 'transformer' in globals():
|
|
total = transformer( total )
|
|
print( '%s.value %s' %(fieldname, total) )
|