/*
* Tigase Jabber/XMPP Server
* Copyright (C) 2004-2012 "Artur Hefczyc" <artur.hefczyc@tigase.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. Look for COPYING file in the top folder.
* If not, see http://www.gnu.org/licenses/.
*
* $Rev$
* Last modified by $Author$
* $Date$
*/
package tigase.util.tracer;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.Calendar;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import tigase.server.Packet;
/**
* Created: Jun 30, 2009 5:18:10 PM
*
* @author <a href="mailto:artur.hefczyc@tigase.org">Artur Hefczyc</a>
* @version $Rev$
*/
public class TigaseTracer {
private static final Logger log =
Logger.getLogger(TigaseTracer.class.getName());
public static final String TRACER_IPS_PROP_KEY = "--tracer-ips";
public static final String TRACER_JIDS_PROP_KEY = "--tracer-jids";
public static final String TRACER_CIDS_PROP_KEY = "--tracer-cids";
private static final String DEF_DIR = "logs";
private static final long DEF_MAX_FILE_SIZE = 10000000;
private static final int DEF_FILES_COUNT = 5;
private static final String DEF_FILE_NAME = "packet-tracing.log";
private static TigaseTracer instance = null;
private static ConcurrentSkipListSet<String> ips =
new ConcurrentSkipListSet<String>();
private static ConcurrentSkipListSet<String> jids =
new ConcurrentSkipListSet<String>();
private static ConcurrentSkipListSet<String> cids =
new ConcurrentSkipListSet<String>();
private ArrayBlockingQueue<String> waiting =
new ArrayBlockingQueue<String>(10000, true);
private Runnable worker = null;
private File files[] = null;
private long maxFileSize = DEF_MAX_FILE_SIZE;
private int filesCount = DEF_FILES_COUNT;
private String dir = DEF_DIR;
private String fileName = DEF_FILE_NAME;
public static TigaseTracer getTracer(String name) {
if (instance == null) {
try {
instance = new TigaseTracer();
} catch (Exception e) {
log.log(Level.WARNING, "Error initializing Tigase tracer: ", e);
}
}
return instance;
}
public static void addIP(String ip) {
ips.add(ip);
}
public static void removeIP(String ip) {
ips.remove(ip);
}
public static void addJid(String jid) {
jids.add(jid);
}
public static void removeJid(String jid) {
jids.remove(jid);
}
public static void addCid(String cid) {
cids.add(cid);
}
public static void removeCid(String cid) {
cids.remove(cid);
}
private TigaseTracer() throws IOException {
init();
}
private void init() throws IOException {
files = new File[filesCount];
for (int i = 0; i < files.length; i++) {
files[i] = new File(dir, fileName + "." + i);
}
worker = new TracingWorker(new FileWriter(files[0], true), files[0].length());
Thread thr = new Thread(worker);
thr.setName("tracing-worker");
thr.setDaemon(true);
thr.start();
}
public boolean trace(String ip, String to_jid, String from_jid, String cid,
String id, String point, String msg, Packet packet) {
if (ip != null && ips.contains(ip)) {
return waiting.offer(format(ip, id, point, msg, packet));
}
if (to_jid != null && jids.contains(to_jid)) {
return waiting.offer(format("TO: " + to_jid, id, point, msg, packet));
}
if (from_jid != null && jids.contains(from_jid)) {
return waiting.offer(format("FROM: " + from_jid, id, point, msg, packet));
}
if (cid != null && cids.contains(cid)) {
return waiting.offer(format(cid, id, point, msg, packet));
}
return false;
}
private String format(String filter, String id, String point, String msg, Packet packet) {
StringBuilder sb = new StringBuilder();
Calendar cal = Calendar.getInstance();
sb.append(cal.get(Calendar.YEAR));
sb.append("-");
sb.append(cal.get(Calendar.MONTH)+1);
sb.append("-");
sb.append(cal.get(Calendar.DAY_OF_MONTH));
sb.append(" ");
sb.append(cal.get(Calendar.HOUR_OF_DAY));
sb.append(":");
sb.append(cal.get(Calendar.MINUTE));
sb.append(":");
sb.append(cal.get(Calendar.SECOND));
sb.append(".");
sb.append(cal.get(Calendar.MILLISECOND));
sb.append("[");
sb.append(filter);
sb.append("] {");
sb.append(id);
sb.append('-');
sb.append(point);
sb.append("} ");
if (msg != null) {
sb.append(msg);
}
if (packet != null) {
sb.append(packet);
}
sb.append('\n');
return sb.toString();
}
public boolean tracegByIP(String ip, String point, String msg, Packet packet) {
return trace(ip, null, null, null, null, point, msg, packet);
}
public boolean traceByToJid(String jid, String point, String msg, Packet packet) {
return trace(null, jid, null, null, null, point, msg, packet);
}
public boolean traceByFromJid(String jid, String point, String msg, Packet packet) {
return trace(null, null, jid, null, null, point, msg, packet);
}
public boolean traceByCid(String cid, String point, String msg, Packet packet) {
return trace(null, null, null, cid, null, point, msg, packet);
}
private Writer rotateFiles(Writer writer) throws IOException {
writer.close();
for (int i = files.length-2; i >= 0; --i) {
File file1 = files[i];
File file2 = files[i+1];
if (file1.exists()) {
if (file2.exists()) {
file2.delete();
}
file1.renameTo(file2);
}
}
return new FileWriter(files[0], false);
}
private class TracingWorker implements Runnable {
private boolean stopped = false;
private Writer writer = null;
private long size = 0;
protected TracingWorker(Writer writer, long initSize) {
this.writer = writer;
this.size = initSize;
}
@Override
public void run() {
while (!stopped) {
try {
String entry = waiting.take();
if (entry != null) {
try {
// Save the log entry
writer.write(entry);
writer.flush();
size += entry.length();
if (size >= maxFileSize) {
writer = rotateFiles(writer);
size = 0;
}
} catch (IOException ex) {
log.log(Level.WARNING, "Can not write to trace file: ", ex);
}
}
} catch (InterruptedException ex) { }
}
}
}
}