Changeset - f75c6e8a701c
[Not reviewed]
0 3 0
HanzZ - 13 years ago 2012-07-30 07:31:48
hanzz.k@gmail.com
More spectrum2 stats
3 files changed with 20 insertions and 19 deletions:
0 comments (0 inline, 0 general)
include/transport/admininterface.h
Show inline comments
 
@@ -3,51 +3,52 @@
 
 *
 
 * Copyright (C) 2011, Jan Kaluza <hanzz.k@gmail.com>
 
 *
 
 * 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; either version 2 of the License, or
 
 * (at your option) any later version.
 
 *
 
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
 
 */
 

	
 
#pragma once
 

	
 
#include <string>
 
#include <map>
 
#include "Swiften/Swiften.h"
 

	
 
namespace Transport {
 

	
 
class Component;
 
class StorageBackend;
 
class UserManager;
 
class NetworkPluginServer;
 
class UserRegistration;
 

	
 
class AdminInterface {
 
	public:
 
		AdminInterface(Component *component, UserManager *userManager, NetworkPluginServer *server = NULL, StorageBackend *storageBackend = NULL, UserRegistration *userRegistration = NULL);
 

	
 
		~AdminInterface();
 

	
 
		void handleQuery(Swift::Message::ref message);
 

	
 
	private:
 
		void handleMessageReceived(Swift::Message::ref message);
 

	
 
		Component *m_component;
 
		StorageBackend *m_storageBackend;
 
		UserManager *m_userManager;
 
		NetworkPluginServer *m_server;
 
		UserRegistration *m_userRegistration;
 
		time_t m_start;
 
};
 

	
 
}
munin/spectrum2_
Show inline comments
 
@@ -60,137 +60,128 @@
 
# 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' )
 
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 == 'registered':
 
	stat = { 'users/registered': None }
 
	title = "Registered users"
 
	vlabel = "users"
 
	info = 'Total users that registerd with spectrum transports.'
 
elif suffix == 'backends_count':
 
	stat = { "backends_count": None }
 
	title = "Backends count"
 
	vlabel = "backends"
 
	info = 'Total number of backends.'
 
elif suffix == 'online':
 
	stat = { 'users/online': None }
 
	stat = { 'online_users_count': None }
 
	title = "Online users"
 
	vlabel = "users"
 
	info = 'Number of users that currently use the spectrum transports.'
 
elif suffix == 'contacts_total':
 
	stat = { 'contacts/total': None }
 
	title = "Buddies in roster (total)"
 
	vlabel = "users"
 
	info = 'Total number of contacts that the users that registered with spectrum have.'
 
elif suffix == 'contacts_online':
 
	stat = { 'contacts/online': None }
 
	title = "Buddies online"
 
	vlabel = "users"
 
	info = 'Total number of contacts that are currently online.'
 
elif suffix == 'messages':
 
	stat = { 'messages/in': 'in', 'messages/out': 'out' }
 
	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/in': 'in', 'messages/out': 'out' }
 
	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 = { 'memory-usage': None }
 
	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 transports
 
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:
src/admininterface.cpp
Show inline comments
 
@@ -5,113 +5,117 @@
 
 *
 
 * 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; either version 2 of the License, or
 
 * (at your option) any later version.
 
 *
 
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
 
 */
 

	
 
#include "transport/admininterface.h"
 
#include "transport/user.h"
 
#include "transport/transport.h"
 
#include "transport/storagebackend.h"
 
#include "transport/conversationmanager.h"
 
#include "transport/rostermanager.h"
 
#include "transport/usermanager.h"
 
#include "transport/networkpluginserver.h"
 
#include "transport/logging.h"
 
#include "transport/userregistration.h"
 
#include "storageresponder.h"
 
#include "transport/memoryusage.h"
 
#include <boost/foreach.hpp>
 

	
 
namespace Transport {
 

	
 
DEFINE_LOGGER(logger, "AdminInterface");
 

	
 
static std::string getArg(const std::string &body) {
 
	std::string ret;
 
	if (body.find(" ") == std::string::npos)
 
		return ret;
 

	
 
	return body.substr(body.find(" ") + 1);
 
}
 

	
 
AdminInterface::AdminInterface(Component *component, UserManager *userManager, NetworkPluginServer *server, StorageBackend *storageBackend, UserRegistration *userRegistration) {
 
	m_component = component;
 
	m_storageBackend = storageBackend;
 
	m_userManager = userManager;
 
	m_server = server;
 
	m_userRegistration = userRegistration;
 
	m_start = time(NULL);
 

	
 
	m_component->getStanzaChannel()->onMessageReceived.connect(bind(&AdminInterface::handleMessageReceived, this, _1));
 
}
 

	
 
AdminInterface::~AdminInterface() {
 
}
 

	
 
void AdminInterface::handleQuery(Swift::Message::ref message) {
 
	LOG4CXX_INFO(logger, "Message from admin received");
 
	message->setTo(message->getFrom());
 
	message->setFrom(m_component->getJID());
 

	
 
	if (message->getBody() == "status") {
 
		int users = m_userManager->getUserCount();
 
		int backends = m_server->getBackendCount();
 
		message->setBody("Running (" + boost::lexical_cast<std::string>(users) + " users connected using " + boost::lexical_cast<std::string>(backends) + " backends)");
 
	}
 
	else if (message->getBody() == "uptime") {
 
		message->setBody(boost::lexical_cast<std::string>(time(0) - m_start));
 
	}
 
	else if (message->getBody() == "online_users") {
 
		std::string lst;
 
		const std::map<std::string, User *> &users = m_userManager->getUsers();
 
		if (users.size() == 0)
 
			lst = "0";
 

	
 
		for (std::map<std::string, User *>::const_iterator it = users.begin(); it != users.end(); it ++) {
 
			lst += (*it).first + "\n";
 
		}
 

	
 
		message->setBody(lst);
 
	}
 
	else if (message->getBody() == "online_users_count") {
 
		int users = m_userManager->getUserCount();
 
		message->setBody(boost::lexical_cast<std::string>(users));
 
	}
 
	else if (message->getBody() == "reload") {
 
		bool done = m_component->getConfig()->reload();
 
		if (done) {
 
			message->setBody("Config reloaded");
 
		}
 
		else {
 
			message->setBody("Error during config reload");
 
		}
 
	}
 
	else if (message->getBody() == "online_users_per_backend") {
 
		std::string lst;
 
		int id = 1;
 

	
 
		const std::list <NetworkPluginServer::Backend *> &backends = m_server->getBackends();
 
		for (std::list <NetworkPluginServer::Backend *>::const_iterator b = backends.begin(); b != backends.end(); b++) {
 
			NetworkPluginServer::Backend *backend = *b;
 
			lst += "Backend " + boost::lexical_cast<std::string>(id) + " (ID=" + backend->id + ")";
 
			lst += backend->acceptUsers ? "" : " - not-accepting";
 
			lst += backend->longRun ? " - long-running" : "";
 
			lst += ":\n";
 
			if (backend->users.size() == 0) {
 
				lst += "   waiting for users\n";
 
			}
 
			else {
 
				time_t now = time(NULL);
 
				for (std::list<User *>::const_iterator u = backend->users.begin(); u != backend->users.end(); u++) {
 
					User *user = *u;
 
					lst += "   " + user->getJID().toBare().toString();
 
					lst += " - non-active for " + boost::lexical_cast<std::string>(now - user->getLastActivity()) + " seconds";
 
					lst += "\n";
 
				}
 
			}
 
@@ -201,156 +205,161 @@ void AdminInterface::handleQuery(Swift::Message::ref message) {
 
		std::string lst;
 
		int id = 1;
 
		const std::list <NetworkPluginServer::Backend *> &backends = m_server->getBackends();
 
		BOOST_FOREACH(NetworkPluginServer::Backend * backend, backends) {
 
			lst += "Backend " + boost::lexical_cast<std::string>(id)  + " (ID=" + backend->id + "): " + boost::lexical_cast<std::string>(backend->shared) + "\n";
 
			id++;
 
		}
 

	
 
		message->setBody(lst);
 
	}
 
	else if (message->getBody() == "used_memory_per_backend") {
 
		std::string lst;
 
		int id = 1;
 
		const std::list <NetworkPluginServer::Backend *> &backends = m_server->getBackends();
 
		BOOST_FOREACH(NetworkPluginServer::Backend * backend, backends) {
 
			lst += "Backend " + boost::lexical_cast<std::string>(id)  + " (ID=" + backend->id + "): " + boost::lexical_cast<std::string>(backend->res - backend->shared) + "\n";
 
			id++;
 
		}
 

	
 
		message->setBody(lst);
 
	}
 
	else if (message->getBody() == "average_memory_per_user_per_backend") {
 
		std::string lst;
 
		int id = 1;
 
		const std::list <NetworkPluginServer::Backend *> &backends = m_server->getBackends();
 
		BOOST_FOREACH(NetworkPluginServer::Backend * backend, backends) {
 
			if (backend->users.size() == 0) {
 
				lst += "Backend " + boost::lexical_cast<std::string>(id)  + " (ID=" + backend->id + "): 0\n";
 
			}
 
			else {
 
				lst += "Backend " + boost::lexical_cast<std::string>(id) + " (ID=" + backend->id + "): " + boost::lexical_cast<std::string>((backend->res - backend->init_res) / backend->users.size()) + "\n";
 
			}
 
			id++;
 
		}
 

	
 
		message->setBody(lst);
 
	}
 
	else if (message->getBody() == "collect_backend") {
 
		m_server->collectBackend();
 
	}
 
	else if (message->getBody() == "crashed_backends") {
 
		std::string lst;
 
		const std::vector<std::string> &backends = m_server->getCrashedBackends();
 
		BOOST_FOREACH(const std::string &backend, backends) {
 
			lst += backend + "\n";
 
		}
 
		message->setBody(lst);
 
	}
 
	else if (message->getBody() == "crashed_backends_count") {
 
		message->setBody(boost::lexical_cast<std::string>(m_server->getCrashedBackends().size()));
 
	}
 
	else if (message->getBody() == "messages_from_xmpp") {
 
		int msgCount = m_userManager->getMessagesToBackend();
 
		message->setBody(boost::lexical_cast<std::string>(msgCount));
 
	}
 
	else if (message->getBody() == "messages_to_xmpp") {
 
		int msgCount = m_userManager->getMessagesToXMPP();
 
		message->setBody(boost::lexical_cast<std::string>(msgCount));
 
	}
 
	else if (message->getBody().find("register ") == 0 && m_userRegistration) {
 
		std::string body = message->getBody();
 
		std::vector<std::string> args;
 
		boost::split(args, body, boost::is_any_of(" "));
 
		if (args.size() == 4) {
 
			UserInfo res;
 
			res.jid = args[1];
 
			res.uin = args[2];
 
			res.password = args[3];
 
			res.language = "en";
 
			res.encoding = "utf-8";
 
			res.vip = 0;
 

	
 
			if (m_userRegistration->registerUser(res)) {
 
				message->setBody("User registered.");
 
			}
 
			else {
 
				message->setBody("Registration failed: User is already registered");
 
			}
 
		}
 
		else {
 
			message->setBody("Bad argument count. See 'help'.");
 
		}
 
	}
 
	else if (message->getBody().find("unregister ") == 0 && m_userRegistration) {
 
		std::string body = message->getBody();
 
		std::vector<std::string> args;
 
		boost::split(args, body, boost::is_any_of(" "));
 
		if (args.size() == 2) {
 
			if (m_userRegistration->unregisterUser(args[1])) {
 
				message->setBody("User unregistered.");
 
			}
 
			else {
 
				message->setBody("Registration failed: User is not registered");
 
			}
 
		}
 
		else {
 
			message->setBody("Bad argument count. See 'help'.");
 
		}
 
	}
 
	else if (message->getBody().find("help") == 0) {
 
		std::string help;
 
		help += "General:\n";
 
		help += "    status - shows instance status\n";
 
		help += "    reload - Reloads config file\n";
 
		help += "    uptime - returns ptime in seconds\n";
 
		help += "Users:\n";
 
		help += "    online_users - returns list of all online users\n";
 
		help += "    online_users_count - number of online users\n";
 
		help += "    online_users_per_backend - shows online users per backends\n";
 
		help += "    has_online_user <bare_JID> - returns 1 if user is online\n";
 
		if (m_userRegistration) {
 
			help += "    register <bare_JID> <legacyName> <password> - registers the new user\n";
 
			help += "    unregister <bare_JID> - unregisters existing user\n";
 
		}
 
		help += "Messages:\n";
 
		help += "    messages_from_xmpp - get number of messages received from XMPP users\n";
 
		help += "    messages_to_xmpp - get number of messages sent to XMPP users\n";
 
		help += "Backends:\n";
 
		help += "    backends_count - number of active backends\n";
 
		help += "    crashed_backends - returns IDs of crashed backends\n";
 
		help += "    crashed_backends_count - returns number of crashed backends\n";
 
		help += "Memory:\n";
 
		help += "    res_memory - Total RESident memory spectrum2 and its backends use in KB\n";
 
		help += "    shr_memory - Total SHaRed memory spectrum2 backends share together in KB\n";
 
		help += "    used_memory - (res_memory - shr_memory)\n";
 
		help += "    average_memory_per_user - (memory_used_without_any_user - res_memory)\n";
 
		help += "    res_memory_per_backend - RESident memory used by backends in KB\n";
 
		help += "    shr_memory_per_backend - SHaRed memory used by backends in KB\n";
 
		help += "    used_memory_per_backend - (res_memory - shr_memory) per backend\n";
 
		help += "    average_memory_per_user_per_backend - (memory_used_without_any_user - res_memory) per backend\n";
 
		
 
		
 
		message->setBody(help);
 
	}
 
	else {
 
		message->setBody("Unknown command. Try \"help\"");
 
	}
 
}
 

	
 
void AdminInterface::handleMessageReceived(Swift::Message::ref message) {
 
	if (!message->getTo().getNode().empty())
 
		return;
 

	
 
	std::vector<std::string> const &x = CONFIG_VECTOR(m_component->getConfig(),"service.admin_jid");
 
	if (std::find(x.begin(), x.end(), message->getFrom().toBare().toString()) == x.end()) {
 
	    LOG4CXX_WARN(logger, "Message not from admin user, but from " << message->getFrom().toBare().toString());
 
	    return;
 
	
 
	}
 
	
 
	// Ignore empty messages
 
	if (message->getBody().empty()) {
 
		return;
 
	}
 

	
 
	handleQuery(message);
 

	
 
	m_component->getStanzaChannel()->sendMessage(message);
 
}
 

	
 
}
0 comments (0 inline, 0 general)