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.async;
18  
19  import org.apache.logging.log4j.Level;
20  import org.apache.logging.log4j.Logger;
21  import org.apache.logging.log4j.core.util.Loader;
22  import org.apache.logging.log4j.status.StatusLogger;
23  import org.apache.logging.log4j.util.PropertiesUtil;
24  
25  /**
26   * Creates {@link AsyncQueueFullPolicy} instances based on user-specified system properties. The {@code AsyncQueueFullPolicy}
27   * created by this factory is used in AsyncLogger, AsyncLoggerConfig and AsyncAppender
28   * to control if events are logged in the current thread, the background thread, or discarded.
29   * <p>
30   * Property {@code "log4j2.AsyncQueueFullPolicy"} controls the routing behaviour. If this property is not specified or has
31   * value {@code "Default"}, this factory creates {@link DefaultAsyncQueueFullPolicy} objects.
32   * </p> <p>
33   * If this property has value {@code "Discard"}, this factory creates {@link DiscardingAsyncQueueFullPolicy} objects.
34   * By default, this router discards events of level {@code INFO}, {@code DEBUG} and {@code TRACE} if the queue is full.
35   * This can be adjusted with property {@code "log4j2.DiscardThreshold"} (name of the level at which to start
36   * discarding).
37   * </p> <p>
38   * For any other value, this
39   * factory interprets the value as the fully qualified name of a class implementing the {@link AsyncQueueFullPolicy}
40   * interface. The class must have a default constructor.
41   * </p>
42   *
43   * @since 2.6
44   */
45  public class AsyncQueueFullPolicyFactory {
46      static final String PROPERTY_NAME_ASYNC_EVENT_ROUTER = "log4j2.AsyncQueueFullPolicy";
47      static final String PROPERTY_VALUE_DEFAULT_ASYNC_EVENT_ROUTER = "Default";
48      static final String PROPERTY_VALUE_DISCARDING_ASYNC_EVENT_ROUTER = "Discard";
49      static final String PROPERTY_NAME_DISCARDING_THRESHOLD_LEVEL = "log4j2.DiscardThreshold";
50  
51      private static final Logger LOGGER = StatusLogger.getLogger();
52  
53      /**
54       * Creates and returns {@link AsyncQueueFullPolicy} instances based on user-specified system properties.
55       * <p>
56       * Property {@code "log4j2.AsyncQueueFullPolicy"} controls the routing behaviour. If this property is not specified or
57       * has value {@code "Default"}, this method returns {@link DefaultAsyncQueueFullPolicy} objects.
58       * </p> <p>
59       * If this property has value {@code "Discard"}, this method returns {@link DiscardingAsyncQueueFullPolicy} objects.
60       * </p> <p>
61       * For any other value, this method interprets the value as the fully qualified name of a class implementing the
62       * {@link AsyncQueueFullPolicy} interface. The class must have a default constructor.
63       * </p>
64       *
65       * @return a new AsyncQueueFullPolicy
66       */
67      public static AsyncQueueFullPolicy create() {
68          final String router = PropertiesUtil.getProperties().getStringProperty(PROPERTY_NAME_ASYNC_EVENT_ROUTER);
69          if (router == null || isRouterSelected(
70                  router, DefaultAsyncQueueFullPolicy.class, PROPERTY_VALUE_DEFAULT_ASYNC_EVENT_ROUTER)) {
71              return new DefaultAsyncQueueFullPolicy();
72          }
73          if (isRouterSelected(
74                  router, DiscardingAsyncQueueFullPolicy.class, PROPERTY_VALUE_DISCARDING_ASYNC_EVENT_ROUTER)) {
75              return createDiscardingAsyncQueueFullPolicy();
76          }
77          return createCustomRouter(router);
78      }
79  
80      private static boolean isRouterSelected(
81              String propertyValue,
82              Class<? extends AsyncQueueFullPolicy> policy,
83              String shortPropertyValue) {
84          return propertyValue != null && (shortPropertyValue.equalsIgnoreCase(propertyValue)
85                  || policy.getName().equals(propertyValue)
86                  || policy.getSimpleName().equals(propertyValue));
87      }
88  
89      private static AsyncQueueFullPolicy createCustomRouter(final String router) {
90          try {
91              final Class<? extends AsyncQueueFullPolicy> cls = Loader.loadClass(router).asSubclass(AsyncQueueFullPolicy.class);
92              LOGGER.debug("Creating custom AsyncQueueFullPolicy '{}'", router);
93              return cls.newInstance();
94          } catch (final Exception ex) {
95              LOGGER.debug("Using DefaultAsyncQueueFullPolicy. Could not create custom AsyncQueueFullPolicy '{}': {}", router,
96                      ex.toString());
97              return new DefaultAsyncQueueFullPolicy();
98          }
99      }
100 
101     private static AsyncQueueFullPolicy createDiscardingAsyncQueueFullPolicy() {
102         final PropertiesUtil util = PropertiesUtil.getProperties();
103         final String level = util.getStringProperty(PROPERTY_NAME_DISCARDING_THRESHOLD_LEVEL, Level.INFO.name());
104         final Level thresholdLevel = Level.toLevel(level, Level.INFO);
105         LOGGER.debug("Creating custom DiscardingAsyncQueueFullPolicy(discardThreshold:{})", thresholdLevel);
106         return new DiscardingAsyncQueueFullPolicy(thresholdLevel);
107     }
108 }