/*
* Copyright 2013-2016 Cel Skeggs
*
* This file is part of the CCRE, the Common Chicken Runtime Engine.
*
* The CCRE 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.
*
* The CCRE 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 the CCRE. If not, see <http://www.gnu.org/licenses/>.
*/
package ccre.log;
import java.util.concurrent.CopyOnWriteArrayList;
import ccre.util.CallerInfo;
import ccre.util.Utils;
import ccre.verifier.FlowPhase;
import ccre.verifier.SetupPhase;
/**
* A class containing easy global methods for logging, as well as holding the
* default logger field.
*
* @author skeggsc
*/
public class Logger {
/**
* The logging targets to write logs to.
*/
public static final CopyOnWriteArrayList<LoggingTarget> targets = new CopyOnWriteArrayList<LoggingTarget>();
private static boolean includeLineNumbers = true;
/**
* Set whether or not filenames and line numbers should be prefixed to
* logging messages, when available.
*
* @param shouldInclude if this debugging info should be included.
*/
public static void setShouldIncludeLineNumbers(boolean shouldInclude) {
includeLineNumbers = shouldInclude;
}
/**
* Get whether or not filenames and line numbers are prefixed to logging
* messages, when available.
*
* @return shouldInclude if this debugging info is included.
*/
public static boolean getShouldIncludeLineNumbers() {
return includeLineNumbers;
}
static {
targets.add(new PrintStreamLogger(System.err));
}
/**
* Add the specified target to the list of targets.
*
* @param lt The target to add.
*/
@SetupPhase
public static synchronized void addTarget(LoggingTarget lt) {
targets.add(lt);
}
/**
* Remove the specified target from the list of targets.
*
* @param lt The target to remove.
*/
@SetupPhase
public static synchronized void removeTarget(LoggingTarget lt) {
targets.remove(lt);
}
/**
* Log a given message and throwable at the given log level.
*
* @param level the level to log at.
* @param message the message to log.
* @param thr the Throwable to log
*/
@FlowPhase
public static void log(LogLevel level, String message, Throwable thr) {
logInternal(level, message, thr);
}
@FlowPhase
private static void logInternal(LogLevel level, String message, Throwable thr) {
if (level == null || message == null) {
throw new NullPointerException();
}
message = prependCallerInfo(3, message);
for (LoggingTarget lt : targets) {
lt.log(level, message, thr);
}
}
/**
* Log a given message and extended message at the given log level.
*
* @param level the level to log at.
* @param message the message to log.
* @param extended the extended message to log
*/
@FlowPhase
public static void logExt(LogLevel level, String message, String extended) {
if (level == null || message == null) {
throw new NullPointerException();
}
message = prependCallerInfo(1, message);
for (LoggingTarget lt : targets) {
lt.log(level, message, extended);
}
}
@FlowPhase
private static String prependCallerInfo(int index, String message) {
if (includeLineNumbers && !message.startsWith("(") && !message.startsWith("[")) {
CallerInfo caller = Utils.getMethodCaller(index + 1);
if (caller != null && caller.getFileName() != null) {
if (caller.getLineNum() > 0) {
return "(" + caller.getFileName() + ":" + caller.getLineNum() + ") " + message;
} else {
return "(" + caller.getFileName() + ") " + message;
}
}
}
return message;
}
/**
* Log a given message at the given log level.
*
* @param level the level to log at.
* @param message the message to log.
*/
@FlowPhase
public static void log(LogLevel level, String message) {
logInternal(level, message, null);
}
/**
* Log the given message at SEVERE level.
*
* @param message the message to log.
*/
@FlowPhase
public static void severe(String message) {
log(LogLevel.SEVERE, message);
}
/**
* Log the given message at WARNING level.
*
* @param message the message to log.
*/
@FlowPhase
public static void warning(String message) {
log(LogLevel.WARNING, message);
}
/**
* Log the given message at INFO level.
*
* @param message the message to log.
*/
@FlowPhase
public static void info(String message) {
log(LogLevel.INFO, message);
}
/**
* Log the given message at CONFIG level.
*
* @param message the message to log.
*/
@FlowPhase
public static void config(String message) {
log(LogLevel.CONFIG, message);
}
/**
* Log the given message at FINE level.
*
* @param message the message to log.
*/
@FlowPhase
public static void fine(String message) {
log(LogLevel.FINE, message);
}
/**
* Log the given message at FINER level.
*
* @param message the message to log.
*/
@FlowPhase
public static void finer(String message) {
log(LogLevel.FINER, message);
}
/**
* Log the given message at FINEST level.
*
* @param message the message to log.
*/
@FlowPhase
public static void finest(String message) {
log(LogLevel.FINEST, message);
}
/**
* Log the given message and exception at SEVERE level.
*
* @param message the message to log.
* @param thr The exception to include in the log.
*/
@FlowPhase
public static void severe(String message, Throwable thr) {
logInternal(LogLevel.SEVERE, message, thr);
}
/**
* Log the given message and exception at WARNING level.
*
* @param message the message to log.
* @param thr The exception to include in the log.
*/
@FlowPhase
public static void warning(String message, Throwable thr) {
logInternal(LogLevel.WARNING, message, thr);
}
/**
* Log the given message and exception at INFO level.
*
* @param message the message to log.
* @param thr The exception to include in the log.
*/
@FlowPhase
public static void info(String message, Throwable thr) {
logInternal(LogLevel.INFO, message, thr);
}
/**
* Log the given message and exception at CONFIG level.
*
* @param message the message to log.
* @param thr The exception to include in the log.
*/
@FlowPhase
public static void config(String message, Throwable thr) {
logInternal(LogLevel.CONFIG, message, thr);
}
/**
* Log the given message and exception at FINE level.
*
* @param message the message to log.
* @param thr The exception to include in the log.
*/
@FlowPhase
public static void fine(String message, Throwable thr) {
logInternal(LogLevel.FINE, message, thr);
}
/**
* Log the given message and exception at FINER level.
*
* @param message the message to log.
* @param thr The exception to include in the log.
*/
@FlowPhase
public static void finer(String message, Throwable thr) {
logInternal(LogLevel.FINER, message, thr);
}
/**
* Log the given message and exception at FINEST level.
*
* @param message the message to log.
* @param thr The exception to include in the log.
*/
@FlowPhase
public static void finest(String message, Throwable thr) {
logInternal(LogLevel.FINEST, message, thr);
}
private Logger() {
}
}