All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.airlift.log.Logging Maven / Gradle / Ivy

The newest version!
/*
 * 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.base.VerifyException;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.net.HostAndPort;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.SettableFuture;
import com.google.errorprone.annotations.concurrent.GuardedBy;
import io.airlift.log.RollingFileMessageOutput.CompressionType;
import io.airlift.units.DataSize;
import org.weakref.jmx.MBeanExport;
import org.weakref.jmx.MBeanExporter;

import java.io.IOException;
import java.io.PrintStream;
import java.io.UncheckedIOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.LogManager;

import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.util.concurrent.Futures.addCallback;
import static com.google.common.util.concurrent.Futures.transform;
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
import static io.airlift.configuration.ConfigurationLoader.loadPropertiesFrom;
import static io.airlift.configuration.ConfigurationUtils.replaceEnvironmentVariables;
import static java.util.Objects.requireNonNull;

/**
 * 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; private static final PrintStream stdErr = System.err; // hard reference to loggers for which we set the level @GuardedBy("this") private final Map loggers = new HashMap<>(); @GuardedBy("this") private OutputStreamHandler consoleHandler; @GuardedBy("this") private boolean configured; private final SettableFuture mBeanExporterAvailableFuture = SettableFuture.create(); private final SettableFuture> mBeanExportsFuture = SettableFuture.create(); /** * 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); } enableConsole(); log.info("Logging to stderr"); redirectStdStreams(); } public void exportMBeans(MBeanExporter exporter) { // Logging can be initialized before MBean export, so the export process must be lazy mBeanExporterAvailableFuture.set(exporter); } public void unexportMBeans() { addCallback( mBeanExportsFuture, new FutureCallback<>() { @Override public void onSuccess(List exports) { exports.forEach(MBeanExport::unexport); } @Override public void onFailure(Throwable t) { throw new VerifyException("Unexpected code path! Should not fail here", t); } }, directExecutor()); } 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 enableConsole() { consoleHandler = new OutputStreamHandler(System.err); ROOT.addHandler(consoleHandler); } public synchronized void disableConsole() { log.info("Disabling stderr output"); ROOT.removeHandler(consoleHandler); consoleHandler = null; } private void logToFile(String logPath, DataSize maxFileSize, DataSize maxTotalSize, CompressionType compressionType, Formatter formatter, List mBeanExportCollector) { log.info("Logging to %s", logPath); RollingFileMessageOutput output = new RollingFileMessageOutput(logPath, maxFileSize, maxTotalSize, compressionType); BufferedHandler handler = new BufferedHandler(output, formatter, new BufferedHandlerErrorManager(stdErr)); handler.initialize(); mBeanExportCollector.add(new LogMBeanExport(handler, BufferedHandler.class, "RollingFileMessageOutput")); ROOT.addHandler(handler); } private void logToSocket(String logPath, Formatter formatter, List mBeanExportCollector) { if (!logPath.startsWith("tcp://") || logPath.lastIndexOf("/") > 6) { throw new IllegalArgumentException("LogPath for sockets must begin with tcp:// and not contain any path component."); } HostAndPort hostAndPort = HostAndPort.fromString(logPath.replace("tcp://", "")); SocketMessageOutput output = new SocketMessageOutput(hostAndPort); BufferedHandler handler = new BufferedHandler(output, formatter, new BufferedHandlerErrorManager(stdErr)); handler.initialize(); mBeanExportCollector.add(new LogMBeanExport(handler, BufferedHandler.class, "SocketMessageOutput")); ROOT.addHandler(handler); } public Level getRootLevel() { return getLevel(ROOT_LOGGER_NAME); } public void setRootLevel(Level newLevel) { setLevel(ROOT_LOGGER_NAME, newLevel); } public void setLevels(String file) throws IOException { loadPropertiesFrom(file).forEach((loggerName, value) -> setLevel(loggerName, Level.valueOf(value.toUpperCase(Locale.US)))); } 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); } public synchronized void clearLevel(String loggerName) { java.util.logging.Logger logger = loggers.remove(loggerName); if (logger != null) { logger.setLevel(null); } } public synchronized void setLevel(String loggerName, Level level) { loggers.computeIfAbsent(loggerName, java.util.logging.Logger::getLogger) .setLevel(level.toJulLevel()); } 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(); } public synchronized void configure(LoggingConfiguration config) { if (configured) { log.warn("Logging already configured; ignoring new configuration."); return; } configured = true; List mBeanExportCollector = new ArrayList<>(); Map logAnnotations = ImmutableMap.of(); if (config.getLogAnnotationFile() != null) { try { logAnnotations = replaceEnvironmentVariables(loadPropertiesFrom(config.getLogAnnotationFile())); } catch (IOException e) { throw new UncheckedIOException(e); } } if (config.getLogPath() != null) { if (config.getLogPath().startsWith("tcp://")) { logToSocket(config.getLogPath(), config.getFormat().createFormatter(logAnnotations), mBeanExportCollector); } else { logToFile( config.getLogPath(), config.getMaxSize(), config.getMaxTotalSize(), config.getCompression(), config.getFormat().createFormatter(logAnnotations), mBeanExportCollector); } } if (!config.isConsoleEnabled()) { disableConsole(); } if (config.getLevelsFile() != null) { try { setLevels(config.getLevelsFile()); } catch (IOException e) { throw new UncheckedIOException(e); } } // Export MBeans when the exporter becomes available mBeanExportsFuture.setFuture(transform( mBeanExporterAvailableFuture, exporter -> mBeanExportCollector.stream() .map(export -> exporter.exportWithGeneratedName(export.object(), export.type(), export.name())) .collect(toImmutableList()), directExecutor())); } private record LogMBeanExport(Object object, Class type, String name) { private LogMBeanExport { requireNonNull(object, "object is null"); requireNonNull(type, "type is null"); requireNonNull(name, "name is null"); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy