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 org.apache.logging.log4j.LoggingException;
20  import org.apache.logging.log4j.core.Appender;
21  import org.apache.logging.log4j.core.Filter;
22  import org.apache.logging.log4j.core.LogEvent;
23  import org.apache.logging.log4j.core.config.AppenderControl;
24  import org.apache.logging.log4j.core.config.Configuration;
25  import org.apache.logging.log4j.core.config.plugins.Plugin;
26  import org.apache.logging.log4j.core.config.plugins.PluginAttr;
27  import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
28  import org.apache.logging.log4j.core.config.plugins.PluginElement;
29  import org.apache.logging.log4j.core.config.plugins.PluginFactory;
30  
31  import java.util.ArrayList;
32  import java.util.List;
33  import java.util.Map;
34  
35  /**
36   * The FailoverAppender will capture exceptions in an Appender and then route the event
37   * to a different appender. Hopefully it is obvious that the Appenders must be configured
38   * to not suppress exceptions for the FailoverAppender to work.
39   */
40  @Plugin(name = "Failover", type = "Core", elementType = "appender", printObject = true)
41  public final class FailoverAppender extends AbstractAppender {
42  
43      private final String primaryRef;
44  
45      private final String[] failovers;
46  
47      private final Configuration config;
48  
49      private AppenderControl primary;
50  
51      private final List<AppenderControl> failoverAppenders = new ArrayList<AppenderControl>();
52  
53      private FailoverAppender(String name, Filter filter, String primary, String[] failovers,
54                              Configuration config, boolean handleExceptions) {
55          super(name, filter, null, handleExceptions);
56          this.primaryRef = primary;
57          this.failovers = failovers;
58          this.config = config;
59      }
60  
61  
62      @Override
63      public void start() {
64          Map<String, Appender> map = config.getAppenders();
65          int errors = 0;
66          if (map.containsKey(primaryRef)) {
67              primary = new AppenderControl(map.get(primaryRef), null, null);
68          } else {
69              LOGGER.error("Unable to locate primary Appender " + primaryRef);
70              ++errors;
71          }
72          for (String name : failovers) {
73              if (map.containsKey(name)) {
74                  failoverAppenders.add(new AppenderControl(map.get(name), null, null));
75              } else {
76                  LOGGER.error("Failover appender " + name + " is not configured");
77              }
78          }
79          if (failoverAppenders.size() == 0) {
80              LOGGER.error("No failover appenders are available");
81              ++errors;
82          }
83          if (errors == 0) {
84              super.start();
85          }
86      }
87  
88      /**
89       * Handle the Log event.
90       * @param event The LogEvent.
91       */
92      public void append(LogEvent event) {
93          RuntimeException re = null;
94          if (!isStarted()) {
95              error("FailoverAppender " + getName() + " did not start successfully");
96              return;
97          }
98          try {
99              primary.callAppender(event);
100         } catch (Exception ex) {
101             re = new LoggingException(ex);
102             boolean written = false;
103             for (AppenderControl control : failoverAppenders) {
104                 try {
105                     control.callAppender(event);
106                     written = true;
107                     break;
108                 } catch (Exception fex) {
109                     continue;
110                 }
111             }
112             if (!written && !isExceptionSuppressed()) {
113                 throw re;
114             }
115         }
116     }
117 
118     @Override
119     public String toString() {
120         StringBuilder sb = new StringBuilder(getName());
121         sb.append(" primary=").append(primary).append(", failover={");
122         boolean first = true;
123         for (String str : failovers) {
124             if (!first) {
125                 sb.append(", ");
126             }
127             sb.append(str);
128             first = false;
129         }
130         sb.append("}");
131         return sb.toString();
132     }
133 
134     /**
135      * Create a Failover Appender.
136      * @param name The name of the Appender (required).
137      * @param primary The name of the primary Appender (required).
138      * @param failovers The name of one or more Appenders to fail over to (at least one is required).
139      * @param config The current Configuration (passed by the Configuration when the appender is created).
140      * @param filter A Filter (optional).
141      * @param suppress "true" if exceptions should be hidden from the application, "false" otherwise.
142      * The default is "true".
143      * @return The FailoverAppender that was created.
144      */
145     @PluginFactory
146     public static FailoverAppender createAppender(@PluginAttr("name") String name,
147                                                   @PluginAttr("primary") String primary,
148                                                   @PluginElement("failovers") String[] failovers,
149                                                   @PluginConfiguration Configuration config,
150                                                   @PluginElement("filters") Filter filter,
151                                                   @PluginAttr("suppressExceptions") String suppress) {
152         if (name == null) {
153             LOGGER.error("A name for the Appender must be specified");
154             return null;
155         }
156         if (primary == null) {
157             LOGGER.error("A primary Appender must be specified");
158             return null;
159         }
160         if (failovers == null || failovers.length == 0) {
161             LOGGER.error("At least one failover Appender must be specified");
162             return null;
163         }
164 
165         boolean handleExceptions = suppress == null ? true : Boolean.valueOf(suppress);
166 
167         return new FailoverAppender(name, filter, primary, failovers, config, handleExceptions);
168     }
169 }