/* * Copyright (C) 2005-2008 Jive Software. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jivesoftware.openfire.plugin; import static org.jivesoftware.openfire.spi.ConnectionManagerImpl.EXECUTOR_FILTER_NAME; import org.apache.mina.filter.executor.ExecutorFilter; import org.apache.mina.management.MINAStatCollector; import org.apache.mina.transport.socket.SocketAcceptor; import org.jivesoftware.database.DbConnectionManager; import org.jivesoftware.openfire.SessionManager; import org.jivesoftware.openfire.XMPPServer; import org.jivesoftware.openfire.spi.ConnectionManagerImpl; import org.jivesoftware.util.JiveGlobals; import org.jivesoftware.util.TaskEngine; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.TimerTask; import java.util.concurrent.ThreadPoolExecutor; /** * Collector of raw data that is print to a log file every minute. * * @author Gaston Dombiak */ public class StatCollector extends TimerTask { private static final Logger Log = LoggerFactory.getLogger(StatCollector.class); private boolean headerPrinter = false; private List<String> content = new ArrayList<String>(); private SocketAcceptor socketAcceptor; // Take a sample every X seconds private int frequency; private boolean started = false; private MINAStatCollector statCollector; public StatCollector(int frequency) { this.frequency = frequency; ConnectionManagerImpl connectionManager = ((ConnectionManagerImpl) XMPPServer.getInstance().getConnectionManager()); if (JiveGlobals.getBooleanProperty("statistic.connectionmanager", false)) { socketAcceptor = connectionManager.getMultiplexerSocketAcceptor(); } else { socketAcceptor = connectionManager.getSocketAcceptor(); } statCollector = new MINAStatCollector(socketAcceptor, frequency - 1000); } @Override public void run() { try { // Collect content StringBuilder sb = new StringBuilder(); // Add current timestamp sb.append(System.currentTimeMillis()); sb.append(','); // Add info about the db connection pool sb.append(DbConnectionManager.getConnectionProvider().toString()); sb.append(','); // Add info about the thread pool that process incoming requests ExecutorFilter executorFilter = (ExecutorFilter) socketAcceptor.getFilterChain().get(EXECUTOR_FILTER_NAME); ThreadPoolExecutor executor = (ThreadPoolExecutor) executorFilter.getExecutor(); sb.append(executor.getCorePoolSize()); sb.append(','); sb.append(executor.getActiveCount()); sb.append(','); try { sb.append(executor.getQueue().size()); } catch (UnsupportedOperationException e) { sb.append(-1); } sb.append(','); sb.append(executor.getCompletedTaskCount()); // Add info about number of connected sessions sb.append(','); sb.append(SessionManager.getInstance().getConnectionsCount(false)); // Add info about MINA statistics sb.append(','); sb.append(statCollector.getMsgRead()); sb.append(','); sb.append(statCollector.getMsgWritten()); sb.append(','); sb.append(statCollector.getQueuedEvents()); sb.append(','); sb.append(statCollector.getScheduledWrites()); // Add new line of content with current stats content.add(sb.toString()); // Check if we need to print content to file (print content every minute) if (content.size() > (60f / frequency * 1000)) { try { File file = new File(JiveGlobals.getHomeDirectory() + File.separator + "logs", JiveGlobals.getProperty("statistic.filename", "stats.txt")); if (!file.exists()) { file.createNewFile(); } BufferedWriter out = new BufferedWriter(new FileWriter(file, true)); if (!headerPrinter) { out.write(new Date().toString()); out.write('\n'); out.write( "Timestamp, DB min, DB max, DB current, DB used, Core Threads, Active Threads, Queue Tasks, Completed Tasks, Sessions, NIO Read, NIO Written, Queued NIO events, Queues NIO writes"); out.write('\n'); headerPrinter = true; } for (String line : content) { out.write(line); out.write('\n'); } out.close(); } catch (IOException e) { Log.error("Error creating statistics log file", e); } content.clear(); } } catch (Exception e) { Log.error("Error collecting and logging server statistics", e); } } public synchronized void start() { if (!started) { started = true; statCollector.start(); TaskEngine.getInstance().scheduleAtFixedRate(this, 1000, frequency); } } public void stop() { if (started) { statCollector.stop(); TaskEngine.getInstance().cancelScheduledTask(this); } } }