package org.fxmisc.cssfx.impl.log;
/*
* #%L
* CSSFX
* %%
* Copyright (C) 2014 CSSFX by Matthieu Brouillard
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.io.PrintStream;
import java.time.Clock;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import java.util.logging.Level;
public class CSSFXLogger {
private static final Clock clock = Clock.systemDefaultZone();
public static void setLoggerFactory(LoggerFactory factory) {
loggerFactory = factory;
}
public static boolean isInitialized() {
return loggerFactory != null;
}
public static void setLogLevel(LogLevel newLevel) {
logLevel = newLevel;
}
public static void console() {
loggerFactory = CONSOLE_LOGGER_FACTORY;
}
public static void jul() {
loggerFactory = JUL_LOGGER_FACTORY;
}
public static void noop() {
loggerFactory = NOOP_LOGGER_FACTORY;
}
/*
* Always use one of the 2 following methods and never keep static references to a logger.
*/
public static Logger logger(String loggerName) {
return loggerFactory.getLogger(loggerName);
}
public static Logger logger(Class<?> loggerClass) {
return loggerFactory.getLogger(loggerClass);
}
public static enum LogLevel {
NONE,
ERROR,
WARN,
INFO,
DEBUG
}
@FunctionalInterface
public static interface Logger {
public void log(LogLevel level, String message, Object ... args);
public default void info(String message, Object ... args) {log(LogLevel.INFO, message, args);};
public default void debug(String message, Object ... args) {log(LogLevel.DEBUG, message, args);};
public default void warn(String message, Object ... args) {log(LogLevel.WARN, message, args);};
public default void error(String message, Object ... args) {log(LogLevel.ERROR, message, args);};
}
@FunctionalInterface
public static interface LoggerFactory {
public default Logger getLogger(Class<?> loggerClass) {
return getLogger(loggerClass.getName());
}
public Logger getLogger(String loggerName);
}
private static final Logger CONSOLE_LOGGER = new Logger() {
private void printLastThrowableArgument(PrintStream output, Object ...args) {
if (args.length > 0 && Throwable.class.isAssignableFrom(args[args.length-1].getClass())) {
Throwable t = (Throwable) args[args.length-1];
t.printStackTrace(output);
}
}
@Override
public void log(LogLevel askedLevel, String message, Object ... args) {
if (askedLevel.ordinal() <= logLevel.ordinal()) {
List<Object> params = new ArrayList<Object>(args.length + 2);
params.add(clock.instant());
params.add(askedLevel);
params.addAll(Arrays.asList(args));
final PrintStream writer = (LogLevel.ERROR.equals(askedLevel))?System.err:System.out;
writer.println(String.format("%s [%5s] " + message, params.toArray()));
printLastThrowableArgument(writer, args);
}
};
};
private final static LoggerFactory JUL_LOGGER_FACTORY = new LoggerFactory() {
@SuppressWarnings("serial")
Map<LogLevel, Level> levelMapping = new HashMap<CSSFXLogger.LogLevel, Level>(){{
put(LogLevel.NONE, Level.OFF);
put(LogLevel.ERROR, Level.SEVERE);
put(LogLevel.WARN, Level.WARNING);
put(LogLevel.INFO, Level.INFO);
put(LogLevel.DEBUG, Level.FINE);
}};
@Override
public Logger getLogger(String loggerName) {
java.util.logging.Logger delegate = java.util.logging.Logger.getLogger(loggerName);
return new Logger() {
@Override
public void log(LogLevel askedLevel, String message, Object ... args) {
Level julLevel = levelMapping.get(askedLevel);
Supplier<String> log = () -> String.format(message, args);
if (args.length > 0 && Throwable.class.isAssignableFrom(args[args.length-1].getClass())) {
Throwable t = (Throwable) args[args.length-1];
delegate.log(julLevel, t, log);
} else {
delegate.log(julLevel, log);
}
};
};
}
};
private final static LoggerFactory CONSOLE_LOGGER_FACTORY = (s) -> CONSOLE_LOGGER;
private final static Logger NOOP_LOGGER = (level, message, args) -> {};
private final static LoggerFactory NOOP_LOGGER_FACTORY = (s) -> NOOP_LOGGER;
private static LoggerFactory loggerFactory = null;
private static LogLevel logLevel = LogLevel.INFO;
}