From 9a94136678c08a439a3f921cb3e076cba2e7fc05 Mon Sep 17 00:00:00 2001 From: javasabr Date: Sun, 7 Jun 2026 11:32:35 +0200 Subject: [PATCH 1/4] implement the next phase of customization support for logger --- .../java/javasabr/rlib/logger/api/Logger.java | 23 +++- .../rlib/logger/api/LoggerManager.java | 2 +- .../rlib/logger/impl/DefaultLogger.java | 2 +- .../logger/impl/DefaultLoggerFactory.java | 2 +- .../logger/impl/DefaultLoggerService.java | 2 +- .../rlib/logger/impl/config/LoggerConfig.java | 1 + .../{ => consumer}/LogMessageConsumer.java | 2 +- .../impl/ConsoleMessageConsumer.java | 6 +- .../config/consumer/impl/package-info.java | 4 + .../impl/config/consumer/package-info.java | 4 + .../impl/config/impl/DefaultLoggerConfig.java | 2 +- .../impl/config/impl/LoggerConfigBuilder.java | 46 ++++++++ .../{ => loader}/LoggerConfigLoader.java | 7 +- .../loader/LoggerConfigLoadersProvider.java | 8 ++ .../{ => loader}/LoggerConfigResolver.java | 5 +- .../impl/DefaultLoggerConfigLoader.java | 11 +- .../impl/PropertyLoggerConfigLoader.java | 79 ++++++++++++++ .../impl/config/loader/impl/package-info.java | 4 + .../impl/config/loader/package-info.java | 4 + .../config/{ => render}/LogMessageRender.java | 2 +- .../impl/SimpleLogMessageRender.java | 8 +- .../impl/config/render/impl/package-info.java | 4 + .../impl/pattern/PatternLogMessageRender.java | 37 +++++++ .../pattern/PatternRenderNodesParser.java | 89 +++++++++++++++ .../node/DateTimePatternRenderNode.java | 29 +++++ .../pattern/node/LevelPatternRenderNode.java | 19 ++++ .../node/MessagePatternRenderNode.java | 17 +++ .../impl/pattern/node/PatternRenderNode.java | 9 ++ .../node/ShortLoggerPatternRenderNode.java | 17 +++ .../pattern/node/StringPatternRenderNode.java | 21 ++++ .../impl/pattern/node/package-info.java | 4 + .../render/impl/pattern/package-info.java | 4 + .../impl/config/render/package-info.java | 4 + .../rlib/logger/impl/DefaultLoggerTest.java | 2 +- .../impl/PropertyLoggerConfigLoaderTest.java | 103 ++++++++++++++++++ .../pattern/PatternRenderNodesParserTest.java | 48 ++++++++ .../resources/example-rlib.logger.properties | 4 + .../property-loader-test-1.properties | 6 + .../slf4j/impl/Slf4jLoggerImplTest.java | 2 +- .../packet/impl/AbstractNetworkPacket.java | 2 +- 40 files changed, 619 insertions(+), 26 deletions(-) rename rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/{ => consumer}/LogMessageConsumer.java (89%) rename rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/{ => consumer}/impl/ConsoleMessageConsumer.java (78%) create mode 100644 rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/consumer/impl/package-info.java create mode 100644 rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/consumer/package-info.java create mode 100644 rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/impl/LoggerConfigBuilder.java rename rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/{ => loader}/LoggerConfigLoader.java (69%) create mode 100644 rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/LoggerConfigLoadersProvider.java rename rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/{ => loader}/LoggerConfigResolver.java (82%) rename rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/{ => loader}/impl/DefaultLoggerConfigLoader.java (72%) create mode 100644 rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/impl/PropertyLoggerConfigLoader.java create mode 100644 rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/impl/package-info.java create mode 100644 rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/package-info.java rename rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/{ => render}/LogMessageRender.java (90%) rename rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/{ => render}/impl/SimpleLogMessageRender.java (81%) create mode 100644 rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/package-info.java create mode 100644 rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/PatternLogMessageRender.java create mode 100644 rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/PatternRenderNodesParser.java create mode 100644 rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/DateTimePatternRenderNode.java create mode 100644 rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/LevelPatternRenderNode.java create mode 100644 rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/MessagePatternRenderNode.java create mode 100644 rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/PatternRenderNode.java create mode 100644 rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/ShortLoggerPatternRenderNode.java create mode 100644 rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/StringPatternRenderNode.java create mode 100644 rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/package-info.java create mode 100644 rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/package-info.java create mode 100644 rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/package-info.java create mode 100644 rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/loader/impl/PropertyLoggerConfigLoaderTest.java create mode 100644 rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/render/impl/pattern/PatternRenderNodesParserTest.java create mode 100644 rlib-logger-impl/src/test/resources/example-rlib.logger.properties create mode 100644 rlib-logger-impl/src/test/resources/property-loader-test-1.properties diff --git a/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/Logger.java b/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/Logger.java index 7dacd5ec..88410782 100644 --- a/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/Logger.java +++ b/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/Logger.java @@ -437,13 +437,27 @@ default boolean enabled(@NonNull LoggerLevel level) { return level.enabled(); } + /** + * Check of enabling the error level. + */ + default boolean errorEnabled() { + return enabled(LoggerLevel.ERROR); + } + /** * Check of enabling the warning level. */ - default boolean warningEnabled() { + default boolean warnEnabled() { return enabled(LoggerLevel.WARNING); } + /** + * Check of enabling the info level. + */ + default boolean infoEnabled() { + return enabled(LoggerLevel.INFO); + } + /** * Check of enabling the debug level. */ @@ -451,6 +465,13 @@ default boolean debugEnabled() { return enabled(LoggerLevel.DEBUG); } + /** + * Check of enabling the trace level. + */ + default boolean traceEnabled() { + return enabled(LoggerLevel.TRACE); + } + /** * Override the enabling status of the logger level. */ diff --git a/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/LoggerManager.java b/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/LoggerManager.java index 859e03cd..aa8cf36c 100644 --- a/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/LoggerManager.java +++ b/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/LoggerManager.java @@ -16,7 +16,7 @@ public class LoggerManager { static { - String className = System.getProperty("com.ss.rlib.logger.factory", ""); + String className = System.getProperty("javasabr.rlib.logger.factory", ""); Class implementation = null; if (!className.isEmpty()) { diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/DefaultLogger.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/DefaultLogger.java index 5e1a75c3..ce9b5d1f 100644 --- a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/DefaultLogger.java +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/DefaultLogger.java @@ -6,7 +6,7 @@ import javasabr.rlib.logger.api.Logger; import javasabr.rlib.logger.api.LoggerLevel; import javasabr.rlib.logger.api.LoggerService; -import javasabr.rlib.logger.impl.config.LogMessageConsumer; +import javasabr.rlib.logger.impl.config.consumer.LogMessageConsumer; import lombok.AccessLevel; import lombok.experimental.FieldDefaults; import org.jspecify.annotations.Nullable; diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/DefaultLoggerFactory.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/DefaultLoggerFactory.java index d532f2c3..263d0e9a 100644 --- a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/DefaultLoggerFactory.java +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/DefaultLoggerFactory.java @@ -3,7 +3,7 @@ import javasabr.rlib.logger.api.Logger; import javasabr.rlib.logger.api.LoggerFactory; import javasabr.rlib.logger.api.LoggerService; -import javasabr.rlib.logger.impl.config.LoggerConfigResolver; +import javasabr.rlib.logger.impl.config.loader.LoggerConfigResolver; import lombok.AccessLevel; import lombok.experimental.FieldDefaults; diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/DefaultLoggerService.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/DefaultLoggerService.java index 11c513e3..48221594 100644 --- a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/DefaultLoggerService.java +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/DefaultLoggerService.java @@ -8,8 +8,8 @@ import javasabr.rlib.logger.api.Logger; import javasabr.rlib.logger.api.LoggerLevel; import javasabr.rlib.logger.api.LoggerService; -import javasabr.rlib.logger.impl.config.LogMessageConsumer; import javasabr.rlib.logger.impl.config.LoggerConfig; +import javasabr.rlib.logger.impl.config.consumer.LogMessageConsumer; import lombok.AccessLevel; import lombok.experimental.FieldDefaults; diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/LoggerConfig.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/LoggerConfig.java index 833e8d43..4a126207 100644 --- a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/LoggerConfig.java +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/LoggerConfig.java @@ -3,6 +3,7 @@ import javasabr.rlib.collections.array.UnsafeArray; import javasabr.rlib.logger.api.Logger; import javasabr.rlib.logger.api.LoggerLevel; +import javasabr.rlib.logger.impl.config.consumer.LogMessageConsumer; /** * Configuration contract for logger levels and message consumers. diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/LogMessageConsumer.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/consumer/LogMessageConsumer.java similarity index 89% rename from rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/LogMessageConsumer.java rename to rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/consumer/LogMessageConsumer.java index c29c8f3c..ed6b6a02 100644 --- a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/LogMessageConsumer.java +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/consumer/LogMessageConsumer.java @@ -1,4 +1,4 @@ -package javasabr.rlib.logger.impl.config; +package javasabr.rlib.logger.impl.config.consumer; import javasabr.rlib.logger.api.Logger; import javasabr.rlib.logger.api.LoggerLevel; diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/impl/ConsoleMessageConsumer.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/consumer/impl/ConsoleMessageConsumer.java similarity index 78% rename from rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/impl/ConsoleMessageConsumer.java rename to rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/consumer/impl/ConsoleMessageConsumer.java index 08780274..81be6c05 100644 --- a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/impl/ConsoleMessageConsumer.java +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/consumer/impl/ConsoleMessageConsumer.java @@ -1,9 +1,9 @@ -package javasabr.rlib.logger.impl.config.impl; +package javasabr.rlib.logger.impl.config.consumer.impl; import javasabr.rlib.logger.api.Logger; import javasabr.rlib.logger.api.LoggerLevel; -import javasabr.rlib.logger.impl.config.LogMessageConsumer; -import javasabr.rlib.logger.impl.config.LogMessageRender; +import javasabr.rlib.logger.impl.config.consumer.LogMessageConsumer; +import javasabr.rlib.logger.impl.config.render.LogMessageRender; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; import lombok.experimental.FieldDefaults; diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/consumer/impl/package-info.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/consumer/impl/package-info.java new file mode 100644 index 00000000..9f143992 --- /dev/null +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/consumer/impl/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package javasabr.rlib.logger.impl.config.consumer.impl; + +import org.jspecify.annotations.NullMarked; diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/consumer/package-info.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/consumer/package-info.java new file mode 100644 index 00000000..40e7516e --- /dev/null +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/consumer/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package javasabr.rlib.logger.impl.config.consumer; + +import org.jspecify.annotations.NullMarked; diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/impl/DefaultLoggerConfig.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/impl/DefaultLoggerConfig.java index 36b7890f..19074272 100644 --- a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/impl/DefaultLoggerConfig.java +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/impl/DefaultLoggerConfig.java @@ -7,8 +7,8 @@ import javasabr.rlib.logger.api.Logger; import javasabr.rlib.logger.api.LoggerLevel; import javasabr.rlib.logger.impl.DefaultLoggerService; -import javasabr.rlib.logger.impl.config.LogMessageConsumer; import javasabr.rlib.logger.impl.config.LoggerConfig; +import javasabr.rlib.logger.impl.config.consumer.LogMessageConsumer; public class DefaultLoggerConfig implements LoggerConfig { diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/impl/LoggerConfigBuilder.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/impl/LoggerConfigBuilder.java new file mode 100644 index 00000000..7dbff13b --- /dev/null +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/impl/LoggerConfigBuilder.java @@ -0,0 +1,46 @@ +package javasabr.rlib.logger.impl.config.impl; + +import javasabr.rlib.collections.array.Array; +import javasabr.rlib.collections.array.ArrayFactory; +import javasabr.rlib.collections.array.MutableArray; +import javasabr.rlib.collections.dictionary.DictionaryFactory; +import javasabr.rlib.collections.dictionary.MutableRefToRefDictionary; +import javasabr.rlib.logger.api.LoggerLevel; +import javasabr.rlib.logger.impl.config.LoggerConfig; +import javasabr.rlib.logger.impl.config.consumer.LogMessageConsumer; +import javasabr.rlib.logger.impl.config.impl.DefaultLoggerConfig.LoggerConsumersKey; +import javasabr.rlib.logger.impl.config.render.LogMessageRender; + +public class LoggerConfigBuilder { + + final MutableRefToRefDictionary loggerLevels; + final MutableRefToRefDictionary renders; + final MutableRefToRefDictionary consumers; + final MutableRefToRefDictionary> loggerConsumers; + + public LoggerConfigBuilder() { + this.loggerLevels = DictionaryFactory.mutableRefToRefDictionary(); + this.renders = DictionaryFactory.mutableRefToRefDictionary(); + this.consumers = DictionaryFactory.mutableRefToRefDictionary(); + this.loggerConsumers = DictionaryFactory.mutableRefToRefDictionary(); + } + + public void registerLoggerLevel(String loggerName, LoggerLevel level) { + loggerLevels.put(loggerName, level); + } + + public void registerLoggerConsumer(String loggerName, LoggerLevel level, LogMessageConsumer consumer) { + var key = new LoggerConsumersKey(loggerName, level); + loggerConsumers + .getOrCompute(key, () -> ArrayFactory.mutableArray(LogMessageConsumer.class)) + .add(consumer); + } + + public LoggerConfig build() { + var tempDictionary = DictionaryFactory + .>mutableRefToRefDictionary(); + loggerConsumers.forEach((key, consumers) -> + tempDictionary.put(key, Array.copyOf(consumers))); + return new DefaultLoggerConfig(loggerLevels.toReadOnly(), tempDictionary.toReadOnly()); + } +} diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/LoggerConfigLoader.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/LoggerConfigLoader.java similarity index 69% rename from rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/LoggerConfigLoader.java rename to rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/LoggerConfigLoader.java index e9bff195..702ddd1c 100644 --- a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/LoggerConfigLoader.java +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/LoggerConfigLoader.java @@ -1,6 +1,7 @@ -package javasabr.rlib.logger.impl.config; +package javasabr.rlib.logger.impl.config.loader; import java.util.Optional; +import javasabr.rlib.logger.impl.config.LoggerConfig; /** * Loader of logger configuration. @@ -9,6 +10,10 @@ */ public interface LoggerConfigLoader { + int ORDER_NORMAL = 100; + int ORDER_LOW = 1000; + int ORDER_HIGH = 0; + /** * Tries to load logger configuration. * diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/LoggerConfigLoadersProvider.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/LoggerConfigLoadersProvider.java new file mode 100644 index 00000000..56a815e2 --- /dev/null +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/LoggerConfigLoadersProvider.java @@ -0,0 +1,8 @@ +package javasabr.rlib.logger.impl.config.loader; + +import javasabr.rlib.collections.array.Array; + +public interface LoggerConfigLoadersProvider { + + Array getLoggerConfigLoaders(); +} diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/LoggerConfigResolver.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/LoggerConfigResolver.java similarity index 82% rename from rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/LoggerConfigResolver.java rename to rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/LoggerConfigResolver.java index 1ddf7a5b..8754f7a5 100644 --- a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/LoggerConfigResolver.java +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/LoggerConfigResolver.java @@ -1,10 +1,11 @@ -package javasabr.rlib.logger.impl.config; +package javasabr.rlib.logger.impl.config.loader; import java.util.Comparator; import java.util.Optional; import javasabr.rlib.collections.array.Array; import javasabr.rlib.collections.array.ArrayCollectors; -import javasabr.rlib.logger.impl.config.impl.DefaultLoggerConfigLoader; +import javasabr.rlib.logger.impl.config.LoggerConfig; +import javasabr.rlib.logger.impl.config.loader.impl.DefaultLoggerConfigLoader; /** * Resolver of logger configuration from available loaders. diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/impl/DefaultLoggerConfigLoader.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/impl/DefaultLoggerConfigLoader.java similarity index 72% rename from rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/impl/DefaultLoggerConfigLoader.java rename to rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/impl/DefaultLoggerConfigLoader.java index 659f7e48..725bad75 100644 --- a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/impl/DefaultLoggerConfigLoader.java +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/impl/DefaultLoggerConfigLoader.java @@ -1,14 +1,17 @@ -package javasabr.rlib.logger.impl.config.impl; +package javasabr.rlib.logger.impl.config.loader.impl; import java.util.Optional; import javasabr.rlib.collections.array.Array; import javasabr.rlib.collections.dictionary.RefToRefDictionary; import javasabr.rlib.logger.api.LoggerLevel; import javasabr.rlib.logger.impl.DefaultLoggerService; -import javasabr.rlib.logger.impl.config.LogMessageConsumer; import javasabr.rlib.logger.impl.config.LoggerConfig; -import javasabr.rlib.logger.impl.config.LoggerConfigLoader; +import javasabr.rlib.logger.impl.config.consumer.LogMessageConsumer; +import javasabr.rlib.logger.impl.config.consumer.impl.ConsoleMessageConsumer; +import javasabr.rlib.logger.impl.config.impl.DefaultLoggerConfig; import javasabr.rlib.logger.impl.config.impl.DefaultLoggerConfig.LoggerConsumersKey; +import javasabr.rlib.logger.impl.config.loader.LoggerConfigLoader; +import javasabr.rlib.logger.impl.config.render.impl.SimpleLogMessageRender; public class DefaultLoggerConfigLoader implements LoggerConfigLoader { @@ -17,11 +20,9 @@ public Optional tryToLoad() { RefToRefDictionary loggerLevels = RefToRefDictionary.of( DefaultLoggerService.ROOT_LOGGER_NAME, LoggerLevel.INFO); - RefToRefDictionary> loggerConsumers = RefToRefDictionary.of( DefaultLoggerConfig.ROOT_INFO_CONSUMERS_KEY, Array.of(new ConsoleMessageConsumer(new SimpleLogMessageRender()))); - return Optional.of(new DefaultLoggerConfig(loggerLevels, loggerConsumers)); } diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/impl/PropertyLoggerConfigLoader.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/impl/PropertyLoggerConfigLoader.java new file mode 100644 index 00000000..18bfce95 --- /dev/null +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/impl/PropertyLoggerConfigLoader.java @@ -0,0 +1,79 @@ +package javasabr.rlib.logger.impl.config.loader.impl; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Optional; +import java.util.Properties; +import javasabr.rlib.logger.api.LoggerLevel; +import javasabr.rlib.logger.impl.DefaultLoggerService; +import javasabr.rlib.logger.impl.config.LoggerConfig; +import javasabr.rlib.logger.impl.config.consumer.impl.ConsoleMessageConsumer; +import javasabr.rlib.logger.impl.config.impl.LoggerConfigBuilder; +import javasabr.rlib.logger.impl.config.loader.LoggerConfigLoader; +import javasabr.rlib.logger.impl.config.render.LogMessageRender; +import javasabr.rlib.logger.impl.config.render.impl.SimpleLogMessageRender; +import javasabr.rlib.logger.impl.config.render.impl.pattern.PatternLogMessageRender; + +public class PropertyLoggerConfigLoader implements LoggerConfigLoader { + + public static final String FILE_MAIN = "/rlib.logger.properties"; + public static final String FILE_TEST = "/rlib.logger-test.properties"; + + @Override + public Optional tryToLoad() { + ClassLoader classLoader = Thread + .currentThread() + .getContextClassLoader(); + InputStream propertiesStream = classLoader.getResourceAsStream(FILE_TEST); + if (propertiesStream == null) { + propertiesStream = classLoader.getResourceAsStream(FILE_MAIN); + } + if (propertiesStream == null) { + return Optional.empty(); + } + Properties properties = new Properties(); + try { + properties.load(propertiesStream); + } catch (IOException ex) { + ex.printStackTrace(); + return Optional.empty(); + } finally { + try { + propertiesStream.close(); + } catch (IOException ex) { + ex.printStackTrace(); + } + } + LoggerConfig loggerConfig = loadFromProperties(properties); + properties.clear(); + return Optional.of(loggerConfig); + } + + LoggerConfig loadFromProperties(Properties properties) { + var builder = new LoggerConfigBuilder(); + LogMessageRender messageRender = null; + for (Object key : properties.keySet()) { + String stringKey = (String) key; + if (stringKey.startsWith("logger.level.")) { + LoggerLevel level = LoggerLevel.valueOf(properties.getProperty(stringKey)); + String loggerName = stringKey.substring("logger.level.".length()); + builder.registerLoggerLevel(loggerName, level); + } else if (stringKey.equals("logger.message.pattern")) { + messageRender = new PatternLogMessageRender(properties.getProperty(stringKey)); + } + } + if (messageRender == null) { + messageRender = new SimpleLogMessageRender(); + } + builder.registerLoggerConsumer( + DefaultLoggerService.ROOT_LOGGER_NAME, + LoggerLevel.TRACE, + new ConsoleMessageConsumer(messageRender)); + return builder.build(); + } + + @Override + public int order() { + return LoggerConfigLoader.ORDER_NORMAL; + } +} diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/impl/package-info.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/impl/package-info.java new file mode 100644 index 00000000..2c2cc3d6 --- /dev/null +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/impl/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package javasabr.rlib.logger.impl.config.loader.impl; + +import org.jspecify.annotations.NullMarked; diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/package-info.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/package-info.java new file mode 100644 index 00000000..a52efece --- /dev/null +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package javasabr.rlib.logger.impl.config.loader; + +import org.jspecify.annotations.NullMarked; diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/LogMessageRender.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/LogMessageRender.java similarity index 90% rename from rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/LogMessageRender.java rename to rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/LogMessageRender.java index 285430e9..696adde1 100644 --- a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/LogMessageRender.java +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/LogMessageRender.java @@ -1,4 +1,4 @@ -package javasabr.rlib.logger.impl.config; +package javasabr.rlib.logger.impl.config.render; import javasabr.rlib.logger.api.Logger; import javasabr.rlib.logger.api.LoggerLevel; diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/impl/SimpleLogMessageRender.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/SimpleLogMessageRender.java similarity index 81% rename from rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/impl/SimpleLogMessageRender.java rename to rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/SimpleLogMessageRender.java index ea5705a7..003eeb07 100644 --- a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/impl/SimpleLogMessageRender.java +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/SimpleLogMessageRender.java @@ -1,10 +1,10 @@ -package javasabr.rlib.logger.impl.config.impl; +package javasabr.rlib.logger.impl.config.render.impl; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import javasabr.rlib.logger.api.Logger; import javasabr.rlib.logger.api.LoggerLevel; -import javasabr.rlib.logger.impl.config.LogMessageRender; +import javasabr.rlib.logger.impl.config.render.LogMessageRender; import lombok.AccessLevel; import lombok.experimental.FieldDefaults; @@ -20,9 +20,9 @@ public SimpleLogMessageRender() { @Override public String render(LoggerLevel level, Logger logger, String message) { var timestamp = timeFormatter.format(LocalDateTime.now()); - return level.title() + return timestamp + ' ' + + level.title() + level.offset() + ' ' - + timestamp + ' ' + logger.shortName() + ": " + message; } diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/package-info.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/package-info.java new file mode 100644 index 00000000..9ee0d1ef --- /dev/null +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package javasabr.rlib.logger.impl.config.render.impl; + +import org.jspecify.annotations.NullMarked; diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/PatternLogMessageRender.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/PatternLogMessageRender.java new file mode 100644 index 00000000..5e2e8fe7 --- /dev/null +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/PatternLogMessageRender.java @@ -0,0 +1,37 @@ +package javasabr.rlib.logger.impl.config.render.impl.pattern; + +import javasabr.rlib.collections.array.UnsafeArray; +import javasabr.rlib.logger.api.Logger; +import javasabr.rlib.logger.api.LoggerLevel; +import javasabr.rlib.logger.impl.config.render.LogMessageRender; +import javasabr.rlib.logger.impl.config.render.impl.pattern.node.PatternRenderNode; +import lombok.AccessLevel; +import lombok.experimental.FieldDefaults; + +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) +public class PatternLogMessageRender implements LogMessageRender { + + UnsafeArray renderNodes; + int initBufferSize; + + public PatternLogMessageRender(String pattern) { + this(pattern, 256); + } + + public PatternLogMessageRender(String pattern, int initBufferSize) { + this.initBufferSize = initBufferSize; + this.renderNodes = PatternRenderNodesParser + .parse(pattern) + .asUnsafe(); + } + + @Override + public String render(LoggerLevel level, Logger logger, String message) { + var buffer = new StringBuilder(initBufferSize); + for (PatternRenderNode renderNode : renderNodes.wrapped()) { + //noinspection DataFlowIssue + renderNode.append(level, logger, message, buffer); + } + return buffer.toString(); + } +} diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/PatternRenderNodesParser.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/PatternRenderNodesParser.java new file mode 100644 index 00000000..a9e8cf3b --- /dev/null +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/PatternRenderNodesParser.java @@ -0,0 +1,89 @@ +package javasabr.rlib.logger.impl.config.render.impl.pattern; + +import javasabr.rlib.collections.array.Array; +import javasabr.rlib.collections.array.ArrayFactory; +import javasabr.rlib.logger.impl.config.render.impl.pattern.node.DateTimePatternRenderNode; +import javasabr.rlib.logger.impl.config.render.impl.pattern.node.LevelPatternRenderNode; +import javasabr.rlib.logger.impl.config.render.impl.pattern.node.MessagePatternRenderNode; +import javasabr.rlib.logger.impl.config.render.impl.pattern.node.PatternRenderNode; +import javasabr.rlib.logger.impl.config.render.impl.pattern.node.ShortLoggerPatternRenderNode; +import javasabr.rlib.logger.impl.config.render.impl.pattern.node.StringPatternRenderNode; + +public class PatternRenderNodesParser { + + public static Array parse(String pattern) { + var parsedNodes = ArrayFactory.mutableArray(PatternRenderNode.class); + var stringBuffer = new StringBuilder(); + for(int i = 0, length = pattern.length(); i < length; i++) { + char nextChar = pattern.charAt(i); + if (nextChar != '%') { + stringBuffer.append(nextChar); + continue; + } + if (!stringBuffer.isEmpty()) { + parsedNodes.add(new StringPatternRenderNode(stringBuffer.toString())); + stringBuffer.setLength(0); + } + var nodeName = resolveNodeName(pattern, i + 1); + var afterNameIndex = i + 1 + nodeName.length(); + ParsedNode parsedNode = parse(nodeName, pattern, afterNameIndex); + parsedNodes.add(parsedNode.renderNode); + i = parsedNode.finishedIndex - 1; + } + if (!stringBuffer.isEmpty()) { + parsedNodes.add(new StringPatternRenderNode(stringBuffer.toString())); + stringBuffer.setLength(0); + } + return Array.copyOf(parsedNodes); + } + + private static String resolveNodeName(String pattern, int startIndex) { + var result = new StringBuilder(); + for (int i = startIndex, length = pattern.length(); i < length; i++) { + char nextChar = pattern.charAt(i); + if (nextChar == '{' || nextChar == ' ' || nextChar == '\t') { + return result.toString(); + } + result.append(nextChar); + } + return result.toString(); + } + + private static ParsedNode parse(String nodeName, String pattern, int afterNameIndex) { + return switch (nodeName) { + case LevelPatternRenderNode.NODE_NAME -> new ParsedNode(new LevelPatternRenderNode(), afterNameIndex); + case MessagePatternRenderNode.NODE_NAME -> new ParsedNode(new MessagePatternRenderNode(), afterNameIndex); + case ShortLoggerPatternRenderNode.NODE_NAME -> new ParsedNode(new ShortLoggerPatternRenderNode(), afterNameIndex); + case DateTimePatternRenderNode.NODE_NAME -> { + var dateTimePattern = extractArgumentsString(pattern, afterNameIndex); + int finishedIndex = afterNameIndex + dateTimePattern.length() + 2; + yield new ParsedNode(new DateTimePatternRenderNode(dateTimePattern), finishedIndex); + } + default -> throw new IllegalArgumentException("Unexpected node name:[%s]".formatted(nodeName)); + }; + } + + private static String extractArgumentsString(String pattern, int afterNameIndex) { + if (pattern.charAt(afterNameIndex) != '{') { + throw new IllegalArgumentException("Missed '{' at position:[%d] in pattern:[%s]" + .formatted(afterNameIndex, pattern)); + } + var result = new StringBuilder(); + int closingBraceIndex = -1; + for (int i = afterNameIndex + 1, length = pattern.length(); i < length; i++) { + char nextChar = pattern.charAt(i); + if (nextChar == '}') { + closingBraceIndex = i; + break; + } + result.append(nextChar); + } + if (closingBraceIndex < 0) { + throw new IllegalArgumentException("Missed closing '}' in pattern:[%s]" + .formatted(pattern)); + } + return result.toString(); + } + + private record ParsedNode(PatternRenderNode renderNode, int finishedIndex) {} +} diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/DateTimePatternRenderNode.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/DateTimePatternRenderNode.java new file mode 100644 index 00000000..c82eac1f --- /dev/null +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/DateTimePatternRenderNode.java @@ -0,0 +1,29 @@ +package javasabr.rlib.logger.impl.config.render.impl.pattern.node; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import javasabr.rlib.logger.api.Logger; +import javasabr.rlib.logger.api.LoggerLevel; +import lombok.AccessLevel; +import lombok.EqualsAndHashCode; +import lombok.experimental.FieldDefaults; + +@EqualsAndHashCode(of = "pattern") +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) +public class DateTimePatternRenderNode implements PatternRenderNode { + + public static final String NODE_NAME = "dateTime"; + + String pattern; + DateTimeFormatter formatter; + + public DateTimePatternRenderNode(String pattern) { + this.formatter = DateTimeFormatter.ofPattern(pattern); + this.pattern = pattern; + } + + @Override + public void append(LoggerLevel level, Logger logger, String message, StringBuilder buffer) { + buffer.append(formatter.format(LocalDateTime.now())); + } +} diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/LevelPatternRenderNode.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/LevelPatternRenderNode.java new file mode 100644 index 00000000..d70697c7 --- /dev/null +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/LevelPatternRenderNode.java @@ -0,0 +1,19 @@ +package javasabr.rlib.logger.impl.config.render.impl.pattern.node; + +import javasabr.rlib.logger.api.Logger; +import javasabr.rlib.logger.api.LoggerLevel; +import lombok.AccessLevel; +import lombok.experimental.FieldDefaults; + +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) +public class LevelPatternRenderNode implements PatternRenderNode { + + public static final String NODE_NAME = "level"; + + @Override + public void append(LoggerLevel level, Logger logger, String message, StringBuilder buffer) { + buffer + .append(level.title()) + .append(level.offset()); + } +} diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/MessagePatternRenderNode.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/MessagePatternRenderNode.java new file mode 100644 index 00000000..f1bc17c0 --- /dev/null +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/MessagePatternRenderNode.java @@ -0,0 +1,17 @@ +package javasabr.rlib.logger.impl.config.render.impl.pattern.node; + +import javasabr.rlib.logger.api.Logger; +import javasabr.rlib.logger.api.LoggerLevel; +import lombok.AccessLevel; +import lombok.experimental.FieldDefaults; + +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) +public class MessagePatternRenderNode implements PatternRenderNode { + + public static final String NODE_NAME = "msg"; + + @Override + public void append(LoggerLevel level, Logger logger, String message, StringBuilder buffer) { + buffer.append(message); + } +} diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/PatternRenderNode.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/PatternRenderNode.java new file mode 100644 index 00000000..f3b982aa --- /dev/null +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/PatternRenderNode.java @@ -0,0 +1,9 @@ +package javasabr.rlib.logger.impl.config.render.impl.pattern.node; + +import javasabr.rlib.logger.api.Logger; +import javasabr.rlib.logger.api.LoggerLevel; + +public interface PatternRenderNode { + + void append(LoggerLevel level, Logger logger, String message, StringBuilder buffer); +} diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/ShortLoggerPatternRenderNode.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/ShortLoggerPatternRenderNode.java new file mode 100644 index 00000000..1e42149f --- /dev/null +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/ShortLoggerPatternRenderNode.java @@ -0,0 +1,17 @@ +package javasabr.rlib.logger.impl.config.render.impl.pattern.node; + +import javasabr.rlib.logger.api.Logger; +import javasabr.rlib.logger.api.LoggerLevel; +import lombok.AccessLevel; +import lombok.experimental.FieldDefaults; + +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) +public class ShortLoggerPatternRenderNode implements PatternRenderNode { + + public static final String NODE_NAME = "shortLogger"; + + @Override + public void append(LoggerLevel level, Logger logger, String message, StringBuilder buffer) { + buffer.append(logger.shortName()); + } +} diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/StringPatternRenderNode.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/StringPatternRenderNode.java new file mode 100644 index 00000000..300478c2 --- /dev/null +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/StringPatternRenderNode.java @@ -0,0 +1,21 @@ +package javasabr.rlib.logger.impl.config.render.impl.pattern.node; + +import javasabr.rlib.logger.api.Logger; +import javasabr.rlib.logger.api.LoggerLevel; +import lombok.AccessLevel; +import lombok.EqualsAndHashCode; +import lombok.RequiredArgsConstructor; +import lombok.experimental.FieldDefaults; + +@EqualsAndHashCode +@RequiredArgsConstructor +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) +public class StringPatternRenderNode implements PatternRenderNode { + + String string; + + @Override + public void append(LoggerLevel level, Logger logger, String message, StringBuilder buffer) { + buffer.append(string); + } +} diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/package-info.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/package-info.java new file mode 100644 index 00000000..bfbc7838 --- /dev/null +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package javasabr.rlib.logger.impl.config.render.impl.pattern.node; + +import org.jspecify.annotations.NullMarked; diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/package-info.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/package-info.java new file mode 100644 index 00000000..d4ab06ee --- /dev/null +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package javasabr.rlib.logger.impl.config.render.impl.pattern; + +import org.jspecify.annotations.NullMarked; diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/package-info.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/package-info.java new file mode 100644 index 00000000..4d14873b --- /dev/null +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package javasabr.rlib.logger.impl.config.render; + +import org.jspecify.annotations.NullMarked; diff --git a/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/DefaultLoggerTest.java b/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/DefaultLoggerTest.java index 70f5c333..8a1d5ac9 100644 --- a/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/DefaultLoggerTest.java +++ b/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/DefaultLoggerTest.java @@ -9,7 +9,7 @@ import javasabr.rlib.logger.api.Logger; import javasabr.rlib.logger.api.LoggerLevel; import javasabr.rlib.logger.api.LoggerManager; -import javasabr.rlib.logger.impl.config.LogMessageConsumer; +import javasabr.rlib.logger.impl.config.consumer.LogMessageConsumer; import javasabr.rlib.logger.impl.config.impl.DefaultLoggerConfig; import javasabr.rlib.logger.impl.config.impl.DefaultLoggerConfig.LoggerConsumersKey; import org.junit.jupiter.api.AfterEach; diff --git a/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/loader/impl/PropertyLoggerConfigLoaderTest.java b/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/loader/impl/PropertyLoggerConfigLoaderTest.java new file mode 100644 index 00000000..a36c9fa0 --- /dev/null +++ b/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/loader/impl/PropertyLoggerConfigLoaderTest.java @@ -0,0 +1,103 @@ +package javasabr.rlib.logger.impl.config.loader.impl; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.IOException; +import java.util.Properties; +import javasabr.rlib.collections.array.Array; +import javasabr.rlib.collections.array.UnsafeArray; +import javasabr.rlib.logger.api.Logger; +import javasabr.rlib.logger.api.LoggerLevel; +import javasabr.rlib.logger.impl.DefaultLogger; +import javasabr.rlib.logger.impl.DefaultLoggerService; +import javasabr.rlib.logger.impl.config.LoggerConfig; +import javasabr.rlib.logger.impl.config.consumer.LogMessageConsumer; +import javasabr.rlib.logger.impl.config.consumer.impl.ConsoleMessageConsumer; +import javasabr.rlib.logger.impl.config.impl.DefaultLoggerConfig; +import javasabr.rlib.logger.impl.config.render.impl.pattern.PatternLogMessageRender; +import javasabr.rlib.logger.impl.config.render.impl.pattern.node.DateTimePatternRenderNode; +import javasabr.rlib.logger.impl.config.render.impl.pattern.node.LevelPatternRenderNode; +import javasabr.rlib.logger.impl.config.render.impl.pattern.node.MessagePatternRenderNode; +import javasabr.rlib.logger.impl.config.render.impl.pattern.node.PatternRenderNode; +import javasabr.rlib.logger.impl.config.render.impl.pattern.node.StringPatternRenderNode; +import org.junit.jupiter.api.Test; + +public class PropertyLoggerConfigLoaderTest { + + @Test + void shouldLoadLoggerConfigCorrectly() throws IOException { + // given: + var loader = new PropertyLoggerConfigLoader(); + var in = PropertyLoggerConfigLoaderTest.class.getResourceAsStream("/property-loader-test-1.properties"); + var properties = new Properties(); + properties.load(in); + + // when: + LoggerConfig loggerConfig = loader.loadFromProperties(properties); + + // then: + assertThat(loggerConfig) + .isInstanceOf(DefaultLoggerConfig.class); + + // when: + var defaultLoggerConfig = (DefaultLoggerConfig) loggerConfig; + var loggerService = new DefaultLoggerService(loggerConfig); + DefaultLogger logger = loggerService.getLogger( + "javasabr.rlib.logger.impl.config.loader.impl.PropertyLoggerConfigLoaderTest"); + UnsafeArray consumers = defaultLoggerConfig.resolveConsumers( + logger, + LoggerLevel.TRACE); + + // then: + assertThat(consumers.size()) + .isEqualTo(1); + assertThat(consumers.get(0)) + .isInstanceOf(ConsoleMessageConsumer.class) + .extracting("logMessageRender") + .isInstanceOf(PatternLogMessageRender.class) + .extracting("renderNodes") + .extracting(object -> (UnsafeArray) object) + .returns(5, Array::size) + .returns(new DateTimePatternRenderNode("d.MM.yyyy HH:mm:ss:SSS"), nodes -> nodes.get(0)) + .returns(new StringPatternRenderNode(" "), nodes -> nodes.get(1)) + .returns(LevelPatternRenderNode.class, nodes -> nodes.get(2).getClass()) + .returns(new StringPatternRenderNode(" : "), nodes -> nodes.get(3)) + .returns(MessagePatternRenderNode.class, nodes -> nodes.get(4).getClass()); + + // when: + DefaultLogger loggerA = loggerService.getLogger( + "javasabr.rlib.logger.impl.config.loader.impl.PropertyLoggerConfigLoaderTest.A"); + DefaultLogger loggerB = loggerService.getLogger( + "javasabr.rlib.logger.impl.config.loader.impl.PropertyLoggerConfigLoaderTest.B"); + DefaultLogger loggerC = loggerService.getLogger( + "javasabr.rlib.logger.impl.config.loader.impl.PropertyLoggerConfigLoaderTest.C"); + DefaultLogger loggerD = loggerService.getLogger( + "javasabr.rlib.logger.impl.config.loader.impl.PropertyLoggerConfigLoaderTest.D"); + + // then: + assertThat(loggerA) + .returns(false, Logger::traceEnabled) + .returns(false, Logger::debugEnabled) + .returns(true, Logger::infoEnabled) + .returns(true, Logger::warnEnabled) + .returns(true, Logger::errorEnabled); + assertThat(loggerB) + .returns(false, Logger::traceEnabled) + .returns(true, Logger::debugEnabled) + .returns(true, Logger::infoEnabled) + .returns(true, Logger::warnEnabled) + .returns(true, Logger::errorEnabled); + assertThat(loggerC) + .returns(true, Logger::traceEnabled) + .returns(true, Logger::debugEnabled) + .returns(true, Logger::infoEnabled) + .returns(true, Logger::warnEnabled) + .returns(true, Logger::errorEnabled); + assertThat(loggerD) + .returns(false, Logger::traceEnabled) + .returns(false, Logger::debugEnabled) + .returns(false, Logger::infoEnabled) + .returns(false, Logger::warnEnabled) + .returns(true, Logger::errorEnabled); + } +} diff --git a/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/render/impl/pattern/PatternRenderNodesParserTest.java b/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/render/impl/pattern/PatternRenderNodesParserTest.java new file mode 100644 index 00000000..33ff3b57 --- /dev/null +++ b/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/render/impl/pattern/PatternRenderNodesParserTest.java @@ -0,0 +1,48 @@ +package javasabr.rlib.logger.impl.config.render.impl.pattern; + +import static org.assertj.core.api.Assertions.assertThat; + +import javasabr.rlib.collections.array.Array; +import javasabr.rlib.logger.impl.config.render.impl.pattern.node.DateTimePatternRenderNode; +import javasabr.rlib.logger.impl.config.render.impl.pattern.node.LevelPatternRenderNode; +import javasabr.rlib.logger.impl.config.render.impl.pattern.node.MessagePatternRenderNode; +import javasabr.rlib.logger.impl.config.render.impl.pattern.node.PatternRenderNode; +import javasabr.rlib.logger.impl.config.render.impl.pattern.node.ShortLoggerPatternRenderNode; +import javasabr.rlib.logger.impl.config.render.impl.pattern.node.StringPatternRenderNode; +import org.junit.jupiter.api.Test; + +public class PatternRenderNodesParserTest { + + @Test + void shouldParseCorrectlyPattern1() { + // given: + var pattern = " %dateTime{d.MM.yyyy HH:mm:ss:SSS} %level %shortLogger : %msg"; + + // when: + Array parsed = PatternRenderNodesParser.parse(pattern); + + // then: + assertThat(parsed.size()).isEqualTo(8); + assertThat(parsed.get(0)) + .isInstanceOf(StringPatternRenderNode.class) + .isEqualTo(new StringPatternRenderNode(" ")); + assertThat(parsed.get(1)) + .isInstanceOf(DateTimePatternRenderNode.class) + .isEqualTo(new DateTimePatternRenderNode("d.MM.yyyy HH:mm:ss:SSS")); + assertThat(parsed.get(2)) + .isInstanceOf(StringPatternRenderNode.class) + .isEqualTo(new StringPatternRenderNode(" ")); + assertThat(parsed.get(3)) + .isInstanceOf(LevelPatternRenderNode.class); + assertThat(parsed.get(4)) + .isInstanceOf(StringPatternRenderNode.class) + .isEqualTo(new StringPatternRenderNode(" ")); + assertThat(parsed.get(5)) + .isInstanceOf(ShortLoggerPatternRenderNode.class); + assertThat(parsed.get(6)) + .isInstanceOf(StringPatternRenderNode.class) + .isEqualTo(new StringPatternRenderNode(" : ")); + assertThat(parsed.get(7)) + .isInstanceOf(MessagePatternRenderNode.class); + } +} diff --git a/rlib-logger-impl/src/test/resources/example-rlib.logger.properties b/rlib-logger-impl/src/test/resources/example-rlib.logger.properties new file mode 100644 index 00000000..6aea4b90 --- /dev/null +++ b/rlib-logger-impl/src/test/resources/example-rlib.logger.properties @@ -0,0 +1,4 @@ +logger.level.example.logger.1=INFO +logger.level.example.logger.2=DEBUG +logger.level.ROOT=WARNING +logger.message.pattern=%dateTime{d.MM.yyyy HH:mm:ss:SSS} %level %shortLogger : %msg diff --git a/rlib-logger-impl/src/test/resources/property-loader-test-1.properties b/rlib-logger-impl/src/test/resources/property-loader-test-1.properties new file mode 100644 index 00000000..27e094ca --- /dev/null +++ b/rlib-logger-impl/src/test/resources/property-loader-test-1.properties @@ -0,0 +1,6 @@ +logger.level.javasabr.rlib.logger.impl.config.loader.impl.PropertyLoggerConfigLoaderTest.A=INFO +logger.level.javasabr.rlib.logger.impl.config.loader.impl.PropertyLoggerConfigLoaderTest.B=DEBUG +logger.level.javasabr.rlib.logger.impl.config.loader.impl.PropertyLoggerConfigLoaderTest.C=TRACE +logger.level.javasabr.rlib.logger.impl.config.loader.impl.PropertyLoggerConfigLoaderTest.D=ERROR +logger.level.ROOT=WARNING +logger.message.pattern=%dateTime{d.MM.yyyy HH:mm:ss:SSS} %level : %msg diff --git a/rlib-logger-slf4j-impl/src/test/java/javasabr/rlib/logger/slf4j/impl/Slf4jLoggerImplTest.java b/rlib-logger-slf4j-impl/src/test/java/javasabr/rlib/logger/slf4j/impl/Slf4jLoggerImplTest.java index 412538d2..a6528c63 100644 --- a/rlib-logger-slf4j-impl/src/test/java/javasabr/rlib/logger/slf4j/impl/Slf4jLoggerImplTest.java +++ b/rlib-logger-slf4j-impl/src/test/java/javasabr/rlib/logger/slf4j/impl/Slf4jLoggerImplTest.java @@ -9,7 +9,7 @@ import javasabr.rlib.logger.api.Logger; import javasabr.rlib.logger.api.LoggerLevel; import javasabr.rlib.logger.impl.DefaultLoggerService; -import javasabr.rlib.logger.impl.config.LogMessageConsumer; +import javasabr.rlib.logger.impl.config.consumer.LogMessageConsumer; import javasabr.rlib.logger.impl.config.impl.DefaultLoggerConfig; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacket.java index 88f91dab..54cfb9d7 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacket.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacket.java @@ -20,7 +20,7 @@ public abstract class AbstractNetworkPacket> implements */ protected void handleException(C connection, ByteBuffer buffer, Exception exception) { log.warn(exception); - if (!log.warningEnabled()) { + if (!log.warnEnabled()) { return; } From 705ee444bcb97b4e5cf59aed3cce47613b9a5a7a Mon Sep 17 00:00:00 2001 From: javasabr Date: Sun, 7 Jun 2026 12:39:38 +0200 Subject: [PATCH 2/4] extend tests --- .../config/loader/LoggerConfigResolver.java | 21 +- .../impl/PropertyLoggerConfigLoader.java | 4 +- .../impl/PropertyLoggerConfigLoaderTest.java | 192 ++++++++++++++++++ .../pattern/PatternRenderNodesParserTest.java | 96 +++++++++ 4 files changed, 306 insertions(+), 7 deletions(-) diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/LoggerConfigResolver.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/LoggerConfigResolver.java index 8754f7a5..1e363748 100644 --- a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/LoggerConfigResolver.java +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/LoggerConfigResolver.java @@ -2,10 +2,13 @@ import java.util.Comparator; import java.util.Optional; +import java.util.ServiceLoader; import javasabr.rlib.collections.array.Array; import javasabr.rlib.collections.array.ArrayCollectors; +import javasabr.rlib.collections.array.ArrayFactory; import javasabr.rlib.logger.impl.config.LoggerConfig; import javasabr.rlib.logger.impl.config.loader.impl.DefaultLoggerConfigLoader; +import javasabr.rlib.logger.impl.config.loader.impl.PropertyLoggerConfigLoader; /** * Resolver of logger configuration from available loaders. @@ -14,12 +17,20 @@ */ public class LoggerConfigResolver { - private static final Array LOADERS = Array - .of(new DefaultLoggerConfigLoader()) - .stream() - .sorted(Comparator.comparingInt(LoggerConfigLoader::order)) - .collect(ArrayCollectors.toArray(LoggerConfigLoader.class)); + private static final Array LOADERS; + static { + var registeredProviders = ArrayFactory.mutableArray(LoggerConfigLoader.class); + registeredProviders.add(new DefaultLoggerConfigLoader()); + registeredProviders.add(new PropertyLoggerConfigLoader()); + for (var provider : ServiceLoader.load(LoggerConfigLoadersProvider.class)) { + registeredProviders.addAll(provider.getLoggerConfigLoaders()); + } + LOADERS = registeredProviders.stream() + .sorted(Comparator.comparingInt(LoggerConfigLoader::order)) + .collect(ArrayCollectors.toArray(LoggerConfigLoader.class)); + } + /** * Loads logger configuration. * diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/impl/PropertyLoggerConfigLoader.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/impl/PropertyLoggerConfigLoader.java index 18bfce95..b14b64be 100644 --- a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/impl/PropertyLoggerConfigLoader.java +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/impl/PropertyLoggerConfigLoader.java @@ -16,8 +16,8 @@ public class PropertyLoggerConfigLoader implements LoggerConfigLoader { - public static final String FILE_MAIN = "/rlib.logger.properties"; - public static final String FILE_TEST = "/rlib.logger-test.properties"; + public static final String FILE_MAIN = "rlib.logger.properties"; + public static final String FILE_TEST = "rlib.logger-test.properties"; @Override public Optional tryToLoad() { diff --git a/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/loader/impl/PropertyLoggerConfigLoaderTest.java b/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/loader/impl/PropertyLoggerConfigLoaderTest.java index a36c9fa0..8aa197a6 100644 --- a/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/loader/impl/PropertyLoggerConfigLoaderTest.java +++ b/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/loader/impl/PropertyLoggerConfigLoaderTest.java @@ -1,9 +1,17 @@ package javasabr.rlib.logger.impl.config.loader.impl; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import java.io.ByteArrayInputStream; import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.Map; +import java.util.Optional; import java.util.Properties; +import java.util.function.Supplier; +import java.util.stream.Collectors; import javasabr.rlib.collections.array.Array; import javasabr.rlib.collections.array.UnsafeArray; import javasabr.rlib.logger.api.Logger; @@ -14,6 +22,7 @@ import javasabr.rlib.logger.impl.config.consumer.LogMessageConsumer; import javasabr.rlib.logger.impl.config.consumer.impl.ConsoleMessageConsumer; import javasabr.rlib.logger.impl.config.impl.DefaultLoggerConfig; +import javasabr.rlib.logger.impl.config.render.impl.SimpleLogMessageRender; import javasabr.rlib.logger.impl.config.render.impl.pattern.PatternLogMessageRender; import javasabr.rlib.logger.impl.config.render.impl.pattern.node.DateTimePatternRenderNode; import javasabr.rlib.logger.impl.config.render.impl.pattern.node.LevelPatternRenderNode; @@ -100,4 +109,187 @@ void shouldLoadLoggerConfigCorrectly() throws IOException { .returns(false, Logger::warnEnabled) .returns(true, Logger::errorEnabled); } + + @Test + void shouldPreferTestPropertiesOverMainProperties() { + // given: + var loader = new PropertyLoggerConfigLoader(); + var contextClassLoader = new ResourceClassLoader(Map.of( + PropertyLoggerConfigLoader.FILE_TEST, "logger.level.ROOT=TRACE", + PropertyLoggerConfigLoader.FILE_MAIN, "logger.level.ROOT=ERROR")); + + // when: + Optional loadedConfig = withContextClassLoader(contextClassLoader, loader::tryToLoad); + + // then: + assertThat(loadedConfig).isPresent(); + + // when: + var loggerService = new DefaultLoggerService(loadedConfig.orElseThrow()); + DefaultLogger logger = loggerService.getLogger("example.logger"); + + // then: + assertThat(logger) + .returns(true, Logger::traceEnabled) + .returns(true, Logger::debugEnabled) + .returns(true, Logger::infoEnabled) + .returns(true, Logger::warnEnabled) + .returns(true, Logger::errorEnabled); + } + + @Test + void shouldFallbackToMainPropertiesWhenTestMissing() { + // given: + var loader = new PropertyLoggerConfigLoader(); + var contextClassLoader = new ResourceClassLoader(Map.of( + PropertyLoggerConfigLoader.FILE_MAIN, "logger.level.ROOT=ERROR")); + + // when: + Optional loadedConfig = withContextClassLoader(contextClassLoader, loader::tryToLoad); + + // then: + assertThat(loadedConfig).isPresent(); + + // when: + var loggerService = new DefaultLoggerService(loadedConfig.orElseThrow()); + DefaultLogger logger = loggerService.getLogger("example.logger"); + + // then: + assertThat(logger) + .returns(false, Logger::traceEnabled) + .returns(false, Logger::debugEnabled) + .returns(false, Logger::infoEnabled) + .returns(false, Logger::warnEnabled) + .returns(true, Logger::errorEnabled); + } + + @Test + void shouldReturnEmptyWhenNoPropertiesFound() { + // given: + var loader = new PropertyLoggerConfigLoader(); + var contextClassLoader = new ResourceClassLoader(Map.of()); + + // when: + Optional loadedConfig = withContextClassLoader(contextClassLoader, loader::tryToLoad); + + // then: + assertThat(loadedConfig).isEmpty(); + } + + @Test + void shouldUseRootLevelForUnconfiguredLogger() { + // given: + var loader = new PropertyLoggerConfigLoader(); + var contextClassLoader = new ResourceClassLoader(Map.of( + PropertyLoggerConfigLoader.FILE_MAIN, + "logger.level.ROOT=WARNING\nlogger.level.configured.logger=TRACE")); + + // when: + Optional loadedConfig = withContextClassLoader(contextClassLoader, loader::tryToLoad); + + // then: + assertThat(loadedConfig).isPresent(); + + // when: + var loggerService = new DefaultLoggerService(loadedConfig.orElseThrow()); + DefaultLogger unconfiguredLogger = loggerService.getLogger("unknown.logger"); + DefaultLogger configuredLogger = loggerService.getLogger("configured.logger"); + + // then: + assertThat(unconfiguredLogger) + .returns(false, Logger::traceEnabled) + .returns(false, Logger::debugEnabled) + .returns(false, Logger::infoEnabled) + .returns(true, Logger::warnEnabled) + .returns(true, Logger::errorEnabled); + assertThat(configuredLogger) + .returns(true, Logger::traceEnabled) + .returns(true, Logger::debugEnabled) + .returns(true, Logger::infoEnabled) + .returns(true, Logger::warnEnabled) + .returns(true, Logger::errorEnabled); + } + + @Test + void shouldUseSimpleMessageRenderWhenPatternIsAbsent() { + // given: + var loader = new PropertyLoggerConfigLoader(); + var properties = new Properties(); + properties.setProperty("logger.level.ROOT", "INFO"); + + // when: + LoggerConfig loggerConfig = loader.loadFromProperties(properties); + + // then: + assertThat(loggerConfig) + .isInstanceOf(DefaultLoggerConfig.class); + + // when: + var defaultLoggerConfig = (DefaultLoggerConfig) loggerConfig; + var loggerService = new DefaultLoggerService(loggerConfig); + DefaultLogger logger = loggerService.getLogger("example.logger"); + UnsafeArray consumers = defaultLoggerConfig.resolveConsumers( + logger, + LoggerLevel.TRACE); + + // then: + assertThat(consumers.size()) + .isEqualTo(1); + assertThat(consumers.get(0)) + .isInstanceOf(ConsoleMessageConsumer.class) + .extracting("logMessageRender") + .isInstanceOf(SimpleLogMessageRender.class); + } + + @Test + void shouldThrowExceptionWhenLevelValueIsInvalid() { + // given: + var loader = new PropertyLoggerConfigLoader(); + var properties = new Properties(); + properties.setProperty("logger.level.ROOT", "INF0"); + + // when/then: + assertThatThrownBy(() -> loader.loadFromProperties(properties)) + .isInstanceOf(IllegalArgumentException.class); + } + + private static T withContextClassLoader(ClassLoader contextClassLoader, Supplier action) { + Thread currentThread = Thread.currentThread(); + ClassLoader previousClassLoader = currentThread.getContextClassLoader(); + try { + currentThread.setContextClassLoader(contextClassLoader); + return action.get(); + } finally { + currentThread.setContextClassLoader(previousClassLoader); + } + } + + private static class ResourceClassLoader extends ClassLoader { + + private final Map resources; + + private ResourceClassLoader(Map resources) { + super(Thread + .currentThread() + .getContextClassLoader()); + this.resources = resources + .entrySet() + .stream() + .collect(Collectors.toUnmodifiableMap( + Map.Entry::getKey, + entry -> entry.getValue().getBytes(StandardCharsets.UTF_8))); + } + + @Override + public InputStream getResourceAsStream(String name) { + byte[] loaded = resources.get(name); + if (loaded != null) { + return new ByteArrayInputStream(loaded); + } + if (PropertyLoggerConfigLoader.FILE_TEST.equals(name) || PropertyLoggerConfigLoader.FILE_MAIN.equals(name)) { + return null; + } + return super.getResourceAsStream(name); + } + } } diff --git a/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/render/impl/pattern/PatternRenderNodesParserTest.java b/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/render/impl/pattern/PatternRenderNodesParserTest.java index 33ff3b57..6153c0f5 100644 --- a/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/render/impl/pattern/PatternRenderNodesParserTest.java +++ b/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/render/impl/pattern/PatternRenderNodesParserTest.java @@ -1,6 +1,7 @@ package javasabr.rlib.logger.impl.config.render.impl.pattern; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import javasabr.rlib.collections.array.Array; import javasabr.rlib.logger.impl.config.render.impl.pattern.node.DateTimePatternRenderNode; @@ -45,4 +46,99 @@ void shouldParseCorrectlyPattern1() { assertThat(parsed.get(7)) .isInstanceOf(MessagePatternRenderNode.class); } + + @Test + void shouldParsePatternWithOnlyLiteralText() { + // given: + var pattern = "just a literal string"; + + // when: + Array parsed = PatternRenderNodesParser.parse(pattern); + + // then: + assertThat(parsed.size()) + .isEqualTo(1); + assertThat(parsed.get(0)) + .isInstanceOf(StringPatternRenderNode.class) + .isEqualTo(new StringPatternRenderNode("just a literal string")); + } + + @Test + void shouldParsePatternWithMessageBetweenLiteralTexts() { + // given: + var pattern = "prefix %msg suffix"; + + // when: + Array parsed = PatternRenderNodesParser.parse(pattern); + + // then: + assertThat(parsed.size()) + .isEqualTo(3); + assertThat(parsed.get(0)) + .isInstanceOf(StringPatternRenderNode.class) + .isEqualTo(new StringPatternRenderNode("prefix ")); + assertThat(parsed.get(1)) + .isInstanceOf(MessagePatternRenderNode.class); + assertThat(parsed.get(2)) + .isInstanceOf(StringPatternRenderNode.class) + .isEqualTo(new StringPatternRenderNode(" suffix")); + } + + @Test + void shouldParsePatternWithSimpleNodeSequence() { + // given: + var pattern = "%level %msg %shortLogger"; + + // when: + Array parsed = PatternRenderNodesParser.parse(pattern); + + // then: + assertThat(parsed.size()) + .isEqualTo(5); + assertThat(parsed.get(0)) + .isInstanceOf(LevelPatternRenderNode.class); + assertThat(parsed.get(1)) + .isInstanceOf(StringPatternRenderNode.class) + .isEqualTo(new StringPatternRenderNode(" ")); + assertThat(parsed.get(2)) + .isInstanceOf(MessagePatternRenderNode.class); + assertThat(parsed.get(3)) + .isInstanceOf(StringPatternRenderNode.class) + .isEqualTo(new StringPatternRenderNode(" ")); + assertThat(parsed.get(4)) + .isInstanceOf(ShortLoggerPatternRenderNode.class); + } + + @Test + void shouldThrowWhenNodeNameIsUnknown() { + // given: + var pattern = "%unknown"; + + // when/then: + assertThatThrownBy(() -> PatternRenderNodesParser.parse(pattern)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Unexpected node name:[unknown]"); + } + + @Test + void shouldThrowWhenDateTimeNodeHasNoOpeningBrace() { + // given: + var pattern = "%dateTime yyyy-MM-dd"; + + // when/then: + assertThatThrownBy(() -> PatternRenderNodesParser.parse(pattern)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Missed '{'"); + } + + @Test + void shouldThrowWhenDateTimeNodeHasNoClosingBrace() { + // given: + var pattern = "%dateTime{yyyy-MM-dd"; + + // when/then: + assertThatThrownBy(() -> PatternRenderNodesParser.parse(pattern)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Missed closing '}'"); + } } From ff2c69086b6124cd24b8f69e9f83b885733ee471 Mon Sep 17 00:00:00 2001 From: javasabr Date: Sun, 7 Jun 2026 12:55:33 +0200 Subject: [PATCH 3/4] improve after review --- .../java/javasabr/rlib/logger/api/Logger.java | 31 +++++++++++++++---- .../loader/LoggerConfigLoadersProvider.java | 11 +++++++ .../pattern/PatternRenderNodesParser.java | 2 +- .../node/DateTimePatternRenderNodeTest.java | 23 ++++++++++++++ .../node/LevelPatternRenderNodeTest.java | 23 ++++++++++++++ .../node/MessagePatternRenderNodeTest.java | 23 ++++++++++++++ .../node/PatternRenderNodeTestUtils.java | 30 ++++++++++++++++++ .../ShortLoggerPatternRenderNodeTest.java | 23 ++++++++++++++ .../node/StringPatternRenderNodeTest.java | 23 ++++++++++++++ 9 files changed, 182 insertions(+), 7 deletions(-) create mode 100644 rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/DateTimePatternRenderNodeTest.java create mode 100644 rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/LevelPatternRenderNodeTest.java create mode 100644 rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/MessagePatternRenderNodeTest.java create mode 100644 rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/PatternRenderNodeTestUtils.java create mode 100644 rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/ShortLoggerPatternRenderNodeTest.java create mode 100644 rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/StringPatternRenderNodeTest.java diff --git a/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/Logger.java b/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/Logger.java index 88410782..195b7af2 100644 --- a/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/Logger.java +++ b/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/Logger.java @@ -431,42 +431,61 @@ default void info(A arg1, B arg2, C arg3, D arg4, @NonNull N4Factor } /** - * Check of enabling the logger level. + * Checks whether logging is enabled at the specified level. + * + * @param level the log level + * @return true if logging is enabled, false otherwise + * @since 10.0.0 */ default boolean enabled(@NonNull LoggerLevel level) { return level.enabled(); } /** - * Check of enabling the error level. + * Checks whether logging is enabled at the error level. + * + * @return true if logging is enabled, false otherwise + * @since 10.0.0 */ default boolean errorEnabled() { return enabled(LoggerLevel.ERROR); } /** - * Check of enabling the warning level. + * Checks whether logging is enabled at the warning level. + * + * @return true if logging is enabled, false otherwise + * @since 10.0.0 */ default boolean warnEnabled() { return enabled(LoggerLevel.WARNING); } /** - * Check of enabling the info level. + * Checks whether logging is enabled at the info level. + * + * @return true if logging is enabled, false otherwise + * @since 10.0.0 */ default boolean infoEnabled() { return enabled(LoggerLevel.INFO); } /** - * Check of enabling the debug level. + * Checks whether logging is enabled at the debug level. + * + * @return true if logging is enabled, false otherwise + * @since 10.0.0 */ default boolean debugEnabled() { return enabled(LoggerLevel.DEBUG); } /** - * Check of enabling the trace level. + * Checks whether logging is enabled at the trace level. + * + * @return true if logging is enabled, false otherwise + * @since 10.0.0 */ default boolean traceEnabled() { return enabled(LoggerLevel.TRACE); diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/LoggerConfigLoadersProvider.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/LoggerConfigLoadersProvider.java index 56a815e2..26691d3d 100644 --- a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/LoggerConfigLoadersProvider.java +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/LoggerConfigLoadersProvider.java @@ -2,7 +2,18 @@ import javasabr.rlib.collections.array.Array; +/** + * Provider of additional logger configuration loaders. + * + * @since 10.0.0 + */ public interface LoggerConfigLoadersProvider { + /** + * Returns additional logger configuration loaders. + * + * @return the logger configuration loaders + * @since 10.0.0 + */ Array getLoggerConfigLoaders(); } diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/PatternRenderNodesParser.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/PatternRenderNodesParser.java index a9e8cf3b..4073d1d3 100644 --- a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/PatternRenderNodesParser.java +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/PatternRenderNodesParser.java @@ -64,7 +64,7 @@ private static ParsedNode parse(String nodeName, String pattern, int afterNameIn } private static String extractArgumentsString(String pattern, int afterNameIndex) { - if (pattern.charAt(afterNameIndex) != '{') { + if (pattern.length() <= afterNameIndex || pattern.charAt(afterNameIndex) != '{') { throw new IllegalArgumentException("Missed '{' at position:[%d] in pattern:[%s]" .formatted(afterNameIndex, pattern)); } diff --git a/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/DateTimePatternRenderNodeTest.java b/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/DateTimePatternRenderNodeTest.java new file mode 100644 index 00000000..b1745297 --- /dev/null +++ b/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/DateTimePatternRenderNodeTest.java @@ -0,0 +1,23 @@ +package javasabr.rlib.logger.impl.config.render.impl.pattern.node; + +import static org.assertj.core.api.Assertions.assertThat; + +import javasabr.rlib.logger.api.LoggerLevel; +import org.junit.jupiter.api.Test; + +class DateTimePatternRenderNodeTest { + + @Test + void shouldAppendCurrentDateTimeUsingProvidedPattern() { + // given: + var node = new DateTimePatternRenderNode("yyyy-MM-dd HH:mm:ss"); + var buffer = new StringBuilder("prefix:"); + + // when: + node.append(LoggerLevel.INFO, PatternRenderNodeTestUtils.LOGGER, "ignored-message", buffer); + + // then: + assertThat(buffer.toString()) + .matches("prefix:\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}"); + } +} diff --git a/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/LevelPatternRenderNodeTest.java b/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/LevelPatternRenderNodeTest.java new file mode 100644 index 00000000..ed10fe1a --- /dev/null +++ b/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/LevelPatternRenderNodeTest.java @@ -0,0 +1,23 @@ +package javasabr.rlib.logger.impl.config.render.impl.pattern.node; + +import static org.assertj.core.api.Assertions.assertThat; + +import javasabr.rlib.logger.api.LoggerLevel; +import org.junit.jupiter.api.Test; + +class LevelPatternRenderNodeTest { + + @Test + void shouldAppendLevelTitleWithOffset() { + // given: + var node = new LevelPatternRenderNode(); + var buffer = new StringBuilder("prefix:"); + + // when: + node.append(LoggerLevel.WARNING, PatternRenderNodeTestUtils.LOGGER, "ignored-message", buffer); + + // then: + assertThat(buffer.toString()) + .isEqualTo("prefix:WARN "); + } +} diff --git a/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/MessagePatternRenderNodeTest.java b/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/MessagePatternRenderNodeTest.java new file mode 100644 index 00000000..5d6b972d --- /dev/null +++ b/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/MessagePatternRenderNodeTest.java @@ -0,0 +1,23 @@ +package javasabr.rlib.logger.impl.config.render.impl.pattern.node; + +import static org.assertj.core.api.Assertions.assertThat; + +import javasabr.rlib.logger.api.LoggerLevel; +import org.junit.jupiter.api.Test; + +class MessagePatternRenderNodeTest { + + @Test + void shouldAppendMessageToBuffer() { + // given: + var node = new MessagePatternRenderNode(); + var buffer = new StringBuilder("prefix:"); + + // when: + node.append(LoggerLevel.ERROR, PatternRenderNodeTestUtils.LOGGER, "actual-message", buffer); + + // then: + assertThat(buffer.toString()) + .isEqualTo("prefix:actual-message"); + } +} diff --git a/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/PatternRenderNodeTestUtils.java b/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/PatternRenderNodeTestUtils.java new file mode 100644 index 00000000..af79af86 --- /dev/null +++ b/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/PatternRenderNodeTestUtils.java @@ -0,0 +1,30 @@ +package javasabr.rlib.logger.impl.config.render.impl.pattern.node; + +import javasabr.rlib.logger.api.Logger; +import javasabr.rlib.logger.api.LoggerLevel; + +final class PatternRenderNodeTestUtils { + + static final Logger LOGGER = new Logger() { + @Override + public String name() { + return "example.logger.PatternRenderNodeTest"; + } + + @Override + public String shortName() { + return "PatternRenderNodeTest"; + } + + @Override + public void print(LoggerLevel level, String message) {} + + @Override + public void print(LoggerLevel level, Throwable exception) {} + + @Override + public void print(LoggerLevel level, String message, Throwable exception) {} + }; + + private PatternRenderNodeTestUtils() {} +} diff --git a/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/ShortLoggerPatternRenderNodeTest.java b/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/ShortLoggerPatternRenderNodeTest.java new file mode 100644 index 00000000..746a9711 --- /dev/null +++ b/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/ShortLoggerPatternRenderNodeTest.java @@ -0,0 +1,23 @@ +package javasabr.rlib.logger.impl.config.render.impl.pattern.node; + +import static org.assertj.core.api.Assertions.assertThat; + +import javasabr.rlib.logger.api.LoggerLevel; +import org.junit.jupiter.api.Test; + +class ShortLoggerPatternRenderNodeTest { + + @Test + void shouldAppendLoggerShortNameToBuffer() { + // given: + var node = new ShortLoggerPatternRenderNode(); + var buffer = new StringBuilder("prefix:"); + + // when: + node.append(LoggerLevel.INFO, PatternRenderNodeTestUtils.LOGGER, "ignored-message", buffer); + + // then: + assertThat(buffer.toString()) + .isEqualTo("prefix:PatternRenderNodeTest"); + } +} diff --git a/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/StringPatternRenderNodeTest.java b/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/StringPatternRenderNodeTest.java new file mode 100644 index 00000000..d4082a61 --- /dev/null +++ b/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/render/impl/pattern/node/StringPatternRenderNodeTest.java @@ -0,0 +1,23 @@ +package javasabr.rlib.logger.impl.config.render.impl.pattern.node; + +import static org.assertj.core.api.Assertions.assertThat; + +import javasabr.rlib.logger.api.LoggerLevel; +import org.junit.jupiter.api.Test; + +class StringPatternRenderNodeTest { + + @Test + void shouldAppendConfiguredStringToBuffer() { + // given: + var node = new StringPatternRenderNode("configured-value"); + var buffer = new StringBuilder("prefix:"); + + // when: + node.append(LoggerLevel.DEBUG, PatternRenderNodeTestUtils.LOGGER, "ignored-message", buffer); + + // then: + assertThat(buffer.toString()) + .isEqualTo("prefix:configured-value"); + } +} From fa1b3761b13db28b051f601f88e5efb430ed8c0d Mon Sep 17 00:00:00 2001 From: javasabr Date: Sun, 7 Jun 2026 15:45:51 +0200 Subject: [PATCH 4/4] small updates --- .../loader/impl/PropertyLoggerConfigLoader.java | 11 ++--------- .../loader/impl/PropertyLoggerConfigLoaderTest.java | 2 +- .../impl/pattern/PatternRenderNodesParserTest.java | 2 +- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/impl/PropertyLoggerConfigLoader.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/impl/PropertyLoggerConfigLoader.java index b14b64be..2d1d4d04 100644 --- a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/impl/PropertyLoggerConfigLoader.java +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/impl/PropertyLoggerConfigLoader.java @@ -32,17 +32,10 @@ public Optional tryToLoad() { return Optional.empty(); } Properties properties = new Properties(); - try { - properties.load(propertiesStream); + try (var source = propertiesStream) { + properties.load(source); } catch (IOException ex) { - ex.printStackTrace(); return Optional.empty(); - } finally { - try { - propertiesStream.close(); - } catch (IOException ex) { - ex.printStackTrace(); - } } LoggerConfig loggerConfig = loadFromProperties(properties); properties.clear(); diff --git a/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/loader/impl/PropertyLoggerConfigLoaderTest.java b/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/loader/impl/PropertyLoggerConfigLoaderTest.java index 8aa197a6..0ee88e25 100644 --- a/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/loader/impl/PropertyLoggerConfigLoaderTest.java +++ b/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/loader/impl/PropertyLoggerConfigLoaderTest.java @@ -31,7 +31,7 @@ import javasabr.rlib.logger.impl.config.render.impl.pattern.node.StringPatternRenderNode; import org.junit.jupiter.api.Test; -public class PropertyLoggerConfigLoaderTest { +class PropertyLoggerConfigLoaderTest { @Test void shouldLoadLoggerConfigCorrectly() throws IOException { diff --git a/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/render/impl/pattern/PatternRenderNodesParserTest.java b/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/render/impl/pattern/PatternRenderNodesParserTest.java index 6153c0f5..032f6dd8 100644 --- a/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/render/impl/pattern/PatternRenderNodesParserTest.java +++ b/rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/config/render/impl/pattern/PatternRenderNodesParserTest.java @@ -12,7 +12,7 @@ import javasabr.rlib.logger.impl.config.render.impl.pattern.node.StringPatternRenderNode; import org.junit.jupiter.api.Test; -public class PatternRenderNodesParserTest { +class PatternRenderNodesParserTest { @Test void shouldParseCorrectlyPattern1() {