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