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 @Override
54 public void log(final Supplier<LoggerConfig> reconfigured, final String loggerName, final String fqcn,
55 final Marker marker, final Level level, final Message data, final Throwable t) {
56
57 final LoggerConfig config = getActiveLoggerConfig(reconfigured);
58 try {
59 config.log(loggerName, fqcn, marker, level, data, t);
60 } finally {
61 config.getReliabilityStrategy().afterLogEvent();
62 }
63 }
64
65
66
67
68 @Override
69 public void log(final Supplier<LoggerConfig> reconfigured, final LogEvent event) {
70 final LoggerConfig config = getActiveLoggerConfig(reconfigured);
71 try {
72 config.log(event);
73 } finally {
74 config.getReliabilityStrategy().afterLogEvent();
75 }
76 }
77
78
79
80
81 @Override
82 public LoggerConfig getActiveLoggerConfig(final Supplier<LoggerConfig> next) {
83 LoggerConfig result = this.loggerConfig;
84 if (!beforeLogEvent()) {
85 result = next.get();
86 return result.getReliabilityStrategy().getActiveLoggerConfig(next);
87 }
88 return result;
89 }
90
91 private boolean beforeLogEvent() {
92 return counter.incrementAndGet() > 0;
93 }
94
95 public void afterLogEvent() {
96 if (counter.decrementAndGet() == 0 && shutdown.get()) {
97 signalCompletionIfShutdown();
98 }
99 }
100
101 private void signalCompletionIfShutdown() {
102 final Lock lock = shutdownLock;
103 lock.lock();
104 try {
105 noLogEvents.signalAll();
106 } finally {
107 lock.unlock();
108 }
109 }
110
111
112
113
114 @Override
115 public void beforeStopAppenders() {
116 waitForCompletion();
117 }
118
119
120
121
122 private void waitForCompletion() {
123 shutdownLock.lock();
124 try {
125 if (shutdown.compareAndSet(false, true)) {
126 int retries = 0;
127
128 while (!counter.compareAndSet(0, Integer.MIN_VALUE)) {
129
130
131 if (counter.get() < 0) {
132 return;
133 }
134
135 try {
136 noLogEvents.await(retries + 1, TimeUnit.SECONDS);
137 } catch (final InterruptedException ie) {
138 if (++retries > MAX_RETRIES) {
139 break;
140 }
141 }
142 }
143 }
144 } finally {
145 shutdownLock.unlock();
146 }
147 }
148
149
150
151
152 @Override
153 public void beforeStopConfiguration(Configuration configuration) {
154
155 }
156
157 }