001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache license, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the license for the specific language governing permissions and
015 * limitations under the license.
016 */
017package org.apache.logging.log4j.internal;
018
019import org.apache.logging.log4j.Level;
020import org.apache.logging.log4j.LogBuilder;
021import org.apache.logging.log4j.Logger;
022import org.apache.logging.log4j.Marker;
023import org.apache.logging.log4j.message.Message;
024import org.apache.logging.log4j.message.SimpleMessage;
025import org.apache.logging.log4j.status.StatusLogger;
026import org.apache.logging.log4j.util.LambdaUtil;
027import org.apache.logging.log4j.util.StackLocatorUtil;
028import org.apache.logging.log4j.util.Supplier;
029
030
031/**
032 * Collects data for a log event and then logs it. This class should be considered private.
033 */
034public class DefaultLogBuilder implements LogBuilder {
035
036    private static Message EMPTY_MESSAGE = new SimpleMessage("");
037    private static final String FQCN = DefaultLogBuilder.class.getName();
038    private static final Logger LOGGER = StatusLogger.getLogger();
039
040    private final Logger logger;
041    private Level level;
042    private Marker marker;
043    private Throwable throwable;
044    private StackTraceElement location;
045    private volatile boolean inUse;
046    private long threadId;
047
048    public DefaultLogBuilder(Logger logger, Level level) {
049        this.logger = logger;
050        this.level = level;
051        this.threadId = Thread.currentThread().getId();
052        this.inUse = true;
053    }
054
055    public DefaultLogBuilder(Logger logger) {
056        this.logger = logger;
057        this.inUse = false;
058        this.threadId = Thread.currentThread().getId();
059    }
060
061    /**
062     * This method should be considered internal. It is used to reset the LogBuilder for a new log message.
063     * @param level The logging level for this event.
064     * @return This LogBuilder instance.
065     */
066    public LogBuilder reset(Level level) {
067        this.inUse = true;
068        this.level = level;
069        this.marker = null;
070        this.throwable = null;
071        this.location = null;
072        return this;
073    }
074
075    @Override
076    public LogBuilder withMarker(Marker marker) {
077        this.marker = marker;
078        return this;
079    }
080
081    @Override
082    public LogBuilder withThrowable(Throwable throwable) {
083        this.throwable = throwable;
084        return this;
085    }
086
087    @Override
088    public LogBuilder withLocation() {
089        location = StackLocatorUtil.getStackTraceElement(2);
090        return this;
091    }
092
093    @Override
094    public LogBuilder withLocation(StackTraceElement location) {
095        this.location = location;
096        return this;
097    }
098
099    public boolean isInUse() {
100        return inUse;
101    }
102
103    @Override
104    public void log(Message message) {
105        if (isValid()) {
106            logMessage(message);
107        }
108    }
109
110    @Override
111    public void log(CharSequence message) {
112        if (isValid()) {
113            logMessage(logger.getMessageFactory().newMessage(message));
114        }
115    }
116
117    @Override
118    public void log(String message) {
119        if (isValid()) {
120            logMessage(logger.getMessageFactory().newMessage(message));
121        }
122    }
123
124    @Override
125    public void log(String message, Object... params) {
126        if (isValid()) {
127            logMessage(logger.getMessageFactory().newMessage(message, params));
128        }
129    }
130
131    @Override
132    public void log(String message, Supplier<?>... params) {
133        if (isValid()) {
134            logMessage(logger.getMessageFactory().newMessage(message, LambdaUtil.getAll(params)));
135        }
136    }
137
138    @Override
139    public void log(Supplier<Message> messageSupplier) {
140        if (isValid()) {
141            logMessage(messageSupplier.get());
142        }
143    }
144
145    @Override
146    public void log(Object message) {
147        if (isValid()) {
148            logMessage(logger.getMessageFactory().newMessage(message));
149        }
150    }
151
152    @Override
153    public void log(String message, Object p0) {
154        if (isValid()) {
155            logMessage(logger.getMessageFactory().newMessage(message, p0));
156        }
157    }
158
159    @Override
160    public void log(String message, Object p0, Object p1) {
161        if (isValid()) {
162            logMessage(logger.getMessageFactory().newMessage(message, p0, p1));
163        }
164    }
165
166    @Override
167    public void log(String message, Object p0, Object p1, Object p2) {
168        if (isValid()) {
169            logMessage(logger.getMessageFactory().newMessage(message, p0, p1, p2));
170        }
171    }
172
173    @Override
174    public void log(String message, Object p0, Object p1, Object p2, Object p3) {
175        if (isValid()) {
176            logMessage(logger.getMessageFactory().newMessage(message, p0, p1, p2, p3));
177        }
178    }
179
180    @Override
181    public void log(String message, Object p0, Object p1, Object p2, Object p3, Object p4) {
182        if (isValid()) {
183            logMessage(logger.getMessageFactory().newMessage(message, p0, p1, p2, p3, p4));
184        }
185    }
186
187    @Override
188    public void log(String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5) {
189        if (isValid()) {
190            logMessage(logger.getMessageFactory().newMessage(message, p0, p1, p2, p3, p4, p5));
191        }
192    }
193
194    @Override
195    public void log(String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5, Object p6) {
196        if (isValid()) {
197            logMessage(logger.getMessageFactory().newMessage(message, p0, p1, p2, p3, p4, p5, p6));
198        }
199    }
200
201    @Override
202    public void log(String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5, Object p6,
203            Object p7) {
204        if (isValid()) {
205            logMessage(logger.getMessageFactory().newMessage(message, p0, p1, p2, p3, p4, p5, p6, p7));
206        }
207    }
208
209    @Override
210    public void log(String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5, Object p6,
211            Object p7, Object p8) {
212        if (isValid()) {
213            logMessage(logger.getMessageFactory().newMessage(message, p0, p1, p2, p3, p4, p5, p6, p7, p8));
214        }
215    }
216
217    @Override
218    public void log(String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5, Object p6,
219            Object p7, Object p8, Object p9) {
220        if (isValid()) {
221            logMessage(logger.getMessageFactory().newMessage(message, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9));
222        }
223    }
224
225    @Override
226    public void log() {
227        if (isValid()) {
228            logMessage(EMPTY_MESSAGE);
229        }
230    }
231
232    private void logMessage(Message message) {
233        try {
234            logger.logMessage(level, marker, FQCN, location, message, throwable);
235        } finally {
236            inUse = false;
237        }
238    }
239
240    private boolean isValid() {
241        if (!inUse) {
242            LOGGER.warn("Attempt to reuse LogBuilder was ignored. {}",
243                    StackLocatorUtil.getCallerClass(2));
244            return false ;
245        }
246        if (this.threadId != Thread.currentThread().getId()) {
247            LOGGER.warn("LogBuilder can only be used on the owning thread. {}",
248                    StackLocatorUtil.getCallerClass(2));
249            return false;
250        }
251        return true;
252    }
253}