/** * Log.java * Copyright 2010 by Michael Peter Christen * First released 22.4.2010 at http://yacy.net * * This file is part of YaCy Content Integration * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program in the file COPYING.LESSER. * If not, see <http://www.gnu.org/licenses/>. */ package net.yacy.cider.util; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import org.apache.log4j.Level; import org.apache.log4j.Logger; /** * the log runner de-synchronizes concurrent threads that share the same logger. * in concurrent environments it can often be seen that a logger synchronizes * all threads at the point where a logging output is done. * This class provides a concurrent access to the log4j logger. A separate * logging thread reads from a logging queue and writes messages from that queue. * * @author m.christen * */ public class Log { protected final static logEntry poison = new logEntry(); protected final static BlockingQueue<logEntry> logQueue = new LinkedBlockingQueue<logEntry>(); private static logRunner logRunnerThread = null; private static final Logger thislog = Logger.getLogger(FileUtils.class.getName()); public final static void startRunner() { logRunnerThread = new logRunner(); logRunnerThread.start(); } public final static void stopRunner() { if (logRunnerThread == null || !logRunnerThread.isAlive()) return; try { logQueue.put(poison); logRunnerThread.join(1000); } catch (InterruptedException e) { } } public static final void logInfo(final Logger logger, final String message) { enQueueLog(logger, Level.INFO, message); } public static final void logInfo(final Logger logger, final String message, final Throwable thrown) { enQueueLog(logger, Level.INFO, message, thrown); } public static final void logDebug(final Logger logger, final String message) { enQueueLog(logger, Level.DEBUG, message); } public static final void logDebug(final Logger logger, final String message, final Throwable thrown) { enQueueLog(logger, Level.DEBUG, message, thrown); } public static final void logWarning(final Logger logger, final String message) { enQueueLog(logger, Level.WARN, message); } public static final void logWarning(final Logger logger, final String message, final Throwable thrown) { enQueueLog(logger, Level.WARN, message, thrown); } public static final void logSevere(final Logger logger, final String message) { enQueueLog(logger, Level.FATAL, message); } public static final void logSevere(final Logger logger, final String message, final Throwable thrown) { enQueueLog(logger, Level.FATAL, message, thrown); } public final static void logException(final Throwable thrown) { enQueueLog(thislog, Level.WARN, thrown.getMessage(), thrown); } public final static void logException(final Logger logger, final Throwable thrown) { enQueueLog(logger, Level.WARN, thrown.getMessage(), thrown); } private final static void enQueueLog(final Logger logger, final Level level, final String message) { if (logRunnerThread == null || !logRunnerThread.isAlive()) { logger.log(level, message); } else { try { logQueue.put(new logEntry(logger, level, message)); } catch (InterruptedException e) { logger.log(level, message); } } } private final static void enQueueLog(final Logger logger, final Level level, final String message, final Throwable thrown) { if (logRunnerThread == null || !logRunnerThread.isAlive()) { logger.log(level, message, thrown); } else { try { logQueue.put(new logEntry(logger, level, message, thrown)); } catch (InterruptedException e) { logger.log(level, message, thrown); } } } protected final static class logEntry { public final Logger logger; public final Level level; public final String message; public final Throwable thrown; public logEntry(final Logger logger, final Level level, final String message, final Throwable thrown) { this.logger = logger; this.level = level; this.message = message; this.thrown = thrown; } public logEntry(final Logger logger, final Level level, final String message) { this(logger, level, message, null); } public logEntry() { this(null, null, null, null); } } protected final static class logRunner extends Thread { public logRunner() { super("LogRunner"); } public void run() { logEntry entry; try { while ((entry = logQueue.take()) != poison) { if (entry.logger != null) { if (entry.thrown == null) { entry.logger.log(entry.level, entry.message); } else { entry.logger.log(entry.level, entry.message, entry.thrown); } } } } catch (InterruptedException e) {} } } }