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