/*
* This file is part of Skript.
*
* Skript 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.
*
* Skript 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 Skript. If not, see <http://www.gnu.org/licenses/>.
*
*
* Copyright 2011-2014 Peter Güttinger
*
*/
package ch.njol.skript.log;
import java.util.Collection;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.bukkit.Bukkit;
import org.eclipse.jdt.annotation.Nullable;
import ch.njol.skript.Skript;
import ch.njol.skript.config.Node;
import ch.njol.skript.log.LogHandler.LogResult;
/**
* @author Peter Güttinger
*/
public abstract class SkriptLogger {
@SuppressWarnings("null")
public final static Level SEVERE = Level.SEVERE;
@Nullable
private static Node node = null;
private static Verbosity verbosity = Verbosity.NORMAL;
static boolean debug;
@SuppressWarnings("null")
public final static Level DEBUG = Level.INFO; // CraftBukkit 1.7+ uses the worst logging library I've ever encountered
// new Level("DEBUG", Level.INFO.intValue()) {
// private final static long serialVersionUID = 8959282461654206205L;
// };
@SuppressWarnings("null")
public final static Logger LOGGER = Bukkit.getServer() != null ? Bukkit.getLogger() : Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); // cannot use Bukkit in tests
private final static HandlerList handlers = new HandlerList();
/**
* Shorthand for <tt>{@link #startLogHandler(LogHandler) startLogHandler}(new {@link RetainingLogHandler}());</tt>
*
* @return A newly created RetainingLogHandler
*/
public final static RetainingLogHandler startRetainingLog() {
return startLogHandler(new RetainingLogHandler());
}
/**
* Shorthand for <tt>{@link #startLogHandler(LogHandler) startLogHandler}(new {@link ParseLogHandler}());</tt>
*
* @return A newly created ParseLogHandler
*/
public final static ParseLogHandler startParseLogHandler() {
return startLogHandler(new ParseLogHandler());
}
/**
* Starts a log handler.
* <p>
* This should be used like this:
*
* <pre>
* LogHandler log = SkriptLogger.startLogHandler(new ...LogHandler());
* try {
* doSomethingThatLogsMessages();
* // do something with the logged messages
* } finally {
* log.stop();
* }
* </pre>
*
* @return The passed LogHandler
* @see #startParseLogHandler()
* @see #startRetainingLog()
* @see BlockingLogHandler
* @see CountingLogHandler
* @see ErrorDescLogHandler
* @see FilteringLogHandler
* @see RedirectingLogHandler
*/
public final static <T extends LogHandler> T startLogHandler(final T h) {
handlers.add(h);
return h;
}
final static void removeHandler(final LogHandler h) {
if (!handlers.contains(h))
return;
if (!h.equals(handlers.remove())) {
int i = 1;
while (!h.equals(handlers.remove()))
i++;
LOGGER.severe("[Skript] " + i + " log handler" + (i == 1 ? " was" : "s were") + " not stopped properly! (at " + getCaller() + ") [if you're a server admin and you see this message please file a bug report at http://dev.bukkit.org/server-mods/skript/tickets/ if there is not already one]");
}
}
final static boolean isStopped(final LogHandler h) {
return !handlers.contains(h);
}
@Nullable
final static StackTraceElement getCaller() {
for (final StackTraceElement e : new Exception().getStackTrace()) {
if (!e.getClassName().startsWith(SkriptLogger.class.getPackage().getName()))
return e;
}
return null;
}
public static void setVerbosity(final Verbosity v) {
verbosity = v;
if (v.compareTo(Verbosity.DEBUG) >= 0)
debug = true;
}
public static void setNode(final @Nullable Node node) {
SkriptLogger.node = node == null || node.getParent() == null ? null : node;
}
@Nullable
public static Node getNode() {
return node;
}
/**
* Logging should be done like this:
*
* <pre>
* if (Skript.logNormal())
* Skript.info("this information is displayed on verbosity normal or higher");
* </pre>
*
* @param level
* @param message
* @see Skript#info(String)
* @see Skript#warning(String)
* @see Skript#error(String)
* @see Skript#logNormal()
* @see Skript#logHigh()
* @see Skript#logVeryHigh()
* @see Skript#debug()
*/
public static void log(final Level level, final String message) {
log(new LogEntry(level, message, node));
}
public static void log(final @Nullable LogEntry entry) {
if (entry == null)
return;
if (Skript.testing() && node != null && node.debug())
System.out.print("---> " + entry.level + "/" + ErrorQuality.get(entry.quality) + ": " + entry.getMessage() + " ::" + LogEntry.findCaller());
for (final LogHandler h : handlers) {
final LogResult r = h.log(entry);
switch (r) {
case CACHED:
return;
case DONT_LOG:
entry.discarded("denied by " + h);
return;
case LOG:
continue;
}
}
entry.logged();
LOGGER.log(entry.getLevel(), "[Skript] " + entry.getMessage());
}
public static void logAll(final Collection<LogEntry> entries) {
for (final LogEntry entry : entries) {
if (entry == null)
continue;
log(entry);
}
}
public static void logTracked(final Level level, final String message, final ErrorQuality quality) {
log(new LogEntry(level, quality.quality(), message, node, true));
}
/**
* Checks whether messages should be logged for the given verbosity.
*
* @param minVerb minimal verbosity
* @return Whether messages should be logged for the given verbosity.
*/
public static boolean log(final Verbosity minVerb) {
return minVerb.compareTo(verbosity) <= 0;
}
public static boolean debug() {
return debug;
}
}