blob: 194436d7e4688154cc3f6abbaffab122743d1437 [file] [log] [blame]
/**
* Copyright (c) 2004-2021 QOS.ch
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
package org.slf4j.jdk.platform.logging;
import static java.util.Objects.requireNonNull;
import java.text.MessageFormat;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import org.slf4j.Logger;
import org.slf4j.helpers.Reporter;
import org.slf4j.spi.CallerBoundaryAware;
import org.slf4j.spi.LoggingEventBuilder;
/**
* Adapts {@link Logger} to {@link System.Logger}.
* @since 2.0.0
*/
class SLF4JPlatformLogger implements System.Logger {
static private final String PRESUMED_CALLER_BOUNDARY = System.Logger.class.getName();
private final Logger slf4jLogger;
public SLF4JPlatformLogger(Logger logger) {
this.slf4jLogger = requireNonNull(logger);
}
@Override
public String getName() {
return slf4jLogger.getName();
}
// The fact that non loggable levels (in java.lang.System.Logger.Level)
// such as ALL and OFF leak into the public interface is quite a pity.
@Override
public boolean isLoggable(Level jplLevel) {
if (jplLevel == Level.ALL)
return true;
if (jplLevel == Level.OFF)
return true;
org.slf4j.event.Level slf4jLevel = jplLevelToSLF4JLevel(jplLevel);
return slf4jLogger.isEnabledForLevel(slf4jLevel);
}
/**
* Transform a {@link Level} to {@link org.slf4j.event.Level}.
*
* This method assumes that Level.ALL or Level.OFF never reach this method.
*
* @param jplLevel
* @return
*/
private org.slf4j.event.Level jplLevelToSLF4JLevel(Level jplLevel) {
switch (jplLevel) {
case TRACE:
return org.slf4j.event.Level.TRACE;
case DEBUG:
return org.slf4j.event.Level.DEBUG;
case INFO:
return org.slf4j.event.Level.INFO;
case WARNING:
return org.slf4j.event.Level.WARN;
case ERROR:
return org.slf4j.event.Level.ERROR;
default:
reportUnknownLevel(jplLevel);
return null;
}
}
@Override
public void log(Level jplLevel, ResourceBundle bundle, String msg, Throwable thrown) {
log(jplLevel, bundle, msg, thrown, (Object[]) null);
}
@Override
public void log(Level jplLevel, ResourceBundle bundle, String format, Object... params) {
log(jplLevel, bundle, format, null, params);
}
/**
* Single point of processing taking all possible parameters.
*
* @param jplLevel
* @param bundle
* @param msg
* @param thrown
* @param params
*/
private void log(Level jplLevel, ResourceBundle bundle, String msg, Throwable thrown, Object... params) {
if (jplLevel == Level.OFF)
return;
if (jplLevel == Level.ALL) {
performLog(org.slf4j.event.Level.TRACE, bundle, msg, thrown, params);
return;
}
org.slf4j.event.Level slf4jLevel = jplLevelToSLF4JLevel(jplLevel);
boolean isEnabled = slf4jLogger.isEnabledForLevel(slf4jLevel);
if (isEnabled) {
performLog(slf4jLevel, bundle, msg, thrown, params);
}
}
private void performLog(org.slf4j.event.Level slf4jLevel, ResourceBundle bundle, String msg, Throwable thrown, Object... params) {
String message = getResourceStringOrMessage(bundle, msg);
LoggingEventBuilder leb = slf4jLogger.makeLoggingEventBuilder(slf4jLevel);
if (thrown != null) {
leb = leb.setCause(thrown);
}
if (params != null && params.length > 0) {
// add the arguments to the logging event for possible processing by the backend
for (Object p : params) {
leb = leb.addArgument(p);
}
// The JDK uses a different formatting convention. We must invoke it now.
message = MessageFormat.format(message, params);
}
if (leb instanceof CallerBoundaryAware) {
CallerBoundaryAware cba = (CallerBoundaryAware) leb;
cba.setCallerBoundary(PRESUMED_CALLER_BOUNDARY);
}
leb.log(message);
}
private void reportUnknownLevel(Level jplLevel) {
String message = "Unknown log level [" + jplLevel + "]";
IllegalArgumentException iae = new IllegalArgumentException(message);
Reporter.error("Unsupported log level", iae);
}
private static String getResourceStringOrMessage(ResourceBundle bundle, String msg) {
if (bundle == null || msg == null)
return msg;
// ResourceBundle::getString throws:
//
// * NullPointerException for null keys
// * ClassCastException if the message is no string
// * MissingResourceException if there is no message for the key
//
// Handle all of these cases here to avoid log-related exceptions from crashing the JVM.
try {
return bundle.getString(msg);
} catch (MissingResourceException ex) {
return msg;
} catch (ClassCastException ex) {
return bundle.getObject(msg).toString();
}
}
}