LoggingUtil.java
/*
* Copyright 2024 Morimekta Utils Authors
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 net.morimekta.tiny.logback;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.jul.LevelChangePropagator;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.Appender;
import ch.qos.logback.core.ConsoleAppender;
import ch.qos.logback.core.FileAppender;
import org.slf4j.LoggerFactory;
import org.slf4j.bridge.SLF4JBridgeHandler;
import java.io.IOException;
import java.util.stream.Stream;
/**
* Utility class for configuring and managing logback logging.
*/
public class LoggingUtil {
/**
* Initialize log forwarding from JUL and Java System logger to SLF4J.
*/
public static void initLogForwarding() {
// Send JUL & java System logger to SLF4J.
LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
var levelChangePropagator = new LevelChangePropagator();
levelChangePropagator.setContext(context);
levelChangePropagator.setResetJUL(true);
context.addListener(levelChangePropagator);
SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();
}
/**
* Flush all console logging appenders to ensure output is written before exit.
*/
public static void flushConsoleLogging() {
// Force console loggers to flush output. Otherwise, some logging may
// be missing just before application exits.
rootLoggingAppenderStream()
.filter(app -> app instanceof ConsoleAppender)
.map(app -> (ConsoleAppender<?>) app)
.forEach(app -> {
try {
app.getOutputStream().flush();
} catch (IOException ignore) {
}
});
}
/**
* Flush all file logging appenders to ensure output is written before exit.
*/
public static void flushFileLogging() {
// Force file loggers to flush output. Otherwise, some logging may
// be missing just before application exits.
rootLoggingAppenderStream()
.filter(app -> app instanceof FileAppender)
.map(app -> (FileAppender<?>) app)
.forEach(app -> {
try {
app.getOutputStream().flush();
} catch (IOException ignore) {
}
});
}
private static Stream<Appender<ILoggingEvent>> rootLoggingAppenderStream() {
return ((LoggerContext) LoggerFactory.getILoggerFactory())
.getLoggerList()
.stream()
.map(Logger::iteratorForAppenders)
.flatMap(it -> {
Stream.Builder<Appender<ILoggingEvent>> builder = Stream.builder();
it.forEachRemaining(builder::add);
return builder.build();
});
}
}