1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.logging.log4j.core.async;
19
20 import java.util.Locale;
21 import java.util.concurrent.Callable;
22 import java.util.concurrent.ExecutorService;
23 import java.util.concurrent.Future;
24 import java.util.concurrent.TimeUnit;
25
26 import com.lmax.disruptor.BlockingWaitStrategy;
27 import com.lmax.disruptor.BusySpinWaitStrategy;
28 import com.lmax.disruptor.ExceptionHandler;
29 import com.lmax.disruptor.SleepingWaitStrategy;
30 import com.lmax.disruptor.TimeoutBlockingWaitStrategy;
31 import com.lmax.disruptor.WaitStrategy;
32 import com.lmax.disruptor.YieldingWaitStrategy;
33 import org.apache.logging.log4j.Logger;
34 import org.apache.logging.log4j.core.util.Constants;
35 import org.apache.logging.log4j.core.util.Integers;
36 import org.apache.logging.log4j.core.util.Loader;
37 import org.apache.logging.log4j.status.StatusLogger;
38 import org.apache.logging.log4j.util.PropertiesUtil;
39
40
41
42
43 final class DisruptorUtil {
44 private static final Logger LOGGER = StatusLogger.getLogger();
45 private static final int RINGBUFFER_MIN_SIZE = 128;
46 private static final int RINGBUFFER_DEFAULT_SIZE = 256 * 1024;
47 private static final int RINGBUFFER_NO_GC_DEFAULT_SIZE = 4 * 1024;
48
49
50
51
52
53
54
55 static final boolean ASYNC_LOGGER_SYNCHRONIZE_ENQUEUE_WHEN_QUEUE_FULL = PropertiesUtil.getProperties()
56 .getBooleanProperty("AsyncLogger.SynchronizeEnqueueWhenQueueFull", true);
57 static final boolean ASYNC_CONFIG_SYNCHRONIZE_ENQUEUE_WHEN_QUEUE_FULL = PropertiesUtil.getProperties()
58 .getBooleanProperty("AsyncLoggerConfig.SynchronizeEnqueueWhenQueueFull", true);
59
60 private DisruptorUtil() {
61 }
62
63 static long getTimeout(final String propertyName, final long defaultTimeout) {
64 return PropertiesUtil.getProperties().getLongProperty(propertyName, defaultTimeout);
65 }
66
67 static WaitStrategy createWaitStrategy(final String propertyName) {
68 final String key = propertyName.startsWith("AsyncLogger.")
69 ? "AsyncLogger.Timeout"
70 : "AsyncLoggerConfig.Timeout";
71 final long timeoutMillis = DisruptorUtil.getTimeout(key, 10L);
72 return createWaitStrategy(propertyName, timeoutMillis);
73 }
74
75 static WaitStrategy createWaitStrategy(final String propertyName, final long timeoutMillis) {
76 final String strategy = PropertiesUtil.getProperties().getStringProperty(propertyName, "TIMEOUT");
77 LOGGER.trace("property {}={}", propertyName, strategy);
78 final String strategyUp = strategy.toUpperCase(Locale.ROOT);
79 switch (strategyUp) {
80 case "SLEEP":
81 return new SleepingWaitStrategy();
82 case "YIELD":
83 return new YieldingWaitStrategy();
84 case "BLOCK":
85 return new BlockingWaitStrategy();
86 case "BUSYSPIN":
87 return new BusySpinWaitStrategy();
88 case "TIMEOUT":
89 return new TimeoutBlockingWaitStrategy(timeoutMillis, TimeUnit.MILLISECONDS);
90 default:
91 return new TimeoutBlockingWaitStrategy(timeoutMillis, TimeUnit.MILLISECONDS);
92 }
93 }
94
95 static int calculateRingBufferSize(final String propertyName) {
96 int ringBufferSize = Constants.ENABLE_THREADLOCALS ? RINGBUFFER_NO_GC_DEFAULT_SIZE : RINGBUFFER_DEFAULT_SIZE;
97 final String userPreferredRBSize = PropertiesUtil.getProperties().getStringProperty(propertyName,
98 String.valueOf(ringBufferSize));
99 try {
100 int size = Integer.parseInt(userPreferredRBSize);
101 if (size < RINGBUFFER_MIN_SIZE) {
102 size = RINGBUFFER_MIN_SIZE;
103 LOGGER.warn("Invalid RingBufferSize {}, using minimum size {}.", userPreferredRBSize,
104 RINGBUFFER_MIN_SIZE);
105 }
106 ringBufferSize = size;
107 } catch (final Exception ex) {
108 LOGGER.warn("Invalid RingBufferSize {}, using default size {}.", userPreferredRBSize, ringBufferSize);
109 }
110 return Integers.ceilingNextPowerOfTwo(ringBufferSize);
111 }
112
113 static ExceptionHandler<RingBufferLogEvent> getAsyncLoggerExceptionHandler() {
114 final String cls = PropertiesUtil.getProperties().getStringProperty("AsyncLogger.ExceptionHandler");
115 if (cls == null) {
116 return new AsyncLoggerDefaultExceptionHandler();
117 }
118 try {
119 @SuppressWarnings("unchecked")
120 final Class<? extends ExceptionHandler<RingBufferLogEvent>> klass =
121 (Class<? extends ExceptionHandler<RingBufferLogEvent>>) Loader.loadClass(cls);
122 return klass.newInstance();
123 } catch (final Exception ignored) {
124 LOGGER.debug("Invalid AsyncLogger.ExceptionHandler value: error creating {}: ", cls, ignored);
125 return new AsyncLoggerDefaultExceptionHandler();
126 }
127 }
128
129 static ExceptionHandler<AsyncLoggerConfigDisruptor.Log4jEventWrapper> getAsyncLoggerConfigExceptionHandler() {
130 final String cls = PropertiesUtil.getProperties().getStringProperty("AsyncLoggerConfig.ExceptionHandler");
131 if (cls == null) {
132 return new AsyncLoggerConfigDefaultExceptionHandler();
133 }
134 try {
135 @SuppressWarnings("unchecked")
136 final Class<? extends ExceptionHandler<AsyncLoggerConfigDisruptor.Log4jEventWrapper>> klass =
137 (Class<? extends ExceptionHandler<AsyncLoggerConfigDisruptor.Log4jEventWrapper>>) Loader.loadClass(cls);
138 return klass.newInstance();
139 } catch (final Exception ignored) {
140 LOGGER.debug("Invalid AsyncLoggerConfig.ExceptionHandler value: error creating {}: ", cls, ignored);
141 return new AsyncLoggerConfigDefaultExceptionHandler();
142 }
143 }
144
145
146
147
148
149
150
151
152 public static long getExecutorThreadId(final ExecutorService executor) {
153 final Future<Long> result = executor.submit(new Callable<Long>() {
154 @Override
155 public Long call() {
156 return Thread.currentThread().getId();
157 }
158 });
159 try {
160 return result.get();
161 } catch (final Exception ex) {
162 final String msg = "Could not obtain executor thread Id. "
163 + "Giving up to avoid the risk of application deadlock.";
164 throw new IllegalStateException(msg, ex);
165 }
166 }
167 }