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