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 private DisruptorUtil() {
50 }
51
52 static long getTimeout(final String propertyName, final long defaultTimeout) {
53 return PropertiesUtil.getProperties().getLongProperty(propertyName, defaultTimeout);
54 }
55
56 static WaitStrategy createWaitStrategy(final String propertyName) {
57 final String key = propertyName.startsWith("AsyncLogger.")
58 ? "AsyncLogger.Timeout"
59 : "AsyncLoggerConfig.Timeout";
60 final long timeoutMillis = DisruptorUtil.getTimeout(key, 10L);
61 return createWaitStrategy(propertyName, timeoutMillis);
62 }
63
64 static WaitStrategy createWaitStrategy(final String propertyName, final long timeoutMillis) {
65 final String strategy = PropertiesUtil.getProperties().getStringProperty(propertyName, "TIMEOUT");
66 LOGGER.trace("property {}={}", propertyName, strategy);
67 final String strategyUp = strategy.toUpperCase(Locale.ROOT);
68 switch (strategyUp) {
69 case "SLEEP":
70 return new SleepingWaitStrategy();
71 case "YIELD":
72 return new YieldingWaitStrategy();
73 case "BLOCK":
74 return new BlockingWaitStrategy();
75 case "BUSYSPIN":
76 return new BusySpinWaitStrategy();
77 case "TIMEOUT":
78 return new TimeoutBlockingWaitStrategy(timeoutMillis, TimeUnit.MILLISECONDS);
79 default:
80 return new TimeoutBlockingWaitStrategy(timeoutMillis, TimeUnit.MILLISECONDS);
81 }
82 }
83
84 static int calculateRingBufferSize(final String propertyName) {
85 int ringBufferSize = Constants.ENABLE_THREADLOCALS ? RINGBUFFER_NO_GC_DEFAULT_SIZE : RINGBUFFER_DEFAULT_SIZE;
86 final String userPreferredRBSize = PropertiesUtil.getProperties().getStringProperty(propertyName,
87 String.valueOf(ringBufferSize));
88 try {
89 int size = Integer.parseInt(userPreferredRBSize);
90 if (size < RINGBUFFER_MIN_SIZE) {
91 size = RINGBUFFER_MIN_SIZE;
92 LOGGER.warn("Invalid RingBufferSize {}, using minimum size {}.", userPreferredRBSize,
93 RINGBUFFER_MIN_SIZE);
94 }
95 ringBufferSize = size;
96 } catch (final Exception ex) {
97 LOGGER.warn("Invalid RingBufferSize {}, using default size {}.", userPreferredRBSize, ringBufferSize);
98 }
99 return Integers.ceilingNextPowerOfTwo(ringBufferSize);
100 }
101
102 static ExceptionHandler<RingBufferLogEvent> getAsyncLoggerExceptionHandler() {
103 final String cls = PropertiesUtil.getProperties().getStringProperty("AsyncLogger.ExceptionHandler");
104 if (cls == null) {
105 return new AsyncLoggerDefaultExceptionHandler();
106 }
107 try {
108 @SuppressWarnings("unchecked")
109 final Class<? extends ExceptionHandler<RingBufferLogEvent>> klass =
110 (Class<? extends ExceptionHandler<RingBufferLogEvent>>) Loader.loadClass(cls);
111 return klass.newInstance();
112 } catch (final Exception ignored) {
113 LOGGER.debug("Invalid AsyncLogger.ExceptionHandler value: error creating {}: ", cls, ignored);
114 return new AsyncLoggerDefaultExceptionHandler();
115 }
116 }
117
118 static ExceptionHandler<AsyncLoggerConfigDisruptor.Log4jEventWrapper> getAsyncLoggerConfigExceptionHandler() {
119 final String cls = PropertiesUtil.getProperties().getStringProperty("AsyncLoggerConfig.ExceptionHandler");
120 if (cls == null) {
121 return new AsyncLoggerConfigDefaultExceptionHandler();
122 }
123 try {
124 @SuppressWarnings("unchecked")
125 final Class<? extends ExceptionHandler<AsyncLoggerConfigDisruptor.Log4jEventWrapper>> klass =
126 (Class<? extends ExceptionHandler<AsyncLoggerConfigDisruptor.Log4jEventWrapper>>) Loader.loadClass(cls);
127 return klass.newInstance();
128 } catch (final Exception ignored) {
129 LOGGER.debug("Invalid AsyncLoggerConfig.ExceptionHandler value: error creating {}: ", cls, ignored);
130 return new AsyncLoggerConfigDefaultExceptionHandler();
131 }
132 }
133
134
135
136
137
138
139
140
141 public static long getExecutorThreadId(final ExecutorService executor) {
142 final Future<Long> result = executor.submit(new Callable<Long>() {
143 @Override
144 public Long call() {
145 return Thread.currentThread().getId();
146 }
147 });
148 try {
149 return result.get();
150 } catch (final Exception ex) {
151 final String msg = "Could not obtain executor thread Id. "
152 + "Giving up to avoid the risk of application deadlock.";
153 throw new IllegalStateException(msg, ex);
154 }
155 }
156 }