1 /** 2 * Copyright (c) 2004-2021 QOS.ch 3 * All rights reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining 6 * a copy of this software and associated documentation files (the 7 * "Software"), to deal in the Software without restriction, including 8 * without limitation the rights to use, copy, modify, merge, publish, 9 * distribute, sublicense, and/or sell copies of the Software, and to 10 * permit persons to whom the Software is furnished to do so, subject to 11 * the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be 14 * included in all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 * 24 */ 25 package org.slf4j.jdk.platform.logging; 26 27 import static java.util.Objects.requireNonNull; 28 29 import java.text.MessageFormat; 30 import java.util.MissingResourceException; 31 import java.util.ResourceBundle; 32 33 import org.slf4j.Logger; 34 import org.slf4j.helpers.Reporter; 35 import org.slf4j.spi.CallerBoundaryAware; 36 import org.slf4j.spi.LoggingEventBuilder; 37 38 /** 39 * Adapts {@link Logger} to {@link System.Logger}. 40 * @since 2.0.0 41 */ 42 class SLF4JPlatformLogger implements System.Logger { 43 44 static private final String PRESUMED_CALLER_BOUNDARY = System.Logger.class.getName(); 45 46 private final Logger slf4jLogger; 47 SLF4JPlatformLogger(Logger logger)48 public SLF4JPlatformLogger(Logger logger) { 49 this.slf4jLogger = requireNonNull(logger); 50 } 51 52 @Override getName()53 public String getName() { 54 return slf4jLogger.getName(); 55 } 56 57 // The fact that non loggable levels (in java.lang.System.Logger.Level) 58 // such as ALL and OFF leak into the public interface is quite a pity. 59 60 @Override isLoggable(Level jplLevel)61 public boolean isLoggable(Level jplLevel) { 62 if (jplLevel == Level.ALL) 63 return true; 64 if (jplLevel == Level.OFF) 65 return true; 66 67 org.slf4j.event.Level slf4jLevel = jplLevelToSLF4JLevel(jplLevel); 68 69 return slf4jLogger.isEnabledForLevel(slf4jLevel); 70 } 71 72 73 /** 74 * Transform a {@link Level} to {@link org.slf4j.event.Level}. 75 * 76 * This method assumes that Level.ALL or Level.OFF never reach this method. 77 * 78 * @param jplLevel 79 * @return 80 */ jplLevelToSLF4JLevel(Level jplLevel)81 private org.slf4j.event.Level jplLevelToSLF4JLevel(Level jplLevel) { 82 switch (jplLevel) { 83 case TRACE: 84 return org.slf4j.event.Level.TRACE; 85 case DEBUG: 86 return org.slf4j.event.Level.DEBUG; 87 case INFO: 88 return org.slf4j.event.Level.INFO; 89 case WARNING: 90 return org.slf4j.event.Level.WARN; 91 case ERROR: 92 return org.slf4j.event.Level.ERROR; 93 default: 94 reportUnknownLevel(jplLevel); 95 return null; 96 } 97 } 98 99 @Override log(Level jplLevel, ResourceBundle bundle, String msg, Throwable thrown)100 public void log(Level jplLevel, ResourceBundle bundle, String msg, Throwable thrown) { 101 log(jplLevel, bundle, msg, thrown, (Object[]) null); 102 } 103 104 @Override log(Level jplLevel, ResourceBundle bundle, String format, Object... params)105 public void log(Level jplLevel, ResourceBundle bundle, String format, Object... params) { 106 log(jplLevel, bundle, format, null, params); 107 } 108 109 /** 110 * Single point of processing taking all possible parameters. 111 * 112 * @param jplLevel 113 * @param bundle 114 * @param msg 115 * @param thrown 116 * @param params 117 */ log(Level jplLevel, ResourceBundle bundle, String msg, Throwable thrown, Object... params)118 private void log(Level jplLevel, ResourceBundle bundle, String msg, Throwable thrown, Object... params) { 119 if (jplLevel == Level.OFF) 120 return; 121 122 if (jplLevel == Level.ALL) { 123 performLog(org.slf4j.event.Level.TRACE, bundle, msg, thrown, params); 124 return; 125 } 126 127 org.slf4j.event.Level slf4jLevel = jplLevelToSLF4JLevel(jplLevel); 128 boolean isEnabled = slf4jLogger.isEnabledForLevel(slf4jLevel); 129 130 if (isEnabled) { 131 performLog(slf4jLevel, bundle, msg, thrown, params); 132 } 133 } 134 performLog(org.slf4j.event.Level slf4jLevel, ResourceBundle bundle, String msg, Throwable thrown, Object... params)135 private void performLog(org.slf4j.event.Level slf4jLevel, ResourceBundle bundle, String msg, Throwable thrown, Object... params) { 136 String message = getResourceStringOrMessage(bundle, msg); 137 LoggingEventBuilder leb = slf4jLogger.makeLoggingEventBuilder(slf4jLevel); 138 if (thrown != null) { 139 leb = leb.setCause(thrown); 140 } 141 if (params != null && params.length > 0) { 142 // add the arguments to the logging event for possible processing by the backend 143 for (Object p : params) { 144 leb = leb.addArgument(p); 145 } 146 // The JDK uses a different formatting convention. We must invoke it now. 147 message = MessageFormat.format(message, params); 148 } 149 if (leb instanceof CallerBoundaryAware) { 150 CallerBoundaryAware cba = (CallerBoundaryAware) leb; 151 cba.setCallerBoundary(PRESUMED_CALLER_BOUNDARY); 152 } 153 leb.log(message); 154 } 155 reportUnknownLevel(Level jplLevel)156 private void reportUnknownLevel(Level jplLevel) { 157 String message = "Unknown log level [" + jplLevel + "]"; 158 IllegalArgumentException iae = new IllegalArgumentException(message); 159 Reporter.error("Unsupported log level", iae); 160 } 161 getResourceStringOrMessage(ResourceBundle bundle, String msg)162 private static String getResourceStringOrMessage(ResourceBundle bundle, String msg) { 163 if (bundle == null || msg == null) 164 return msg; 165 // ResourceBundle::getString throws: 166 // 167 // * NullPointerException for null keys 168 // * ClassCastException if the message is no string 169 // * MissingResourceException if there is no message for the key 170 // 171 // Handle all of these cases here to avoid log-related exceptions from crashing the JVM. 172 try { 173 return bundle.getString(msg); 174 } catch (MissingResourceException ex) { 175 return msg; 176 } catch (ClassCastException ex) { 177 return bundle.getObject(msg).toString(); 178 } 179 } 180 181 } 182