diff --git a/README.md b/README.md index 7986c96..1cf3729 100644 --- a/README.md +++ b/README.md @@ -47,9 +47,9 @@ provider. With the ELF4J facade, opting for tinylog as the logging implementatio The usual [tinylog configuration](https://tinylog.org/v2/configuration/) applies. Note: Only one logging provider such as this should be in effect at run-time. If multiple providers end up in the final -build of an application, somehow, then the `elf4j.logger.factory.fqcn` system property will have to be used to select +build of an application, somehow, then the `elf4j.service.provider.fqcn` system property will have to be used to select the desired provider. For example, ``` -java -Delf4j.logger.factory.fqcn="elf4j.tinylog.TinylogLoggerFactory" -jar MyApplication.jar +java -Delf4j.service.provider.fqcn="elf4j.tinylog.TinylogLoggerFactory" -jar MyApplication.jar ``` diff --git a/pom.xml b/pom.xml index c1b741c..534eb6a 100644 --- a/pom.xml +++ b/pom.xml @@ -31,7 +31,7 @@ io.github.elf4j elf4j-tinylog - 12.0.0 + 13.0.0 jar elf4j-tinylog @@ -68,7 +68,7 @@ io.github.elf4j elf4j - 3.0.3 + 4.1.0 org.tinylog @@ -130,6 +130,31 @@ + + com.diffplug.spotless + spotless-maven-plugin + 2.43.0 + + + spotless-apply-id + process-sources + + apply + + + + + + + 2.43.0 + + true + + + + + + diff --git a/src/main/java/elf4j/tinylog/TinylogLogger.java b/src/main/java/elf4j/tinylog/TinylogLogger.java index a603eb0..3be2d76 100644 --- a/src/main/java/elf4j/tinylog/TinylogLogger.java +++ b/src/main/java/elf4j/tinylog/TinylogLogger.java @@ -25,8 +25,18 @@ package elf4j.tinylog; +import static elf4j.Level.*; + import elf4j.Level; import elf4j.Logger; +import java.util.Arrays; +import java.util.EnumMap; +import java.util.EnumSet; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Supplier; +import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; import lombok.EqualsAndHashCode; import lombok.NonNull; import lombok.ToString; @@ -36,24 +46,11 @@ import org.tinylog.provider.ProviderRegistry; import org.tinylog.runtime.RuntimeProvider; -import javax.annotation.Nullable; -import javax.annotation.concurrent.Immutable; -import java.util.Arrays; -import java.util.EnumMap; -import java.util.EnumSet; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Supplier; - -import static elf4j.Level.*; - -/** - * Adapt tinylog capabilities to cater an ELF4J Logger - */ +/** Adapt tinylog capabilities to cater an ELF4J Logger */ @Immutable @ToString @EqualsAndHashCode -final class TinylogLogger implements Logger { +public final class TinylogLogger implements Logger { private static final LoggingProvider LOGGING_PROVIDER = ProviderRegistry.getLoggingProvider(); private static final MessageFormatter MESSAGE_FORMATTER = new LegacyMessageFormatter(); private static final EnumMap> LOGGER_CACHE; @@ -87,8 +84,12 @@ final class TinylogLogger implements Logger { ENABLEMENT_CACHE = new ConcurrentHashMap<>(); } - @EqualsAndHashCode.Include @NonNull private final String callerClassName; - @EqualsAndHashCode.Include @NonNull private final Level level; + @EqualsAndHashCode.Include + @NonNull private final String callerClassName; + + @EqualsAndHashCode.Include + @NonNull private final Level level; + @NonNull private final org.tinylog.Level tinylogLevel; TinylogLogger(@NonNull String callerClassName, @NonNull Level level) { @@ -130,8 +131,8 @@ public Logger atLevel(Level level) { @Override public boolean isEnabled() { - return ENABLEMENT_CACHE.computeIfAbsent(this, - logger -> LOGGING_PROVIDER.isEnabled(CALLER_DEPTH_ENABLED_CHECK, null, logger.tinylogLevel)); + return ENABLEMENT_CACHE.computeIfAbsent( + this, logger -> LOGGING_PROVIDER.isEnabled(CALLER_DEPTH_ENABLED_CHECK, null, logger.tinylogLevel)); } @Override @@ -159,23 +160,25 @@ public void log(Throwable t, String message, Object... args) { tinylog(t, message, args); } - public @NonNull String getCallerClassName() { + @NonNull String getCallerClassName() { return callerClassName; } - private void tinylog(@Nullable final Throwable exception, - @Nullable final Object message, - @Nullable final Object[] args) { - if (Boolean.FALSE.equals((ENABLEMENT_CACHE.computeIfAbsent(this, - logger -> LOGGING_PROVIDER.isEnabled(CALLER_DEPTH_ENABLED_LOG, null, logger.tinylogLevel))))) { + private void tinylog( + @Nullable final Throwable exception, @Nullable final Object message, @Nullable final Object[] args) { + if (Boolean.FALSE.equals((ENABLEMENT_CACHE.computeIfAbsent( + this, logger -> LOGGING_PROVIDER.isEnabled(CALLER_DEPTH_ENABLED_LOG, null, logger.tinylogLevel))))) { return; } - LOGGING_PROVIDER.log(CALLER_DEPTH_LOG, + LOGGING_PROVIDER.log( + CALLER_DEPTH_LOG, null, this.tinylogLevel, exception, args == null ? null : MESSAGE_FORMATTER, resolve(message), - args == null ? null : Arrays.stream(args).map(TinylogLogger::resolve).toArray()); + args == null + ? null + : Arrays.stream(args).map(TinylogLogger::resolve).toArray()); } } diff --git a/src/main/java/elf4j/tinylog/TinylogLoggerFactory.java b/src/main/java/elf4j/tinylog/TinylogLoggerFactory.java index 265016c..9817518 100644 --- a/src/main/java/elf4j/tinylog/TinylogLoggerFactory.java +++ b/src/main/java/elf4j/tinylog/TinylogLoggerFactory.java @@ -25,15 +25,16 @@ package elf4j.tinylog; -import elf4j.spi.LoggerFactory; +import elf4j.spi.LogServiceProvider; /** * Provider class implementation of ELF4J SPI, loadable via {@link java.util.ServiceLoader}. * - * @see Javadoc of - * ServiceLoader + * @see Javadoc of ServiceLoader */ -public final class TinylogLoggerFactory implements LoggerFactory { +public final class TinylogLoggerFactory implements LogServiceProvider { + /** A default constructor is required by the JDK Service Loader framework */ + public TinylogLoggerFactory() {} @Override public TinylogLogger logger() { diff --git a/src/main/resources/META-INF/services/elf4j.spi.LoggerFactory b/src/main/resources/META-INF/services/elf4j.spi.LogServiceProvider similarity index 94% rename from src/main/resources/META-INF/services/elf4j.spi.LoggerFactory rename to src/main/resources/META-INF/services/elf4j.spi.LogServiceProvider index 745869e..7bccbbd 100644 --- a/src/main/resources/META-INF/services/elf4j.spi.LoggerFactory +++ b/src/main/resources/META-INF/services/elf4j.spi.LogServiceProvider @@ -23,5 +23,4 @@ # # -elf4j.tinylog.TinylogLoggerFactory -#elf4j.util.NoopLoggerFactory \ No newline at end of file +elf4j.tinylog.TinylogLoggerFactory \ No newline at end of file diff --git a/src/test/java/elf4j/tinylog/TinylogLoggerTest.java b/src/test/java/elf4j/tinylog/TinylogLoggerTest.java index c83e815..2c28b1c 100644 --- a/src/test/java/elf4j/tinylog/TinylogLoggerTest.java +++ b/src/test/java/elf4j/tinylog/TinylogLoggerTest.java @@ -25,17 +25,16 @@ package elf4j.tinylog; +import static elf4j.Level.*; +import static org.junit.jupiter.api.Assertions.*; + import elf4j.Level; import elf4j.Logger; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; - import java.util.Arrays; import java.util.function.Supplier; import java.util.stream.Collectors; - -import static elf4j.Level.*; -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; class TinylogLoggerTest { @@ -52,7 +51,8 @@ void cacheLoggerWithSameNameAndLevel() { @Test void defaultNameAndLevel() { - logger.log("no-arg logger instance {} in class {} has default logger name: {}, and default level: {}", + logger.log( + "no-arg logger instance {} in class {} has default logger name: {}, and default level: {}", logger, this.getClass().getName(), ((TinylogLogger) logger).getCallerClassName(), @@ -77,25 +77,27 @@ void exceptionMessageAndArgs() { TinylogLogger error = (TinylogLogger) defaultLogger.atError(); Throwable ex = new Exception("ex message"); error.log(ex); - error.atInfo() - .log("{} is an immutable Logger instance whose name is {}, and level is {}", - error, - error.getCallerClassName(), - error.getLevel()); + error.atInfo().log( + "{} is an immutable Logger instance whose name is {}, and level is {}", + error, + error.getCallerClassName(), + error.getLevel()); assertEquals(Level.ERROR, error.getLevel()); error.atError() - .log(ex, + .log( + ex, "here the {} call is unnecessary because a Logger instance is immutable, and the {} instance's log level is already and will always be {}", "atError()", error, ERROR); - error.log(ex, + error.log( + ex, "now at Level.ERROR, together with the exception stack trace, logging some items expensive to compute: 1. {} 2. {} 3. {} 4. {}", "usually an Object-type argument's Object.toString result is used for the final log message, except that...", (Supplier) () -> "the Supplier.get result will be used instead for a Supplier-type argument", "this allows for a mixture of Supplier and other Object types of arguments to compute to a sensible final log message", - (Supplier) () -> Arrays.stream(new Object[] { - "suppose this is an expensive message argument coming as a Supplier" }) + (Supplier) () -> Arrays.stream( + new Object[] {"suppose this is an expensive message argument coming as a Supplier"}) .collect(Collectors.toList())); } @@ -103,21 +105,25 @@ void exceptionMessageAndArgs() { void messagesAndArgs() { defaultLogger.log("default logger name is usually the same as the API caller class name"); assertEquals(ReadmeSample.class.getName(), defaultLogger.getCallerClassName()); - defaultLogger.log("default log level is {}, which depends on the individual logging provider", + defaultLogger.log( + "default log level is {}, which depends on the individual logging provider", defaultLogger.getLevel()); TinylogLogger info = (TinylogLogger) defaultLogger.atInfo(); info.log("level set omitted here but we know the level is {}", INFO); assertEquals(INFO, info.getLevel()); - info.log("Supplier and other Object args can be mixed: Object arg1 {}, Supplier arg2 {}, Object arg3 {}", + info.log( + "Supplier and other Object args can be mixed: Object arg1 {}, Supplier arg2 {}, Object arg3 {}", "a11111", (Supplier) () -> "a22222", "a33333"); info.atWarn() - .log("switched to WARN level on the fly. that is, {} is a different Logger instance from {}", + .log( + "switched to WARN level on the fly. that is, {} is a different Logger instance from {}", "`info.atWarn()`", "`info`"); assertNotSame(info, info.atWarn()); - assertEquals(info.getCallerClassName(), + assertEquals( + info.getCallerClassName(), ((TinylogLogger) info.atWarn()).getCallerClassName(), "same name, only level is different"); assertEquals(WARN, info.atWarn().getLevel()); @@ -132,15 +138,16 @@ class ReadmeSample2 { @Test void levelGuard() { if (logger.atDebug().isEnabled()) { - logger.atDebug() - .log("a {} message guarded by a {}, so that no {} is created unless this logger instance - name and level combined - is {}", - "long and expensive-to-construct", - "level check", - "message object", - "enabled by system configuration of the logging provider"); + logger.atDebug().log( + "a {} message guarded by a {}, so that no {} is created unless this logger instance - name and level combined - is {}", + "long and expensive-to-construct", + "level check", + "message object", + "enabled by system configuration of the logging provider"); } - logger.atDebug() - .log((Supplier) () -> "alternative to the level guard, using a Supplier function like this should achieve the same goal of avoiding unnecessary message creation, pending quality of the logging provider"); + logger.atDebug().log( + () -> + "alternative to the level guard, using a Supplier function like this should achieve the same goal of avoiding unnecessary message creation, pending quality of the logging provider"); } } -} \ No newline at end of file +}