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     */
017    package org.apache.logging.log4j.simple;
018    
019    import java.io.ByteArrayOutputStream;
020    import java.io.PrintStream;
021    import java.text.DateFormat;
022    import java.text.SimpleDateFormat;
023    import java.util.Date;
024    import java.util.Map;
025    
026    import org.apache.logging.log4j.Level;
027    import org.apache.logging.log4j.Marker;
028    import org.apache.logging.log4j.ThreadContext;
029    import org.apache.logging.log4j.message.Message;
030    import org.apache.logging.log4j.message.MessageFactory;
031    import org.apache.logging.log4j.spi.AbstractLogger;
032    import 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     */
037    public 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.length > 0 && 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    }