001/**
002 * Copyright (c) 2004-2022 QOS.ch
003 * All rights reserved.
004 *
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 *
013 * The  above  copyright  notice  and  this permission  notice  shall  be
014 * included in all copies or substantial portions of the Software.
015 *
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 *
024 */
025package org.slf4j.spi;
026
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 *
039 * <p>It is assumed that when </p>
040 *
041 * @since 2.0.0
042 */
043public class DefaultLoggingEventBuilder implements LoggingEventBuilder, CallerBoundaryAware {
044
045    
046    // The caller boundary when the log() methods are invoked, is this class itself.
047    
048    static String DLEB_FQCN = DefaultLoggingEventBuilder.class.getName();
049    
050    protected DefaultLoggingEvent loggingEvent;
051    protected Logger logger;
052
053    public DefaultLoggingEventBuilder(Logger logger, Level level) {
054        this.logger = logger;
055        loggingEvent = new DefaultLoggingEvent(level, logger);
056    }
057
058    /**
059     * Add a marker to the current logging event being built.
060     * 
061     * It is possible to add multiple markers to the same logging event.
062     *
063     * @param marker the marker to add
064     */
065    @Override
066    public LoggingEventBuilder addMarker(Marker marker) {
067        loggingEvent.addMarker(marker);
068        return this;
069    }
070
071    @Override
072    public LoggingEventBuilder setCause(Throwable t) {
073        loggingEvent.setThrowable(t);
074        return this;
075    }
076
077    @Override
078    public LoggingEventBuilder addArgument(Object p) {
079        loggingEvent.addArgument(p);
080        return this;
081    }
082
083
084    @Override
085    public LoggingEventBuilder addArgument(Supplier<?> objectSupplier) {
086        loggingEvent.addArgument(objectSupplier.get());
087        return this;
088    }
089
090    @Override
091    public void setCallerBoundary(String fqcn) {
092        loggingEvent.setCallerBoundary(fqcn);
093    }
094
095    @Override
096    public void log() {
097        log(loggingEvent);
098    }
099
100    @Override
101    public LoggingEventBuilder setMessage(String message) {
102        loggingEvent.setMessage(message);
103        return this;
104    }
105    @Override
106    public LoggingEventBuilder setMessage(Supplier<String> messageSupplier) {
107        loggingEvent.setMessage(messageSupplier.get());
108        return this;
109    }
110
111    @Override
112    public void log(String message) {
113        loggingEvent.setMessage(message);
114        log(loggingEvent);
115    }
116
117    @Override
118    public void log(String message, Object arg) {
119        loggingEvent.setMessage(message);
120        loggingEvent.addArgument(arg);
121        log(loggingEvent);
122    }
123
124    @Override
125    public void log(String message, Object arg0, Object arg1) {
126        loggingEvent.setMessage(message);
127        loggingEvent.addArgument(arg0);
128        loggingEvent.addArgument(arg1);
129        log(loggingEvent);
130    }
131
132    @Override
133    public void log(String message, Object... args) {
134        loggingEvent.setMessage(message);
135        loggingEvent.addArguments(args);
136
137        log(loggingEvent);
138    }
139
140    @Override
141    public void log(Supplier<String> messageSupplier) {
142        if (messageSupplier == null) {
143            log((String) null);
144        } else {
145            log(messageSupplier.get());
146        }
147    }
148    
149    protected void log(LoggingEvent aLoggingEvent) {
150        setCallerBoundary(DLEB_FQCN);
151        if (logger instanceof LoggingEventAware) {
152            ((LoggingEventAware) logger).log(aLoggingEvent);
153        } else {
154            logViaPublicSLF4JLoggerAPI(aLoggingEvent);
155        }
156    }
157
158    private void logViaPublicSLF4JLoggerAPI(LoggingEvent aLoggingEvent) {
159        Object[] argArray = aLoggingEvent.getArgumentArray();
160        int argLen = argArray == null ? 0 : argArray.length;
161
162        Throwable t = aLoggingEvent.getThrowable();
163        int tLen = t == null ? 0 : 1;
164
165        String msg = aLoggingEvent.getMessage();
166
167        Object[] combinedArguments = new Object[argLen + tLen];
168
169        if (argArray != null) {
170            System.arraycopy(argArray, 0, combinedArguments, 0, argLen);
171        }
172        if (t != null) {
173            combinedArguments[argLen] = t;
174        }
175
176        msg = mergeMarkersAndKeyValuePairs(aLoggingEvent, msg);
177
178        switch (aLoggingEvent.getLevel()) {
179        case TRACE:
180            logger.trace(msg, combinedArguments);
181            break;
182        case DEBUG:
183            logger.debug(msg, combinedArguments);
184            break;
185        case INFO:
186            logger.info(msg, combinedArguments);
187            break;
188        case WARN:
189            logger.warn(msg, combinedArguments);
190            break;
191        case ERROR:
192            logger.error(msg, combinedArguments);
193            break;
194        }
195
196    }
197
198    /**
199     * Prepend markers and key-value pairs to the message.
200     * 
201     * @param aLoggingEvent
202     * @param msg
203     * @return
204     */
205    private String mergeMarkersAndKeyValuePairs(LoggingEvent aLoggingEvent, String msg) {
206
207        StringBuilder sb = null;
208
209        if (aLoggingEvent.getMarkers() != null) {
210            sb = new StringBuilder();
211            for (Marker marker : aLoggingEvent.getMarkers()) {
212                sb.append(marker);
213                sb.append(' ');
214            }
215        }
216
217        if (aLoggingEvent.getKeyValuePairs() != null) {
218            if (sb == null) {
219                sb = new StringBuilder();
220            }
221            for (KeyValuePair kvp : aLoggingEvent.getKeyValuePairs()) {
222                sb.append(kvp.key);
223                sb.append('=');
224                sb.append(kvp.value);
225                sb.append(' ');
226            }
227        }
228
229        if (sb != null) {
230            sb.append(msg);
231            return sb.toString();
232        } else {
233            return msg;
234        }
235    }
236
237
238
239    @Override
240    public LoggingEventBuilder addKeyValue(String key, Object value) {
241        loggingEvent.addKeyValue(key, value);
242        return this;
243    }
244
245    @Override
246    public LoggingEventBuilder addKeyValue(String key, Supplier<Object> value) {
247        loggingEvent.addKeyValue(key, value.get());
248        return this;
249    }
250
251}