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.ByteArrayOutputStream;
020import java.io.PrintStream;
021import java.text.DateFormat;
022import java.text.SimpleDateFormat;
023import java.util.Date;
024import java.util.Map;
025
026import org.apache.logging.log4j.Level;
027import org.apache.logging.log4j.Marker;
028import org.apache.logging.log4j.ThreadContext;
029import org.apache.logging.log4j.message.Message;
030import org.apache.logging.log4j.message.MessageFactory;
031import org.apache.logging.log4j.spi.AbstractLogger;
032import org.apache.logging.log4j.util.PropertiesUtil;
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
062    public SimpleLogger(final String name, final Level defaultLevel, final boolean showLogName,
063                        final boolean showShortLogName, final boolean showDateTime, final boolean showContextMap,
064                        final String dateTimeFormat, final MessageFactory messageFactory, final PropertiesUtil props,
065                        final PrintStream stream) {
066        super(name, messageFactory);
067        final String lvl = props.getStringProperty(SimpleLoggerContext.SYSTEM_PREFIX + name + ".level");
068        this.level = Level.toLevel(lvl, defaultLevel);
069        if (showShortLogName) {
070            final int index = name.lastIndexOf(".");
071            if (index > 0 && index < name.length()) {
072                this.logName = name.substring(index + 1);
073            } else {
074                this.logName = name;
075            }
076        } else if (showLogName) {
077            this.logName = name;
078        } else {
079                this.logName = null;
080        }
081        this.showDateTime = showDateTime;
082        this.showContextMap = showContextMap;
083        this.stream = stream;
084
085        if (showDateTime) {
086            try {
087                this.dateFormatter = new SimpleDateFormat(dateTimeFormat);
088            } catch (final IllegalArgumentException e) {
089                // If the format pattern is invalid - use the default format
090                this.dateFormatter = new SimpleDateFormat(SimpleLoggerContext.DEFAULT_DATE_TIME_FORMAT);
091            }
092        }
093    }
094
095    @Override
096    public Level getLevel() {
097        return level;
098    }
099
100    @Override
101    public boolean isEnabled(final Level level, final Marker marker, final Message msg, final Throwable t) {
102        return this.level.intLevel() >= level.intLevel();
103    }
104
105    @Override
106    public boolean isEnabled(final Level level, final Marker marker, final Object msg, final Throwable t) {
107        return this.level.intLevel() >= level.intLevel();
108    }
109
110    @Override
111    public boolean isEnabled(final Level level, final Marker marker, final String msg) {
112        return this.level.intLevel() >= level.intLevel();
113    }
114
115    @Override
116    public boolean isEnabled(final Level level, final Marker marker, final String msg, final Object... p1) {
117        return this.level.intLevel() >= level.intLevel();
118    }
119
120    @Override
121    public boolean isEnabled(final Level level, final Marker marker, final String msg, final Throwable t) {
122        return this.level.intLevel() >= level.intLevel();
123    }
124
125    @Override
126    public void logMessage(final String fqcn, final Level level, final Marker marker, final Message msg, 
127            final Throwable throwable) {
128        final StringBuilder sb = new StringBuilder();
129        // Append date-time if so configured
130        if (showDateTime) {
131            final Date now = new Date();
132            String dateText;
133            synchronized (dateFormatter) {
134                dateText = dateFormatter.format(now);
135            }
136            sb.append(dateText);
137            sb.append(SPACE);
138        }
139
140        sb.append(level.toString());
141        sb.append(SPACE);
142        if (logName != null && logName.length() > 0) {
143            sb.append(logName);
144            sb.append(SPACE);
145        }
146        sb.append(msg.getFormattedMessage());
147        if (showContextMap) {
148            final Map<String, String> mdc = ThreadContext.getContext();
149            if (mdc.size() > 0) {
150                sb.append(SPACE);
151                sb.append(mdc.toString());
152                sb.append(SPACE);
153            }
154        }
155        final Object[] params = msg.getParameters();
156        Throwable t;
157        if (throwable == null && params != null && params[params.length - 1] instanceof Throwable) {
158            t = (Throwable) params[params.length - 1];
159        } else {
160            t = throwable;
161        }
162        if (t != null) {
163            sb.append(SPACE);
164            final ByteArrayOutputStream baos = new ByteArrayOutputStream();
165            t.printStackTrace(new PrintStream(baos));
166            sb.append(baos.toString());
167        }
168        stream.println(sb.toString());
169    }
170
171    public void setLevel(final Level level) {
172        if (level != null) {
173            this.level = level;
174        }
175    }
176
177    public void setStream(final PrintStream stream) {
178        this.stream = stream;
179    }
180
181}