/**
* Analytica - beta version - Systems Monitoring Tool
*
* Copyright (C) 2013, KleeGroup, direction.technique@kleegroup.com (http://www.kleegroup.com)
* KleeGroup, Centre d'affaire la Boursidi�re - BP 159 - 92357 Le Plessis Robinson Cedex - France
*
* 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 3 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, see <http://www.gnu.org/licenses>
*
* Linking this library statically or dynamically with other modules is making a combined work based on this library.
* Thus, the terms and conditions of the GNU General Public License cover the whole combination.
*
* As a special exception, the copyright holders of this library give you permission to link this library
* with independent modules to produce an executable, regardless of the license terms of these independent modules,
* and to copy and distribute the resulting executable under terms of your choice, provided that you also meet,
* for each linked independent module, the terms and conditions of the license of that module.
* An independent module is a module which is not derived from or based on this library.
* If you modify this library, you may extend this exception to your version of the library,
* but you are not obliged to do so.
* If you do not wish to do so, delete this exception statement from your version.
*/
package io.analytica.agent.impl.net;
import io.analytica.KProcessJsonCodec;
import io.analytica.api.KProcess;
import io.analytica.api.KProcessConnector;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;
import org.apache.log4j.Logger;
/**
* TODO voir http://ghads.wordpress.com/2008/09/24/calling-a-rest-webservice-from-java-without-libs/
* @author npiedeloup
* @version $Id: RemoteNetPlugin.java,v 1.4 2012/06/14 13:49:17 npiedeloup Exp $
*/
public final class FileLogConnector implements KProcessConnector {
// private static final String VERSION_MAJOR = "1.0"; //definit la compatibilit�
// private static final String VERSION_MINOR = "0";
// private static final String VERSION = VERSION_MAJOR + "." + VERSION_MINOR;
private static final String DATE_FORMAT = "yyyyMMdd HH:mm:ss";
private final Logger logger = Logger.getLogger(FileLogConnector.class);
private final long spoolFrequencyMs = 250;
private Thread processSpoolerThread = null;
private final ConcurrentLinkedQueue<KProcess> processQueue = new ConcurrentLinkedQueue<KProcess>();
private final String fileName;
public FileLogConnector(final String fileName) {
if (fileName == null || fileName.trim().length() == 0) {
throw new IllegalArgumentException("fileName to spool process is required");
}
//---------------------------------------------------------------------
this.fileName = fileName;
}
/** {@inheritDoc} */
public void add(final KProcess process) {
processQueue.add(process);
}
/** {@inheritDoc} */
public void start() {
processSpoolerThread = new SpoolProcessThread(this);
processSpoolerThread.start();
final File spoolFile = new File(fileName);
final File dir = spoolFile.getParentFile();
dir.mkdirs();
try {
spoolFile.createNewFile();
} catch (final IOException e) {
throw new RuntimeException("Can't create " + fileName, e);
}
if (!(spoolFile.exists() && spoolFile.canWrite())) {
throw new IllegalArgumentException("Can't write " + fileName);
}
logger.info("Start Analytica FileLogNetPlugin : log to " + fileName);
}
/** {@inheritDoc} */
public void stop() {
processSpoolerThread.interrupt();
try {
processSpoolerThread.join(10000);//on attend 10s max
} catch (final InterruptedException e) {
//rien, si interrupt on continu l'arret
}
processSpoolerThread = null;
flushProcessQueue();
logger.info("Stop Analytica RemoteNetPlugin");
}
private static class SpoolProcessThread extends Thread {
private final FileLogConnector fileLogConnector;
SpoolProcessThread(final FileLogConnector fileLogConnector) {
super("AnalyticaSpoolProcessThread");
setDaemon(false); //ce n'est pas un d�mon car on veux envoyer les derniers process
//-----------------------------------------------------------------
this.fileLogConnector = fileLogConnector;
}
/** {@inheritDoc} */
@Override
public void run() {
while (!isInterrupted()) {
try {
fileLogConnector.waitToSendPacket();
} catch (final InterruptedException e) {
interrupt();//On remet le flag qui a �t� reset lors du throw InterruptedException (pour le test isInterrupted())
//on envoi avant l'arret du serveur
}
//On flush la queue sur :
// - le timeout
// - un interrupt (arret du serveur)
fileLogConnector.flushProcessQueue();
}
}
}
/**
* On attend la constitution d'un paquet.
* Rend la main apr�s :
* - le timeout
* - un processQueue.notify (taille max de la queue atteinte)
* - un interrupt (arret du serveur)
* @throws InterruptedException Si interrupt
*/
void waitToSendPacket() throws InterruptedException {
synchronized (processQueue) {
processQueue.wait(spoolFrequencyMs);
}
}
/**
* Effectue le flush de la queue des processes � envoyer.
*/
void flushProcessQueue() {
final List<KProcess> processes = new ArrayList<KProcess>();
KProcess head;
do {
head = processQueue.poll();
if (head != null) {
processes.add(head);
}
} while (head != null); //On depile tout : car lors de l'arret du serveur on aura pas d'autre flush
if (!processes.isEmpty()) {
final String json = KProcessJsonCodec.toJson(processes);
writeToLogFile(json);
//logger.info("Spool " + processes.size() + " processes to " + spoolLogger.getName());
}
}
private void writeToLogFile(final String json) {
final SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
Writer writer;
try {
writer = new FileWriter(fileName, true);
try {
final BufferedWriter out = new BufferedWriter(writer);
try {
doWriteToLogFile(json, sdf, out);
} finally {
out.close();
}
} finally {
writer.close();
}
} catch (final IOException e) {
logger.error("Can't write in logFile :" + fileName + " : " + e.getMessage());
e.printStackTrace();
throw new RuntimeException("Can't write in logFile :" + fileName, e); //stopera le thread
}
}
private static void doWriteToLogFile(final String json, final SimpleDateFormat sdf, final BufferedWriter out) throws IOException {
out.write(sdf.format(new Date()));
out.write(" [AnalyticaProcess] - ");
out.write(json);
out.write("\n");
}
}