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 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            try {
086                this.dateFormatter = new SimpleDateFormat(dateTimeFormat);
087            } catch (final IllegalArgumentException e) {
088                // If the format pattern is invalid - use the default format
089                this.dateFormatter = new SimpleDateFormat(SimpleLoggerContext.DEFAULT_DATE_TIME_FORMAT);
090            }
091        }
092    }
093
094    @Override
095    public Level getLevel() {
096        return level;
097    }
098
099    @Override
100    public boolean isEnabled(final Level testLevel, final Marker marker, final Message msg, final Throwable t) {
101        return this.level.intLevel() >= testLevel.intLevel();
102    }
103
104    @Override
105    public boolean isEnabled(final Level testLevel, final Marker marker, final Object msg, final Throwable t) {
106        return this.level.intLevel() >= testLevel.intLevel();
107    }
108
109    @Override
110    public boolean isEnabled(final Level testLevel, final Marker marker, final String msg) {
111        return this.level.intLevel() >= testLevel.intLevel();
112    }
113
114    @Override
115    public boolean isEnabled(final Level testLevel, final Marker marker, final String msg, final Object... p1) {
116        return this.level.intLevel() >= testLevel.intLevel();
117    }
118
119    @Override
120    public boolean isEnabled(final Level testLevel, final Marker marker, final String msg, final Throwable t) {
121        return this.level.intLevel() >= testLevel.intLevel();
122    }
123
124    @Override
125    public void logMessage(final String fqcn, final Level mgsLevel, final Marker marker, final Message msg,
126            final Throwable throwable) {
127        final StringBuilder sb = new StringBuilder();
128        // Append date-time if so configured
129        if (showDateTime) {
130            final Date now = new Date();
131            String dateText;
132            synchronized (dateFormatter) {
133                dateText = dateFormatter.format(now);
134            }
135            sb.append(dateText);
136            sb.append(SPACE);
137        }
138
139        sb.append(mgsLevel.toString());
140        sb.append(SPACE);
141        if (Strings.isNotEmpty(logName)) {
142            sb.append(logName);
143            sb.append(SPACE);
144        }
145        sb.append(msg.getFormattedMessage());
146        if (showContextMap) {
147            final Map<String, String> mdc = ThreadContext.getImmutableContext();
148            if (mdc.size() > 0) {
149                sb.append(SPACE);
150                sb.append(mdc.toString());
151                sb.append(SPACE);
152            }
153        }
154        final Object[] params = msg.getParameters();
155        Throwable t;
156        if (throwable == null && params != null && params.length > 0
157                && params[params.length - 1] instanceof Throwable) {
158            t = (Throwable) params[params.length - 1];
159        } else {
160            t = throwable;
161        }
162        stream.println(sb.toString());
163        if (t != null) {
164            stream.print(SPACE);
165            t.printStackTrace(stream);
166        }
167    }
168
169    public void setLevel(final Level level) {
170        if (level != null) {
171            this.level = level;
172        }
173    }
174
175    public void setStream(final PrintStream stream) {
176        this.stream = stream;
177    }
178
179}