diff --git a/pom.xml b/pom.xml index 870a6cd..a9ce9bb 100644 --- a/pom.xml +++ b/pom.xml @@ -31,6 +31,7 @@ + 17 UTF-8 1.4.12 2.0.7 @@ -98,6 +99,11 @@ sentry-logback 6.11.0 + + jakarta.annotation + jakarta.annotation-api + 1.3.5 + @@ -108,8 +114,8 @@ org.mockito - mockito-all - 1.9.5 + mockito-core + 5.14.2 test @@ -127,6 +133,16 @@ + + org.apache.maven.plugins + maven-surefire-plugin + 3.1.2 + + @{argLine} -javaagent:${org.mockito:mockito-core:jar} + --add-opens java.base/java.lang=ALL-UNNAMED + --add-opens java.base/java.util=ALL-UNNAMED + + maven-checkstyle-plugin @@ -140,25 +156,6 @@ com.coveo fmt-maven-plugin - - com.github.spotbugs - spotbugs-maven-plugin - 4.1.4 - - Max - Low - true - true - - - - verify - - check - - - - maven-javadoc-plugin diff --git a/src/main/java/com/spotify/logging/LoggingConfigurator.java b/src/main/java/com/spotify/logging/LoggingConfigurator.java index 0aadffa..f0c1ef7 100644 --- a/src/main/java/com/spotify/logging/LoggingConfigurator.java +++ b/src/main/java/com/spotify/logging/LoggingConfigurator.java @@ -39,6 +39,7 @@ import static ch.qos.logback.classic.Level.OFF; import static java.lang.System.getenv; +import ch.qos.logback.classic.AsyncAppender; import ch.qos.logback.classic.Logger; import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.encoder.PatternLayoutEncoder; @@ -222,6 +223,19 @@ public static void configureDefaults( * a Docker container will capture these logs for further processing. */ public static void configureLogstashEncoderDefaults(final Level level) { + configureLogstashEncoderDefaults(level, null); + } + + /** + * Configure logging with the LogstashEncoder library. + * (https://github.com/logstash/logstash-logback-encoder) + * + *

The supplied {@link AsyncAppender} will wrap an appender that is configured to send the log + * messages to stdout. It is the responsibility of the caller to stop the {@link AsyncAppender} to + * properly flush the logging events from its queue. + */ + public static void configureLogstashEncoderDefaults( + final Level level, @Nullable final AsyncAppender asyncAppender) { final Logger rootLogger = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); final LoggerContext context = rootLogger.getLoggerContext(); @@ -232,14 +246,22 @@ public static void configureLogstashEncoderDefaults(final Level level) { encoder.addProvider(new ArgumentsJsonProvider()); encoder.start(); - final ConsoleAppender appender = new ConsoleAppender<>(); - appender.setTarget("System.out"); - appender.setName("stdout"); - appender.setEncoder(encoder); - appender.setContext(context); - appender.start(); + final ConsoleAppender consoleAppender = new ConsoleAppender<>(); + consoleAppender.setTarget("System.out"); + consoleAppender.setName("stdout"); + consoleAppender.setEncoder(encoder); + consoleAppender.setContext(context); + consoleAppender.start(); + + if (asyncAppender != null) { + asyncAppender.setContext(context); + asyncAppender.addAppender(consoleAppender); + asyncAppender.start(); + rootLogger.addAppender(asyncAppender); + } else { + rootLogger.addAppender(consoleAppender); + } - rootLogger.addAppender(appender); rootLogger.setLevel(level.logbackLevel); UncaughtExceptionLogger.setDefaultUncaughtExceptionHandler(); diff --git a/src/main/java/com/spotify/logging/logback/SpotifyInternalAppender.java b/src/main/java/com/spotify/logging/logback/SpotifyInternalAppender.java index e619c8a..d288115 100644 --- a/src/main/java/com/spotify/logging/logback/SpotifyInternalAppender.java +++ b/src/main/java/com/spotify/logging/logback/SpotifyInternalAppender.java @@ -58,7 +58,7 @@ public void start() { // our internal syslog-ng configuration splits logs up based on service name, and expects the // format below. - String serviceAndPid = String.format("%s[%s]", serviceName, getMyPid()); + String serviceAndPid = "%s[%s]".formatted(serviceName, getMyPid()); setSuffixPattern( serviceAndPid + ": " diff --git a/src/test/java/com/spotify/logging/JewelCliLoggingConfiguratorTest.java b/src/test/java/com/spotify/logging/JewelCliLoggingConfiguratorTest.java index 7a8be6b..6b7565d 100644 --- a/src/test/java/com/spotify/logging/JewelCliLoggingConfiguratorTest.java +++ b/src/test/java/com/spotify/logging/JewelCliLoggingConfiguratorTest.java @@ -42,7 +42,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner; import org.slf4j.LoggerFactory; @RunWith(MockitoJUnitRunner.class) @@ -68,7 +68,6 @@ public void syslog() { @Test public void threadlog() throws InterruptedException { - when(mockOptions.syslog()).thenReturn(false); when(mockOptions.logFileName()).thenReturn("logback_test.xml"); JewelCliLoggingConfigurator.configure(mockOptions); diff --git a/src/test/java/com/spotify/logging/LoggingConfiguratorTest.java b/src/test/java/com/spotify/logging/LoggingConfiguratorTest.java index 795c5b9..a12f5b8 100644 --- a/src/test/java/com/spotify/logging/LoggingConfiguratorTest.java +++ b/src/test/java/com/spotify/logging/LoggingConfiguratorTest.java @@ -42,6 +42,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import ch.qos.logback.classic.AsyncAppender; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Logger; import ch.qos.logback.classic.LoggerContext; @@ -49,6 +50,7 @@ import ch.qos.logback.classic.net.SyslogAppender; import ch.qos.logback.core.ConsoleAppender; import ch.qos.logback.core.status.Status; +import com.spotify.logging.LoggingConfigurator.ReplaceNewLines; import com.spotify.logging.logback.CustomLogstashEncoder; import io.sentry.logback.SentryAppender; import net.logstash.logback.composite.loggingevent.ArgumentsJsonProvider; @@ -66,26 +68,19 @@ public void testGetSyslogAppender() { final LoggerContext context = new LoggerContext(); SyslogAppender appender = - (SyslogAppender) - getSyslogAppender(context, "", -1, LoggingConfigurator.ReplaceNewLines.OFF); + (SyslogAppender) getSyslogAppender(context, "", -1, ReplaceNewLines.OFF); assertEquals("wrong host", "localhost", appender.getSyslogHost()); assertEquals("wrong port", 514, appender.getPort()); - appender = - (SyslogAppender) - getSyslogAppender(context, null, -1, LoggingConfigurator.ReplaceNewLines.OFF); + appender = (SyslogAppender) getSyslogAppender(context, null, -1, ReplaceNewLines.OFF); assertEquals("wrong host", "localhost", appender.getSyslogHost()); assertEquals("wrong port", 514, appender.getPort()); - appender = - (SyslogAppender) - getSyslogAppender(context, "host", -1, LoggingConfigurator.ReplaceNewLines.OFF); + appender = (SyslogAppender) getSyslogAppender(context, "host", -1, ReplaceNewLines.OFF); assertEquals("wrong host", "host", appender.getSyslogHost()); assertEquals("wrong port", 514, appender.getPort()); - appender = - (SyslogAppender) - getSyslogAppender(context, null, 999, LoggingConfigurator.ReplaceNewLines.OFF); + appender = (SyslogAppender) getSyslogAppender(context, null, 999, ReplaceNewLines.OFF); assertEquals("wrong host", "localhost", appender.getSyslogHost()); assertEquals("wrong port", 999, appender.getPort()); } @@ -95,15 +90,13 @@ public void testGetSyslogAppenderRespectsNewLineReplacement() { final LoggerContext context = new LoggerContext(); SyslogAppender appender = - (SyslogAppender) - getSyslogAppender(context, "", -1, LoggingConfigurator.ReplaceNewLines.OFF); + (SyslogAppender) getSyslogAppender(context, "", -1, ReplaceNewLines.OFF); assertEquals("%property{ident}[%property{pid}]: %msg", appender.getSuffixPattern()); appender = (SyslogAppender) getSyslogAppender(context, "", -1, null); assertEquals("%property{ident}[%property{pid}]: %msg", appender.getSuffixPattern()); - appender = - (SyslogAppender) getSyslogAppender(context, "", -1, LoggingConfigurator.ReplaceNewLines.ON); + appender = (SyslogAppender) getSyslogAppender(context, "", -1, ReplaceNewLines.ON); assertEquals( "%property{ident}[%property{pid}]: %replace(%msg){'[\\r\\n]', ''}", appender.getSuffixPattern()); @@ -172,6 +165,29 @@ public void shouldConfigureLogstashEncoderWithLevel() { assertLogstashEncoder(Level.DEBUG); } + @Test + public void shouldConfigureLogstashEncoderWithLevelAndAsyncAppender() { + // Given + final AsyncAppender asyncAppender = new AsyncAppender(); + + // When + LoggingConfigurator.configureLogstashEncoderDefaults( + LoggingConfigurator.Level.DEBUG, asyncAppender); + + // Then + final Logger rootLogger = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); + final ConsoleAppender stdout = (ConsoleAppender) asyncAppender.getAppender("stdout"); + final CustomLogstashEncoder encoder = (CustomLogstashEncoder) stdout.getEncoder(); + assertTrue(stdout.getEncoder() instanceof CustomLogstashEncoder); + assertEquals(Level.DEBUG, rootLogger.getLevel()); + assertEquals( + 1, + encoder.getProviders().getProviders().stream() + .filter(ArgumentsJsonProvider.class::isInstance) + .count()); + assertTrue(asyncAppender.isStarted()); + } + @Test public void shouldConfigureDefaultWithIdentAndLevelWhenSyslogEnvVarIsNotSet() { LoggingConfigurator.configureDefaults("some-ident", LoggingConfigurator.Level.DEBUG); diff --git a/src/test/java/com/spotify/logging/logback/LoggerThresholdFilterTest.java b/src/test/java/com/spotify/logging/logback/LoggerThresholdFilterTest.java index 45e10d0..d01aa94 100644 --- a/src/test/java/com/spotify/logging/logback/LoggerThresholdFilterTest.java +++ b/src/test/java/com/spotify/logging/logback/LoggerThresholdFilterTest.java @@ -157,8 +157,7 @@ public void filterSpotifyAtInfoOthersAtWarn() { actual = andFilterReplies(actual, nextReply); } - assertEquals( - String.format("Logger: %s, Level: %s", logger, level.toString()), expected, actual); + assertEquals("Logger: %s, Level: %s".formatted(logger, level.toString()), expected, actual); } } }