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.simple;
018
019import java.io.PrintStream;
020import java.text.DateFormat;
021import java.text.SimpleDateFormat;
022import java.util.Date;
023import java.util.Map;
024
025import org.apache.logging.log4j.Level;
026import org.apache.logging.log4j.Marker;
027import org.apache.logging.log4j.ThreadContext;
028import org.apache.logging.log4j.message.Message;
029import org.apache.logging.log4j.message.MessageFactory;
030import org.apache.logging.log4j.spi.AbstractLogger;
031import org.apache.logging.log4j.util.PropertiesUtil;
032import org.apache.logging.log4j.util.Strings;
033
034/**
035 * This is the default logger that is used when no suitable logging implementation is available.
036 */
037public class SimpleLogger extends AbstractLogger {
038
039    private static final long serialVersionUID = 1L;
040
041    private static final char SPACE = ' ';
042
043    /**
044     * Used to format times.
045     * <p>
046     * Note that DateFormat is not Thread-safe.
047     * </p>
048     */
049    private final DateFormat dateFormatter;
050
051    private Level level;
052
053    private final boolean showDateTime;
054
055    private final boolean showContextMap;
056
057    private PrintStream stream;
058
059    private final String logName;
060
061    public SimpleLogger(final String name, final Level defaultLevel, final boolean showLogName,
062            final boolean showShortLogName, final boolean showDateTime, final boolean showContextMap,
063            final String dateTimeFormat, final MessageFactory messageFactory, final PropertiesUtil props,
064            final PrintStream stream) {
065        super(name, messageFactory);
066        final String lvl = props.getStringProperty(SimpleLoggerContext.SYSTEM_PREFIX + name + ".level");
067        this.level = Level.toLevel(lvl, defaultLevel);
068        if (showShortLogName) {
069            final int index = name.lastIndexOf(".");
070            if (index > 0 && index < name.length()) {
071                this.logName = name.substring(index + 1);
072            } else {
073                this.logName = name;
074            }
075        } else if (showLogName) {
076            this.logName = name;
077        } else {
078            this.logName = null;
079        }
080        this.showDateTime = showDateTime;
081        this.showContextMap = showContextMap;
082        this.stream = stream;
083
084        if (showDateTime) {
085            DateFormat format;
086            try {
087                format = new SimpleDateFormat(dateTimeFormat);
088            } catch (final IllegalArgumentException e) {
089                // If the format pattern is invalid - use the default format
090                format = new SimpleDateFormat(SimpleLoggerContext.DEFAULT_DATE_TIME_FORMAT);
091            }
092            this.dateFormatter = format;
093        } else {
094            this.dateFormatter = null;
095        }
096    }
097
098    @Override
099    public Level getLevel() {
100        return level;
101    }
102
103    @Override
104    public boolean isEnabled(final Level testLevel, final Marker marker, final Message msg, final Throwable t) {
105        return this.level.intLevel() >= testLevel.intLevel();
106    }
107
108    @Override
109    public boolean isEnabled(final Level testLevel, final Marker marker, final CharSequence msg, final Throwable t) {
110        return this.level.intLevel() >= testLevel.intLevel();
111    }
112
113    @Override
114    public boolean isEnabled(final Level testLevel, final Marker marker, final Object msg, final Throwable t) {
115        return this.level.intLevel() >= testLevel.intLevel();
116    }
117
118    @Override
119    public boolean isEnabled(final Level testLevel, final Marker marker, final String msg) {
120        return this.level.intLevel() >= testLevel.intLevel();
121    }
122
123    @Override
124    public boolean isEnabled(final Level testLevel, final Marker marker, final String msg, final Object... p1) {
125        return this.level.intLevel() >= testLevel.intLevel();
126    }
127
128    @Override
129    public boolean isEnabled(final Level testLevel, final Marker marker, final String message, final Object p0) {
130        return this.level.intLevel() >= testLevel.intLevel();
131    }
132
133    @Override
134    public boolean isEnabled(final Level testLevel, final Marker marker, final String message, final Object p0,
135            final Object p1) {
136        return this.level.intLevel() >= testLevel.intLevel();
137    }
138
139    @Override
140    public boolean isEnabled(final Level testLevel, final Marker marker, final String message, final Object p0,
141            final Object p1, final Object p2) {
142        return this.level.intLevel() >= testLevel.intLevel();
143    }
144
145    @Override
146    public boolean isEnabled(final Level testLevel, final Marker marker, final String message, final Object p0,
147            final Object p1, final Object p2, final Object p3) {
148        return this.level.intLevel() >= testLevel.intLevel();
149    }
150
151    @Override
152    public boolean isEnabled(final Level testLevel, final Marker marker, final String message, final Object p0,
153            final Object p1, final Object p2, final Object p3,
154            final Object p4) {
155        return this.level.intLevel() >= testLevel.intLevel();
156    }
157
158    @Override
159    public boolean isEnabled(final Level testLevel, final Marker marker, final String message, final Object p0,
160            final Object p1, final Object p2, final Object p3,
161            final Object p4, final Object p5) {
162        return this.level.intLevel() >= testLevel.intLevel();
163    }
164
165    @Override
166    public boolean isEnabled(final Level testLevel, final Marker marker, final String message, final Object p0,
167            final Object p1, final Object p2, final Object p3,
168            final Object p4, final Object p5, final Object p6) {
169        return this.level.intLevel() >= testLevel.intLevel();
170    }
171
172    @Override
173    public boolean isEnabled(final Level testLevel, final Marker marker, final String message, final Object p0,
174            final Object p1, final Object p2, final Object p3,
175            final Object p4, final Object p5, final Object p6,
176            final Object p7) {
177        return this.level.intLevel() >= testLevel.intLevel();
178    }
179
180    @Override
181    public boolean isEnabled(final Level testLevel, final Marker marker, final String message, final Object p0,
182            final Object p1, final Object p2, final Object p3,
183            final Object p4, final Object p5, final Object p6,
184            final Object p7, final Object p8) {
185        return this.level.intLevel() >= testLevel.intLevel();
186    }
187
188    @Override
189    public boolean isEnabled(final Level testLevel, final Marker marker, final String message, final Object p0,
190            final Object p1, final Object p2, final Object p3,
191            final Object p4, final Object p5, final Object p6,
192            final Object p7, final Object p8, final Object p9) {
193        return this.level.intLevel() >= testLevel.intLevel();
194    }
195
196    @Override
197    public boolean isEnabled(final Level testLevel, final Marker marker, final String msg, final Throwable t) {
198        return this.level.intLevel() >= testLevel.intLevel();
199    }
200
201    @Override
202    public void logMessage(final String fqcn, final Level mgsLevel, final Marker marker, final Message msg,
203            final Throwable throwable) {
204        final StringBuilder sb = new StringBuilder();
205        // Append date-time if so configured
206        if (showDateTime) {
207            final Date now = new Date();
208            String dateText;
209            synchronized (dateFormatter) {
210                dateText = dateFormatter.format(now);
211            }
212            sb.append(dateText);
213            sb.append(SPACE);
214        }
215
216        sb.append(mgsLevel.toString());
217        sb.append(SPACE);
218        if (Strings.isNotEmpty(logName)) {
219            sb.append(logName);
220            sb.append(SPACE);
221        }
222        sb.append(msg.getFormattedMessage());
223        if (showContextMap) {
224            final Map<String, String> mdc = ThreadContext.getImmutableContext();
225            if (mdc.size() > 0) {
226                sb.append(SPACE);
227                sb.append(mdc.toString());
228                sb.append(SPACE);
229            }
230        }
231        final Object[] params = msg.getParameters();
232        Throwable t;
233        if (throwable == null && params != null && params.length > 0
234                && params[params.length - 1] instanceof Throwable) {
235            t = (Throwable) params[params.length - 1];
236        } else {
237            t = throwable;
238        }
239        stream.println(sb.toString());
240        if (t != null) {
241            stream.print(SPACE);
242            t.printStackTrace(stream);
243        }
244    }
245
246    public void setLevel(final Level level) {
247        if (level != null) {
248            this.level = level;
249        }
250    }
251
252    public void setStream(final PrintStream stream) {
253        this.stream = stream;
254    }
255
256}