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