001/** 002 * Copyright (c) 2004-2022 QOS.ch 003 * All rights reserved. 004 * <p> 005 * Permission is hereby granted, free of charge, to any person obtaining 006 * a copy of this software and associated documentation files (the 007 * "Software"), to deal in the Software without restriction, including 008 * without limitation the rights to use, copy, modify, merge, publish, 009 * distribute, sublicense, and/or sell copies of the Software, and to 010 * permit persons to whom the Software is furnished to do so, subject to 011 * the following conditions: 012 * <p> 013 * The above copyright notice and this permission notice shall be 014 * included in all copies or substantial portions of the Software. 015 * <p> 016 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 017 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 018 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 019 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 020 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 021 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 022 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 023 */ 024package org.slf4j.spi; 025 026import java.util.List; 027import java.util.function.Supplier; 028 029import org.slf4j.Logger; 030import org.slf4j.Marker; 031import org.slf4j.event.DefaultLoggingEvent; 032import org.slf4j.event.KeyValuePair; 033import org.slf4j.event.Level; 034import org.slf4j.event.LoggingEvent; 035 036/** 037 * Default implementation of {@link LoggingEventBuilder} 038 */ 039public class DefaultLoggingEventBuilder implements LoggingEventBuilder, CallerBoundaryAware { 040 041 042 // The caller boundary when the log() methods are invoked, is this class itself. 043 044 static String DLEB_FQCN = DefaultLoggingEventBuilder.class.getName(); 045 046 protected DefaultLoggingEvent loggingEvent; 047 protected Logger logger; 048 049 public DefaultLoggingEventBuilder(Logger logger, Level level) { 050 this.logger = logger; 051 loggingEvent = new DefaultLoggingEvent(level, logger); 052 } 053 054 /** 055 * Add a marker to the current logging event being built. 056 * <p> 057 * It is possible to add multiple markers to the same logging event. 058 * 059 * @param marker the marker to add 060 */ 061 @Override 062 public LoggingEventBuilder addMarker(Marker marker) { 063 loggingEvent.addMarker(marker); 064 return this; 065 } 066 067 @Override 068 public LoggingEventBuilder setCause(Throwable t) { 069 loggingEvent.setThrowable(t); 070 return this; 071 } 072 073 @Override 074 public LoggingEventBuilder addArgument(Object p) { 075 this.loggingEvent.addArgument(p); 076 return this; 077 } 078 079 @Override 080 public LoggingEventBuilder addArgument(Supplier<?> objectSupplier) { 081 this.loggingEvent.addArgument(objectSupplier.get()); 082 return this; 083 } 084 085 @Override 086 public LoggingEventBuilder addKeyValue(String key, Object value) { 087 loggingEvent.addKeyValue(key, value); 088 return this; 089 } 090 091 @Override 092 public LoggingEventBuilder addKeyValue(String key, Supplier<Object> value) { 093 loggingEvent.addKeyValue(key, value.get()); 094 return this; 095 } 096 097 @Override 098 public void setCallerBoundary(String fqcn) { 099 this.loggingEvent.setCallerBoundary(fqcn); 100 } 101 102 @Override 103 public void log() { 104 log(this.loggingEvent); 105 } 106 107 @Override 108 public LoggingEventBuilder setMessage(String message) { 109 this.loggingEvent.setMessage(message); 110 return this; 111 } 112 113 @Override 114 public LoggingEventBuilder setMessage(Supplier<String> messageSupplier) { 115 this.loggingEvent.setMessage(messageSupplier.get()); 116 return this; 117 } 118 119 @Override 120 public void log(String message) { 121 this.loggingEvent.setMessage(message); 122 log(this.loggingEvent); 123 } 124 125 @Override 126 public void log(String message, Object arg) { 127 this.loggingEvent.setMessage(message); 128 this.loggingEvent.addArgument(arg); 129 log(this.loggingEvent); 130 } 131 132 @Override 133 public void log(String message, Object arg0, Object arg1) { 134 this.loggingEvent.setMessage(message); 135 this.loggingEvent.addArgument(arg0); 136 this.loggingEvent.addArgument(arg1); 137 log(this.loggingEvent); 138 } 139 140 @Override 141 public void log(String message, Object... args) { 142 this.loggingEvent.setMessage(message); 143 this.loggingEvent.addArguments(args); 144 145 log(this.loggingEvent); 146 } 147 148 @Override 149 public void log(Supplier<String> messageSupplier) { 150 if(messageSupplier == null) { 151 log((String) null); 152 } else { 153 log(messageSupplier.get()); 154 } 155 } 156 157 protected void log(LoggingEvent aLoggingEvent) { 158 if(aLoggingEvent.getCallerBoundary() == null) { 159 setCallerBoundary(DLEB_FQCN); 160 } 161 162 if(logger instanceof LoggingEventAware) { 163 ((LoggingEventAware) logger).log(aLoggingEvent); 164 } else if(logger instanceof LocationAwareLogger) { 165 logViaLocationAwareLoggerAPI((LocationAwareLogger) logger, aLoggingEvent); 166 } else { 167 logViaPublicSLF4JLoggerAPI(aLoggingEvent); 168 } 169 } 170 171 private void logViaLocationAwareLoggerAPI(LocationAwareLogger locationAwareLogger, LoggingEvent aLoggingEvent) { 172 String msg = aLoggingEvent.getMessage(); 173 List<Marker> markerList = aLoggingEvent.getMarkers(); 174 String mergedMessage = mergeMarkersAndKeyValuePairsAndMessage(aLoggingEvent); 175 locationAwareLogger.log(null, aLoggingEvent.getCallerBoundary(), aLoggingEvent.getLevel().toInt(), 176 mergedMessage, 177 aLoggingEvent.getArgumentArray(), aLoggingEvent.getThrowable()); 178 } 179 180 private void logViaPublicSLF4JLoggerAPI(LoggingEvent aLoggingEvent) { 181 Object[] argArray = aLoggingEvent.getArgumentArray(); 182 int argLen = argArray == null ? 0 : argArray.length; 183 184 Throwable t = aLoggingEvent.getThrowable(); 185 int tLen = t == null ? 0 : 1; 186 187 Object[] combinedArguments = new Object[argLen + tLen]; 188 189 if(argArray != null) { 190 System.arraycopy(argArray, 0, combinedArguments, 0, argLen); 191 } 192 if(t != null) { 193 combinedArguments[argLen] = t; 194 } 195 196 String mergedMessage = mergeMarkersAndKeyValuePairsAndMessage(aLoggingEvent); 197 198 199 switch(aLoggingEvent.getLevel()) { 200 case TRACE: 201 logger.trace(mergedMessage, combinedArguments); 202 break; 203 case DEBUG: 204 logger.debug(mergedMessage, combinedArguments); 205 break; 206 case INFO: 207 logger.info(mergedMessage, combinedArguments); 208 break; 209 case WARN: 210 logger.warn(mergedMessage, combinedArguments); 211 break; 212 case ERROR: 213 logger.error(mergedMessage, combinedArguments); 214 break; 215 } 216 } 217 218 219 /** 220 * Prepend markers and key-value pairs to the message. 221 * 222 * @param aLoggingEvent 223 * 224 * @return 225 */ 226 private String mergeMarkersAndKeyValuePairsAndMessage(LoggingEvent aLoggingEvent) { 227 StringBuilder sb = mergeMarkers(aLoggingEvent.getMarkers(), null); 228 sb = mergeKeyValuePairs(aLoggingEvent.getKeyValuePairs(), sb); 229 final String mergedMessage = mergeMessage(aLoggingEvent.getMessage(), sb); 230 return mergedMessage; 231 } 232 233 private StringBuilder mergeMarkers(List<Marker> markerList, StringBuilder sb) { 234 if(markerList == null || markerList.isEmpty()) 235 return sb; 236 237 if(sb == null) 238 sb = new StringBuilder(); 239 240 for(Marker marker : markerList) { 241 sb.append(marker); 242 sb.append(' '); 243 } 244 return sb; 245 } 246 247 private StringBuilder mergeKeyValuePairs(List<KeyValuePair> keyValuePairList, StringBuilder sb) { 248 if(keyValuePairList == null || keyValuePairList.isEmpty()) 249 return sb; 250 251 if(sb == null) 252 sb = new StringBuilder(); 253 254 for(KeyValuePair kvp : keyValuePairList) { 255 sb.append(kvp.key); 256 sb.append('='); 257 sb.append(kvp.value); 258 sb.append(' '); 259 } 260 return sb; 261 } 262 263 private String mergeMessage(String msg, StringBuilder sb) { 264 if(sb != null) { 265 sb.append(msg); 266 return sb.toString(); 267 } else { 268 return msg; 269 } 270 } 271 272 273 274 275 276 277}