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 || PROPERTY_VALUE_DEFAULT_ASYNC_EVENT_ROUTER.equals(router)
70 || DefaultAsyncQueueFullPolicy.class.getSimpleName().equals(router)
71 || DefaultAsyncQueueFullPolicy.class.getName().equals(router)) {
72 return new DefaultAsyncQueueFullPolicy();
73 }
74 if (PROPERTY_VALUE_DISCARDING_ASYNC_EVENT_ROUTER.equals(router)
75 || DiscardingAsyncQueueFullPolicy.class.getSimpleName().equals(router)
76 || DiscardingAsyncQueueFullPolicy.class.getName().equals(router)) {
77 return createDiscardingAsyncQueueFullPolicy();
78 }
79 return createCustomRouter(router);
80 }
81
82 private static AsyncQueueFullPolicy createCustomRouter(final String router) {
83 try {
84 final Class<? extends AsyncQueueFullPolicy> cls = Loader.loadClass(router).asSubclass(AsyncQueueFullPolicy.class);
85 LOGGER.debug("Creating custom AsyncQueueFullPolicy '{}'", router);
86 return cls.newInstance();
87 } catch (final Exception ex) {
88 LOGGER.debug("Using DefaultAsyncQueueFullPolicy. Could not create custom AsyncQueueFullPolicy '{}': {}", router,
89 ex.toString());
90 return new DefaultAsyncQueueFullPolicy();
91 }
92 }
93
94 private static AsyncQueueFullPolicy createDiscardingAsyncQueueFullPolicy() {
95 final PropertiesUtil util = PropertiesUtil.getProperties();
96 final String level = util.getStringProperty(PROPERTY_NAME_DISCARDING_THRESHOLD_LEVEL, Level.INFO.name());
97 final Level thresholdLevel = Level.toLevel(level, Level.INFO);
98 LOGGER.debug("Creating custom DiscardingAsyncQueueFullPolicy(discardThreshold:{})", thresholdLevel);
99 return new DiscardingAsyncQueueFullPolicy(thresholdLevel);
100 }
101 }