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