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.Filter;
023import org.apache.logging.log4j.core.Layout;
024import org.apache.logging.log4j.core.config.plugins.Plugin;
025import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
026import org.apache.logging.log4j.core.config.plugins.PluginFactory;
027import org.apache.logging.log4j.core.layout.PatternLayout;
028import org.apache.logging.log4j.core.util.CloseShieldOutputStream;
029
030/**
031 * Appends log events to a given output stream using a layout.
032 * <p>
033 * Character encoding is handled within the Layout.
034 * </p>
035 */
036@Plugin(name = "OutputStream", category = "Core", elementType = "appender", printObject = true)
037public final class OutputStreamAppender extends AbstractOutputStreamAppender<OutputStreamManager> {
038
039    /**
040     * Builds OutputStreamAppender instances.
041     */
042    public static class Builder implements org.apache.logging.log4j.core.util.Builder<OutputStreamAppender> {
043
044        private Filter filter;
045
046        private boolean follow = false;
047
048        private boolean ignoreExceptions = true;
049
050        private Layout<? extends Serializable> layout = PatternLayout.createDefaultLayout();
051
052        private String name;
053
054        private OutputStream target;
055
056        @Override
057        public OutputStreamAppender build() {
058            return new OutputStreamAppender(name, layout, filter, getManager(target, follow, layout), ignoreExceptions);
059        }
060
061        public Builder setFilter(final Filter aFilter) {
062            this.filter = aFilter;
063            return this;
064        }
065
066        public Builder setFollow(final boolean shouldFollow) {
067            this.follow = shouldFollow;
068            return this;
069        }
070
071        public Builder setIgnoreExceptions(final boolean shouldIgnoreExceptions) {
072            this.ignoreExceptions = shouldIgnoreExceptions;
073            return this;
074        }
075
076        public Builder setLayout(final Layout<? extends Serializable> aLayout) {
077            this.layout = aLayout;
078            return this;
079        }
080
081        public Builder setName(final String aName) {
082            this.name = aName;
083            return this;
084        }
085
086        public Builder setTarget(final OutputStream aTarget) {
087            this.target = aTarget;
088            return this;
089        }
090    }
091    /**
092     * Holds data to pass to factory method.
093     */
094    private static class FactoryData {
095        private final Layout<? extends Serializable> layout;
096        private final String name;
097        private final OutputStream os;
098
099        /**
100         * Builds instances.
101         * 
102         * @param os
103         *            The OutputStream.
104         * @param type
105         *            The name of the target.
106         * @param layout
107         *            A Serializable layout
108         */
109        public FactoryData(final OutputStream os, final String type, final Layout<? extends Serializable> layout) {
110            this.os = os;
111            this.name = type;
112            this.layout = layout;
113        }
114    }
115
116    /**
117     * Creates the manager.
118     */
119    private static class OutputStreamManagerFactory implements ManagerFactory<OutputStreamManager, FactoryData> {
120
121        /**
122         * Creates an OutputStreamManager.
123         * 
124         * @param name
125         *            The name of the entity to manage.
126         * @param data
127         *            The data required to create the entity.
128         * @return The OutputStreamManager
129         */
130        @Override
131        public OutputStreamManager createManager(final String name, final FactoryData data) {
132            return new OutputStreamManager(data.os, data.name, data.layout, true);
133        }
134    }
135
136    private static OutputStreamManagerFactory factory = new OutputStreamManagerFactory();
137
138    private static final long serialVersionUID = 1L;
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}