
io.airlift.log.Logging Maven / Gradle / Ivy
/*
* Copyright 2010 Proofpoint, Inc.
*
* 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.
*/
package io.airlift.log;
import com.google.common.collect.ImmutableSortedMap;
import javax.annotation.concurrent.GuardedBy;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.Reader;
import java.util.Collections;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Handler;
import java.util.logging.LogManager;
/**
* Initializes the logging subsystem.
*
* java.util.Logging, System.out and System.err are tunneled through the logging system.
*
* System.out and System.err are assigned to loggers named "stdout" and "stderr", respectively.
*/
public class Logging
{
private static final Logger log = Logger.get(Logging.class);
private static final String ROOT_LOGGER_NAME = "";
private static final java.util.logging.Logger ROOT = java.util.logging.Logger.getLogger("");
private static Logging instance;
// hard reference to loggers for which we set the level
private final Map loggers = new ConcurrentHashMap<>();
@GuardedBy("this")
private OutputStreamHandler consoleHandler;
/**
* Sets up default logging:
*
* - INFO level
* - Log entries are written to stderr
*
* @return the logging system singleton
*/
public static synchronized Logging initialize()
{
if (instance == null) {
instance = new Logging();
}
return instance;
}
private Logging()
{
ROOT.setLevel(Level.INFO.toJulLevel());
for (Handler handler : ROOT.getHandlers()) {
ROOT.removeHandler(handler);
}
rewireStdStreams();
}
@SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
private void rewireStdStreams()
{
logConsole(new NonCloseableOutputStream(System.err));
log.info("Logging to stderr");
redirectStdStreams();
}
@SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
private static void redirectStdStreams()
{
System.setOut(new PrintStream(new LoggingOutputStream(Logger.get("stdout")), true));
System.setErr(new PrintStream(new LoggingOutputStream(Logger.get("stderr")), true));
}
private synchronized void logConsole(OutputStream stream)
{
consoleHandler = new OutputStreamHandler(stream);
ROOT.addHandler(consoleHandler);
}
public synchronized void disableConsole()
{
log.info("Disabling stderr output");
ROOT.removeHandler(consoleHandler);
consoleHandler = null;
}
@SuppressWarnings("MethodMayBeStatic")
public void logToFile(String logPath, int maxHistory, long maxSizeInBytes)
{
log.info("Logging to %s", logPath);
RollingFileHandler rollingFileHandler = new RollingFileHandler(logPath, maxHistory, maxSizeInBytes);
ROOT.addHandler(rollingFileHandler);
}
public Level getRootLevel()
{
return getLevel(ROOT_LOGGER_NAME);
}
public void setRootLevel(Level newLevel)
{
setLevel(ROOT_LOGGER_NAME, newLevel);
}
public void setLevels(File file)
throws IOException
{
Properties properties = new Properties();
try (Reader reader = new FileReader(file)) {
properties.load(reader);
}
processLevels(properties);
}
@SuppressWarnings("MethodMayBeStatic")
public Level getLevel(String loggerName)
{
return getEffectiveLevel(java.util.logging.Logger.getLogger(loggerName));
}
private static Level getEffectiveLevel(java.util.logging.Logger logger)
{
java.util.logging.Level level = logger.getLevel();
if (level == null) {
java.util.logging.Logger parent = logger.getParent();
if (parent != null) {
return getEffectiveLevel(parent);
}
}
if (level == null) {
return Level.OFF;
}
return Level.fromJulLevel(level);
}
@SuppressWarnings("MethodMayBeStatic")
public void setLevel(String loggerName, Level level)
{
loggers.computeIfAbsent(loggerName, java.util.logging.Logger::getLogger)
.setLevel(level.toJulLevel());
}
@SuppressWarnings("MethodMayBeStatic")
public Map getAllLevels()
{
ImmutableSortedMap.Builder levels = ImmutableSortedMap.naturalOrder();
for (String loggerName : Collections.list(LogManager.getLogManager().getLoggerNames())) {
java.util.logging.Level level = java.util.logging.Logger.getLogger(loggerName).getLevel();
if (level != null) {
levels.put(loggerName, Level.fromJulLevel(level));
}
}
return levels.build();
}
private void processLevels(Properties properties)
{
for (Map.Entry