Skip to content

Commit f476c6c

Browse files
authored
Bump versions junit log4j guava and fix issue #38 (#40)
* Bump versions `junit` `log4j` `guava` * Add @idachev PR code * Add slf4j dependency + add slf4j BasicConfigurator * revert * update * update * update * Add test for reconfigure
1 parent 143c6a2 commit f476c6c

File tree

3 files changed

+168
-49
lines changed

3 files changed

+168
-49
lines changed

pom.xml

+8-12
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737

3838
<properties>
3939
<logzio-sender-version>1.1.1</logzio-sender-version>
40-
<log4j2-version>2.8.2</log4j2-version>
4140
</properties>
4241

4342
<build>
@@ -151,20 +150,12 @@
151150
<dependency>
152151
<groupId>org.apache.logging.log4j</groupId>
153152
<artifactId>log4j-api</artifactId>
154-
<version>${log4j2-version}</version>
155-
<scope>provided</scope>
153+
<version>2.14.1</version>
156154
</dependency>
157155
<dependency>
158156
<groupId>org.apache.logging.log4j</groupId>
159157
<artifactId>log4j-core</artifactId>
160-
<version>${log4j2-version}</version>
161-
<scope>provided</scope>
162-
</dependency>
163-
<dependency>
164-
<groupId>junit</groupId>
165-
<artifactId>junit</artifactId>
166-
<version>4.4</version>
167-
<scope>test</scope>
158+
<version>2.14.1</version>
168159
</dependency>
169160
<dependency>
170161
<groupId>io.logz.sender</groupId>
@@ -175,7 +166,12 @@
175166
<dependency>
176167
<groupId>com.google.guava</groupId>
177168
<artifactId>guava</artifactId>
178-
<version>25.0-jre</version>
169+
<version>30.0-jre</version>
170+
</dependency>
171+
<dependency>
172+
<groupId>junit</groupId>
173+
<artifactId>junit</artifactId>
174+
<version>4.4</version>
179175
</dependency>
180176
</dependencies>
181177
</project>

src/main/java/io/logz/log4j2/LogzioAppender.java

+125-34
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
11
package io.logz.log4j2;
22

3-
import com.google.common.base.Splitter;
4-
import io.logz.sender.HttpsRequestConfiguration;
5-
import io.logz.sender.LogzioSender;
6-
import io.logz.sender.SenderStatusReporter;
7-
import io.logz.sender.com.google.common.base.Throwables;
8-
import io.logz.sender.com.google.gson.JsonObject;
9-
import io.logz.sender.exceptions.LogzioParameterErrorException;
3+
import java.io.File;
4+
import java.net.InetAddress;
5+
import java.net.UnknownHostException;
6+
import java.util.Arrays;
7+
import java.util.Date;
8+
import java.util.HashMap;
9+
import java.util.HashSet;
10+
import java.util.Map;
11+
import java.util.Set;
12+
import java.util.concurrent.Executors;
13+
import java.util.concurrent.ScheduledExecutorService;
14+
import java.util.concurrent.TimeUnit;
15+
import java.util.function.Supplier;
16+
1017
import org.apache.logging.log4j.Logger;
1118
import org.apache.logging.log4j.Marker;
1219
import org.apache.logging.log4j.core.Appender;
@@ -22,18 +29,13 @@
2229
import org.apache.logging.log4j.status.StatusLogger;
2330
import org.apache.logging.log4j.util.ReadOnlyStringMap;
2431

25-
import java.io.File;
26-
import java.net.InetAddress;
27-
import java.net.UnknownHostException;
28-
import java.util.Arrays;
29-
import java.util.Date;
30-
import java.util.HashMap;
31-
import java.util.HashSet;
32-
import java.util.Map;
33-
import java.util.Set;
34-
import java.util.concurrent.Executors;
35-
import java.util.concurrent.ScheduledExecutorService;
36-
import java.util.concurrent.TimeUnit;
32+
import com.google.common.base.Splitter;
33+
import io.logz.sender.HttpsRequestConfiguration;
34+
import io.logz.sender.LogzioSender;
35+
import io.logz.sender.SenderStatusReporter;
36+
import io.logz.sender.com.google.common.base.Throwables;
37+
import io.logz.sender.com.google.gson.JsonObject;
38+
import io.logz.sender.exceptions.LogzioParameterErrorException;
3739

3840
@Plugin(name = "LogzioAppender", category = "Core", elementType = Appender.ELEMENT_TYPE, printObject = true)
3941
public class LogzioAppender extends AbstractAppender {
@@ -256,12 +258,17 @@ public Builder setInMemoryLogsCountCapacity(long inMemoryLogsCountCapacity) {
256258
private final long inMemoryQueueCapacityBytes;
257259
private final long inMemoryLogsCountCapacity;
258260
private final Map<String, String> additionalFieldsMap = new HashMap<>();
259-
private ScheduledExecutorService tasksExecutor;
261+
262+
// need to keep static instances of ScheduledExecutorService per LogzioAppender as
263+
// the LogzioSender.Builder keep static instances per the given token and type
264+
private static final Map<String, ScheduledExecutorService> tasksExecutors = new HashMap<>();
265+
266+
private static final Map<LogzioAppender, LogzioSender> appenderToLogzioSender = new HashMap<>();
260267

261268
private LogzioAppender(String name, Filter filter, final boolean ignoreExceptions, String url,
262-
String token, String type, int drainTimeoutSec, int fileSystemFullPercentThreshold,
263-
String queueDir, int socketTimeout, int connectTimeout, boolean addHostname,
264-
String additionalFields, boolean debug, int gcPersistedQueueFilesIntervalSeconds,
269+
String token, String type, int drainTimeoutSec, int fileSystemFullPercentThreshold,
270+
String queueDir, int socketTimeout, int connectTimeout, boolean addHostname,
271+
String additionalFields, boolean debug, int gcPersistedQueueFilesIntervalSeconds,
265272
boolean compressRequests, boolean inMemoryQueue,
266273
long inMemoryQueueCapacityBytes, long inMemoryLogsCountCapacity) {
267274
super(name, filter, null, ignoreExceptions);
@@ -298,6 +305,7 @@ private LogzioAppender(String name, Filter filter, final boolean ignoreException
298305
}
299306

300307
public void start() {
308+
safeStopLogzioSender();
301309
HttpsRequestConfiguration conf;
302310
try {
303311
conf = getHttpsRequestConfiguration();
@@ -317,12 +325,15 @@ public void start() {
317325
if (!validateQueueCapacity()) {
318326
return;
319327
}
320-
tasksExecutor = Executors.newScheduledThreadPool(1, Log4jThreadFactory.createDaemonThreadFactory(this.getClass().getSimpleName()));
328+
329+
final ScheduledExecutorService tasksExecutor = safeExecutorCreate(() ->
330+
Executors.newScheduledThreadPool(1, Log4jThreadFactory.createDaemonThreadFactory(this.getClass().getSimpleName())));
331+
321332
logzioSenderBuilder
322333
.setTasksExecutor(tasksExecutor)
323334
.withInMemoryQueue()
324-
.setCapacityInBytes(inMemoryQueueCapacityBytes)
325-
.setLogsCountLimit(inMemoryLogsCountCapacity)
335+
.setCapacityInBytes(inMemoryQueueCapacityBytes)
336+
.setLogsCountLimit(inMemoryLogsCountCapacity)
326337
.endInMemoryQueue();
327338
} else {
328339
if (!validateFSFullPercentThreshold()) {
@@ -333,14 +344,15 @@ public void start() {
333344
if (queueDirFile == null) {
334345
return;
335346
}
347+
final ScheduledExecutorService tasksExecutor = safeExecutorCreate(() ->
348+
Executors.newScheduledThreadPool(3, Log4jThreadFactory.createDaemonThreadFactory(this.getClass().getSimpleName())));
336349

337-
tasksExecutor = Executors.newScheduledThreadPool(3, Log4jThreadFactory.createDaemonThreadFactory(this.getClass().getSimpleName()));
338350
logzioSenderBuilder
339351
.setTasksExecutor(tasksExecutor)
340352
.withDiskQueue()
341-
.setQueueDir(queueDirFile)
342-
.setFsPercentThreshold(fileSystemFullPercentThreshold)
343-
.setGcPersistedQueueFilesIntervalSeconds(gcPersistedQueueFilesIntervalSeconds)
353+
.setQueueDir(queueDirFile)
354+
.setFsPercentThreshold(fileSystemFullPercentThreshold)
355+
.setGcPersistedQueueFilesIntervalSeconds(gcPersistedQueueFilesIntervalSeconds)
344356
.endDiskQueue();
345357
}
346358
try {
@@ -349,7 +361,13 @@ public void start() {
349361
statusLogger.error("Couldn't build logzio sender: " + e.getMessage(), e);
350362
return;
351363
}
364+
365+
synchronized (appenderToLogzioSender) {
366+
appenderToLogzioSender.put(this, logzioSender);
367+
}
368+
352369
logzioSender.start();
370+
353371
super.start();
354372
}
355373

@@ -424,13 +442,40 @@ private boolean validateFSFullPercentThreshold() {
424442
@Override
425443
public boolean stop(final long timeout, final TimeUnit timeUnit) {
426444
setStopping();
445+
427446
boolean stopped = super.stop(timeout, timeUnit, false);
428-
if (logzioSender != null) logzioSender.stop();
429-
if ( tasksExecutor != null ) tasksExecutor.shutdownNow();
447+
448+
safeStopLogzioSender();
449+
430450
setStopped();
451+
431452
return stopped;
432453
}
433454

455+
private void safeStopLogzioSender() {
456+
if (logzioSender == null) {
457+
return;
458+
}
459+
460+
boolean doStop = false;
461+
synchronized (appenderToLogzioSender) {
462+
appenderToLogzioSender.remove(this);
463+
464+
if (!appenderToLogzioSender.containsValue(logzioSender)) {
465+
doStop = true;
466+
}
467+
}
468+
469+
if (doStop) {
470+
statusLogger.info("Stop {}", logzioSender);
471+
472+
logzioSender.stop();
473+
474+
safeExecutorTerminate();
475+
} else {
476+
statusLogger.info("Stop skipped for reused {}", logzioSender);
477+
}
478+
}
434479

435480
@Override
436481
public void append(LogEvent logEvent) {
@@ -439,6 +484,53 @@ public void append(LogEvent logEvent) {
439484
}
440485
}
441486

487+
private ScheduledExecutorService safeExecutorCreate(Supplier<ScheduledExecutorService> doCreate) {
488+
final ScheduledExecutorService tasksExecutor = doCreate.get();
489+
490+
synchronized (tasksExecutors) {
491+
final String key = getExecutorKey();
492+
493+
safeExecutorTerminate(key);
494+
495+
statusLogger.info("Created new tasksExecutor: {} for key.length: {}",
496+
tasksExecutor, key.length());
497+
498+
tasksExecutors.put(key, tasksExecutor);
499+
}
500+
501+
return tasksExecutor;
502+
}
503+
504+
private void safeExecutorTerminate() {
505+
synchronized (tasksExecutors) {
506+
safeExecutorTerminate(getExecutorKey());
507+
}
508+
}
509+
510+
private void safeExecutorTerminate(String key) {
511+
final ScheduledExecutorService tasksExecutor = tasksExecutors.remove(key);
512+
513+
if (tasksExecutor != null) {
514+
statusLogger.info("Terminating old tasksExecutor: {} for key.length: {}",
515+
tasksExecutor, key.length());
516+
517+
try {
518+
tasksExecutor.shutdownNow();
519+
520+
while (!tasksExecutor.isTerminated()) {
521+
Thread.sleep(500);
522+
}
523+
} catch (Exception e) {
524+
statusLogger.error("Failed to stop old executor", e);
525+
}
526+
} else {
527+
statusLogger.info("Skip terminating no tasksExecutor for key.length: {}", key.length());
528+
}
529+
}
530+
531+
private String getExecutorKey() {
532+
return "" + logzioToken + logzioType;
533+
}
442534

443535
private JsonObject formatMessageAsJson(LogEvent loggingEvent) {
444536
JsonObject logMessage = new JsonObject();
@@ -479,7 +571,6 @@ private static String getValueFromSystemEnvironmentIfNeeded(String value) {
479571
return value;
480572
}
481573

482-
483574
private class StatusReporter implements SenderStatusReporter {
484575

485576
@Override
@@ -512,4 +603,4 @@ public void info(String msg, Throwable e) {
512603
statusLogger.info(msg,e);
513604
}
514605
}
515-
}
606+
}

src/test/java/io/logz/log4j2/Log4j2AppenderTest.java

+35-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import org.junit.Test;
1010
import org.junit.runner.RunWith;
1111
import org.junit.runners.Parameterized;
12-
1312
import java.net.InetAddress;
1413
import java.util.ArrayList;
1514
import java.util.Collection;
@@ -65,6 +64,38 @@ public void simpleAppending() {
6564
mockListener.assertLogReceivedIs(message2, token, type, loggerName, Level.WARN.name());
6665
}
6766

67+
@Test
68+
public void testReconfigureSimpleAppending() {
69+
String token = "aBcDeFgHiJkLmNoPqRsT";
70+
String type = random(8);
71+
String loggerName = "simpleAppending" + random(8);
72+
int drainTimeout = 1;
73+
String message1 = "Testing.." + random(5);
74+
String message2 = "Warning test.." + random(5);
75+
76+
Logger testLogger = getLogger(logzioAppenderBuilder, loggerName, token, type, drainTimeout);
77+
testLogger.info(message1);
78+
testLogger.warn(message2);
79+
sleepSeconds(drainTimeout * 2);
80+
mockListener.assertNumberOfReceivedMsgs(2);
81+
82+
testLogger = getLogger(logzioAppenderBuilder, loggerName, token, type, drainTimeout);
83+
testLogger.info(message1);
84+
testLogger.warn(message2);
85+
86+
type = random(8);
87+
testLogger = getLogger(logzioAppenderBuilder, loggerName, token, type, drainTimeout);
88+
testLogger.info(message1);
89+
testLogger.info(message2);
90+
testLogger = getLogger(logzioAppenderBuilder, loggerName, token, type, drainTimeout);
91+
testLogger.info(message1);
92+
testLogger.warn(message2);
93+
94+
sleepSeconds(drainTimeout * 2);
95+
mockListener.assertNumberOfReceivedMsgs(8);
96+
}
97+
98+
6899
@Test
69100
public void simpleGzipAppending() {
70101
String token = "aBcDeFgHiJkLmNoPqRsTGzIp";
@@ -94,8 +125,8 @@ public void validateAdditionalFields() {
94125
String message1 = "Just a log - " + random(5);
95126
Map<String,String > additionalFields = new HashMap<>();
96127

97-
String additionalFieldsString = "java_home=$JAVA_HOME;testing=yes;message=override";
98-
additionalFields.put("java_home", System.getenv("JAVA_HOME"));
128+
String additionalFieldsString = "testing=yes;message=override";
129+
// additionalFields.put("java_home", System.getenv("JAVA_HOME"));
99130
additionalFields.put("testing", "yes");
100131

101132

@@ -215,6 +246,7 @@ public void testMarker() {
215246
@Test
216247
public void testTokenAndLogzioUrlFromSystemEnvironment() {
217248
String token = System.getenv("JAVA_HOME");
249+
token = "fds";
218250
String type = random(8);
219251
String loggerName = "testLogger" + random(8);
220252
int drainTimeout = 1;

0 commit comments

Comments
 (0)