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.core.appender;
018
019import java.io.Writer;
020
021import org.apache.logging.log4j.core.Filter;
022import org.apache.logging.log4j.core.StringLayout;
023import org.apache.logging.log4j.core.config.plugins.Plugin;
024import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
025import org.apache.logging.log4j.core.config.plugins.PluginFactory;
026import org.apache.logging.log4j.core.layout.PatternLayout;
027import org.apache.logging.log4j.core.util.CloseShieldWriter;
028
029/**
030 * Appends log events to a {@link Writer}.
031 */
032@Plugin(name = "Writer", category = "Core", elementType = "appender", printObject = true)
033public final class WriterAppender extends AbstractWriterAppender<WriterManager> {
034
035    /**
036     * Builds WriterAppender instances.
037     */
038    public static class Builder implements org.apache.logging.log4j.core.util.Builder<WriterAppender> {
039
040        private Filter filter;
041
042        private boolean follow = false;
043
044        private boolean ignoreExceptions = true;
045
046        private StringLayout layout = PatternLayout.createDefaultLayout();
047
048        private String name;
049
050        private Writer target;
051
052        @Override
053        public WriterAppender build() {
054            return new WriterAppender(name, layout, filter, getManager(target, follow, layout), ignoreExceptions);
055        }
056
057        public Builder setFilter(final Filter aFilter) {
058            this.filter = aFilter;
059            return this;
060        }
061
062        public Builder setFollow(final boolean shouldFollow) {
063            this.follow = shouldFollow;
064            return this;
065        }
066
067        public Builder setIgnoreExceptions(final boolean shouldIgnoreExceptions) {
068            this.ignoreExceptions = shouldIgnoreExceptions;
069            return this;
070        }
071
072        public Builder setLayout(final StringLayout aLayout) {
073            this.layout = aLayout;
074            return this;
075        }
076
077        public Builder setName(final String aName) {
078            this.name = aName;
079            return this;
080        }
081
082        public Builder setTarget(final Writer aTarget) {
083            this.target = aTarget;
084            return this;
085        }
086    }
087    /**
088     * Holds data to pass to factory method.
089     */
090    private static class FactoryData {
091        private final StringLayout layout;
092        private final String name;
093        private final Writer writer;
094
095        /**
096         * Builds instances.
097         * 
098         * @param writer
099         *            The OutputStream.
100         * @param type
101         *            The name of the target.
102         * @param layout
103         *            A String layout
104         */
105        public FactoryData(final Writer writer, final String type, final StringLayout layout) {
106            this.writer = writer;
107            this.name = type;
108            this.layout = layout;
109        }
110    }
111
112    private static class WriterManagerFactory implements ManagerFactory<WriterManager, FactoryData> {
113
114        /**
115         * Creates a WriterManager.
116         * 
117         * @param name
118         *            The name of the entity to manage.
119         * @param data
120         *            The data required to create the entity.
121         * @return The WriterManager
122         */
123        @Override
124        public WriterManager createManager(final String name, final FactoryData data) {
125            return new WriterManager(data.writer, data.name, data.layout, true);
126        }
127    }
128
129    private static WriterManagerFactory factory = new WriterManagerFactory();
130
131    private static final long serialVersionUID = 1L;
132
133    /**
134     * Creates a WriterAppender.
135     * 
136     * @param layout
137     *            The layout to use or null to get the default layout.
138     * @param filter
139     *            The Filter or null.
140     * @param target
141     *            The target Writer
142     * @param follow
143     *            If true will follow changes to the underlying output stream.
144     *            Use false as the default.
145     * @param name
146     *            The name of the Appender (required).
147     * @param ignore
148     *            If {@code "true"} (default) exceptions encountered when
149     *            appending events are logged; otherwise they are propagated to
150     *            the caller. Use true as the default.
151     * @return The ConsoleAppender.
152     */
153    @PluginFactory
154    public static WriterAppender createAppender(StringLayout layout, final Filter filter, final Writer target,
155            final String name, final boolean follow, final boolean ignore) {
156        if (name == null) {
157            LOGGER.error("No name provided for WriterAppender");
158            return null;
159        }
160        if (layout == null) {
161            layout = PatternLayout.createDefaultLayout();
162        }
163        return new WriterAppender(name, layout, filter, getManager(target, follow, layout), ignore);
164    }
165
166    private static WriterManager getManager(final Writer target, final boolean follow, final StringLayout layout) {
167        final Writer writer = new CloseShieldWriter(target);
168        final String managerName = target.getClass().getName() + "@" + Integer.toHexString(target.hashCode()) + '.'
169                + follow;
170        return WriterManager.getManager(managerName, new FactoryData(writer, managerName, layout), factory);
171    }
172
173    @PluginBuilderFactory
174    public static Builder newBuilder() {
175        return new Builder();
176    }
177
178    private WriterAppender(final String name, final StringLayout layout, final Filter filter,
179            final WriterManager manager, final boolean ignoreExceptions) {
180        super(name, layout, filter, ignoreExceptions, true, manager);
181    }
182
183}