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