View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
16   */
17  package org.apache.logging.log4j.core.appender;
18  
19  import java.io.OutputStream;
20  import java.io.Serializable;
21  
22  import org.apache.logging.log4j.core.Appender;
23  import org.apache.logging.log4j.core.Core;
24  import org.apache.logging.log4j.core.Filter;
25  import org.apache.logging.log4j.core.Layout;
26  import org.apache.logging.log4j.core.config.Property;
27  import org.apache.logging.log4j.core.config.plugins.Plugin;
28  import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
29  import org.apache.logging.log4j.core.config.plugins.PluginFactory;
30  import org.apache.logging.log4j.core.layout.PatternLayout;
31  import org.apache.logging.log4j.core.util.CloseShieldOutputStream;
32  import org.apache.logging.log4j.core.util.NullOutputStream;
33  
34  /**
35   * Appends log events to a given output stream using a layout.
36   * <p>
37   * Character encoding is handled within the Layout.
38   * </p>
39   */
40  @Plugin(name = "OutputStream", category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE, printObject = true)
41  public final class OutputStreamAppender extends AbstractOutputStreamAppender<OutputStreamManager> {
42  
43      /**
44       * Builds OutputStreamAppender instances.
45       *
46       * @param <B>
47       *            The type to build.
48       */
49      public static class Builder<B extends Builder<B>> extends AbstractOutputStreamAppender.Builder<B>
50              implements org.apache.logging.log4j.core.util.Builder<OutputStreamAppender> {
51  
52          private boolean follow = false;
53  
54          private final boolean ignoreExceptions = true;
55  
56          private OutputStream target;
57  
58          @Override
59          public OutputStreamAppender build() {
60              final Layout<? extends Serializable> layout = getLayout();
61              final Layout<? extends Serializable> actualLayout = layout == null ? PatternLayout.createDefaultLayout()
62                      : layout;
63              return new OutputStreamAppender(getName(), actualLayout, getFilter(), getManager(target, follow, actualLayout),
64                      ignoreExceptions, getPropertyArray());
65          }
66  
67          public B setFollow(final boolean shouldFollow) {
68              this.follow = shouldFollow;
69              return asBuilder();
70          }
71  
72          public B setTarget(final OutputStream aTarget) {
73              this.target = aTarget;
74              return asBuilder();
75          }
76      }
77  
78      /**
79       * Holds data to pass to factory method.
80       */
81      private static class FactoryData {
82          private final Layout<? extends Serializable> layout;
83          private final String name;
84          private final OutputStream os;
85  
86          /**
87           * Builds instances.
88           *
89           * @param os
90           *            The OutputStream.
91           * @param type
92           *            The name of the target.
93           * @param layout
94           *            A Serializable layout
95           */
96          public FactoryData(final OutputStream os, final String type, final Layout<? extends Serializable> layout) {
97              this.os = os;
98              this.name = type;
99              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 }