Commit aa03ff5e authored by Gaston Dombiak's avatar Gaston Dombiak Committed by gato

Added statistics.

git-svn-id: http://svn.igniterealtime.org/svn/repos/wildfire/trunk@3841 b35dd754-fafc-0310-a699-88a17e54d16e
parent fd99960a
......@@ -166,6 +166,11 @@
## Removed key: 'group.summary.list_group'
## Removed key: 'session.summary.info'
## Removed key: 'user.summary.info'
##
## 3.0.0
## Added key: 'startup.multiplexer'
## Added section: 'muc.stats..*'
## Removed key: 'pubsub.form.authorization.node'
# Wildfire
......@@ -291,6 +296,7 @@ startup.starting.muc=Multi User Chat domain: {0}
startup.caches=Initializing caches
startup.channels=Initializing channels
startup.server=Started server (unencrypted) socket on port: {0}
startup.multiplexer=Started multiplexer (unencrypted) socket on port: {0}
startup.component=Started component (unencrypted) socket on port: {0}
startup.plain=Started plain (unencrypted) socket on port: {0}
startup.ssl=Started SSL (encrypted) socket on port: {0}
......@@ -854,6 +860,20 @@ muc.tasks.conversation.logging=Conversation Logging
muc.tasks.flush=Flush interval (seconds):
muc.tasks.batch=Batch size:
# MUC Statistics
muc.stats.occupants.name=Occupants
muc.stats.occupants.description=Total Room Occupants
muc.stats.occupants.label=Total Room Occupants
muc.stats.users.name=Users
muc.stats.users.description=Number of Connected Users
muc.stats.users.label=Number of Connected Users
muc.stats.incoming.name=Incoming Messages
muc.stats.incoming.description=Rate of Incoming Messages
muc.stats.incoming.label=Incoming Messages
muc.stats.outgoing.name=Outgoing Messages
muc.stats.outgoing.description=Rate of Outgoing Messages
muc.stats.outgoing.label=Outgoing Messages
# Offline messages Page
offline.messages.title=Offline Messages
......@@ -1723,7 +1743,6 @@ pubsub.form.subscription.keywords=Keyword to match
pubsub.form.authorization.title=PubSub subscriber request
pubsub.form.authorization.instruction=Use the following form to approve or deny the subscription \
request.
pubsub.form.authorization.node=Node ID
pubsub.form.authorization.subscriber=Subscriber Address
pubsub.form.authorization.allow=Allow this JID to subscribe to this pubsub node?
pubsub.command.pending-subscriptions.label=Authorize Pending Subscriptions
......
......@@ -82,6 +82,13 @@ public interface MUCUser extends ChannelHandler {
*/
void removeRole(String roomName);
/**
* Returns true if the user is currently present in one or more rooms.
*
* @return true if the user is currently present in one or more rooms.
*/
boolean isJoined();
/**
* Get time (in milliseconds from System currentTimeMillis()) since last packet.
*
......
......@@ -11,14 +11,14 @@
package org.jivesoftware.wildfire.muc;
import java.util.List;
import java.util.Collection;
import org.jivesoftware.wildfire.auth.UnauthorizedException;
import org.jivesoftware.wildfire.user.UserNotFoundException;
import org.xmpp.packet.Message;
import org.xmpp.packet.JID;
import org.xmpp.component.Component;
import org.xmpp.packet.JID;
import org.xmpp.packet.Message;
import java.util.Collection;
import java.util.List;
/**
* Manages groupchat conversations, chatrooms, and users. This class is designed to operate
......@@ -283,4 +283,12 @@ public interface MultiUserChatServer extends Component {
* @param sender the real XMPPAddress of the sender (e.g. john@example.org).
*/
void logConversation(MUCRoom room, Message message, JID sender);
/**
* Notification message indicating the server that an incoming message was broadcasted
* to a given number of occupants.
*
* @param numOccupants number of occupants that received the message.
*/
void messageBroadcastedTo(int numOccupants);
}
\ No newline at end of file
......@@ -844,7 +844,7 @@ public class MUCRoomImpl implements MUCRoom {
}
if (isLogEnabled()) {
MUCRole senderRole = null;
JID senderAddress = null;
JID senderAddress;
if (message.getTo() != null && message.getTo().getResource() != null) {
senderRole = occupants.get(message.getTo().getResource());
}
......@@ -859,6 +859,7 @@ public class MUCRoomImpl implements MUCRoom {
// Log the conversation
server.logConversation(this, message, senderAddress);
}
server.messageBroadcastedTo(occupants.size());
}
/**
......
......@@ -11,19 +11,21 @@
package org.jivesoftware.wildfire.muc.spi;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import org.dom4j.Element;
import org.jivesoftware.wildfire.muc.*;
import org.jivesoftware.util.*;
import org.jivesoftware.wildfire.*;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log;
import org.jivesoftware.util.NotFoundException;
import org.jivesoftware.wildfire.PacketException;
import org.jivesoftware.wildfire.PacketRouter;
import org.jivesoftware.wildfire.auth.UnauthorizedException;
import org.jivesoftware.wildfire.muc.*;
import org.jivesoftware.wildfire.user.UserAlreadyExistsException;
import org.jivesoftware.wildfire.user.UserNotFoundException;
import org.xmpp.packet.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/**
* Implementation of MUCUser. There will be a MUCUser per user that is connected to one or more
* rooms. A MUCUser contains a collection of MUCRoles for each room where the user has joined.
......@@ -74,6 +76,10 @@ public class MUCUserImpl implements MUCUser {
return role;
}
public boolean isJoined() {
return !roles.isEmpty();
}
public Iterator<MUCRole> getRoles() {
return Collections.unmodifiableCollection(roles.values()).iterator();
}
......
......@@ -29,6 +29,8 @@ import org.jivesoftware.wildfire.forms.FormField;
import org.jivesoftware.wildfire.forms.spi.XDataFormImpl;
import org.jivesoftware.wildfire.forms.spi.XFormFieldImpl;
import org.jivesoftware.wildfire.muc.*;
import org.jivesoftware.wildfire.stats.Statistic;
import org.jivesoftware.wildfire.stats.StatisticsManager;
import org.jivesoftware.wildfire.user.UserNotFoundException;
import org.xmpp.component.ComponentManager;
import org.xmpp.packet.*;
......@@ -37,6 +39,8 @@ import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
/**
* Implements the chat server as a cached memory resident chat server. The server is also
......@@ -59,6 +63,17 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
private static final FastDateFormat dateFormatter = FastDateFormat
.getInstance("yyyyMMdd'T'HH:mm:ss", TimeZone.getTimeZone("GMT+0"));
/**
* Statistics keys
*/
private static final String roomsStatKey = "muc_rooms";
private static final String occupantsStatKey = "muc_occupants";
private static final String usersStatKey = "muc_users";
private static final String incomingStatKey = "muc_incoming";
private static final String outgoingStatKey = "muc_outgoing";
/**
* The time to elapse between clearing of idle chat users.
*/
......@@ -167,6 +182,17 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
*/
private final long cleanup_frequency = 60 * 60 * 1000;
/**
* Total number of received messages in all rooms since the last reset. The counter
* is reset each time the Statistic makes a sampling.
*/
private AtomicInteger inMessages = new AtomicInteger(0);
/**
* Total number of broadcasted messages in all rooms since the last reset. The counter
* is reset each time the Statistic makes a sampling.
*/
private AtomicLong outMessages = new AtomicLong(0);
/**
* Create a new group chat server.
*/
......@@ -294,14 +320,14 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
for (MUCUser user : users.values()) {
try {
if (user.getLastPacketTime() < deadline) {
// Kick the user from all the rooms that he/she had previuosly joined
Iterator<MUCRole> roles = user.getRoles();
// If user is not present in any room then remove the user from
// the list of users
if (!roles.hasNext()) {
if (!user.isJoined()) {
removeUser(user.getAddress());
continue;
}
// Kick the user from all the rooms that he/she had previuosly joined
Iterator<MUCRole> roles = user.getRoles();
MUCRole role;
MUCRoom room;
Presence kickedPresence;
......@@ -781,6 +807,12 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
router)) {
rooms.put(room.getName().toLowerCase(), room);
}
// Add statistics
addTotalRoomStats();
addTotalOccupantsStats();
addTotalConnectedUsers();
addNumberIncomingMessages();
addNumberOutgoingMessages();
}
public void stop() {
......@@ -789,16 +821,69 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
routingTable.removeRoute(getAddress());
timer.cancel();
logAllConversation();
// Remove the statistics.
StatisticsManager.getInstance().removeStatistic(roomsStatKey);
StatisticsManager.getInstance().removeStatistic(occupantsStatKey);
StatisticsManager.getInstance().removeStatistic(usersStatKey);
StatisticsManager.getInstance().removeStatistic(incomingStatKey);
StatisticsManager.getInstance().removeStatistic(outgoingStatKey);
}
public long getTotalChatTime() {
return totalChatTime;
}
/**
* Retuns the number of existing rooms in the server (i.e. persistent or not,
* in memory or not).
*
* @return the number of existing rooms in the server.
*/
public int getNumberChatRooms() {
return rooms.size();
}
/**
* Retuns the total number of occupants in all rooms in the server.
*
* @return the number of existing rooms in the server.
*/
public int getNumberConnectedUsers() {
int total = 0;
for (MUCUser user : users.values()) {
if (user.isJoined()) {
total = total + 1;
}
}
return total;
}
/**
* Retuns the total number of users that have joined in all rooms in the server.
*
* @return the number of existing rooms in the server.
*/
public int getNumberRoomOccupants() {
int total = 0;
for (MUCRoom room : rooms.values()) {
total = total + room.getOccupantsCount();
}
return total;
}
public void logConversation(MUCRoom room, Message message, JID sender) {
logQueue.add(new ConversationLogEntry(new Date(), room, message, sender));
}
public void messageBroadcastedTo(int numOccupants) {
// Increment counter of received messages that where broadcasted by one
inMessages.incrementAndGet();
// Increment counter of outgoing messages with the number of room occupants
// that received the message
outMessages.addAndGet(numOccupants);
}
public Iterator<DiscoServerItem> getItems() {
ArrayList<DiscoServerItem> items = new ArrayList<DiscoServerItem>();
......@@ -1038,4 +1123,157 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
}
return buf.toString();
}
/****************** Statistics code ************************/
private void addTotalRoomStats() {
// Register a statistic.
Statistic statistic = new Statistic() {
public String getKey() {
return roomsStatKey;
}
public String getName() {
return LocaleUtils.getLocalizedString("muc.room.summary.total_room");
}
public Type getStatType() {
return Type.COUNT;
}
public String getDescription() {
return LocaleUtils.getLocalizedString("muc.room.summary.total_room");
}
public String getUnits() {
return LocaleUtils.getLocalizedString("muc.room.summary.total_room");
}
public double sample(long timePeriod) {
return getNumberChatRooms();
}
};
StatisticsManager.getInstance().addStatistic(statistic);
}
private void addTotalOccupantsStats() {
// Register a statistic.
Statistic statistic = new Statistic() {
public String getKey() {
return occupantsStatKey;
}
public String getName() {
return LocaleUtils.getLocalizedString("muc.stats.occupants.name");
}
public Type getStatType() {
return Type.COUNT;
}
public String getDescription() {
return LocaleUtils.getLocalizedString("muc.stats.occupants.description");
}
public String getUnits() {
return LocaleUtils.getLocalizedString("muc.stats.occupants.label");
}
public double sample(long timePeriod) {
return getNumberRoomOccupants();
}
};
StatisticsManager.getInstance().addStatistic(statistic);
}
private void addTotalConnectedUsers() {
// Register a statistic.
Statistic statistic = new Statistic() {
public String getKey() {
return usersStatKey;
}
public String getName() {
return LocaleUtils.getLocalizedString("muc.stats.users.name");
}
public Type getStatType() {
return Type.COUNT;
}
public String getDescription() {
return LocaleUtils.getLocalizedString("muc.stats.users.description");
}
public String getUnits() {
return LocaleUtils.getLocalizedString("muc.stats.users.label");
}
public double sample(long timePeriod) {
return getNumberConnectedUsers();
}
};
StatisticsManager.getInstance().addStatistic(statistic);
}
private void addNumberIncomingMessages() {
// Register a statistic.
Statistic statistic = new Statistic() {
public String getKey() {
return incomingStatKey;
}
public String getName() {
return LocaleUtils.getLocalizedString("muc.stats.incoming.name");
}
public Type getStatType() {
return Type.RATE;
}
public String getDescription() {
return LocaleUtils.getLocalizedString("muc.stats.incoming.description");
}
public String getUnits() {
return LocaleUtils.getLocalizedString("muc.stats.incoming.label");
}
public double sample(long timePeriod) {
int received = inMessages.getAndSet(0);
return received/timePeriod;
}
};
StatisticsManager.getInstance().addStatistic(statistic);
}
private void addNumberOutgoingMessages() {
// Register a statistic.
Statistic statistic = new Statistic() {
public String getKey() {
return outgoingStatKey;
}
public String getName() {
return LocaleUtils.getLocalizedString("muc.stats.outgoing.name");
}
public Type getStatType() {
return Type.RATE;
}
public String getDescription() {
return LocaleUtils.getLocalizedString("muc.stats.outgoing.description");
}
public String getUnits() {
return LocaleUtils.getLocalizedString("muc.stats.outgoing.label");
}
public double sample(long timePeriod) {
long received = outMessages.getAndSet(0);
return received/timePeriod;
}
};
StatisticsManager.getInstance().addStatistic(statistic);
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment