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}