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 */
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     * 
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        loggingEvent.addArgument(p);
076        return this;
077    }
078
079    @Override
080    public LoggingEventBuilder addArgument(Supplier<?> objectSupplier) {
081        loggingEvent.addArgument(objectSupplier.get());
082        return this;
083    }
084
085    @Override
086    public void setCallerBoundary(String fqcn) {
087        loggingEvent.setCallerBoundary(fqcn);
088    }
089
090    @Override
091    public void log() {
092        log(loggingEvent);
093    }
094
095    @Override
096    public LoggingEventBuilder setMessage(String message) {
097        loggingEvent.setMessage(message);
098        return this;
099    }
100    @Override
101    public LoggingEventBuilder setMessage(Supplier<String> messageSupplier) {
102        loggingEvent.setMessage(messageSupplier.get());
103        return this;
104    }
105
106    @Override
107    public void log(String message) {
108        loggingEvent.setMessage(message);
109        log(loggingEvent);
110    }
111
112    @Override
113    public void log(String message, Object arg) {
114        loggingEvent.setMessage(message);
115        loggingEvent.addArgument(arg);
116        log(loggingEvent);
117    }
118
119    @Override
120    public void log(String message, Object arg0, Object arg1) {
121        loggingEvent.setMessage(message);
122        loggingEvent.addArgument(arg0);
123        loggingEvent.addArgument(arg1);
124        log(loggingEvent);
125    }
126
127    @Override
128    public void log(String message, Object... args) {
129        loggingEvent.setMessage(message);
130        loggingEvent.addArguments(args);
131
132        log(loggingEvent);
133    }
134
135    @Override
136    public void log(Supplier<String> messageSupplier) {
137        if (messageSupplier == null) {
138            log((String) null);
139        } else {
140            log(messageSupplier.get());
141        }
142    }
143    
144    protected void log(LoggingEvent aLoggingEvent) {
145        setCallerBoundary(DLEB_FQCN);
146        if (logger instanceof LoggingEventAware) {
147            ((LoggingEventAware) logger).log(aLoggingEvent);
148        } else {
149            logViaPublicSLF4JLoggerAPI(aLoggingEvent);
150        }
151    }
152
153    private void logViaPublicSLF4JLoggerAPI(LoggingEvent aLoggingEvent) {
154        Object[] argArray = aLoggingEvent.getArgumentArray();
155        int argLen = argArray == null ? 0 : argArray.length;
156
157        Throwable t = aLoggingEvent.getThrowable();
158        int tLen = t == null ? 0 : 1;
159
160        String msg = aLoggingEvent.getMessage();
161
162        Object[] combinedArguments = new Object[argLen + tLen];
163
164        if (argArray != null) {
165            System.arraycopy(argArray, 0, combinedArguments, 0, argLen);
166        }
167        if (t != null) {
168            combinedArguments[argLen] = t;
169        }
170
171        msg = mergeMarkersAndKeyValuePairs(aLoggingEvent, msg);
172
173        switch (aLoggingEvent.getLevel()) {
174        case TRACE:
175            logger.trace(msg, combinedArguments);
176            break;
177        case DEBUG:
178            logger.debug(msg, combinedArguments);
179            break;
180        case INFO:
181            logger.info(msg, combinedArguments);
182            break;
183        case WARN:
184            logger.warn(msg, combinedArguments);
185            break;
186        case ERROR:
187            logger.error(msg, combinedArguments);
188            break;
189        }
190
191    }
192
193    /**
194     * Prepend markers and key-value pairs to the message.
195     * 
196     * @param aLoggingEvent
197     * @param msg
198     * @return
199     */
200    private String mergeMarkersAndKeyValuePairs(LoggingEvent aLoggingEvent, String msg) {
201
202        StringBuilder sb = null;
203
204        if (aLoggingEvent.getMarkers() != null) {
205            sb = new StringBuilder();
206            for (Marker marker : aLoggingEvent.getMarkers()) {
207                sb.append(marker);
208                sb.append(' ');
209            }
210        }
211
212        if (aLoggingEvent.getKeyValuePairs() != null) {
213            if (sb == null) {
214                sb = new StringBuilder();
215            }
216            for (KeyValuePair kvp : aLoggingEvent.getKeyValuePairs()) {
217                sb.append(kvp.key);
218                sb.append('=');
219                sb.append(kvp.value);
220                sb.append(' ');
221            }
222        }
223
224        if (sb != null) {
225            sb.append(msg);
226            return sb.toString();
227        } else {
228            return msg;
229        }
230    }
231
232
233
234    @Override
235    public LoggingEventBuilder addKeyValue(String key, Object value) {
236        loggingEvent.addKeyValue(key, value);
237        return this;
238    }
239
240    @Override
241    public LoggingEventBuilder addKeyValue(String key, Supplier<Object> value) {
242        loggingEvent.addKeyValue(key, value.get());
243        return this;
244    }
245
246}