1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.logging.log4j.core.config;
19
20 import java.util.Objects;
21 import java.util.concurrent.TimeUnit;
22 import java.util.concurrent.atomic.AtomicBoolean;
23 import java.util.concurrent.atomic.AtomicInteger;
24 import java.util.concurrent.locks.Condition;
25 import java.util.concurrent.locks.Lock;
26 import java.util.concurrent.locks.ReentrantLock;
27
28 import org.apache.logging.log4j.Level;
29 import org.apache.logging.log4j.Marker;
30 import org.apache.logging.log4j.core.LogEvent;
31 import org.apache.logging.log4j.message.Message;
32 import org.apache.logging.log4j.util.Supplier;
33
34
35
36
37
38 public class AwaitCompletionReliabilityStrategy implements ReliabilityStrategy {
39 private static final int MAX_RETRIES = 3;
40 private final AtomicInteger counter = new AtomicInteger();
41 private final AtomicBoolean shutdown = new AtomicBoolean(false);
42 private final Lock shutdownLock = new ReentrantLock();
43 private final Condition noLogEvents = shutdownLock.newCondition();
44 private final LoggerConfig loggerConfig;
45
46 public AwaitCompletionReliabilityStrategy(final LoggerConfig loggerConfig) {
47 this.loggerConfig = Objects.requireNonNull(loggerConfig, "loggerConfig is null");
48 }
49
50
51
52
53
54
55
56
57 @Override
58 public void log(final Supplier<LoggerConfig> reconfigured, final String loggerName, final String fqcn,
59 final Marker marker, final Level level, final Message data, final Throwable t) {
60
61 final LoggerConfig config = getActiveLoggerConfig(reconfigured);
62 try {
63 config.log(loggerName, fqcn, marker, level, data, t);
64 } finally {
65 config.getReliabilityStrategy().afterLogEvent();
66 }
67 }
68
69
70
71
72
73
74
75 @Override
76 public void log(final Supplier<LoggerConfig> reconfigured, final LogEvent event) {
77 final LoggerConfig config = getActiveLoggerConfig(reconfigured);
78 try {
79 config.log(event);
80 } finally {
81 config.getReliabilityStrategy().afterLogEvent();
82 }
83 }
84
85
86
87
88
89
90
91
92 @Override
93 public LoggerConfig getActiveLoggerConfig(final Supplier<LoggerConfig> next) {
94 LoggerConfig result = this.loggerConfig;
95 if (!beforeLogEvent()) {
96 result = next.get();
97 return result.getReliabilityStrategy().getActiveLoggerConfig(next);
98 }
99 return result;
100 }
101
102 private boolean beforeLogEvent() {
103 return counter.incrementAndGet() > 0;
104 }
105
106 @Override
107 public void afterLogEvent() {
108 if (counter.decrementAndGet() == 0 && shutdown.get()) {
109 signalCompletionIfShutdown();
110 }
111 }
112
113 private void signalCompletionIfShutdown() {
114 final Lock lock = shutdownLock;
115 lock.lock();
116 try {
117 noLogEvents.signalAll();
118 } finally {
119 lock.unlock();
120 }
121 }
122
123
124
125
126
127
128 @Override
129 public void beforeStopAppenders() {
130 waitForCompletion();
131 }
132
133
134
135
136 private void waitForCompletion() {
137 shutdownLock.lock();
138 try {
139 if (shutdown.compareAndSet(false, true)) {
140 int retries = 0;
141
142 while (!counter.compareAndSet(0, Integer.MIN_VALUE)) {
143
144
145 if (counter.get() < 0) {
146 return;
147 }
148
149 try {
150 noLogEvents.await(retries + 1, TimeUnit.SECONDS);
151 } catch (final InterruptedException ie) {
152 if (++retries > MAX_RETRIES) {
153 break;
154 }
155 }
156 }
157 }
158 } finally {
159 shutdownLock.unlock();
160 }
161 }
162
163
164
165
166
167
168
169
170 @Override
171 public void beforeStopConfiguration(final Configuration configuration) {
172
173 }
174
175 }