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.web.appender;
018
019import java.io.Serializable;
020
021import javax.servlet.ServletContext;
022
023import org.apache.logging.log4j.core.Filter;
024import org.apache.logging.log4j.core.Layout;
025import org.apache.logging.log4j.core.LogEvent;
026import org.apache.logging.log4j.core.appender.AbstractAppender;
027import org.apache.logging.log4j.core.config.plugins.Plugin;
028import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
029import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
030import org.apache.logging.log4j.core.layout.AbstractStringLayout;
031import org.apache.logging.log4j.core.layout.PatternLayout;
032import org.apache.logging.log4j.web.WebLoggerContextUtils;
033
034/**
035 * Logs using the ServletContext's log method
036 */
037@Plugin(name = "Servlet", category = "Core", elementType = "appender", printObject = true)
038public class ServletAppender extends AbstractAppender {
039
040        public static class Builder<B extends Builder<B>> extends AbstractAppender.Builder<B>
041                        implements org.apache.logging.log4j.core.util.Builder<ServletAppender> {
042
043        @PluginBuilderAttribute
044        private boolean logThrowables;
045
046                @Override
047                public ServletAppender build() {
048                        final String name = getName();
049                        if (name == null) {
050                                LOGGER.error("No name provided for ServletAppender");
051                        }
052                        final ServletContext servletContext = WebLoggerContextUtils.getServletContext();
053                        if (servletContext == null) {
054                                LOGGER.error("No servlet context is available");
055                                return null;
056                        }
057                        Layout<? extends Serializable> layout = getLayout();
058                        if (layout == null) {
059                                layout = PatternLayout.createDefaultLayout();
060                        } else if (!(layout instanceof AbstractStringLayout)) {
061                                LOGGER.error("Layout must be a StringLayout to log to ServletContext");
062                                return null;
063                        }
064                        return new ServletAppender(name, layout, getFilter(), servletContext, isIgnoreExceptions(), logThrowables);
065                }
066
067        /**
068         * Logs with {@link ServletContext#log(String, Throwable)} if true and with {@link ServletContext#log(String)} if false.
069         * 
070         * @return whether to log a Throwable with the servlet context.
071         */
072        public boolean isLogThrowables() {
073            return logThrowables;
074        }
075
076        /**
077         * Logs with {@link ServletContext#log(String, Throwable)} if true and with {@link ServletContext#log(String)} if false.
078         */
079        public void setLogThrowables(final boolean logThrowables) {
080            this.logThrowables = logThrowables;
081        }
082
083        }
084    
085    @PluginBuilderFactory
086    public static <B extends Builder<B>> B newBuilder() {
087        return new Builder<B>().asBuilder();
088    }
089
090    private final ServletContext servletContext;
091    private final boolean logThrowables;
092    
093    private ServletAppender(final String name, final Layout<? extends Serializable> layout, final Filter filter,
094            final ServletContext servletContext, final boolean ignoreExceptions, final boolean logThrowables) {
095        super(name, filter, layout, ignoreExceptions);
096        this.servletContext = servletContext;
097        this.logThrowables = logThrowables;
098    }
099
100    @Override
101    public void append(final LogEvent event) {
102        final String serialized = ((AbstractStringLayout) getLayout()).toSerializable(event);
103        if (logThrowables) {
104            servletContext.log(serialized, event.getThrown());
105        } else {
106            servletContext.log(serialized);
107        }
108    }
109
110    /**
111     * Creates a Servlet Appender.
112     * @param layout The layout to use (required). Must extend {@link AbstractStringLayout}.
113     * @param filter The Filter or null.
114     * @param name The name of the Appender (required).
115     * @param ignoreExceptions If {@code true} (default) exceptions encountered when appending events are logged;
116     *                         otherwise they are propagated to the caller.
117     * @return The ServletAppender.
118     * @deprecated Use {@link #newBuilder()}.
119     */
120    @Deprecated
121    public static ServletAppender createAppender(final Layout<? extends Serializable> layout, final Filter filter,
122            final String name, final boolean ignoreExceptions) {
123        // @formatter:off
124        return newBuilder()
125                        .withFilter(filter)
126                        .withIgnoreExceptions(ignoreExceptions)
127                        .withLayout(layout)
128                        .withName(name)
129                        .build();
130        // @formatter:on
131    }
132
133}