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.Serializable;
20  import java.nio.charset.Charset;
21  import java.util.Objects;
22  
23  import org.apache.logging.log4j.core.Appender;
24  import org.apache.logging.log4j.core.ErrorHandler;
25  import org.apache.logging.log4j.core.Filter;
26  import org.apache.logging.log4j.core.Layout;
27  import org.apache.logging.log4j.core.LogEvent;
28  import org.apache.logging.log4j.core.config.Configuration;
29  import org.apache.logging.log4j.core.config.Property;
30  import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
31  import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
32  import org.apache.logging.log4j.core.config.plugins.PluginElement;
33  import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
34  import org.apache.logging.log4j.core.filter.AbstractFilterable;
35  import org.apache.logging.log4j.core.layout.PatternLayout;
36  import org.apache.logging.log4j.core.util.Integers;
37  
38  /**
39   * Abstract base class for Appenders. Although Appenders do not have to extend this class, doing so will simplify their
40   * implementation.
41   */
42  public abstract class AbstractAppender extends AbstractFilterable implements Appender {
43  
44      /**
45       * Subclasses can extend this abstract Builder.
46       *
47       * @param <B> The type to build.
48       */
49      public abstract static class Builder<B extends Builder<B>> extends AbstractFilterable.Builder<B> {
50  
51          @PluginBuilderAttribute
52          private boolean ignoreExceptions = true;
53  
54          @PluginElement("Layout")
55          private Layout<? extends Serializable> layout;
56  
57          @PluginBuilderAttribute
58          @Required(message = "No appender name provided")
59          private String name;
60  
61          @PluginConfiguration
62          private Configuration configuration;
63  
64          public Configuration getConfiguration() {
65              return configuration;
66          }
67  
68          public Layout<? extends Serializable> getLayout() {
69              return layout;
70          }
71  
72          public String getName() {
73              return name;
74          }
75  
76          public Layout<? extends Serializable> getOrCreateLayout() {
77              if (layout == null) {
78                  return PatternLayout.createDefaultLayout();
79              }
80              return layout;
81          }
82  
83          public Layout<? extends Serializable> getOrCreateLayout(final Charset charset) {
84              if (layout == null) {
85                  return PatternLayout.newBuilder().withCharset(charset).build();
86              }
87              return layout;
88          }
89  
90          public boolean isIgnoreExceptions() {
91              return ignoreExceptions;
92          }
93  
94          public B setConfiguration(final Configuration configuration) {
95              this.configuration = configuration;
96              return asBuilder();
97          }
98  
99          public B setIgnoreExceptions(final boolean ignoreExceptions) {
100             this.ignoreExceptions = ignoreExceptions;
101             return asBuilder();
102         }
103 
104         public B setLayout(final Layout<? extends Serializable> layout) {
105             this.layout = layout;
106             return asBuilder();
107         }
108 
109         public B setName(final String name) {
110             this.name = name;
111             return asBuilder();
112         }
113 
114         /**
115          * @deprecated Use {@link #setConfiguration(Configuration)}
116          */
117         @Deprecated
118         public B withConfiguration(final Configuration configuration) {
119             this.configuration = configuration;
120             return asBuilder();
121         }
122 
123         /**
124          * @deprecated use {@link #setIgnoreExceptions(boolean)}.
125          */
126         @Deprecated
127         public B withIgnoreExceptions(final boolean ignoreExceptions) {
128             return setIgnoreExceptions(ignoreExceptions);
129         }
130 
131         /**
132          * @deprecated use {@link #setLayout(Layout)}.
133          */
134         @Deprecated
135         public B withLayout(final Layout<? extends Serializable> layout) {
136             return setLayout(layout);
137         }
138 
139         /**
140          * @deprecated use {@link #setName(String)}.
141          */
142         @Deprecated
143         public B withName(final String name) {
144             return setName(name);
145         }
146 
147     }
148 
149     public static int parseInt(final String s, final int defaultValue) {
150         try {
151             return Integers.parseInt(s, defaultValue);
152         } catch (final NumberFormatException e) {
153             LOGGER.error("Could not parse \"{}\" as an integer,  using default value {}: {}", s, defaultValue, e);
154             return defaultValue;
155         }
156     }
157     private final String name;
158     private final boolean ignoreExceptions;
159     private final Layout<? extends Serializable> layout;
160 
161     private ErrorHandler handler = new DefaultErrorHandler(this);
162 
163     /**
164      * Constructor that defaults to suppressing exceptions.
165      *
166      * @param name The Appender name.
167      * @param filter The Filter to associate with the Appender.
168      * @param layout The layout to use to format the event.
169      * @deprecated Use {@link #AbstractAppender(String, Filter, Layout, boolean, Property[])}.
170      */
171     @Deprecated
172     protected AbstractAppender(final String name, final Filter filter, final Layout<? extends Serializable> layout) {
173         this(name, filter, layout, true, Property.EMPTY_ARRAY);
174     }
175 
176     /**
177      * Constructor.
178      *
179      * @param name The Appender name.
180      * @param filter The Filter to associate with the Appender.
181      * @param layout The layout to use to format the event.
182      * @param ignoreExceptions If true, exceptions will be logged and suppressed. If false errors will be logged and
183      *            then passed to the application.
184      * @deprecated Use {@link #AbstractAppender(String, Filter, Layout, boolean, Property[])}
185      */
186     @Deprecated
187     protected AbstractAppender(final String name, final Filter filter, final Layout<? extends Serializable> layout,
188             final boolean ignoreExceptions) {
189         this(name, filter, layout, ignoreExceptions, Property.EMPTY_ARRAY);
190     }
191 
192     /**
193      * Constructor.
194      *
195      * @param name The Appender name.
196      * @param filter The Filter to associate with the Appender.
197      * @param layout The layout to use to format the event.
198      * @param ignoreExceptions If true, exceptions will be logged and suppressed. If false errors will be logged and
199      *            then passed to the application.
200      * @since 2.11.2
201      */
202     protected AbstractAppender(final String name, final Filter filter, final Layout<? extends Serializable> layout,
203             final boolean ignoreExceptions, final Property[] properties) {
204         super(filter, properties);
205         this.name = Objects.requireNonNull(name, "name");
206         this.layout = layout;
207         this.ignoreExceptions = ignoreExceptions;
208     }
209 
210     /**
211      * Handle an error with a message using the {@link ErrorHandler} configured for this Appender.
212      *
213      * @param msg The message.
214      */
215     public void error(final String msg) {
216         handler.error(msg);
217     }
218 
219     /**
220      * Handle an error with a message, exception, and a logging event, using the {@link ErrorHandler} configured for
221      * this Appender.
222      *
223      * @param msg The message.
224      * @param event The LogEvent.
225      * @param t The Throwable.
226      */
227     public void error(final String msg, final LogEvent event, final Throwable t) {
228         handler.error(msg, event, t);
229     }
230 
231     /**
232      * Handle an error with a message and an exception using the {@link ErrorHandler} configured for this Appender.
233      *
234      * @param msg The message.
235      * @param t The Throwable.
236      */
237     public void error(final String msg, final Throwable t) {
238         handler.error(msg, t);
239     }
240 
241     /**
242      * Returns the ErrorHandler, if any.
243      *
244      * @return The ErrorHandler.
245      */
246     @Override
247     public ErrorHandler getHandler() {
248         return handler;
249     }
250 
251     /**
252      * Returns the Layout for the appender.
253      *
254      * @return The Layout used to format the event.
255      */
256     @Override
257     public Layout<? extends Serializable> getLayout() {
258         return layout;
259     }
260 
261     /**
262      * Returns the name of the Appender.
263      *
264      * @return The name of the Appender.
265      */
266     @Override
267     public String getName() {
268         return name;
269     }
270 
271     /**
272      * Some appenders need to propagate exceptions back to the application. When {@code ignoreExceptions} is
273      * {@code false} the AppenderControl will allow the exception to percolate.
274      *
275      * @return {@code true} if exceptions will be logged but now thrown, {@code false} otherwise.
276      */
277     @Override
278     public boolean ignoreExceptions() {
279         return ignoreExceptions;
280     }
281 
282     /**
283      * The handler must be set before the appender is started.
284      *
285      * @param handler The ErrorHandler to use.
286      */
287     @Override
288     public void setHandler(final ErrorHandler handler) {
289         if (handler == null) {
290             LOGGER.error("The handler cannot be set to null");
291             return;
292         }
293         if (isStarted()) {
294             LOGGER.error("The handler cannot be changed once the appender is started");
295             return;
296         }
297         this.handler = handler;
298     }
299 
300     /**
301      * Serializes the given event using the appender's layout if present.
302      *
303      * @param event
304      *            the event to serialize.
305      * @return the serialized event or null if no layout is present.
306      */
307     protected Serializable toSerializable(final LogEvent event) {
308         return layout != null ? layout.toSerializable(event) : null;
309     }
310 
311     @Override
312     public String toString() {
313         return name;
314     }
315 
316 }