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