001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017package org.apache.logging.log4j.core.async; 018 019import org.apache.logging.log4j.Level; 020import org.apache.logging.log4j.Logger; 021import org.apache.logging.log4j.core.util.Loader; 022import org.apache.logging.log4j.status.StatusLogger; 023import org.apache.logging.log4j.util.PropertiesUtil; 024 025/** 026 * Creates {@link AsyncQueueFullPolicy} instances based on user-specified system properties. The {@code AsyncQueueFullPolicy} 027 * created by this factory is used in AsyncLogger, AsyncLoggerConfig and AsyncAppender 028 * to control if events are logged in the current thread, the background thread, or discarded. 029 * <p> 030 * Property {@code "log4j2.AsyncQueueFullPolicy"} controls the routing behaviour. If this property is not specified or has 031 * value {@code "Default"}, this factory creates {@link DefaultAsyncQueueFullPolicy} objects. 032 * </p> <p> 033 * If this property has value {@code "Discard"}, this factory creates {@link DiscardingAsyncQueueFullPolicy} objects. 034 * By default, this router discards events of level {@code INFO}, {@code DEBUG} and {@code TRACE} if the queue is full. 035 * This can be adjusted with property {@code "log4j2.DiscardThreshold"} (name of the level at which to start 036 * discarding). 037 * </p> <p> 038 * For any other value, this 039 * factory interprets the value as the fully qualified name of a class implementing the {@link AsyncQueueFullPolicy} 040 * interface. The class must have a default constructor. 041 * </p> 042 * 043 * @since 2.6 044 */ 045public class AsyncQueueFullPolicyFactory { 046 static final String PROPERTY_NAME_ASYNC_EVENT_ROUTER = "log4j2.AsyncQueueFullPolicy"; 047 static final String PROPERTY_VALUE_DEFAULT_ASYNC_EVENT_ROUTER = "Default"; 048 static final String PROPERTY_VALUE_DISCARDING_ASYNC_EVENT_ROUTER = "Discard"; 049 static final String PROPERTY_NAME_DISCARDING_THRESHOLD_LEVEL = "log4j2.DiscardThreshold"; 050 051 private static final Logger LOGGER = StatusLogger.getLogger(); 052 053 /** 054 * Creates and returns {@link AsyncQueueFullPolicy} instances based on user-specified system properties. 055 * <p> 056 * Property {@code "log4j2.AsyncQueueFullPolicy"} controls the routing behaviour. If this property is not specified or 057 * has value {@code "Default"}, this method returns {@link DefaultAsyncQueueFullPolicy} objects. 058 * </p> <p> 059 * If this property has value {@code "Discard"}, this method returns {@link DiscardingAsyncQueueFullPolicy} objects. 060 * </p> <p> 061 * For any other value, this method interprets the value as the fully qualified name of a class implementing the 062 * {@link AsyncQueueFullPolicy} interface. The class must have a default constructor. 063 * </p> 064 * 065 * @return a new AsyncQueueFullPolicy 066 */ 067 public static AsyncQueueFullPolicy create() { 068 final String router = PropertiesUtil.getProperties().getStringProperty(PROPERTY_NAME_ASYNC_EVENT_ROUTER); 069 if (router == null || isRouterSelected( 070 router, DefaultAsyncQueueFullPolicy.class, PROPERTY_VALUE_DEFAULT_ASYNC_EVENT_ROUTER)) { 071 return new DefaultAsyncQueueFullPolicy(); 072 } 073 if (isRouterSelected( 074 router, DiscardingAsyncQueueFullPolicy.class, PROPERTY_VALUE_DISCARDING_ASYNC_EVENT_ROUTER)) { 075 return createDiscardingAsyncQueueFullPolicy(); 076 } 077 return createCustomRouter(router); 078 } 079 080 private static boolean isRouterSelected( 081 String propertyValue, 082 Class<? extends AsyncQueueFullPolicy> policy, 083 String shortPropertyValue) { 084 return propertyValue != null && (shortPropertyValue.equalsIgnoreCase(propertyValue) 085 || policy.getName().equals(propertyValue) 086 || policy.getSimpleName().equals(propertyValue)); 087 } 088 089 private static AsyncQueueFullPolicy createCustomRouter(final String router) { 090 try { 091 final Class<? extends AsyncQueueFullPolicy> cls = Loader.loadClass(router).asSubclass(AsyncQueueFullPolicy.class); 092 LOGGER.debug("Creating custom AsyncQueueFullPolicy '{}'", router); 093 return cls.newInstance(); 094 } catch (final Exception ex) { 095 LOGGER.debug("Using DefaultAsyncQueueFullPolicy. Could not create custom AsyncQueueFullPolicy '{}': {}", router, 096 ex.toString()); 097 return new DefaultAsyncQueueFullPolicy(); 098 } 099 } 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}