From d949d13304906d96a5b8ea93465c9b8d9a8b029c Mon Sep 17 00:00:00 2001 From: Alexander Yevsyukov Date: Wed, 25 Jun 2025 14:02:38 +0100 Subject: [PATCH 01/28] Rename Flogger classes to Jvm --- .../backend/jul/AbstractJulBackend.java | 2 +- .../backend/jul/AbstractJulRecord.java | 12 +- .../spine/logging/backend/jul/JulRecord.java | 6 +- .../spine/logging/backend/jul/JulBackend.kt | 6 +- .../logging/backend/jul/JulBackendFactory.kt | 4 +- .../logging/backend/jul/JulRecordSpec.kt | 18 +-- .../backend/jul/given/FakeJulRecord.kt | 12 +- .../backend/jul/given/JulBackendTestEnv.kt | 2 +- .../backend/log4j2/Log4j2BackendFactory.java | 4 +- .../backend/log4j2/Log4j2LogEventUtil.java | 34 +++--- .../backend/log4j2/Log4j2LoggerBackend.java | 4 +- .../logging/backend/log4j2/ValueQueue.java | 6 +- ....spine.logging.jvm.backend.BackendFactory} | 0 .../log4j2/Log4j2BackendFactorySpec.kt | 2 +- .../backend/log4j2/Log4j2LoggerBackendSpec.kt | 16 +-- .../backend/log4j2/Log4j2ScopedLoggingSpec.kt | 14 +-- .../logging/backend/probe/CaptureLogData.kt | 2 +- .../backend/probe/DynamicBackendFactory.kt | 4 +- .../probe/DynamicBackendFactoryService.kt | 4 +- .../backend/probe/MemoizingBackendFactory.kt | 2 +- .../probe/MemoizingLoggerBackendFactory.kt | 2 +- .../backend/probe/TypedBackendFactory.kt | 2 +- .../dependency/lib/{Flogger.kt => Jvm.kt} | 2 +- .../logging/context/grpc/GrpcContextData.java | 12 +- .../context/grpc/GrpcContextDataProvider.java | 12 +- .../grpc/GrpcScopedLoggingContext.java | 16 +-- .../logging/context/grpc/package-info.java | 2 +- ...e.logging.jvm.context.ContextDataProvider} | 0 .../grpc/GrpcContextDataProviderSpec.kt | 4 +- .../logging/context/std/StdContextData.kt | 10 +- .../context/std/StdContextDataProvider.kt | 14 +-- ...e.logging.jvm.context.ContextDataProvider} | 0 .../context/std/StdContextDataProviderSpec.kt | 4 +- flogger/README.md | 2 +- .../{flogger => jvm}/AbstractLogger.java | 16 +-- .../{flogger => jvm}/CountingRateLimiter.java | 8 +- .../{flogger => jvm}/DurationRateLimiter.java | 14 +-- .../{flogger => jvm}/FluentLogger2.java | 16 +-- .../FloggerApi.java => jvm/JvmApi.java} | 38 +++---- .../JvmLogSite.java} | 24 ++-- .../JvmLogSites.java} | 32 +++--- .../JvmMetadataKey.java} | 28 ++--- .../logging/{flogger => jvm}/LazyArg.java | 2 +- .../logging/{flogger => jvm}/LazyArgs.java | 4 +- .../logging/{flogger => jvm}/LogContext.java | 104 +++++++++--------- .../LogPerBucketingStrategy.java | 8 +- .../logging/{flogger => jvm}/LogSiteKey.java | 4 +- .../logging/{flogger => jvm}/LogSiteMap.java | 6 +- .../{flogger => jvm}/LogSiteStackTrace.java | 2 +- .../{flogger => jvm}/LoggingScope.java | 8 +- .../LoggingScopeProvider.java | 2 +- .../{flogger => jvm}/RateLimitStatus.java | 4 +- .../{flogger => jvm}/SamplingRateLimiter.java | 6 +- .../SpecializedLogSiteKey.java | 4 +- .../{flogger => jvm}/StackBasedLogSite.java | 12 +- .../logging/{flogger => jvm}/StackSize.java | 8 +- .../backend/BackendFactory.java | 4 +- .../backend/BaseMessageFormatter.java | 14 +-- .../{flogger => jvm}/backend/Clock.java | 4 +- .../{flogger => jvm}/backend/FormatChar.java | 2 +- .../backend/FormatOptions.java | 6 +- .../{flogger => jvm}/backend/FormatType.java | 2 +- .../backend/KeyValueFormatter.java | 4 +- .../{flogger => jvm}/backend/LogData.java | 6 +- .../backend/LogMessageFormatter.java | 2 +- .../backend/LoggerBackend.java | 6 +- .../backend/LoggingException.java | 2 +- .../backend/MessageUtils.java | 16 +-- .../{flogger => jvm}/backend/Metadata.java | 16 +-- .../backend/MetadataHandler.java | 58 +++++----- .../backend/MetadataKeyValueHandlers.java | 18 +-- .../backend/MetadataProcessor.java | 72 ++++++------ .../{flogger => jvm}/backend/Platform.java | 18 +-- .../backend/SimpleMessageFormatter.java | 22 ++-- .../backend/TemplateContext.java | 6 +- .../backend/package-info.java | 2 +- .../context/ContextDataProvider.java | 10 +- .../context/ContextMetadata.java | 32 +++--- .../{flogger => jvm}/context/LogLevelMap.java | 4 +- .../context/NoOpContextDataProvider.java | 12 +- .../{flogger => jvm}/context/ScopeType.java | 8 +- .../context/ScopedLoggingContext.java | 20 ++-- .../context/ScopedLoggingContexts.java | 10 +- .../{flogger => jvm}/context/SegmentTrie.java | 4 +- .../{flogger => jvm}/context/Tags.java | 8 +- .../context/package-info.java | 2 +- .../{flogger => jvm}/package-info.java | 2 +- .../parameter/BraceStyleParameter.java | 8 +- .../parameter/DateTimeFormat.java | 2 +- .../parameter/DateTimeParameter.java | 4 +- .../{flogger => jvm}/parameter/Parameter.java | 4 +- .../parameter/ParameterVisitor.java | 6 +- .../parameter/SimpleParameter.java | 8 +- .../parameter/package-info.java | 2 +- .../parser/BraceStyleMessageParser.java | 2 +- .../DefaultBraceStyleMessageParser.java | 4 +- .../parser/DefaultPrintfMessageParser.java | 20 ++-- .../parser/MessageBuilder.java | 8 +- .../parser/MessageParser.java | 4 +- .../parser/ParseException.java | 2 +- .../parser/PrintfMessageParser.java | 2 +- .../{flogger => jvm}/parser/package-info.java | 2 +- .../logging/{flogger => jvm}/util/Checks.java | 2 +- .../{flogger => jvm}/util/RecursionDepth.java | 2 +- .../util/StaticMethodCaller.java | 2 +- .../{flogger => jvm}/util/package-info.java | 2 +- .../JvmMetadataKeys.kt} | 14 +-- .../{flogger => jvm}/AbstractLoggerSpec.kt | 10 +- .../CountingRateLimiterSpec.kt | 12 +- .../DurationRateLimiterSpec.kt | 16 +-- .../{flogger => jvm}/FluentLogger2Spec.kt | 22 ++-- .../JvmLogSitesSpec.kt} | 24 ++-- .../JvmMetadataKeySpec.kt} | 30 ++--- .../{flogger => jvm}/LogContextSpec.kt | 50 ++++----- .../LogPerBucketingStrategySpec.kt | 2 +- .../{flogger => jvm}/LogSiteMapSpec.kt | 8 +- .../{flogger => jvm}/LogSiteStackTraceSpec.kt | 2 +- .../{flogger => jvm}/LoggingScopeSpec.kt | 4 +- .../{flogger => jvm}/RateLimitStatusSpec.kt | 14 +-- .../SamplingRateLimiterSpec.kt | 16 +-- .../SpecializedLogSiteKeySpec.kt | 4 +- .../{flogger => jvm}/StackBasedLogSiteSpec.kt | 4 +- .../backend/BaseMessageFormatterSpec.kt | 6 +- .../backend/FormatCharSpec.kt | 26 ++--- .../backend/FormatOptionsSpec.kt | 26 ++--- .../backend/FormatTypeSpec.kt | 12 +- .../backend/KeyValueFormatterSpec.kt | 2 +- .../backend/LightweightProcessorSpec.kt | 2 +- .../backend/MessageUtilsSpec.kt | 24 ++-- .../backend/MetadataHandlerSpec.kt | 20 ++-- .../backend/MetadataKeyValueHandlersSpec.kt | 16 +-- .../backend/MetadataProcessorSpec.kt | 20 ++-- .../backend/SimpleMessageFormatterSpec.kt | 14 +-- .../backend/SimpleProcessorSpec.kt | 2 +- .../backend/given/FakeLogData.kt | 30 ++--- .../backend/given/FakeMetadata.kt | 14 +-- .../backend/given/MemoizingLoggerBackend.kt | 6 +- .../backend/given/MetadataAssertions.kt | 18 +-- .../AbstractContextDataProviderSpec.kt | 26 ++--- .../context/ContextMetadataSpec.kt | 16 +-- .../context/LogLevelMapSpec.kt | 4 +- .../context/ScopedLoggingContextSpec.kt | 6 +- .../context/SegmentTrieSpec.kt | 4 +- .../{flogger => jvm}/context/TagsSpec.kt | 2 +- .../{flogger => jvm}/given/BackendTestEnv.kt | 2 +- .../given/ConfigurableLogger.kt | 16 +-- .../{flogger => jvm}/given/FakeLogSite.kt | 8 +- .../given/FormattingBackend.kt | 6 +- .../given/LogDataAssertions.kt | 4 +- .../given/MemoizingKvHandler.kt | 6 +- .../parameter/ParameterSpec.kt | 4 +- .../parameter/SimpleParameterSpec.kt | 18 +-- .../parser/BraceStyleMessageParserSpec.kt | 10 +- .../DefaultBraceStyleMessageParserSpec.kt | 14 +-- .../parser/DefaultPrintfMessageParserSpec.kt | 8 +- .../parser/PrintfMessageParserSpec.kt | 10 +- .../parser/given/ParserTestEnv.kt | 22 ++-- .../generator/PlatformProviderGenerator.java | 12 +- .../kotlin/io/spine/logging/JvmLogger.kt | 16 +-- .../kotlin/io/spine/logging/JvmMetadataKey.kt | 2 +- .../kotlin/io/spine/logging/LogSiteLookup.kt | 12 +- .../kotlin/io/spine/logging/LoggingFactory.kt | 4 +- .../logging/context/LoggingContextFactory.kt | 6 +- .../backend/system/DefaultPlatform.java | 12 +- .../system/StackBasedCallerFinder.java | 12 +- .../logging/backend/system/SystemClock.java | 2 +- .../backend/system/DefaultPlatformSpec.kt | 4 +- .../system/given/DefaultPlatformTestEnv.kt | 16 +-- .../backend/system/given/JavaServices.kt | 10 +- .../src/test/kotlin/LogLevelMapITest.kt | 2 +- .../src/test/kotlin/LogLevelMapITest.kt | 2 +- 171 files changed, 916 insertions(+), 916 deletions(-) rename backends/log4j2-backend/src/main/resources/META-INF/services/{io.spine.logging.flogger.backend.BackendFactory => io.spine.logging.jvm.backend.BackendFactory} (100%) rename buildSrc/src/main/kotlin/io/spine/dependency/lib/{Flogger.kt => Jvm.kt} (99%) rename contexts/grpc-context/src/main/resources/META-INF/services/{io.spine.logging.flogger.context.ContextDataProvider => io.spine.logging.jvm.context.ContextDataProvider} (100%) rename contexts/std-context/src/main/resources/META-INF/services/{io.spine.logging.flogger.context.ContextDataProvider => io.spine.logging.jvm.context.ContextDataProvider} (100%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/AbstractLogger.java (95%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/CountingRateLimiter.java (95%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/DurationRateLimiter.java (94%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/FluentLogger2.java (92%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger/FloggerApi.java => jvm/JvmApi.java} (97%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger/FloggerLogSite.java => jvm/JvmLogSite.java} (93%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger/FloggerLogSites.java => jvm/JvmLogSites.java} (85%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger/FloggerMetadataKey.java => jvm/JvmMetadataKey.java} (94%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/LazyArg.java (98%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/LazyArgs.java (97%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/LogContext.java (94%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/LogPerBucketingStrategy.java (97%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/LogSiteKey.java (96%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/LogSiteMap.java (97%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/LogSiteStackTrace.java (98%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/LoggingScope.java (96%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/LoggingScopeProvider.java (98%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/RateLimitStatus.java (99%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/SamplingRateLimiter.java (96%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/SpecializedLogSiteKey.java (96%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/StackBasedLogSite.java (89%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/StackSize.java (93%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/backend/BackendFactory.java (97%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/backend/BaseMessageFormatter.java (95%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/backend/Clock.java (96%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/backend/FormatChar.java (99%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/backend/FormatOptions.java (99%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/backend/FormatType.java (99%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/backend/KeyValueFormatter.java (98%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/backend/LogData.java (97%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/backend/LogMessageFormatter.java (98%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/backend/LoggerBackend.java (97%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/backend/LoggingException.java (98%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/backend/MessageUtils.java (95%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/backend/Metadata.java (90%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/backend/MetadataHandler.java (84%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/backend/MetadataKeyValueHandlers.java (87%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/backend/MetadataProcessor.java (88%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/backend/Platform.java (96%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/backend/SimpleMessageFormatter.java (92%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/backend/TemplateContext.java (94%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/backend/package-info.java (97%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/context/ContextDataProvider.java (96%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/context/ContextMetadata.java (88%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/context/LogLevelMap.java (98%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/context/NoOpContextDataProvider.java (93%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/context/ScopeType.java (94%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/context/ScopedLoggingContext.java (97%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/context/ScopedLoggingContexts.java (96%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/context/SegmentTrie.java (99%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/context/Tags.java (99%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/context/package-info.java (97%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/package-info.java (97%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/parameter/BraceStyleParameter.java (95%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/parameter/DateTimeFormat.java (99%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/parameter/DateTimeParameter.java (96%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/parameter/Parameter.java (97%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/parameter/ParameterVisitor.java (96%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/parameter/SimpleParameter.java (95%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/parameter/package-info.java (97%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/parser/BraceStyleMessageParser.java (99%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/parser/DefaultBraceStyleMessageParser.java (96%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/parser/DefaultPrintfMessageParser.java (89%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/parser/MessageBuilder.java (96%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/parser/MessageParser.java (96%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/parser/ParseException.java (99%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/parser/PrintfMessageParser.java (99%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/parser/package-info.java (97%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/util/Checks.java (98%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/util/RecursionDepth.java (98%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/util/StaticMethodCaller.java (99%) rename flogger/middleware/src/main/java/io/spine/logging/{flogger => jvm}/util/package-info.java (97%) rename flogger/middleware/src/main/kotlin/io/spine/logging/{flogger/FloggerMetadataKeys.kt => jvm/JvmMetadataKeys.kt} (82%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/AbstractLoggerSpec.kt (96%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/CountingRateLimiterSpec.kt (93%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/DurationRateLimiterSpec.kt (93%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/FluentLogger2Spec.kt (84%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger/FloggerLogSitesSpec.kt => jvm/JvmLogSitesSpec.kt} (82%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger/FloggerMetadataKeySpec.kt => jvm/JvmMetadataKeySpec.kt} (90%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/LogContextSpec.kt (96%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/LogPerBucketingStrategySpec.kt (99%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/LogSiteMapSpec.kt (96%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/LogSiteStackTraceSpec.kt (98%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/LoggingScopeSpec.kt (95%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/RateLimitStatusSpec.kt (93%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/SamplingRateLimiterSpec.kt (90%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/SpecializedLogSiteKeySpec.kt (97%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/StackBasedLogSiteSpec.kt (97%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/backend/BaseMessageFormatterSpec.kt (98%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/backend/FormatCharSpec.kt (85%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/backend/FormatOptionsSpec.kt (92%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/backend/FormatTypeSpec.kt (92%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/backend/KeyValueFormatterSpec.kt (99%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/backend/LightweightProcessorSpec.kt (97%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/backend/MessageUtilsSpec.kt (88%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/backend/MetadataHandlerSpec.kt (91%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/backend/MetadataKeyValueHandlersSpec.kt (87%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/backend/MetadataProcessorSpec.kt (93%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/backend/SimpleMessageFormatterSpec.kt (95%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/backend/SimpleProcessorSpec.kt (97%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/backend/given/FakeLogData.kt (85%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/backend/given/FakeMetadata.kt (82%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/backend/given/MemoizingLoggerBackend.kt (94%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/backend/given/MetadataAssertions.kt (82%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/context/AbstractContextDataProviderSpec.kt (95%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/context/ContextMetadataSpec.kt (91%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/context/LogLevelMapSpec.kt (97%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/context/ScopedLoggingContextSpec.kt (93%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/context/SegmentTrieSpec.kt (98%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/context/TagsSpec.kt (99%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/given/BackendTestEnv.kt (97%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/given/ConfigurableLogger.kt (88%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/given/FakeLogSite.kt (94%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/given/FormattingBackend.kt (95%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/given/LogDataAssertions.kt (96%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/given/MemoizingKvHandler.kt (89%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/parameter/ParameterSpec.kt (96%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/parameter/SimpleParameterSpec.kt (88%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/parser/BraceStyleMessageParserSpec.kt (95%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/parser/DefaultBraceStyleMessageParserSpec.kt (88%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/parser/DefaultPrintfMessageParserSpec.kt (93%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/parser/PrintfMessageParserSpec.kt (95%) rename flogger/middleware/src/test/kotlin/io/spine/logging/{flogger => jvm}/parser/given/ParserTestEnv.kt (90%) diff --git a/backends/jul-backend/src/main/java/io/spine/logging/backend/jul/AbstractJulBackend.java b/backends/jul-backend/src/main/java/io/spine/logging/backend/jul/AbstractJulBackend.java index c39bc2b53..663f80ef4 100644 --- a/backends/jul-backend/src/main/java/io/spine/logging/backend/jul/AbstractJulBackend.java +++ b/backends/jul-backend/src/main/java/io/spine/logging/backend/jul/AbstractJulBackend.java @@ -26,7 +26,7 @@ package io.spine.logging.backend.jul; -import io.spine.logging.flogger.backend.LoggerBackend; +import io.spine.logging.jvm.backend.LoggerBackend; import java.util.logging.Filter; import java.util.logging.Handler; diff --git a/backends/jul-backend/src/main/java/io/spine/logging/backend/jul/AbstractJulRecord.java b/backends/jul-backend/src/main/java/io/spine/logging/backend/jul/AbstractJulRecord.java index b4925f101..504766a2b 100644 --- a/backends/jul-backend/src/main/java/io/spine/logging/backend/jul/AbstractJulRecord.java +++ b/backends/jul-backend/src/main/java/io/spine/logging/backend/jul/AbstractJulRecord.java @@ -26,12 +26,12 @@ package io.spine.logging.backend.jul; -import io.spine.logging.flogger.backend.LogData; -import io.spine.logging.flogger.backend.LogMessageFormatter; -import io.spine.logging.flogger.backend.MessageUtils; -import io.spine.logging.flogger.backend.Metadata; -import io.spine.logging.flogger.backend.MetadataProcessor; -import io.spine.logging.flogger.backend.SimpleMessageFormatter; +import io.spine.logging.jvm.backend.LogData; +import io.spine.logging.jvm.backend.LogMessageFormatter; +import io.spine.logging.jvm.backend.MessageUtils; +import io.spine.logging.jvm.backend.Metadata; +import io.spine.logging.jvm.backend.MetadataProcessor; +import io.spine.logging.jvm.backend.SimpleMessageFormatter; import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.util.Arrays; diff --git a/backends/jul-backend/src/main/java/io/spine/logging/backend/jul/JulRecord.java b/backends/jul-backend/src/main/java/io/spine/logging/backend/jul/JulRecord.java index 1a72a597b..80c169b60 100644 --- a/backends/jul-backend/src/main/java/io/spine/logging/backend/jul/JulRecord.java +++ b/backends/jul-backend/src/main/java/io/spine/logging/backend/jul/JulRecord.java @@ -26,9 +26,9 @@ package io.spine.logging.backend.jul; -import io.spine.logging.flogger.LogContext; -import io.spine.logging.flogger.backend.LogData; -import io.spine.logging.flogger.backend.Metadata; +import io.spine.logging.jvm.LogContext; +import io.spine.logging.jvm.backend.LogData; +import io.spine.logging.jvm.backend.Metadata; import java.util.logging.LogRecord; diff --git a/backends/jul-backend/src/main/kotlin/io/spine/logging/backend/jul/JulBackend.kt b/backends/jul-backend/src/main/kotlin/io/spine/logging/backend/jul/JulBackend.kt index 33aa8afeb..e7383e071 100644 --- a/backends/jul-backend/src/main/kotlin/io/spine/logging/backend/jul/JulBackend.kt +++ b/backends/jul-backend/src/main/kotlin/io/spine/logging/backend/jul/JulBackend.kt @@ -26,9 +26,9 @@ package io.spine.logging.backend.jul -import io.spine.logging.flogger.backend.LogData -import io.spine.logging.flogger.backend.LoggerBackend -import io.spine.logging.flogger.backend.Platform +import io.spine.logging.jvm.backend.LogData +import io.spine.logging.jvm.backend.LoggerBackend +import io.spine.logging.jvm.backend.Platform import java.util.logging.Handler import java.util.logging.Level import java.util.logging.LogRecord diff --git a/backends/jul-backend/src/main/kotlin/io/spine/logging/backend/jul/JulBackendFactory.kt b/backends/jul-backend/src/main/kotlin/io/spine/logging/backend/jul/JulBackendFactory.kt index 2d37ba6f3..b1c0879e5 100644 --- a/backends/jul-backend/src/main/kotlin/io/spine/logging/backend/jul/JulBackendFactory.kt +++ b/backends/jul-backend/src/main/kotlin/io/spine/logging/backend/jul/JulBackendFactory.kt @@ -26,8 +26,8 @@ package io.spine.logging.backend.jul -import io.spine.logging.flogger.backend.BackendFactory -import io.spine.logging.flogger.backend.LoggerBackend +import io.spine.logging.jvm.backend.BackendFactory +import io.spine.logging.jvm.backend.LoggerBackend /** * A [BackendFactory] producing [LoggerBackend] which supports publishing diff --git a/backends/jul-backend/src/test/kotlin/io/spine/logging/backend/jul/JulRecordSpec.kt b/backends/jul-backend/src/test/kotlin/io/spine/logging/backend/jul/JulRecordSpec.kt index b3b402706..fb84982a3 100644 --- a/backends/jul-backend/src/test/kotlin/io/spine/logging/backend/jul/JulRecordSpec.kt +++ b/backends/jul-backend/src/test/kotlin/io/spine/logging/backend/jul/JulRecordSpec.kt @@ -35,14 +35,14 @@ import io.kotest.matchers.string.shouldContain import io.kotest.matchers.string.shouldEndWith import io.kotest.matchers.string.shouldNotContain import io.kotest.matchers.types.shouldBeSameInstanceAs -import io.spine.logging.flogger.FloggerMetadataKey -import io.spine.logging.flogger.LogContext.Key -import io.spine.logging.flogger.backend.Metadata -import io.spine.logging.flogger.backend.given.FakeLogData -import io.spine.logging.flogger.backend.given.FakeMetadata -import io.spine.logging.flogger.context.Tags -import io.spine.logging.flogger.parser.ParseException -import io.spine.logging.flogger.singleKey +import io.spine.logging.jvm.JvmMetadataKey +import io.spine.logging.jvm.LogContext.Key +import io.spine.logging.jvm.backend.Metadata +import io.spine.logging.jvm.backend.given.FakeLogData +import io.spine.logging.jvm.backend.given.FakeMetadata +import io.spine.logging.jvm.context.Tags +import io.spine.logging.jvm.parser.ParseException +import io.spine.logging.jvm.singleKey import java.time.Instant.ofEpochMilli import java.util.concurrent.TimeUnit.NANOSECONDS import java.util.logging.Level @@ -62,7 +62,7 @@ internal class JulRecordSpec { private val INT_KEY = singleKey("int") private val STR_KEY = singleKey("str") private val PATH_KEY = - object : FloggerMetadataKey("path", String::class.java, true) { + object : JvmMetadataKey("path", String::class.java, true) { override fun emitRepeated(values: Iterator, out: KeyValueHandler) { val joined = values.asSequence().joinToString("/") out.handle(label, joined) diff --git a/backends/jul-backend/src/test/kotlin/io/spine/logging/backend/jul/given/FakeJulRecord.kt b/backends/jul-backend/src/test/kotlin/io/spine/logging/backend/jul/given/FakeJulRecord.kt index 7ad0da10b..a1a6d936f 100644 --- a/backends/jul-backend/src/test/kotlin/io/spine/logging/backend/jul/given/FakeJulRecord.kt +++ b/backends/jul-backend/src/test/kotlin/io/spine/logging/backend/jul/given/FakeJulRecord.kt @@ -27,12 +27,12 @@ package io.spine.logging.backend.jul.given import io.spine.logging.backend.jul.AbstractJulRecord -import io.spine.logging.flogger.backend.LogData -import io.spine.logging.flogger.backend.LogMessageFormatter -import io.spine.logging.flogger.backend.Metadata -import io.spine.logging.flogger.backend.MetadataProcessor -import io.spine.logging.flogger.backend.SimpleMessageFormatter -import io.spine.logging.flogger.backend.given.FakeLogData +import io.spine.logging.jvm.backend.LogData +import io.spine.logging.jvm.backend.LogMessageFormatter +import io.spine.logging.jvm.backend.Metadata +import io.spine.logging.jvm.backend.MetadataProcessor +import io.spine.logging.jvm.backend.SimpleMessageFormatter +import io.spine.logging.jvm.backend.given.FakeLogData /** * An instantiatable [AbstractJulRecord]. diff --git a/backends/jul-backend/src/test/kotlin/io/spine/logging/backend/jul/given/JulBackendTestEnv.kt b/backends/jul-backend/src/test/kotlin/io/spine/logging/backend/jul/given/JulBackendTestEnv.kt index fe5a3a58d..4f03a7f37 100644 --- a/backends/jul-backend/src/test/kotlin/io/spine/logging/backend/jul/given/JulBackendTestEnv.kt +++ b/backends/jul-backend/src/test/kotlin/io/spine/logging/backend/jul/given/JulBackendTestEnv.kt @@ -28,7 +28,7 @@ package io.spine.logging.backend.jul.given import io.spine.logging.backend.jul.AbstractJulBackend import io.spine.logging.backend.jul.given.MemoizingJulBackend.ForcingLogger -import io.spine.logging.flogger.backend.LogData +import io.spine.logging.jvm.backend.LogData import java.util.logging.Handler import java.util.logging.Level import java.util.logging.LogRecord diff --git a/backends/log4j2-backend/src/main/java/io/spine/logging/backend/log4j2/Log4j2BackendFactory.java b/backends/log4j2-backend/src/main/java/io/spine/logging/backend/log4j2/Log4j2BackendFactory.java index b0adb3918..f7b3f3fae 100644 --- a/backends/log4j2-backend/src/main/java/io/spine/logging/backend/log4j2/Log4j2BackendFactory.java +++ b/backends/log4j2-backend/src/main/java/io/spine/logging/backend/log4j2/Log4j2BackendFactory.java @@ -26,8 +26,8 @@ package io.spine.logging.backend.log4j2; -import io.spine.logging.flogger.backend.LoggerBackend; -import io.spine.logging.flogger.backend.BackendFactory; +import io.spine.logging.jvm.backend.LoggerBackend; +import io.spine.logging.jvm.backend.BackendFactory; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.core.Logger; diff --git a/backends/log4j2-backend/src/main/java/io/spine/logging/backend/log4j2/Log4j2LogEventUtil.java b/backends/log4j2-backend/src/main/java/io/spine/logging/backend/log4j2/Log4j2LogEventUtil.java index fa1e55a13..0994a02ee 100644 --- a/backends/log4j2-backend/src/main/java/io/spine/logging/backend/log4j2/Log4j2LogEventUtil.java +++ b/backends/log4j2-backend/src/main/java/io/spine/logging/backend/log4j2/Log4j2LogEventUtil.java @@ -26,23 +26,23 @@ package io.spine.logging.backend.log4j2; -import static io.spine.logging.flogger.backend.MetadataProcessor.forScopeAndLogSite; +import static io.spine.logging.jvm.backend.MetadataProcessor.forScopeAndLogSite; import static java.util.concurrent.TimeUnit.NANOSECONDS; import static java.util.concurrent.TimeUnit.SECONDS; import static java.util.logging.Level.WARNING; -import io.spine.logging.flogger.LogContext; -import io.spine.logging.flogger.FloggerLogSite; -import io.spine.logging.flogger.FloggerMetadataKey; -import io.spine.logging.flogger.backend.BaseMessageFormatter; -import io.spine.logging.flogger.backend.LogData; -import io.spine.logging.flogger.backend.MessageUtils; -import io.spine.logging.flogger.backend.Metadata; -import io.spine.logging.flogger.backend.MetadataHandler; -import io.spine.logging.flogger.backend.Platform; -import io.spine.logging.flogger.backend.SimpleMessageFormatter; -import io.spine.logging.flogger.context.ScopedLoggingContext; -import io.spine.logging.flogger.context.Tags; +import io.spine.logging.jvm.LogContext; +import io.spine.logging.jvm.JvmLogSite; +import io.spine.logging.jvm.JvmMetadataKey; +import io.spine.logging.jvm.backend.BaseMessageFormatter; +import io.spine.logging.jvm.backend.LogData; +import io.spine.logging.jvm.backend.MessageUtils; +import io.spine.logging.jvm.backend.Metadata; +import io.spine.logging.jvm.backend.MetadataHandler; +import io.spine.logging.jvm.backend.Platform; +import io.spine.logging.jvm.backend.SimpleMessageFormatter; +import io.spine.logging.jvm.context.ScopedLoggingContext; +import io.spine.logging.jvm.context.Tags; import java.util.logging.Level; import java.util.stream.Collectors; import java.util.stream.StreamSupport; @@ -111,7 +111,7 @@ private static LogEvent toLog4jLogEvent( org.apache.logging.log4j.Level level, Throwable thrown) { - FloggerLogSite logSite = logData.getLogSite(); + JvmLogSite logSite = logData.getLogSite(); StackTraceElement locationInfo = new StackTraceElement( logSite.getClassName(), @@ -205,11 +205,11 @@ private static void appendLogData(LogData data, StringBuilder out) { out.append("\n line number: ").append(data.getLogSite().getLineNumber()); } - private static final MetadataHandler HANDLER = + private static final MetadataHandler HANDLER = MetadataHandler.builder(Log4j2LogEventUtil::handleMetadata).build(); private static void handleMetadata( - FloggerMetadataKey key, Object value, FloggerMetadataKey.KeyValueHandler kvh) { + JvmMetadataKey key, Object value, JvmMetadataKey.KeyValueHandler kvh) { if (key.getClass().equals(LogContext.Key.TAGS.getClass())) { processTags(key, value, kvh); } else { @@ -225,7 +225,7 @@ private static void handleMetadata( } private static void processTags( - FloggerMetadataKey key, Object value, FloggerMetadataKey.KeyValueHandler kvh) { + JvmMetadataKey key, Object value, JvmMetadataKey.KeyValueHandler kvh) { ValueQueue valueQueue = ValueQueue.appendValueToNewQueue(value); // Unlike single metadata (which is usually formatted as a single value), tags are always // formatted as a list. diff --git a/backends/log4j2-backend/src/main/java/io/spine/logging/backend/log4j2/Log4j2LoggerBackend.java b/backends/log4j2-backend/src/main/java/io/spine/logging/backend/log4j2/Log4j2LoggerBackend.java index 6000e729b..1b3861376 100644 --- a/backends/log4j2-backend/src/main/java/io/spine/logging/backend/log4j2/Log4j2LoggerBackend.java +++ b/backends/log4j2-backend/src/main/java/io/spine/logging/backend/log4j2/Log4j2LoggerBackend.java @@ -26,8 +26,8 @@ package io.spine.logging.backend.log4j2; -import io.spine.logging.flogger.backend.LogData; -import io.spine.logging.flogger.backend.LoggerBackend; +import io.spine.logging.jvm.backend.LogData; +import io.spine.logging.jvm.backend.LoggerBackend; import org.apache.logging.log4j.core.Logger; import static io.spine.logging.backend.log4j2.Log4j2LogEventUtil.toLog4jLevel; diff --git a/backends/log4j2-backend/src/main/java/io/spine/logging/backend/log4j2/ValueQueue.java b/backends/log4j2-backend/src/main/java/io/spine/logging/backend/log4j2/ValueQueue.java index a40450f64..067c197a8 100644 --- a/backends/log4j2-backend/src/main/java/io/spine/logging/backend/log4j2/ValueQueue.java +++ b/backends/log4j2-backend/src/main/java/io/spine/logging/backend/log4j2/ValueQueue.java @@ -26,10 +26,10 @@ package io.spine.logging.backend.log4j2; -import static io.spine.logging.flogger.util.Checks.checkNotNull; +import static io.spine.logging.jvm.util.Checks.checkNotNull; -import io.spine.logging.flogger.FloggerMetadataKey.KeyValueHandler; -import io.spine.logging.flogger.context.Tags; +import io.spine.logging.jvm.JvmMetadataKey.KeyValueHandler; +import io.spine.logging.jvm.context.Tags; import java.util.Iterator; import java.util.LinkedList; import java.util.List; diff --git a/backends/log4j2-backend/src/main/resources/META-INF/services/io.spine.logging.flogger.backend.BackendFactory b/backends/log4j2-backend/src/main/resources/META-INF/services/io.spine.logging.jvm.backend.BackendFactory similarity index 100% rename from backends/log4j2-backend/src/main/resources/META-INF/services/io.spine.logging.flogger.backend.BackendFactory rename to backends/log4j2-backend/src/main/resources/META-INF/services/io.spine.logging.jvm.backend.BackendFactory diff --git a/backends/log4j2-backend/src/test/kotlin/io/spine/logging/backend/log4j2/Log4j2BackendFactorySpec.kt b/backends/log4j2-backend/src/test/kotlin/io/spine/logging/backend/log4j2/Log4j2BackendFactorySpec.kt index bf6cb2cfa..fdc680947 100644 --- a/backends/log4j2-backend/src/test/kotlin/io/spine/logging/backend/log4j2/Log4j2BackendFactorySpec.kt +++ b/backends/log4j2-backend/src/test/kotlin/io/spine/logging/backend/log4j2/Log4j2BackendFactorySpec.kt @@ -26,7 +26,7 @@ package io.spine.logging.backend.log4j2 -import io.spine.logging.flogger.backend.BackendFactory +import io.spine.logging.jvm.backend.BackendFactory import io.kotest.matchers.collections.shouldHaveSize import io.kotest.matchers.nulls.shouldNotBeNull import io.kotest.matchers.types.shouldBeInstanceOf diff --git a/backends/log4j2-backend/src/test/kotlin/io/spine/logging/backend/log4j2/Log4j2LoggerBackendSpec.kt b/backends/log4j2-backend/src/test/kotlin/io/spine/logging/backend/log4j2/Log4j2LoggerBackendSpec.kt index 06a24bc66..7a2766c17 100644 --- a/backends/log4j2-backend/src/test/kotlin/io/spine/logging/backend/log4j2/Log4j2LoggerBackendSpec.kt +++ b/backends/log4j2-backend/src/test/kotlin/io/spine/logging/backend/log4j2/Log4j2LoggerBackendSpec.kt @@ -33,13 +33,13 @@ import io.kotest.matchers.shouldBe import io.kotest.matchers.string.shouldContain import io.kotest.matchers.types.shouldBeSameInstanceAs import io.spine.logging.backend.log4j2.given.MemoizingAppender -import io.spine.logging.flogger.FloggerLogSite -import io.spine.logging.flogger.LogContext.Key -import io.spine.logging.flogger.backend.given.FakeLogData -import io.spine.logging.flogger.given.FakeLogSite -import io.spine.logging.flogger.parser.ParseException -import io.spine.logging.flogger.repeatedKey -import io.spine.logging.flogger.singleKey +import io.spine.logging.jvm.JvmLogSite +import io.spine.logging.jvm.LogContext.Key +import io.spine.logging.jvm.backend.given.FakeLogData +import io.spine.logging.jvm.given.FakeLogSite +import io.spine.logging.jvm.parser.ParseException +import io.spine.logging.jvm.repeatedKey +import io.spine.logging.jvm.singleKey import java.util.concurrent.atomic.AtomicInteger import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.core.Appender @@ -175,7 +175,7 @@ internal class Log4j2LoggerBackendSpec { testLogSite(logSite) } - private fun testLogSite(logSite: FloggerLogSite) { + private fun testLogSite(logSite: JvmLogSite) { val data = FakeLogData("") .setLogSite(logSite) backend.log(data) diff --git a/backends/log4j2-backend/src/test/kotlin/io/spine/logging/backend/log4j2/Log4j2ScopedLoggingSpec.kt b/backends/log4j2-backend/src/test/kotlin/io/spine/logging/backend/log4j2/Log4j2ScopedLoggingSpec.kt index bad09f4e9..0349c6e62 100644 --- a/backends/log4j2-backend/src/test/kotlin/io/spine/logging/backend/log4j2/Log4j2ScopedLoggingSpec.kt +++ b/backends/log4j2-backend/src/test/kotlin/io/spine/logging/backend/log4j2/Log4j2ScopedLoggingSpec.kt @@ -29,12 +29,12 @@ package io.spine.logging.backend.log4j2 import io.kotest.matchers.collections.shouldHaveSize import io.kotest.matchers.shouldBe import io.spine.logging.backend.log4j2.given.MemoizingAppender -import io.spine.logging.flogger.LogContext.Key -import io.spine.logging.flogger.context.ContextDataProvider -import io.spine.logging.flogger.context.Tags -import io.spine.logging.flogger.given.ConfigurableLogger -import io.spine.logging.flogger.repeatedKey -import io.spine.logging.flogger.singleKey +import io.spine.logging.jvm.LogContext.Key +import io.spine.logging.jvm.context.ContextDataProvider +import io.spine.logging.jvm.context.Tags +import io.spine.logging.jvm.given.ConfigurableLogger +import io.spine.logging.jvm.repeatedKey +import io.spine.logging.jvm.singleKey import java.util.concurrent.atomic.AtomicInteger import org.apache.logging.log4j.Level import org.apache.logging.log4j.LogManager @@ -48,7 +48,7 @@ import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test /** - * Tests for interaction between [ScopedLoggingContext][io.spine.logging.flogger.context.ScopedLoggingContext] + * Tests for interaction between [ScopedLoggingContext][io.spine.logging.jvm.context.ScopedLoggingContext] * and [Log4j2LoggerBackend]. * * `ScopedLoggingContext` is abstract. To test it with Log4j backend, diff --git a/backends/probe-backend/src/main/kotlin/io/spine/logging/backend/probe/CaptureLogData.kt b/backends/probe-backend/src/main/kotlin/io/spine/logging/backend/probe/CaptureLogData.kt index 739caed5c..797fe09af 100644 --- a/backends/probe-backend/src/main/kotlin/io/spine/logging/backend/probe/CaptureLogData.kt +++ b/backends/probe-backend/src/main/kotlin/io/spine/logging/backend/probe/CaptureLogData.kt @@ -26,7 +26,7 @@ package io.spine.logging.backend.probe -import io.spine.logging.flogger.backend.LogData +import io.spine.logging.jvm.backend.LogData /** * Runs the given [action], capturing all log data that are passed diff --git a/backends/probe-backend/src/main/kotlin/io/spine/logging/backend/probe/DynamicBackendFactory.kt b/backends/probe-backend/src/main/kotlin/io/spine/logging/backend/probe/DynamicBackendFactory.kt index 84b7c336a..bcb7bfafe 100644 --- a/backends/probe-backend/src/main/kotlin/io/spine/logging/backend/probe/DynamicBackendFactory.kt +++ b/backends/probe-backend/src/main/kotlin/io/spine/logging/backend/probe/DynamicBackendFactory.kt @@ -26,8 +26,8 @@ package io.spine.logging.backend.probe -import io.spine.logging.flogger.backend.LoggerBackend -import io.spine.logging.flogger.backend.BackendFactory +import io.spine.logging.jvm.backend.LoggerBackend +import io.spine.logging.jvm.backend.BackendFactory import io.spine.logging.backend.jul.JulBackendFactory /** diff --git a/backends/probe-backend/src/main/kotlin/io/spine/logging/backend/probe/DynamicBackendFactoryService.kt b/backends/probe-backend/src/main/kotlin/io/spine/logging/backend/probe/DynamicBackendFactoryService.kt index f3bff6af5..9acbbb0fc 100644 --- a/backends/probe-backend/src/main/kotlin/io/spine/logging/backend/probe/DynamicBackendFactoryService.kt +++ b/backends/probe-backend/src/main/kotlin/io/spine/logging/backend/probe/DynamicBackendFactoryService.kt @@ -27,8 +27,8 @@ package io.spine.logging.backend.probe import com.google.auto.service.AutoService -import io.spine.logging.flogger.backend.LoggerBackend -import io.spine.logging.flogger.backend.BackendFactory +import io.spine.logging.jvm.backend.LoggerBackend +import io.spine.logging.jvm.backend.BackendFactory /** * Adapts [DynamicBackendFactory] to be used with Java's diff --git a/backends/probe-backend/src/main/kotlin/io/spine/logging/backend/probe/MemoizingBackendFactory.kt b/backends/probe-backend/src/main/kotlin/io/spine/logging/backend/probe/MemoizingBackendFactory.kt index a77742a1e..3a37abfbd 100644 --- a/backends/probe-backend/src/main/kotlin/io/spine/logging/backend/probe/MemoizingBackendFactory.kt +++ b/backends/probe-backend/src/main/kotlin/io/spine/logging/backend/probe/MemoizingBackendFactory.kt @@ -26,7 +26,7 @@ package io.spine.logging.backend.probe -import io.spine.logging.flogger.backend.LoggerBackend +import io.spine.logging.jvm.backend.LoggerBackend /** * A backend factory that stores the created instances of [LoggerBackend]. diff --git a/backends/probe-backend/src/main/kotlin/io/spine/logging/backend/probe/MemoizingLoggerBackendFactory.kt b/backends/probe-backend/src/main/kotlin/io/spine/logging/backend/probe/MemoizingLoggerBackendFactory.kt index f82050373..997d7709d 100644 --- a/backends/probe-backend/src/main/kotlin/io/spine/logging/backend/probe/MemoizingLoggerBackendFactory.kt +++ b/backends/probe-backend/src/main/kotlin/io/spine/logging/backend/probe/MemoizingLoggerBackendFactory.kt @@ -26,7 +26,7 @@ package io.spine.logging.backend.probe -import io.spine.logging.flogger.backend.given.MemoizingLoggerBackend +import io.spine.logging.jvm.backend.given.MemoizingLoggerBackend /** * A factory of [MemoizingLoggerBackend]. diff --git a/backends/probe-backend/src/main/kotlin/io/spine/logging/backend/probe/TypedBackendFactory.kt b/backends/probe-backend/src/main/kotlin/io/spine/logging/backend/probe/TypedBackendFactory.kt index 3f54b4978..6fed1542a 100644 --- a/backends/probe-backend/src/main/kotlin/io/spine/logging/backend/probe/TypedBackendFactory.kt +++ b/backends/probe-backend/src/main/kotlin/io/spine/logging/backend/probe/TypedBackendFactory.kt @@ -26,7 +26,7 @@ package io.spine.logging.backend.probe -import io.spine.logging.flogger.backend.LoggerBackend +import io.spine.logging.jvm.backend.LoggerBackend /** * A typed [BackendFactory][io.spine.logging.backend.system.BackendFactory]. diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Flogger.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Jvm.kt similarity index 99% rename from buildSrc/src/main/kotlin/io/spine/dependency/lib/Flogger.kt rename to buildSrc/src/main/kotlin/io/spine/dependency/lib/Jvm.kt index 769c90543..49396f5d7 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Flogger.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Jvm.kt @@ -29,7 +29,7 @@ package io.spine.dependency.lib // https://github.com/google/flogger @Deprecated("Please use Spine Logging library instead.") @Suppress("unused", "ConstPropertyName") -object Flogger { +object Jvm { internal const val version = "0.7.4" const val lib = "com.google.flogger:flogger:$version" diff --git a/contexts/grpc-context/src/main/java/io/spine/logging/context/grpc/GrpcContextData.java b/contexts/grpc-context/src/main/java/io/spine/logging/context/grpc/GrpcContextData.java index b476db326..bdacd3d47 100644 --- a/contexts/grpc-context/src/main/java/io/spine/logging/context/grpc/GrpcContextData.java +++ b/contexts/grpc-context/src/main/java/io/spine/logging/context/grpc/GrpcContextData.java @@ -26,12 +26,12 @@ package io.spine.logging.context.grpc; -import io.spine.logging.flogger.LoggingScope; -import io.spine.logging.flogger.context.ContextMetadata; -import io.spine.logging.flogger.context.LogLevelMap; -import io.spine.logging.flogger.context.ScopeType; -import io.spine.logging.flogger.context.ScopedLoggingContext.ScopeList; -import io.spine.logging.flogger.context.Tags; +import io.spine.logging.jvm.LoggingScope; +import io.spine.logging.jvm.context.ContextMetadata; +import io.spine.logging.jvm.context.LogLevelMap; +import io.spine.logging.jvm.context.ScopeType; +import io.spine.logging.jvm.context.ScopedLoggingContext.ScopeList; +import io.spine.logging.jvm.context.Tags; import java.util.concurrent.atomic.AtomicReference; import java.util.logging.Level; import org.jspecify.annotations.Nullable; diff --git a/contexts/grpc-context/src/main/java/io/spine/logging/context/grpc/GrpcContextDataProvider.java b/contexts/grpc-context/src/main/java/io/spine/logging/context/grpc/GrpcContextDataProvider.java index 242db3778..f328e4ba8 100644 --- a/contexts/grpc-context/src/main/java/io/spine/logging/context/grpc/GrpcContextDataProvider.java +++ b/contexts/grpc-context/src/main/java/io/spine/logging/context/grpc/GrpcContextDataProvider.java @@ -26,12 +26,12 @@ package io.spine.logging.context.grpc; -import io.spine.logging.flogger.LoggingScope; -import io.spine.logging.flogger.context.ContextDataProvider; -import io.spine.logging.flogger.context.ContextMetadata; -import io.spine.logging.flogger.context.ScopeType; -import io.spine.logging.flogger.context.ScopedLoggingContext; -import io.spine.logging.flogger.context.Tags; +import io.spine.logging.jvm.LoggingScope; +import io.spine.logging.jvm.context.ContextDataProvider; +import io.spine.logging.jvm.context.ContextMetadata; +import io.spine.logging.jvm.context.ScopeType; +import io.spine.logging.jvm.context.ScopedLoggingContext; +import io.spine.logging.jvm.context.Tags; import io.grpc.Context; import java.util.logging.Level; import org.jspecify.annotations.Nullable; diff --git a/contexts/grpc-context/src/main/java/io/spine/logging/context/grpc/GrpcScopedLoggingContext.java b/contexts/grpc-context/src/main/java/io/spine/logging/context/grpc/GrpcScopedLoggingContext.java index 5fc00bc81..1a27ac022 100644 --- a/contexts/grpc-context/src/main/java/io/spine/logging/context/grpc/GrpcScopedLoggingContext.java +++ b/contexts/grpc-context/src/main/java/io/spine/logging/context/grpc/GrpcScopedLoggingContext.java @@ -26,14 +26,14 @@ package io.spine.logging.context.grpc; -import static io.spine.logging.flogger.util.Checks.checkNotNull; +import static io.spine.logging.jvm.util.Checks.checkNotNull; -import io.spine.logging.flogger.FloggerMetadataKey; -import io.spine.logging.flogger.context.ContextMetadata; -import io.spine.logging.flogger.context.LogLevelMap; -import io.spine.logging.flogger.context.ScopeType; -import io.spine.logging.flogger.context.ScopedLoggingContext; -import io.spine.logging.flogger.context.Tags; +import io.spine.logging.jvm.JvmMetadataKey; +import io.spine.logging.jvm.context.ContextMetadata; +import io.spine.logging.jvm.context.LogLevelMap; +import io.spine.logging.jvm.context.ScopeType; +import io.spine.logging.jvm.context.ScopedLoggingContext; +import io.spine.logging.jvm.context.Tags; import io.grpc.Context; import org.jspecify.annotations.Nullable; @@ -99,7 +99,7 @@ public boolean addTags(Tags tags) { } @Override - public boolean addMetadata(FloggerMetadataKey key, T value) { + public boolean addMetadata(JvmMetadataKey key, T value) { // Serves as the null pointer check, and we don't care much about the extra allocation in the // case where there's no context, because that should be very rare (and the singleton is small). ContextMetadata metadata = ContextMetadata.singleton(key, value); diff --git a/contexts/grpc-context/src/main/java/io/spine/logging/context/grpc/package-info.java b/contexts/grpc-context/src/main/java/io/spine/logging/context/grpc/package-info.java index 40aad02f8..42b335764 100644 --- a/contexts/grpc-context/src/main/java/io/spine/logging/context/grpc/package-info.java +++ b/contexts/grpc-context/src/main/java/io/spine/logging/context/grpc/package-info.java @@ -26,7 +26,7 @@ /** * Contains {@link io.grpc.Context gRPC}-based implementation of - * {@link io.spine.logging.flogger.context.ScopedLoggingContext ScopedLoggingContext}. + * {@link io.spine.logging.jvm.context.ScopedLoggingContext ScopedLoggingContext}. * * @see Original Java code of Google Flogger */ diff --git a/contexts/grpc-context/src/main/resources/META-INF/services/io.spine.logging.flogger.context.ContextDataProvider b/contexts/grpc-context/src/main/resources/META-INF/services/io.spine.logging.jvm.context.ContextDataProvider similarity index 100% rename from contexts/grpc-context/src/main/resources/META-INF/services/io.spine.logging.flogger.context.ContextDataProvider rename to contexts/grpc-context/src/main/resources/META-INF/services/io.spine.logging.jvm.context.ContextDataProvider diff --git a/contexts/grpc-context/src/test/kotlin/io/spine/logging/context/grpc/GrpcContextDataProviderSpec.kt b/contexts/grpc-context/src/test/kotlin/io/spine/logging/context/grpc/GrpcContextDataProviderSpec.kt index 0eae5dd6b..1faf3278c 100644 --- a/contexts/grpc-context/src/test/kotlin/io/spine/logging/context/grpc/GrpcContextDataProviderSpec.kt +++ b/contexts/grpc-context/src/test/kotlin/io/spine/logging/context/grpc/GrpcContextDataProviderSpec.kt @@ -29,8 +29,8 @@ package io.spine.logging.context.grpc import io.kotest.matchers.nulls.shouldNotBeNull import io.kotest.matchers.optional.shouldBePresent import io.kotest.matchers.types.shouldBeInstanceOf -import io.spine.logging.flogger.context.AbstractContextDataProviderSpec -import io.spine.logging.flogger.context.ContextDataProvider +import io.spine.logging.jvm.context.AbstractContextDataProviderSpec +import io.spine.logging.jvm.context.ContextDataProvider import java.util.* import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test diff --git a/contexts/std-context/src/main/kotlin/io/spine/logging/context/std/StdContextData.kt b/contexts/std-context/src/main/kotlin/io/spine/logging/context/std/StdContextData.kt index 6f6611345..b06b3bacd 100644 --- a/contexts/std-context/src/main/kotlin/io/spine/logging/context/std/StdContextData.kt +++ b/contexts/std-context/src/main/kotlin/io/spine/logging/context/std/StdContextData.kt @@ -29,11 +29,11 @@ package io.spine.logging.context.std import io.spine.logging.Level import io.spine.logging.compareTo import io.spine.logging.context.LogLevelMap -import io.spine.logging.flogger.LoggingScope -import io.spine.logging.flogger.context.ContextMetadata -import io.spine.logging.flogger.context.ScopeType -import io.spine.logging.flogger.context.ScopedLoggingContext.ScopeList -import io.spine.logging.flogger.context.Tags +import io.spine.logging.jvm.LoggingScope +import io.spine.logging.jvm.context.ContextMetadata +import io.spine.logging.jvm.context.ScopeType +import io.spine.logging.jvm.context.ScopedLoggingContext.ScopeList +import io.spine.logging.jvm.context.Tags /** * The data of a scoped logging context with merging capabilities when diff --git a/contexts/std-context/src/main/kotlin/io/spine/logging/context/std/StdContextDataProvider.kt b/contexts/std-context/src/main/kotlin/io/spine/logging/context/std/StdContextDataProvider.kt index aff4fda8b..44b8af444 100644 --- a/contexts/std-context/src/main/kotlin/io/spine/logging/context/std/StdContextDataProvider.kt +++ b/contexts/std-context/src/main/kotlin/io/spine/logging/context/std/StdContextDataProvider.kt @@ -27,13 +27,13 @@ package io.spine.logging.context.std import io.spine.logging.context.toMap -import io.spine.logging.flogger.LoggingScope -import io.spine.logging.flogger.backend.Metadata -import io.spine.logging.flogger.context.ContextDataProvider -import io.spine.logging.flogger.context.ScopeType -import io.spine.logging.flogger.context.ScopedLoggingContext -import io.spine.logging.flogger.context.ScopedLoggingContext.LoggingContextCloseable -import io.spine.logging.flogger.context.Tags +import io.spine.logging.jvm.LoggingScope +import io.spine.logging.jvm.backend.Metadata +import io.spine.logging.jvm.context.ContextDataProvider +import io.spine.logging.jvm.context.ScopeType +import io.spine.logging.jvm.context.ScopedLoggingContext +import io.spine.logging.jvm.context.ScopedLoggingContext.LoggingContextCloseable +import io.spine.logging.jvm.context.Tags import io.spine.logging.toJavaLogging import io.spine.logging.toLevel import java.util.logging.Level diff --git a/contexts/std-context/src/main/resources/META-INF/services/io.spine.logging.flogger.context.ContextDataProvider b/contexts/std-context/src/main/resources/META-INF/services/io.spine.logging.jvm.context.ContextDataProvider similarity index 100% rename from contexts/std-context/src/main/resources/META-INF/services/io.spine.logging.flogger.context.ContextDataProvider rename to contexts/std-context/src/main/resources/META-INF/services/io.spine.logging.jvm.context.ContextDataProvider diff --git a/contexts/std-context/src/test/kotlin/io/spine/logging/context/std/StdContextDataProviderSpec.kt b/contexts/std-context/src/test/kotlin/io/spine/logging/context/std/StdContextDataProviderSpec.kt index bdaf62ab9..d0ef8bc1c 100644 --- a/contexts/std-context/src/test/kotlin/io/spine/logging/context/std/StdContextDataProviderSpec.kt +++ b/contexts/std-context/src/test/kotlin/io/spine/logging/context/std/StdContextDataProviderSpec.kt @@ -29,8 +29,8 @@ package io.spine.logging.context.std import io.kotest.matchers.nulls.shouldNotBeNull import io.kotest.matchers.optional.shouldBePresent import io.kotest.matchers.types.shouldBeInstanceOf -import io.spine.logging.flogger.context.AbstractContextDataProviderSpec -import io.spine.logging.flogger.context.ContextDataProvider +import io.spine.logging.jvm.context.AbstractContextDataProviderSpec +import io.spine.logging.jvm.context.ContextDataProvider import java.util.* import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test diff --git a/flogger/README.md b/flogger/README.md index cc77a6095..093e36886 100644 --- a/flogger/README.md +++ b/flogger/README.md @@ -3,7 +3,7 @@ This directory contains Flogger [modules][flogger-github] built with Gradle. Original Flogger sources have been repackaged from `com.google.common.*` -to `io.spine.logging.flogger.*`. It prevents a runtime clash in situations +to `io.spine.logging.jvm.*`. It prevents a runtime clash in situations when a user has both `spine-logging` and `flogger` on the classpath. However, a user is not meant to use two logging libraries simultaneously. `flogger` may appear on the classpath as a transitive dependency. diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/AbstractLogger.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/AbstractLogger.java similarity index 95% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/AbstractLogger.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/AbstractLogger.java index aedfced67..02afd0655 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/AbstractLogger.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/AbstractLogger.java @@ -24,16 +24,16 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger; +package io.spine.logging.jvm; -import static io.spine.logging.flogger.util.Checks.checkNotNull; +import static io.spine.logging.jvm.util.Checks.checkNotNull; import static java.util.concurrent.TimeUnit.NANOSECONDS; -import io.spine.logging.flogger.backend.LogData; -import io.spine.logging.flogger.backend.LoggerBackend; -import io.spine.logging.flogger.backend.LoggingException; -import io.spine.logging.flogger.backend.MessageUtils; -import io.spine.logging.flogger.util.RecursionDepth; +import io.spine.logging.jvm.backend.LogData; +import io.spine.logging.jvm.backend.LoggerBackend; +import io.spine.logging.jvm.backend.LoggingException; +import io.spine.logging.jvm.backend.MessageUtils; +import io.spine.logging.jvm.util.RecursionDepth; import java.text.SimpleDateFormat; import java.util.Date; import java.util.logging.Level; @@ -47,7 +47,7 @@ * @see * Original Java code of Google Flogger */ -public abstract class AbstractLogger> { +public abstract class AbstractLogger> { /** * An upper bound on the depth of reentrant logging allowed by Flogger. Logger backends may choose * to react to reentrant logging sooner than this, but once this value is reached, a warning is diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/CountingRateLimiter.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/CountingRateLimiter.java similarity index 95% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/CountingRateLimiter.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/CountingRateLimiter.java index bb2159c1b..4a77931aa 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/CountingRateLimiter.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/CountingRateLimiter.java @@ -24,11 +24,11 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger; +package io.spine.logging.jvm; -import static io.spine.logging.flogger.LogContext.Key.LOG_EVERY_N; +import static io.spine.logging.jvm.LogContext.Key.LOG_EVERY_N; -import io.spine.logging.flogger.backend.Metadata; +import io.spine.logging.jvm.backend.Metadata; import java.util.concurrent.atomic.AtomicLong; import org.jspecify.annotations.Nullable; @@ -83,7 +83,7 @@ static RateLimitStatus check(Metadata metadata, LogSiteKey logSiteKey) { /** * Increments the invocation count and returns true if it reached the specified rate limit count. * This is invoked during post-processing if a rate limiting count was set via {@link - * FloggerApi#every(int)}. + * JvmApi#every(int)}. */ // Visible for testing. RateLimitStatus incrementAndCheckLogCount(int rateLimitCount) { diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/DurationRateLimiter.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/DurationRateLimiter.java similarity index 94% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/DurationRateLimiter.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/DurationRateLimiter.java index 84a6d0934..da908d31f 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/DurationRateLimiter.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/DurationRateLimiter.java @@ -24,15 +24,15 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger; +package io.spine.logging.jvm; -import static io.spine.logging.flogger.LogContext.Key.LOG_AT_MOST_EVERY; -import static io.spine.logging.flogger.util.Checks.checkArgument; -import static io.spine.logging.flogger.util.Checks.checkNotNull; +import static io.spine.logging.jvm.LogContext.Key.LOG_AT_MOST_EVERY; +import static io.spine.logging.jvm.util.Checks.checkArgument; +import static io.spine.logging.jvm.util.Checks.checkNotNull; import static java.lang.Math.max; -import io.spine.logging.flogger.backend.LogData; -import io.spine.logging.flogger.backend.Metadata; +import io.spine.logging.jvm.backend.LogData; +import io.spine.logging.jvm.backend.Metadata; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; import org.jspecify.annotations.Nullable; @@ -136,7 +136,7 @@ public boolean equals(Object obj) { /** * Checks whether the current time stamp is after the rate limiting period and if so, updates the * time stamp and returns true. This is invoked during post-processing if a rate limiting duration - * was set via {@link FloggerApi#atMostEvery(int, TimeUnit)}. + * was set via {@link JvmApi#atMostEvery(int, TimeUnit)}. */ // Visible for testing. RateLimitStatus checkLastTimestamp(long timestampNanos, RateLimitPeriod period) { diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/FluentLogger2.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/FluentLogger2.java similarity index 92% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/FluentLogger2.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/FluentLogger2.java index b5af7288d..086681da1 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/FluentLogger2.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/FluentLogger2.java @@ -24,17 +24,17 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger; +package io.spine.logging.jvm; -import io.spine.logging.flogger.backend.LoggerBackend; -import io.spine.logging.flogger.backend.Platform; -import io.spine.logging.flogger.parser.DefaultPrintfMessageParser; -import io.spine.logging.flogger.parser.MessageParser; +import io.spine.logging.jvm.backend.LoggerBackend; +import io.spine.logging.jvm.backend.Platform; +import io.spine.logging.jvm.parser.DefaultPrintfMessageParser; +import io.spine.logging.jvm.parser.MessageParser; import java.util.logging.Level; /** - * The default implementation of {@link AbstractLogger} which returns the basic {@link FloggerApi} + * The default implementation of {@link AbstractLogger} which returns the basic {@link JvmApi} * and uses the default parser and system configured backend. *

* Note that when extending the logging API or specifying a new parser, you will need to create a @@ -57,13 +57,13 @@ public final class FluentLogger2 extends AbstractLogger { * a separate top-level API and LogContext is created, allowing it to be shared by other * implementations. */ - public interface Api extends FloggerApi {} + public interface Api extends JvmApi {} /** * The non-wildcard, fully specified, no-op API implementation. This is required to provide a * no-op implementation whose type is compatible with this logger's API. */ - private static final class NoOp extends FloggerApi.NoOp implements Api {} + private static final class NoOp extends JvmApi.NoOp implements Api {} // Singleton instance of the no-op API. This variable is purposefully declared as an instance of // the NoOp type instead of the Api type. This helps ProGuard optimization recognize the type of diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/FloggerApi.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/JvmApi.java similarity index 97% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/FloggerApi.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/JvmApi.java index 11faeab92..db8bdfb65 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/FloggerApi.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/JvmApi.java @@ -24,11 +24,11 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger; +package io.spine.logging.jvm; import org.jspecify.annotations.Nullable; -import static io.spine.logging.flogger.util.Checks.checkNotNull; +import static io.spine.logging.jvm.util.Checks.checkNotNull; import java.util.concurrent.TimeUnit; @@ -56,7 +56,7 @@ * Original Java code of Google Flogger */ @SuppressWarnings({"ClassWithTooManyMethods", "OverlyComplexClass"}) -public interface FloggerApi> { +public interface JvmApi> { /** * Associates a {@link Throwable} instance with the current log statement, to be interpreted as * the cause of this statement. @@ -265,15 +265,15 @@ public interface FloggerApi> { * Aggregates stateful logging with respect to a scoped context determined by the given scope * provider. * - *

When {@link io.spine.logging.flogger.context.ScopedLoggingContext ScopedLoggingContext} - * is used to create a context, it can be bound to a {@link io.spine.logging.flogger.context.ScopeType ScopeType}. + *

When {@link io.spine.logging.jvm.context.ScopedLoggingContext ScopedLoggingContext} + * is used to create a context, it can be bound to a {@link io.spine.logging.jvm.context.ScopeType ScopeType}. * For example: * *

{@code
    * ScopedLoggingContexts.newContext(REQUEST).run(() -> scopedMethod(x, y, z));
    * }
* - * where {@link io.spine.logging.flogger.context.ScopeType#REQUEST REQUEST} defines the scope + * where {@link io.spine.logging.jvm.context.ScopeType#REQUEST REQUEST} defines the scope * type for the context in which {@code scopedMethod()} is called. Within this context, the scope * associated with the {@code REQUEST} type can then be used to aggregate logging behavior: * @@ -281,7 +281,7 @@ public interface FloggerApi> { * logger.atInfo().atMostEvery(5, SECONDS).per(REQUEST).log("Some message..."); * } * - *

New scope types can be created for specific subtasks using {@link io.spine.logging.flogger.context.ScopeType#create ScopeType.create("")} + *

New scope types can be created for specific subtasks using {@link io.spine.logging.jvm.context.ScopeType#create ScopeType.create("")} * but it is recommended to use shared constants (such as {@code ScopeType.REQUEST}) wherever feasible to * avoid confusion. * @@ -329,7 +329,7 @@ public interface FloggerApi> { *

  • Key value pairs which are explicitly extracted from logs by tools. * * - *

    Metadata keys can support repeated values (see {@link FloggerMetadataKey#canRepeat()}), and if a + *

    Metadata keys can support repeated values (see {@link JvmMetadataKey#canRepeat()}), and if a * repeatable key is used multiple times in the same log statement, the effect is to collect all * the given values in order. If a non-repeatable key is passed multiple times, only the last * value is retained (though callers should not rely on this behavior and should simply avoid @@ -342,9 +342,9 @@ public interface FloggerApi> { * @param value a value to be associated with the key in this log statement. Null values are * allowed, but the effect is always a no-op * @throws NullPointerException if the given key is null - * @see FloggerMetadataKey + * @see JvmMetadataKey */ - API with(FloggerMetadataKey key, @Nullable T value); + API with(JvmMetadataKey key, @Nullable T value); /** * Sets a boolean metadata key constant to {@code true} for this log statement in a structured way @@ -363,9 +363,9 @@ public interface FloggerApi> { * * @param key the boolean metadata key (expected to be a static constant) * @throws NullPointerException if the given key is null - * @see FloggerMetadataKey + * @see JvmMetadataKey */ - API with(FloggerMetadataKey key); + API with(JvmMetadataKey key); /** * Sets the log site for the current log statement. Explicit log site injection is very rarely @@ -386,7 +386,7 @@ public interface FloggerApi> { * and then code can do: * *

    {@code
    -   * import static io.spine.logging.flogger.LogSites.logSite;
    +   * import static io.spine.logging.jvm.LogSites.logSite;
        * }
    * * and elsewhere: @@ -418,7 +418,7 @@ public interface FloggerApi> { * * @param logSite Log site which uniquely identifies any per-log statement resources. */ - API withInjectedLogSite(@Nullable FloggerLogSite logSite); + API withInjectedLogSite(@Nullable JvmLogSite logSite); /** * Internal method not for public use. This method is only intended for use by the logger @@ -815,19 +815,19 @@ void log( void log(String msg, double p1, double p2); /** - * An implementation of {@link FloggerApi} which does nothing and discards all parameters. + * An implementation of {@link JvmApi} which does nothing and discards all parameters. *

    * This class (or a subclass in the case of an extended API) should be returned whenever logging * is definitely disabled (e.g. when the log level is too low). */ - public static class NoOp> implements FloggerApi { + public static class NoOp> implements JvmApi { @SuppressWarnings("unchecked") protected final API noOp() { return (API) this; } @Override - public API withInjectedLogSite(FloggerLogSite logSite) { + public API withInjectedLogSite(JvmLogSite logSite) { return noOp(); } @@ -846,14 +846,14 @@ public final boolean isEnabled() { } @Override - public final API with(FloggerMetadataKey key, @Nullable T value) { + public final API with(JvmMetadataKey key, @Nullable T value) { // Identical to the check in LogContext for consistency. checkNotNull(key, "metadata key"); return noOp(); } @Override - public final API with(FloggerMetadataKey key) { + public final API with(JvmMetadataKey key) { // Do this inline rather than calling with(key, true) to keep no-op minimal. checkNotNull(key, "metadata key"); return noOp(); diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/FloggerLogSite.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/JvmLogSite.java similarity index 93% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/FloggerLogSite.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/JvmLogSite.java index e6a812470..2fd68850c 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/FloggerLogSite.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/JvmLogSite.java @@ -24,9 +24,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger; +package io.spine.logging.jvm; -import static io.spine.logging.flogger.util.Checks.checkNotNull; +import static io.spine.logging.jvm.util.Checks.checkNotNull; import org.jspecify.annotations.Nullable; @@ -50,14 +50,14 @@ * @see * Original Java code of Google Flogger */ -public abstract class FloggerLogSite implements LogSiteKey { +public abstract class JvmLogSite implements LogSiteKey { /** A value used for line numbers when the true information is not available. */ public static final int UNKNOWN_LINE = 0; /** * An singleton LogSite instance used to indicate that valid log site information cannot be * determined. This can be used to indicate that log site information is not available by - * injecting it via {@link FloggerApi#withInjectedLogSite} which will suppress any further + * injecting it via {@link JvmApi#withInjectedLogSite} which will suppress any further * log site analysis for that log statement. This is also returned if stack trace analysis * fails for any reason. *

    @@ -65,8 +65,8 @@ public abstract class FloggerLogSite implements LogSiteKey { * methods which rely on being able to look up site specific metadata will be disabled and * essentially become "no ops". */ - public static final FloggerLogSite INVALID = - new FloggerLogSite() { + public static final JvmLogSite INVALID = + new JvmLogSite() { @Override public String getClassName() { return ""; @@ -153,18 +153,18 @@ public final String toString() { * directly. */ @Deprecated - public static FloggerLogSite injectedLogSite( + public static JvmLogSite injectedLogSite( String internalClassName, String methodName, int encodedLineNumber, @Nullable String sourceFileName) { - return new InjectedFloggerLogSite(internalClassName, + return new InjectedJvmLogSite(internalClassName, methodName, encodedLineNumber, sourceFileName); } - private static final class InjectedFloggerLogSite extends FloggerLogSite { + private static final class InjectedJvmLogSite extends JvmLogSite { /** Internal (slash-separated) fully qualified class name (eg, "com/example/Foo$Bar"). */ private final String internalClassName; @@ -175,7 +175,7 @@ private static final class InjectedFloggerLogSite extends FloggerLogSite { @Nullable private final String sourceFileName; private int hashcode = 0; - private InjectedFloggerLogSite( + private InjectedJvmLogSite( String internalClassName, String methodName, int encodedLineNumber, @@ -214,8 +214,8 @@ public String getFileName() { @Override public boolean equals(Object obj) { - if (obj instanceof InjectedFloggerLogSite) { - InjectedFloggerLogSite other = (InjectedFloggerLogSite) obj; + if (obj instanceof InjectedJvmLogSite) { + InjectedJvmLogSite other = (InjectedJvmLogSite) obj; // Probably not worth optimizing for "this == obj" because all strings should be interned. return methodName.equals(other.methodName) && encodedLineNumber == other.encodedLineNumber diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/FloggerLogSites.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/JvmLogSites.java similarity index 85% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/FloggerLogSites.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/JvmLogSites.java index d519cde48..7e9b24480 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/FloggerLogSites.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/JvmLogSites.java @@ -24,26 +24,26 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger; +package io.spine.logging.jvm; -import io.spine.logging.flogger.backend.Platform; +import io.spine.logging.jvm.backend.Platform; import org.jspecify.annotations.Nullable; /** * Helper class to generate log sites for the current line of code. This class is deliberately - * isolated (rather than having the method in {@link FloggerLogSite} itself) because manual log site + * isolated (rather than having the method in {@link JvmLogSite} itself) because manual log site * injection is rare and by isolating it into a separate class may help encourage users to think * carefully about the issue. * * @see * Original Java code of Google Flogger */ -public final class FloggerLogSites { +public final class JvmLogSites { /** * Returns a {@code LogSite} for the caller of the specified class. This can be used in - * conjunction with the {@link FloggerApi#withInjectedLogSite(FloggerLogSite)} method to implement + * conjunction with the {@link JvmApi#withInjectedLogSite(JvmLogSite)} method to implement * logging helper methods. In some platforms, log site determination may be unsupported, and in - * those cases this method will always return the {@link FloggerLogSite#INVALID} instance. + * those cases this method will always return the {@link JvmLogSite#INVALID} instance. *

    * For example (in {@code MyLoggingHelper}): *

    {@code
    @@ -82,18 +82,18 @@ public final class FloggerLogSites {
        * @param loggingApi the logging API to be identified as the source of log statements (this must
        *        appear somewhere on the stack above the point at which this method is called).
        * @return the log site of the caller of the specified logging API,
    -   *        or {@link FloggerLogSite#INVALID} if the logging API was not found.
    +   *        or {@link JvmLogSite#INVALID} if the logging API was not found.
        */
    -  public static FloggerLogSite callerOf(Class loggingApi) {
    +  public static JvmLogSite callerOf(Class loggingApi) {
         // Can't skip anything here since someone could pass in LogSite.class.
         return Platform.getCallerFinder().findLogSite(loggingApi, 0);
       }
     
       /**
        * Returns a {@code LogSite} for the current line of code. This can be used in conjunction with
    -   * the {@link FloggerApi#withInjectedLogSite(FloggerLogSite)} method to implement logging helper
    + * the {@link JvmApi#withInjectedLogSite(JvmLogSite)} method to implement logging helper
        * methods. In some platforms, log site determination may be unsupported, and in those cases this
    -   * method will always return the {@link FloggerLogSite#INVALID} instance.
    +   * method will always return the {@link JvmLogSite#INVALID} instance.
        * 

    * For example (in {@code MyLoggingHelper}): *

    {@code
    @@ -128,21 +128,21 @@ public static FloggerLogSite callerOf(Class loggingApi) {
        *
        * @return the log site of the caller of this method.
        */
    -  public static FloggerLogSite logSite() {
    +  public static JvmLogSite logSite() {
         // Don't call "callerOf()" to avoid making another stack entry.
    -    return Platform.getCallerFinder().findLogSite(FloggerLogSites.class, 0);
    +    return Platform.getCallerFinder().findLogSite(JvmLogSites.class, 0);
       }
     
       /**
        * Returns a new {@code LogSite} which reflects the information in the given {@link
    -   * StackTraceElement}, or {@link FloggerLogSite#INVALID} if given {@code null}.
    +   * StackTraceElement}, or {@link JvmLogSite#INVALID} if given {@code null}.
        *
        * 

    This method is useful when log site information is only available via an external API, * which returns {@link StackTraceElement}. */ - public static FloggerLogSite logSiteFrom(@Nullable StackTraceElement e) { - return e != null ? new StackBasedLogSite(e) : FloggerLogSite.INVALID; + public static JvmLogSite logSiteFrom(@Nullable StackTraceElement e) { + return e != null ? new StackBasedLogSite(e) : JvmLogSite.INVALID; } - private FloggerLogSites() {} + private JvmLogSites() {} } diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/FloggerMetadataKey.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/JvmMetadataKey.java similarity index 94% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/FloggerMetadataKey.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/JvmMetadataKey.java index 96a94190f..8050016c4 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/FloggerMetadataKey.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/JvmMetadataKey.java @@ -24,13 +24,13 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger; +package io.spine.logging.jvm; -import static io.spine.logging.flogger.util.Checks.checkMetadataIdentifier; -import static io.spine.logging.flogger.util.Checks.checkNotNull; -import static io.spine.logging.flogger.util.Checks.checkState; +import static io.spine.logging.jvm.util.Checks.checkMetadataIdentifier; +import static io.spine.logging.jvm.util.Checks.checkNotNull; +import static io.spine.logging.jvm.util.Checks.checkState; -import io.spine.logging.flogger.backend.Platform; +import io.spine.logging.jvm.backend.Platform; import java.util.Iterator; /** @@ -60,7 +60,7 @@ * {@code equals()} (rather than '==') since this will be safe in cases where non-singleton keys * exist, and is just as fast if the keys are singletons. * - *

    It is strongly recommended that any public {@link FloggerMetadataKey} instances are defined + *

    It is strongly recommended that any public {@link JvmMetadataKey} instances are defined * as {@code public static final} fields in a top-level or nested class, which does no logging. * Ideally a separate class would be defined to hold only the keys, since this allows keys * to be loaded very early in the logging {@link Platform} lifecycle without risking any static @@ -94,7 +94,7 @@ * @see * Original Java code of Google Flogger */ -public class FloggerMetadataKey { +public class JvmMetadataKey { // High levels of reentrant logging could well be caused by custom metadata keys. This is set // lower than the total limit on reentrant logging because it's one of the more likely ways in // which unbounded reentrant logging could occur, but it's also easy to mitigate. @@ -104,7 +104,7 @@ public class FloggerMetadataKey { * Callback interface to handle additional contextual {@code Metadata} in log statements. This * interface is only intended to be implemented by logger backend classes as part of handling * metadata, and should not be used in any general application code, other than to implement the - * {@link FloggerMetadataKey#emit} method in this class. + * {@link JvmMetadataKey#emit} method in this class. */ public interface KeyValueHandler { /** Handle a single key/value a pair of contextual metadata for a log statement. */ @@ -127,8 +127,8 @@ public interface KeyValueHandler { * primitive class may lead to a runtime exception because metadata keys * are used with generics. */ - public static FloggerMetadataKey single(String label, Class clazz) { - return new FloggerMetadataKey<>(label, clazz, false, false); + public static JvmMetadataKey single(String label, Class clazz) { + return new JvmMetadataKey<>(label, clazz, false, false); } /** @@ -147,8 +147,8 @@ public static FloggerMetadataKey single(String label, Class * primitive class may lead to a runtime exception because metadata keys * are used with generics. */ - public static FloggerMetadataKey repeated(String label, Class clazz) { - return new FloggerMetadataKey<>(label, clazz, true, false); + public static JvmMetadataKey repeated(String label, Class clazz) { + return new JvmMetadataKey<>(label, clazz, true, false); } private final String label; @@ -162,13 +162,13 @@ public static FloggerMetadataKey repeated(String label, Class clazz) { * but occasionally it can be useful to create a specific subtype to control the formatting of * values or to have a family of related keys with a common parent type. */ - protected FloggerMetadataKey(String label, Class clazz, boolean canRepeat) { + protected JvmMetadataKey(String label, Class clazz, boolean canRepeat) { this(label, clazz, canRepeat, true); } // Private constructor to allow instances generated by static factory methods to be marked as // non-custom. - private FloggerMetadataKey(String label, Class clazz, + private JvmMetadataKey(String label, Class clazz, boolean canRepeat, boolean isCustom) { this.label = checkMetadataIdentifier(label); this.clazz = checkNotNull(clazz, "class"); diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/LazyArg.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/LazyArg.java similarity index 98% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/LazyArg.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/LazyArg.java index 9656ac916..9e59ddf42 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/LazyArg.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/LazyArg.java @@ -24,7 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger; +package io.spine.logging.jvm; import org.jspecify.annotations.Nullable; diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/LazyArgs.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/LazyArgs.java similarity index 97% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/LazyArgs.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/LazyArgs.java index e15a50b72..8fac1aa5f 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/LazyArgs.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/LazyArgs.java @@ -24,9 +24,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger; +package io.spine.logging.jvm; -import static io.spine.logging.flogger.util.Checks.checkNotNull; +import static io.spine.logging.jvm.util.Checks.checkNotNull; /** * Static utility methods for lazy argument evaluation in Flogger. The {@link #lazy(LazyArg)} diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/LogContext.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/LogContext.java similarity index 94% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/LogContext.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/LogContext.java index 1721e1ab6..f4f7f326d 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/LogContext.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/LogContext.java @@ -24,15 +24,15 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger; - -import io.spine.logging.flogger.DurationRateLimiter.RateLimitPeriod; -import io.spine.logging.flogger.backend.LogData; -import io.spine.logging.flogger.backend.Metadata; -import io.spine.logging.flogger.backend.Platform; -import io.spine.logging.flogger.backend.TemplateContext; -import io.spine.logging.flogger.context.Tags; -import io.spine.logging.flogger.parser.MessageParser; +package io.spine.logging.jvm; + +import io.spine.logging.jvm.DurationRateLimiter.RateLimitPeriod; +import io.spine.logging.jvm.backend.LogData; +import io.spine.logging.jvm.backend.Metadata; +import io.spine.logging.jvm.backend.Platform; +import io.spine.logging.jvm.backend.TemplateContext; +import io.spine.logging.jvm.context.Tags; +import io.spine.logging.jvm.parser.MessageParser; import org.jspecify.annotations.Nullable; import java.util.Arrays; @@ -42,15 +42,15 @@ import java.util.concurrent.TimeUnit; import java.util.logging.Level; -import static io.spine.logging.flogger.FloggerLogSite.injectedLogSite; -import static io.spine.logging.flogger.util.Checks.checkNotNull; +import static io.spine.logging.jvm.JvmLogSite.injectedLogSite; +import static io.spine.logging.jvm.util.Checks.checkNotNull; import static io.spine.reflect.CallerFinder.stackForCallerOf; import static java.util.concurrent.TimeUnit.NANOSECONDS; /** * The base context for a logging statement, which implements the base logging API. * - *

    This class is an implementation of the base {@link FloggerApi} interface and acts as a holder + *

    This class is an implementation of the base {@link JvmApi} interface and acts as a holder * for any state applied to the log statement during the fluent call sequence. The lifecycle of a * logging context is very short; it is created by a logger, usually in response to a call to the * {@link AbstractLogger#at(Level)} method, and normally lasts only as long as the log statement. @@ -66,8 +66,8 @@ * @see * Original Java code of Google Flogger */ -public abstract class LogContext, API extends FloggerApi> - implements FloggerApi, LogData { +public abstract class LogContext, API extends JvmApi> + implements JvmApi, LogData { /** * The predefined metadata keys used by the default logging API. Backend implementations can use @@ -78,38 +78,38 @@ public static final class Key { private Key() {} /** * The key associated with a {@link Throwable} cause to be associated with the log message. This - * value is set by {@link FloggerApi#withCause(Throwable)}. + * value is set by {@link JvmApi#withCause(Throwable)}. */ - public static final FloggerMetadataKey LOG_CAUSE = - FloggerMetadataKey.single("cause", Throwable.class); + public static final JvmMetadataKey LOG_CAUSE = + JvmMetadataKey.single("cause", Throwable.class); /** * The key associated with a rate limiting counter for "1-in-N" rate limiting. The value is set - * by {@link FloggerApi#every(int)}. + * by {@link JvmApi#every(int)}. */ - public static final FloggerMetadataKey LOG_EVERY_N = - FloggerMetadataKey.single("ratelimit_count", Integer.class); + public static final JvmMetadataKey LOG_EVERY_N = + JvmMetadataKey.single("ratelimit_count", Integer.class); /** * The key associated with a rate limiting counter for "1-in-N" randomly sampled rate limiting. - * The value is set by {@link FloggerApi#onAverageEvery(int)}. + * The value is set by {@link JvmApi#onAverageEvery(int)}. */ - public static final FloggerMetadataKey LOG_SAMPLE_EVERY_N = - FloggerMetadataKey.single("sampling_count", Integer.class); + public static final JvmMetadataKey LOG_SAMPLE_EVERY_N = + JvmMetadataKey.single("sampling_count", Integer.class); /** * The key associated with a rate limiting period for "at most once every N" rate limiting. The - * value is set by {@link FloggerApi#atMostEvery(int, TimeUnit)}. + * value is set by {@link JvmApi#atMostEvery(int, TimeUnit)}. */ - public static final FloggerMetadataKey LOG_AT_MOST_EVERY = - FloggerMetadataKey.single("ratelimit_period", RateLimitPeriod.class); + public static final JvmMetadataKey LOG_AT_MOST_EVERY = + JvmMetadataKey.single("ratelimit_period", RateLimitPeriod.class); /** * The key associated with a count of rate limited logs. This is only public so backends can * reference the key to control formatting. */ - public static final FloggerMetadataKey SKIPPED_LOG_COUNT = - FloggerMetadataKey.single("skipped", Integer.class); + public static final JvmMetadataKey SKIPPED_LOG_COUNT = + JvmMetadataKey.single("skipped", Integer.class); /** * The key associated with a sequence of log site "grouping keys". These serve to specialize the @@ -117,8 +117,8 @@ private Key() {} * by the {@code per()} methods and is only public so backends can reference the key to control * formatting. */ - public static final FloggerMetadataKey LOG_SITE_GROUPING_KEY = - new FloggerMetadataKey<>("group_by", Object.class, true) { + public static final JvmMetadataKey LOG_SITE_GROUPING_KEY = + new JvmMetadataKey<>("group_by", Object.class, true) { @Override public void emitRepeated(Iterator keys, KeyValueHandler out) { if (keys.hasNext()) { @@ -172,8 +172,8 @@ public void emitRepeated(Iterator keys, KeyValueHandler out) { * Thus it makes no sense to provide a public method to set this value programmatically for a * log statement. */ - public static final FloggerMetadataKey WAS_FORCED = - FloggerMetadataKey.single("forced", Boolean.class); + public static final JvmMetadataKey WAS_FORCED = + JvmMetadataKey.single("forced", Boolean.class); /** * The key associated with any injected {@link Tags}. @@ -187,8 +187,8 @@ public void emitRepeated(Iterator keys, KeyValueHandler out) { * normal log message arguments is always the preferred way to indicate unstrctured log data. * Users should never build new {@link Tags} instances just to pass them into a log statement. */ - public static final FloggerMetadataKey TAGS = - new FloggerMetadataKey<>("tags", Tags.class, false) { + public static final JvmMetadataKey TAGS = + new JvmMetadataKey<>("tags", Tags.class, false) { @Override public void emit(Tags tags, KeyValueHandler out) { for (Map.Entry> e : tags.asMap().entrySet()) { @@ -208,8 +208,8 @@ public void emit(Tags tags, KeyValueHandler out) { * Key associated with the metadata for specifying additional stack information with a log * statement. */ - public static final FloggerMetadataKey CONTEXT_STACK_SIZE = - FloggerMetadataKey.single("stack_size", StackSize.class); + public static final JvmMetadataKey CONTEXT_STACK_SIZE = + JvmMetadataKey.single("stack_size", StackSize.class); } static final class MutableMetadata extends Metadata { @@ -241,11 +241,11 @@ public int size() { } @Override - public FloggerMetadataKey getKey(int n) { + public JvmMetadataKey getKey(int n) { if (n >= keyValueCount) { throw new IndexOutOfBoundsException(); } - return (FloggerMetadataKey) keyValuePairs[2 * n]; + return (JvmMetadataKey) keyValuePairs[2 * n]; } @Override @@ -256,7 +256,7 @@ public Object getValue(int n) { return keyValuePairs[(2 * n) + 1]; } - private int indexOf(FloggerMetadataKey key) { + private int indexOf(JvmMetadataKey key) { for (var index = 0; index < keyValueCount; index++) { if (keyValuePairs[2 * index].equals(key)) { return index; @@ -267,7 +267,7 @@ private int indexOf(FloggerMetadataKey key) { @Override @Nullable - public T findValue(FloggerMetadataKey key) { + public T findValue(JvmMetadataKey key) { var index = indexOf(key); return index != -1 ? key.cast(keyValuePairs[(2 * index) + 1]) : null; } @@ -277,7 +277,7 @@ public T findValue(FloggerMetadataKey key) { * cannot be repeated, and there is already a value for the key in the metadata, then the * existing value is replaced, otherwise the value is added at the end of the metadata. */ - void addValue(FloggerMetadataKey key, T value) { + void addValue(JvmMetadataKey key, T value) { if (!key.canRepeat()) { var index = indexOf(key); if (index != -1) { @@ -298,7 +298,7 @@ void addValue(FloggerMetadataKey key, T value) { } /** Removes all key/value pairs for a given key. */ - void removeAllValues(FloggerMetadataKey key) { + void removeAllValues(JvmMetadataKey key) { var index = indexOf(key); if (index >= 0) { var dest = 2 * index; @@ -349,7 +349,7 @@ public String toString() { /** Additional metadata for this log statement (added via fluent API methods). */ private MutableMetadata metadata = null; /** The log site information for this log statement (set immediately prior to post-processing). */ - private FloggerLogSite logSite = null; + private JvmLogSite logSite = null; /** Rate limit status (only set if rate limiting occurs). */ private RateLimitStatus rateLimitStatus = null; /** The template context if formatting is required (set only after post-processing). */ @@ -435,7 +435,7 @@ public final String getLoggerName() { } @Override - public final FloggerLogSite getLogSite() { + public final JvmLogSite getLogSite() { if (logSite == null) { throw new IllegalStateException("cannot request log site information prior to postProcess()"); } @@ -492,7 +492,7 @@ public final Metadata getMetadata() { * @param key the metadata key (see {@link LogData}). * @param value the metadata value. */ - protected final void addMetadata(FloggerMetadataKey key, T value) { + protected final void addMetadata(JvmMetadataKey key, T value) { if (metadata == null) { metadata = new MutableMetadata(); } @@ -505,7 +505,7 @@ protected final void addMetadata(FloggerMetadataKey key, T value) { * * @param key the metadata key (see {@link LogData}). */ - protected final void removeMetadata(FloggerMetadataKey key) { + protected final void removeMetadata(JvmMetadataKey key) { if (metadata != null) { metadata.removeAllValues(key); } @@ -544,7 +544,7 @@ protected final void removeMetadata(FloggerMetadataKey key) { * {@link LogSiteMap}. This will correctly handle "specialized" log-site keys and remove the risk * of memory leaks due to retaining unused log site data indefinitely. * - *

    Note that the given {@code logSiteKey} can be more specific than the {@link FloggerLogSite} + *

    Note that the given {@code logSiteKey} can be more specific than the {@link JvmLogSite} * of a log statement (i.e. a single log statement can have multiple distinct versions of * its state). See {@link #per(Enum)} for more information. * @@ -686,7 +686,7 @@ private boolean shouldLog() { "logger backend must not return a null LogSite"); } LogSiteKey logSiteKey = null; - if (logSite != FloggerLogSite.INVALID) { + if (logSite != JvmLogSite.INVALID) { logSiteKey = logSite; // Log site keys are only modified when we have metadata in the log statement. if (metadata != null && metadata.size() > 0) { @@ -776,7 +776,7 @@ private void logImpl(String message, Object... args) { // ---- Log site injection (used by pre-processors and special cases) ---- @Override - public final API withInjectedLogSite(FloggerLogSite logSite) { + public final API withInjectedLogSite(JvmLogSite logSite) { // First call wins (since auto-injection will typically target the log() method at the end of // the chain and might not check for previous explicit injection). In particular it MUST be // allowed for a caller to specify the "INVALID" log site, and have that set the field here to @@ -810,7 +810,7 @@ public final boolean isEnabled() { } @Override - public final API with(FloggerMetadataKey key, @Nullable T value) { + public final API with(JvmMetadataKey key, @Nullable T value) { // Null keys are always bad (even if the value is also null). This is one of the few places // where the logger API will throw a runtime exception (and as such it's important to ensure // the NoOp implementation also does the check). The reasoning for this is that the metadata @@ -824,7 +824,7 @@ public final API with(FloggerMetadataKey key, @Nullable T value) { } @Override - public final API with(FloggerMetadataKey key) { + public final API with(JvmMetadataKey key) { return with(key, Boolean.TRUE); } @@ -868,7 +868,7 @@ public final API onAverageEvery(int n) { return everyImpl(Key.LOG_SAMPLE_EVERY_N, n, "sampling"); } - private API everyImpl(FloggerMetadataKey key, int n, String label) { + private API everyImpl(JvmMetadataKey key, int n, String label) { // See wasForced() for discussion as to why this occurs before argument checking. if (wasForced()) { return api(); diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/LogPerBucketingStrategy.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/LogPerBucketingStrategy.java similarity index 97% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/LogPerBucketingStrategy.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/LogPerBucketingStrategy.java index 02872c122..6f68edb69 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/LogPerBucketingStrategy.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/LogPerBucketingStrategy.java @@ -24,10 +24,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger; +package io.spine.logging.jvm; -import static io.spine.logging.flogger.util.Checks.checkArgument; -import static io.spine.logging.flogger.util.Checks.checkNotNull; +import static io.spine.logging.jvm.util.Checks.checkArgument; +import static io.spine.logging.jvm.util.Checks.checkNotNull; import java.util.HashMap; import org.jspecify.annotations.Nullable; @@ -226,7 +226,7 @@ protected LogPerBucketingStrategy(String name) { *

    Warning: If keys are not known to have natural singleton semantics * (e.g. {@code String}) then returning the given key instance is generally a bad idea. * Even if the set of key values is small, the set of distinct allocated instances passed to - * {@link FloggerApi#per(Object,LogPerBucketingStrategy)} can be unbounded, and that's what matters. + * {@link JvmApi#per(Object,LogPerBucketingStrategy)} can be unbounded, and that's what matters. * As such, it is always better to map keys to some singleton identifier or intern the keys in * some way. * diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/LogSiteKey.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/LogSiteKey.java similarity index 96% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/LogSiteKey.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/LogSiteKey.java index e2c94a36d..ac7807aa1 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/LogSiteKey.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/LogSiteKey.java @@ -24,11 +24,11 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger; +package io.spine.logging.jvm; /** * A tagging interface to mark implementations that are suitable for use as a key for looking up - * per log site persistent state. Normally the class used is just {@link FloggerLogSite} but other, + * per log site persistent state. Normally the class used is just {@link JvmLogSite} but other, * more specific, keys can be used. There are no method requirements on this interface, * but the instance must have correct {@code equals()}, {@code hashCode()} and {@code toString()} * implementations and must be at least as unique as the associated {@code LogSite} (i.e., two keys diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/LogSiteMap.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/LogSiteMap.java similarity index 97% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/LogSiteMap.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/LogSiteMap.java index cbd3509a2..f252c84e6 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/LogSiteMap.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/LogSiteMap.java @@ -24,11 +24,11 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger; +package io.spine.logging.jvm; -import static io.spine.logging.flogger.util.Checks.checkNotNull; +import static io.spine.logging.jvm.util.Checks.checkNotNull; -import io.spine.logging.flogger.backend.Metadata; +import io.spine.logging.jvm.backend.Metadata; import java.util.concurrent.ConcurrentHashMap; /** diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/LogSiteStackTrace.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/LogSiteStackTrace.java similarity index 98% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/LogSiteStackTrace.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/LogSiteStackTrace.java index a4e41a47d..bbc293306 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/LogSiteStackTrace.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/LogSiteStackTrace.java @@ -24,7 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger; +package io.spine.logging.jvm; import org.jspecify.annotations.Nullable; diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/LoggingScope.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/LoggingScope.java similarity index 96% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/LoggingScope.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/LoggingScope.java index 781c87bd7..e9bf41966 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/LoggingScope.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/LoggingScope.java @@ -24,11 +24,11 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger; +package io.spine.logging.jvm; -import static io.spine.logging.flogger.util.Checks.checkNotNull; +import static io.spine.logging.jvm.util.Checks.checkNotNull; -import io.spine.logging.flogger.backend.Metadata; +import io.spine.logging.jvm.backend.Metadata; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; import java.util.Queue; @@ -39,7 +39,7 @@ * stateful logging operations (e.g. rate limiting). * *

    Scopes are provided via the {@link LoggingScopeProvider} interface and found by looking for - * the current {@link io.spine.logging.flogger.context.ScopedLoggingContext ScopedLoggingContexts}. + * the current {@link io.spine.logging.jvm.context.ScopedLoggingContext ScopedLoggingContexts}. * *

    Stateful fluent logging APIs which need to look up per log site information (e.g. rate limit * state) should do so via a {@link LogSiteMap} using the {@link LogSiteKey} passed into the {@link diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/LoggingScopeProvider.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/LoggingScopeProvider.java similarity index 98% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/LoggingScopeProvider.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/LoggingScopeProvider.java index 1878604a6..e9c9b6e6a 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/LoggingScopeProvider.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/LoggingScopeProvider.java @@ -24,7 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger; +package io.spine.logging.jvm; import org.jspecify.annotations.Nullable; diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/RateLimitStatus.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/RateLimitStatus.java similarity index 99% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/RateLimitStatus.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/RateLimitStatus.java index e787ff9dd..a5ed6db14 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/RateLimitStatus.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/RateLimitStatus.java @@ -24,9 +24,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger; +package io.spine.logging.jvm; -import io.spine.logging.flogger.backend.Metadata; +import io.spine.logging.jvm.backend.Metadata; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import org.jspecify.annotations.Nullable; diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/SamplingRateLimiter.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/SamplingRateLimiter.java similarity index 96% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/SamplingRateLimiter.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/SamplingRateLimiter.java index 75b28a6d8..944510f5f 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/SamplingRateLimiter.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/SamplingRateLimiter.java @@ -24,15 +24,15 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger; +package io.spine.logging.jvm; -import io.spine.logging.flogger.backend.Metadata; +import io.spine.logging.jvm.backend.Metadata; import org.jspecify.annotations.Nullable; import java.util.Random; import java.util.concurrent.atomic.AtomicInteger; -import static io.spine.logging.flogger.LogContext.Key.LOG_SAMPLE_EVERY_N; +import static io.spine.logging.jvm.LogContext.Key.LOG_SAMPLE_EVERY_N; /** * Rate limiter to support {@code onAverageEvery(N)} functionality. diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/SpecializedLogSiteKey.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/SpecializedLogSiteKey.java similarity index 96% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/SpecializedLogSiteKey.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/SpecializedLogSiteKey.java index d35095c37..58e5292d9 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/SpecializedLogSiteKey.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/SpecializedLogSiteKey.java @@ -24,9 +24,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger; +package io.spine.logging.jvm; -import static io.spine.logging.flogger.util.Checks.checkNotNull; +import static io.spine.logging.jvm.util.Checks.checkNotNull; import org.jspecify.annotations.Nullable; diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/StackBasedLogSite.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/StackBasedLogSite.java similarity index 89% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/StackBasedLogSite.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/StackBasedLogSite.java index 7501be161..f1592589f 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/StackBasedLogSite.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/StackBasedLogSite.java @@ -24,9 +24,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger; +package io.spine.logging.jvm; -import static io.spine.logging.flogger.util.Checks.checkNotNull; +import static io.spine.logging.jvm.util.Checks.checkNotNull; import static java.lang.Math.max; import org.jspecify.annotations.Nullable; @@ -44,13 +44,13 @@ * * *

    This class should not be used directly outside the core Flogger libraries. If you need to - * generate a {@link FloggerLogSite} from a {@link StackTraceElement}, use {@link - * FloggerLogSites#logSiteFrom(StackTraceElement) LogSites.logSiteFrom(myStackTaceElement)}. + * generate a {@link JvmLogSite} from a {@link StackTraceElement}, use {@link + * JvmLogSites#logSiteFrom(StackTraceElement) LogSites.logSiteFrom(myStackTaceElement)}. * * @see * Original Java code of Google Flogger */ -final class StackBasedLogSite extends FloggerLogSite { +final class StackBasedLogSite extends JvmLogSite { // StackTraceElement is unmodifiable once created. private final StackTraceElement stackElement; @@ -71,7 +71,7 @@ public String getMethodName() { @Override public int getLineNumber() { // Prohibit negative numbers (which can appear in stack trace elements) from being returned. - return max(stackElement.getLineNumber(), FloggerLogSite.UNKNOWN_LINE); + return max(stackElement.getLineNumber(), JvmLogSite.UNKNOWN_LINE); } @Override diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/StackSize.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/StackSize.java similarity index 93% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/StackSize.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/StackSize.java index 52079bee2..cdbb147c7 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/StackSize.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/StackSize.java @@ -24,10 +24,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger; +package io.spine.logging.jvm; /** - * Enum values to be passed into {@link FloggerApi#withStackTrace} to control + * Enum values to be passed into {@link JvmApi#withStackTrace} to control * the maximum number of stack trace elements created. * *

    Note that the precise value returned by {@link #getMaxDepth()} may change over time, @@ -46,8 +46,8 @@ public enum StackSize { *

    * Requesting a small stack trace for log statements which occur under normal circumstances is * acceptable, but may affect performance. Consider using - * {@link FloggerApi#withStackTrace(StackSize)} in conjunction with rate limiting methods, - * such as {@link FloggerApi#atMostEvery(int, java.util.concurrent.TimeUnit)}, to mitigate + * {@link JvmApi#withStackTrace(StackSize)} in conjunction with rate limiting methods, + * such as {@link JvmApi#atMostEvery(int, java.util.concurrent.TimeUnit)}, to mitigate * performance issues. *

    * The current maximum size of a {@code SMALL} stack trace is 10 elements, but this may change. diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/backend/BackendFactory.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/BackendFactory.java similarity index 97% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/backend/BackendFactory.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/backend/BackendFactory.java index 78f946cc6..2d657469c 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/backend/BackendFactory.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/BackendFactory.java @@ -24,7 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.backend; +package io.spine.logging.jvm.backend; /** * An API to create logger backends for a given class name. This is implemented as an abstract class @@ -59,7 +59,7 @@ * the jar file containing the implementation. When creating an implementation of this class, you * can provide serivce metadata (and thereby allow users to get your implementation just by * including your jar file) by either manually including a {@code - * META-INF/services/io.spine.logging.flogger.backend.BackendFactory} file containing the + * META-INF/services/io.spine.logging.jvm.backend.BackendFactory} file containing the * name of your implementation class or by annotating your implementation class using * {@code @AutoService(BackendFactory.class)}. See the documentation of both {@link diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/backend/BaseMessageFormatter.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/BaseMessageFormatter.java similarity index 95% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/backend/BaseMessageFormatter.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/backend/BaseMessageFormatter.java index 40de09a34..f65cef5ca 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/backend/BaseMessageFormatter.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/BaseMessageFormatter.java @@ -24,15 +24,15 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.backend; +package io.spine.logging.jvm.backend; -import static io.spine.logging.flogger.backend.FormatOptions.FLAG_UPPER_CASE; -import static io.spine.logging.flogger.util.Checks.checkNotNull; +import static io.spine.logging.jvm.backend.FormatOptions.FLAG_UPPER_CASE; +import static io.spine.logging.jvm.util.Checks.checkNotNull; -import io.spine.logging.flogger.parameter.DateTimeFormat; -import io.spine.logging.flogger.parameter.Parameter; -import io.spine.logging.flogger.parameter.ParameterVisitor; -import io.spine.logging.flogger.parser.MessageBuilder; +import io.spine.logging.jvm.parameter.DateTimeFormat; +import io.spine.logging.jvm.parameter.Parameter; +import io.spine.logging.jvm.parameter.ParameterVisitor; +import io.spine.logging.jvm.parser.MessageBuilder; import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.util.Calendar; import java.util.Date; diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/backend/Clock.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/Clock.java similarity index 96% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/backend/Clock.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/backend/Clock.java index e1c7e36a1..534ebb3ac 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/backend/Clock.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/Clock.java @@ -24,7 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.backend; +package io.spine.logging.jvm.backend; /** * A clock to return walltime timestamps for log statements. This is implemented as an abstract @@ -59,7 +59,7 @@ * the jar file containing the implementation. When creating an implementation of this class, you * can provide serivce metadata (and thereby allow users to get your implementation just by * including your jar file) by either manually including a {@code - * META-INF/services/io.spine.logging.flogger.backend.Clock} file containing the name of + * META-INF/services/io.spine.logging.jvm.backend.Clock} file containing the name of * your implementation class or by annotating your implementation class using {@code @AutoService(Clock.class)}. * See the documentation of both {@link java.util.ServiceLoader} and {@code DefaultPlatform} for diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/backend/FormatChar.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/FormatChar.java similarity index 99% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/backend/FormatChar.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/backend/FormatChar.java index 666d9383e..67c473f21 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/backend/FormatChar.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/FormatChar.java @@ -24,7 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.backend; +package io.spine.logging.jvm.backend; /** * An enum representing the printf-like formatting characters that must be supported by all logging diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/backend/FormatOptions.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/FormatOptions.java similarity index 99% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/backend/FormatOptions.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/backend/FormatOptions.java index 976b2ac88..138c827fe 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/backend/FormatOptions.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/FormatOptions.java @@ -24,9 +24,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.backend; +package io.spine.logging.jvm.backend; -import io.spine.logging.flogger.parser.ParseException; +import io.spine.logging.jvm.parser.ParseException; import com.google.errorprone.annotations.CanIgnoreReturnValue; import org.jspecify.annotations.Nullable; @@ -388,7 +388,7 @@ static boolean checkFlagConsistency(int flags, boolean hasWidth) { *

    * Note that there is not requirement for options used internally in custom message parsers to be * validated, but any format options passed through the - * {@link io.spine.logging.flogger.parameter.ParameterVisitor ParameterVisitor} interface must + * {@link io.spine.logging.jvm.parameter.ParameterVisitor ParameterVisitor} interface must * be valid with respect to the associated {@link FormatChar} instance. * * @param formatChar the formatting rule to check these options against. diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/backend/FormatType.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/FormatType.java similarity index 99% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/backend/FormatType.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/backend/FormatType.java index 070046a7c..3dfd89caa 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/backend/FormatType.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/FormatType.java @@ -24,7 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.backend; +package io.spine.logging.jvm.backend; import java.math.BigDecimal; import java.math.BigInteger; diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/backend/KeyValueFormatter.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/KeyValueFormatter.java similarity index 98% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/backend/KeyValueFormatter.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/backend/KeyValueFormatter.java index d1f8c1b46..5537e1b44 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/backend/KeyValueFormatter.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/KeyValueFormatter.java @@ -24,9 +24,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.backend; +package io.spine.logging.jvm.backend; -import io.spine.logging.flogger.FloggerMetadataKey.KeyValueHandler; +import io.spine.logging.jvm.JvmMetadataKey.KeyValueHandler; import java.util.Arrays; import java.util.HashSet; import java.util.Set; diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/backend/LogData.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/LogData.java similarity index 97% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/backend/LogData.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/backend/LogData.java index 1da9d3a26..7fbd8d9ad 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/backend/LogData.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/LogData.java @@ -24,9 +24,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.backend; +package io.spine.logging.jvm.backend; -import io.spine.logging.flogger.FloggerLogSite; +import io.spine.logging.jvm.JvmLogSite; import java.util.logging.Level; /** @@ -66,7 +66,7 @@ public interface LogData { * * @throws IllegalStateException if called prior to the postProcess() method being called. */ - FloggerLogSite getLogSite(); + JvmLogSite getLogSite(); /** * Returns any additional metadata for this log statement. If no additional metadata is present, diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/backend/LogMessageFormatter.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/LogMessageFormatter.java similarity index 98% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/backend/LogMessageFormatter.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/backend/LogMessageFormatter.java index e01bd27b1..15a8f59cd 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/backend/LogMessageFormatter.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/LogMessageFormatter.java @@ -24,7 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.backend; +package io.spine.logging.jvm.backend; import com.google.errorprone.annotations.CanIgnoreReturnValue; diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/backend/LoggerBackend.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/LoggerBackend.java similarity index 97% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/backend/LoggerBackend.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/backend/LoggerBackend.java index 7667ad015..c72daa731 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/backend/LoggerBackend.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/LoggerBackend.java @@ -24,10 +24,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.backend; +package io.spine.logging.jvm.backend; -import io.spine.logging.flogger.AbstractLogger; -import io.spine.logging.flogger.parser.ParseException; +import io.spine.logging.jvm.AbstractLogger; +import io.spine.logging.jvm.parser.ParseException; import java.util.logging.Level; diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/backend/LoggingException.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/LoggingException.java similarity index 98% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/backend/LoggingException.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/backend/LoggingException.java index 689c5c7ac..acd55e57f 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/backend/LoggingException.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/LoggingException.java @@ -24,7 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.backend; +package io.spine.logging.jvm.backend; import org.jspecify.annotations.Nullable; diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/backend/MessageUtils.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/MessageUtils.java similarity index 95% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/backend/MessageUtils.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/backend/MessageUtils.java index 4c0aef23e..89a5ff801 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/backend/MessageUtils.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/MessageUtils.java @@ -24,13 +24,13 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.backend; +package io.spine.logging.jvm.backend; -import static io.spine.logging.flogger.backend.FormatOptions.FLAG_LEFT_ALIGN; -import static io.spine.logging.flogger.backend.FormatOptions.FLAG_SHOW_ALT_FORM; -import static io.spine.logging.flogger.backend.FormatOptions.FLAG_UPPER_CASE; +import static io.spine.logging.jvm.backend.FormatOptions.FLAG_LEFT_ALIGN; +import static io.spine.logging.jvm.backend.FormatOptions.FLAG_SHOW_ALT_FORM; +import static io.spine.logging.jvm.backend.FormatOptions.FLAG_UPPER_CASE; -import io.spine.logging.flogger.FloggerLogSite; +import io.spine.logging.jvm.JvmLogSite; import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.io.IOException; import java.math.BigInteger; @@ -62,13 +62,13 @@ private MessageUtils() {} /** * Appends log-site information in the default format, including a trailing space. * - * @param logSite the log site to be appended (ingored if {@link FloggerLogSite#INVALID}). + * @param logSite the log site to be appended (ingored if {@link JvmLogSite#INVALID}). * @param out the destination buffer. * @return whether the log-site was appended. */ @CanIgnoreReturnValue - public static boolean appendLogSite(FloggerLogSite logSite, StringBuilder out) { - if (logSite == FloggerLogSite.INVALID) { + public static boolean appendLogSite(JvmLogSite logSite, StringBuilder out) { + if (logSite == JvmLogSite.INVALID) { return false; } out.append(logSite.getClassName()) diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/backend/Metadata.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/Metadata.java similarity index 90% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/backend/Metadata.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/backend/Metadata.java index 0bbf5bcf8..d140db0ca 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/backend/Metadata.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/Metadata.java @@ -24,9 +24,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.backend; +package io.spine.logging.jvm.backend; -import io.spine.logging.flogger.FloggerMetadataKey; +import io.spine.logging.jvm.JvmMetadataKey; import org.jspecify.annotations.Nullable; /** @@ -34,7 +34,7 @@ * directly via methods in the fluent API, of as part of a scoped logging context. * *

    Metadata keys can be “single valued” or “repeating” based on - * {@link FloggerMetadataKey#canRepeat() MetadataKey.canRepeat()}, but it is permitted for + * {@link JvmMetadataKey#canRepeat() MetadataKey.canRepeat()}, but it is permitted for * a {@code Metadata} implementation to retain multiple single valued keys, and in that situation * the key at the largest index is the one that should be used. * @@ -43,7 +43,7 @@ * of the sequence of key/value pairs, and this is what results in the potential for multiple single * valued keys to exist. * - *

    If the value of a single valued key is required, the {@link #findValue(FloggerMetadataKey)} + *

    If the value of a single valued key is required, the {@link #findValue(JvmMetadataKey)} * method should be used to look it up. For all other metadata processing, a {@link MetadataProcessor} * should be created to ensure that scope and log site metadata can be merged correctly. * @@ -70,7 +70,7 @@ public int size() { } @Override - public FloggerMetadataKey getKey(int n) { + public JvmMetadataKey getKey(int n) { throw cannotReadFromEmpty(); } @@ -85,7 +85,7 @@ private static IndexOutOfBoundsException cannotReadFromEmpty() { @Override @Nullable - public T findValue(FloggerMetadataKey key) { + public T findValue(JvmMetadataKey key) { return null; } } @@ -99,7 +99,7 @@ public T findValue(FloggerMetadataKey key) { * @throws IndexOutOfBoundsException if either {@code n} is negative or {@code n} is greater * or equal to {@code getCount()}. */ - public abstract FloggerMetadataKey getKey(int n); + public abstract JvmMetadataKey getKey(int n); /** * Returns the non-null value for the Nth piece of metadata. @@ -116,5 +116,5 @@ public T findValue(FloggerMetadataKey key) { */ // TODO(dbeaumont): Make this throw an exception for repeated keys. @Nullable - public abstract T findValue(FloggerMetadataKey key); + public abstract T findValue(JvmMetadataKey key); } diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/backend/MetadataHandler.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataHandler.java similarity index 84% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/backend/MetadataHandler.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataHandler.java index ae5fb384b..c532ce0fe 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/backend/MetadataHandler.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataHandler.java @@ -24,12 +24,12 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.backend; +package io.spine.logging.jvm.backend; -import static io.spine.logging.flogger.util.Checks.checkArgument; -import static io.spine.logging.flogger.util.Checks.checkNotNull; +import static io.spine.logging.jvm.util.Checks.checkArgument; +import static io.spine.logging.jvm.util.Checks.checkNotNull; -import io.spine.logging.flogger.FloggerMetadataKey; +import io.spine.logging.jvm.JvmMetadataKey; import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.util.HashMap; import java.util.Iterator; @@ -61,7 +61,7 @@ public abstract class MetadataHandler { * @param context an arbitrary context object supplied to the process method. * @param the key/value type. */ - protected abstract void handle(FloggerMetadataKey key, T value, C context); + protected abstract void handle(JvmMetadataKey key, T value, C context); /** * Handles values for a repeatable metadata key. The method is called for all repeatable keys @@ -74,7 +74,7 @@ public abstract class MetadataHandler { * @param context an arbitrary context object supplied to the process method. * @param the key/value type. */ - protected void handleRepeated(FloggerMetadataKey key, Iterator values, C context) { + protected void handleRepeated(JvmMetadataKey key, Iterator values, C context) { while (values.hasNext()) { handle(key, values.next(), context); } @@ -115,7 +115,7 @@ public interface ValueHandler { * @param value associated metadata value. * @param context an arbitrary context object supplied to the process method. */ - void handle(FloggerMetadataKey key, T value, C context); + void handle(JvmMetadataKey key, T value, C context); } /** @@ -134,7 +134,7 @@ public interface RepeatedValueHandler { * instance is read-only and must not be held beyond the scope of this callback. * @param context an arbitrary context object supplied to the process method. */ - void handle(FloggerMetadataKey key, Iterator values, C context); + void handle(JvmMetadataKey key, Iterator values, C context); } /** @@ -148,16 +148,16 @@ public static final class Builder { private static final ValueHandler IGNORE_VALUE = new ValueHandler() { @Override - public void handle(FloggerMetadataKey key, Object value, Object context) {} + public void handle(JvmMetadataKey key, Object value, Object context) {} }; // Since the context is ignored, this can safely be cast to RepeatedValueHandler. private static final RepeatedValueHandler IGNORE_REPEATED_VALUE = (key, value, context) -> { /* No op. */ }; - private final Map, ValueHandler> singleValueHandlers = + private final Map, ValueHandler> singleValueHandlers = new HashMap<>(); - private final Map, RepeatedValueHandler> repeatedValueHandlers = + private final Map, RepeatedValueHandler> repeatedValueHandlers = new HashMap<>(); private final ValueHandler defaultHandler; private RepeatedValueHandler defaultRepeatedHandler = null; @@ -169,10 +169,10 @@ private Builder(ValueHandler defaultHandler) { /** * Sets a handler for any unknown repeated keys which allows values to be processed via a * generic {@link Iterator}. To handle repeated values against a known key with their expected - * type, register a handler via {@link #addRepeatedHandler(FloggerMetadataKey,RepeatedValueHandler)}. + * type, register a handler via {@link #addRepeatedHandler(JvmMetadataKey,RepeatedValueHandler)}. * *

    Note that if a repeated key is associated with an individual value handler (i.e. via - * {@link #addHandler(FloggerMetadataKey,ValueHandler)}), then that will be used in preference + * {@link #addHandler(JvmMetadataKey,ValueHandler)}), then that will be used in preference * to the default handler set here. * * @param defaultHandler the default handler for unknown repeated keys/values. @@ -195,7 +195,7 @@ public Builder setDefaultRepeatedHandler( */ @CanIgnoreReturnValue public Builder addHandler( - FloggerMetadataKey key, ValueHandler handler) { + JvmMetadataKey key, ValueHandler handler) { checkNotNull(key, "key"); checkNotNull(handler, "handler"); repeatedValueHandlers.remove(key); @@ -214,7 +214,7 @@ public Builder addHandler( */ @CanIgnoreReturnValue public Builder addRepeatedHandler( - FloggerMetadataKey key, RepeatedValueHandler handler) { + JvmMetadataKey key, RepeatedValueHandler handler) { checkNotNull(key, "key"); checkNotNull(handler, "handler"); checkArgument(key.canRepeat(), "key must be repeating"); @@ -231,9 +231,9 @@ public Builder addRepeatedHandler( * @return the builder instance for chaining. */ @CanIgnoreReturnValue - public Builder ignoring(FloggerMetadataKey key, FloggerMetadataKey... rest) { + public Builder ignoring(JvmMetadataKey key, JvmMetadataKey... rest) { checkAndIgnore(key); - for (FloggerMetadataKey k : rest) { + for (JvmMetadataKey k : rest) { checkAndIgnore(k); } return this; @@ -246,14 +246,14 @@ public Builder ignoring(FloggerMetadataKey key, FloggerMetadataKey... r * @return the builder instance for chaining. */ @CanIgnoreReturnValue - public Builder ignoring(Iterable> keys) { - for (FloggerMetadataKey k : keys) { + public Builder ignoring(Iterable> keys) { + for (JvmMetadataKey k : keys) { checkAndIgnore(k); } return this; } - void checkAndIgnore(FloggerMetadataKey key) { + void checkAndIgnore(JvmMetadataKey key) { checkNotNull(key, "key"); // It is more efficient to ignore a repeated key explicitly. if (key.canRepeat()) { @@ -273,15 +273,15 @@ void checkAndIgnore(FloggerMetadataKey key) { * @return the builder instance for chaining. */ @CanIgnoreReturnValue - public Builder removeHandlers(FloggerMetadataKey key, FloggerMetadataKey... rest) { + public Builder removeHandlers(JvmMetadataKey key, JvmMetadataKey... rest) { checkAndRemove(key); - for (FloggerMetadataKey k : rest) { + for (JvmMetadataKey k : rest) { checkAndRemove(k); } return this; } - void checkAndRemove(FloggerMetadataKey key) { + void checkAndRemove(JvmMetadataKey key) { checkNotNull(key, "key"); singleValueHandlers.remove(key); repeatedValueHandlers.remove(key); @@ -294,9 +294,9 @@ public MetadataHandler build() { } private static final class MapBasedhandler extends MetadataHandler { - private final Map, ValueHandler> singleValueHandlers = + private final Map, ValueHandler> singleValueHandlers = new HashMap<>(); - private final Map, RepeatedValueHandler> repeatedValueHandlers = + private final Map, RepeatedValueHandler> repeatedValueHandlers = new HashMap<>(); private final ValueHandler defaultHandler; private final RepeatedValueHandler defaultRepeatedHandler; @@ -310,7 +310,7 @@ private MapBasedhandler(Builder builder) { @SuppressWarnings("unchecked") // See comments for why casting is safe. @Override - protected void handle(FloggerMetadataKey key, T value, C context) { + protected void handle(JvmMetadataKey key, T value, C context) { // Safe cast because of how our private map is managed. ValueHandler handler = (ValueHandler) singleValueHandlers.get(key); @@ -318,13 +318,13 @@ protected void handle(FloggerMetadataKey key, T value, C context) { handler.handle(key, value, context); } else { // Casting MetadataKey to "" is safe since it only produces elements of 'T'. - defaultHandler.handle((FloggerMetadataKey) key, value, context); + defaultHandler.handle((JvmMetadataKey) key, value, context); } } @SuppressWarnings("unchecked") // See comments for why casting is safe. @Override - protected void handleRepeated(FloggerMetadataKey key, Iterator values, C context) { + protected void handleRepeated(JvmMetadataKey key, Iterator values, C context) { // Safe cast because of how our private map is managed. RepeatedValueHandler handler = (RepeatedValueHandler) repeatedValueHandlers.get(key); @@ -334,7 +334,7 @@ protected void handleRepeated(FloggerMetadataKey key, Iterator values, // Casting MetadataKey to "" is safe since it only produces elements of 'T'. // Casting the iterator is safe since it also only produces elements of 'T'. defaultRepeatedHandler.handle( - (FloggerMetadataKey) key, (Iterator) values, context); + (JvmMetadataKey) key, (Iterator) values, context); } else { // Dispatches keys individually. super.handleRepeated(key, values, context); diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/backend/MetadataKeyValueHandlers.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataKeyValueHandlers.java similarity index 87% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/backend/MetadataKeyValueHandlers.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataKeyValueHandlers.java index 296a6041f..5da8761bc 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/backend/MetadataKeyValueHandlers.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataKeyValueHandlers.java @@ -24,12 +24,12 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.backend; +package io.spine.logging.jvm.backend; -import io.spine.logging.flogger.FloggerMetadataKey; -import io.spine.logging.flogger.FloggerMetadataKey.KeyValueHandler; -import io.spine.logging.flogger.backend.MetadataHandler.RepeatedValueHandler; -import io.spine.logging.flogger.backend.MetadataHandler.ValueHandler; +import io.spine.logging.jvm.JvmMetadataKey; +import io.spine.logging.jvm.JvmMetadataKey.KeyValueHandler; +import io.spine.logging.jvm.backend.MetadataHandler.RepeatedValueHandler; +import io.spine.logging.jvm.backend.MetadataHandler.ValueHandler; import java.util.Iterator; import java.util.Set; @@ -45,7 +45,7 @@ public final class MetadataKeyValueHandlers { private static final ValueHandler EMIT_METADATA = new ValueHandler() { @Override - public void handle(FloggerMetadataKey key, Object value, KeyValueHandler kvf) { + public void handle(JvmMetadataKey key, Object value, KeyValueHandler kvf) { key.safeEmit(value, kvf); } }; @@ -53,7 +53,7 @@ public void handle(FloggerMetadataKey key, Object value, KeyValueHandler private static final RepeatedValueHandler EMIT_REPEATED_METADATA = new RepeatedValueHandler() { @Override - public void handle(FloggerMetadataKey key, Iterator value, KeyValueHandler kvf) { + public void handle(JvmMetadataKey key, Iterator value, KeyValueHandler kvf) { key.safeEmitRepeated(value, kvf); } }; @@ -79,7 +79,7 @@ public static RepeatedValueHandler getDefaultRepeatedVa * @return a builder configured with the default key/value handlers and ignored keys. */ public static MetadataHandler.Builder getDefaultBuilder( - Set> ignored) { + Set> ignored) { return MetadataHandler.builder(getDefaultValueHandler()) .setDefaultRepeatedHandler(getDefaultRepeatedValueHandler()) .ignoring(ignored); @@ -92,7 +92,7 @@ public static MetadataHandler.Builder getDefaultBuilder( * * @return a handler configured with the default key/value handlers and ignored keys. */ - public static MetadataHandler getDefaultHandler(Set> ignored) { + public static MetadataHandler getDefaultHandler(Set> ignored) { return getDefaultBuilder(ignored).build(); } diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/backend/MetadataProcessor.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataProcessor.java similarity index 88% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/backend/MetadataProcessor.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataProcessor.java index a7e813371..6b7b38320 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/backend/MetadataProcessor.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataProcessor.java @@ -24,13 +24,13 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.backend; +package io.spine.logging.jvm.backend; -import static io.spine.logging.flogger.util.Checks.checkArgument; -import static io.spine.logging.flogger.util.Checks.checkNotNull; +import static io.spine.logging.jvm.util.Checks.checkArgument; +import static io.spine.logging.jvm.util.Checks.checkNotNull; -import io.spine.logging.flogger.LogContext; -import io.spine.logging.flogger.FloggerMetadataKey; +import io.spine.logging.jvm.LogContext; +import io.spine.logging.jvm.JvmMetadataKey; import java.util.AbstractSet; import java.util.ArrayList; import java.util.Collections; @@ -72,10 +72,10 @@ public abstract class MetadataProcessor { public void process(MetadataHandler handler, C context) {} @Override - public void handle(FloggerMetadataKey key, MetadataHandler handler, C context) {} + public void handle(JvmMetadataKey key, MetadataHandler handler, C context) {} @Override - public T getSingleValue(FloggerMetadataKey key) { + public T getSingleValue(JvmMetadataKey key) { return null; } @@ -85,7 +85,7 @@ public int keyCount() { } @Override - public Set> keySet() { + public Set> keySet() { return Collections.emptySet(); } }; @@ -138,7 +138,7 @@ private MetadataProcessor() {} * * *

    Note that equal or identical repeated values are permitted, and no "deduplication" is - * performed. This is very much in contrast to the {@link io.spine.logging.flogger.context.Tags + * performed. This is very much in contrast to the {@link io.spine.logging.jvm.context.Tags * Tags} mechanism, which de-duplicates mappings and reorders keys and values to generate a * minimal, canonical representation. * @@ -155,14 +155,14 @@ private MetadataProcessor() {} * The handler method invoked depends on whether the key is single valued or repeated. * If no metadata is present for the given key, the handler is not invoked. */ - public abstract void handle(FloggerMetadataKey key, MetadataHandler handler, C context); + public abstract void handle(JvmMetadataKey key, MetadataHandler handler, C context); /** * Returns the unique value for a single valued key, or {@code null} if not present. * * @throws IllegalArgumentException if passed a repeatable key (even if that key has one value). */ - public abstract T getSingleValue(FloggerMetadataKey key); + public abstract T getSingleValue(JvmMetadataKey key); /** * Returns the number of unique keys represented by this processor. This is the same as the size @@ -172,11 +172,11 @@ private MetadataProcessor() {} public abstract int keyCount(); /** - * Returns the set of {@link FloggerMetadataKey}s known to this processor, in the order in which + * Returns the set of {@link JvmMetadataKey}s known to this processor, in the order in which * they will be processed. Note that this implementation is lightweight, but not necessarily * performant for things like containment testing. */ - public abstract Set> keySet(); + public abstract Set> keySet(); /* * The values in the keyMap array are structured as: @@ -225,7 +225,7 @@ public void process(MetadataHandler handler, C context) { } @Override - public void handle(FloggerMetadataKey key, MetadataHandler handler, C context) { + public void handle(JvmMetadataKey key, MetadataHandler handler, C context) { int index = indexOf(key, keyMap, keyCount); if (index >= 0) { dispatch(key, keyMap[index], handler, context); @@ -233,7 +233,7 @@ public void handle(FloggerMetadataKey key, MetadataHandler handler, C } @Override - public T getSingleValue(FloggerMetadataKey key) { + public T getSingleValue(JvmMetadataKey key) { checkArgument(!key.canRepeat(), "key must be single valued"); int index = indexOf(key, keyMap, keyCount); // For single keys, the keyMap values are just the value index. @@ -246,18 +246,18 @@ public int keyCount() { } @Override - public Set> keySet() { + public Set> keySet() { // We may want to cache this, since it's effectively immutable, but it's also a small and // likely short lived instance, so quite possibly not worth it for the cost of another field. - return new AbstractSet>() { + return new AbstractSet>() { @Override public int size() { return keyCount; } @Override - public Iterator> iterator() { - return new Iterator>() { + public Iterator> iterator() { + return new Iterator>() { private int i = 0; @Override @@ -266,7 +266,7 @@ public boolean hasNext() { } @Override - public FloggerMetadataKey next() { + public JvmMetadataKey next() { return getKey(keyMap[i++] & 0x1F); } @@ -280,7 +280,7 @@ public void remove() { } // Separate method to re-capture the value type. - private void dispatch(FloggerMetadataKey key, int n, + private void dispatch(JvmMetadataKey key, int n, MetadataHandler handler, C context) { if (!key.canRepeat()) { // For single keys, the keyMap values are just the value index. @@ -294,13 +294,13 @@ private void dispatch(FloggerMetadataKey key, int n, // same a little on allocations. However this is a fixed size instance and repeated keys are // a fairly unusual use case. private final class ValueIterator implements Iterator { - private final FloggerMetadataKey key; + private final JvmMetadataKey key; private int nextIndex; // For repeated keys, the bits 5-32 contain a mask of additional indices (where bit 5 // implies index 1, since index 0 cannot apply to an additional repeated value). private int mask; - private ValueIterator(FloggerMetadataKey key, int valueIndices) { + private ValueIterator(JvmMetadataKey key, int valueIndices) { this.key = key; // Get the first element index (lowest 5 bits, 0-27). this.nextIndex = valueIndices & 0x1F; @@ -341,7 +341,7 @@ private int prepareKeyMap(int[] keyMap) { long bloomFilterMask = 0L; int count = 0; for (int n = 0; n < keyMap.length; n++) { - FloggerMetadataKey key = getKey(n); + JvmMetadataKey key = getKey(n); // Use the bloom filter mask to get a quick true-negative test for whether we've seen this // key before. Most keys are distinct and this test is very reliable up to 10-15 keys, so // it saves building a HashSet or similar to track the set of unique keys. @@ -377,7 +377,7 @@ private int prepareKeyMap(int[] keyMap) { } // Returns the (unique) index into the keyMap array for the given key. - private int indexOf(FloggerMetadataKey key, int[] keyMap, int count) { + private int indexOf(JvmMetadataKey key, int[] keyMap, int count) { for (int i = 0; i < count; i++) { // Low 5 bits of keyMap values are *always* an index to a valid metadata key. if (key.equals(getKey(keyMap[i] & 0x1F))) { @@ -387,7 +387,7 @@ private int indexOf(FloggerMetadataKey key, int[] keyMap, int count) { return -1; } - private FloggerMetadataKey getKey(int n) { + private JvmMetadataKey getKey(int n) { int scopeSize = scope.size(); return n >= scopeSize ? logged.getKey(n - scopeSize) : scope.getKey(n); } @@ -405,14 +405,14 @@ private Object getValue(int n) { * during processing. */ private static final class SimpleProcessor extends MetadataProcessor { - private final Map, Object> map; + private final Map, Object> map; private SimpleProcessor(Metadata scope, Metadata logged) { - LinkedHashMap, Object> map = new LinkedHashMap, Object>(); + LinkedHashMap, Object> map = new LinkedHashMap, Object>(); addTo(map, scope); addTo(map, logged); // Wrap any repeated value lists to make them unmodifiable (required for correctness). - for (Map.Entry, Object> e : map.entrySet()) { + for (Map.Entry, Object> e : map.entrySet()) { if (e.getKey().canRepeat()) { e.setValue(Collections.unmodifiableList((List) e.getValue())); } @@ -422,9 +422,9 @@ private SimpleProcessor(Metadata scope, Metadata logged) { // Unlike the LightweightProcessor, we copy references from the Metadata eagerly, so can "cast" // values to their key-types early, ensuring safe casting when dispatching. - private static void addTo(Map, Object> map, Metadata metadata) { + private static void addTo(Map, Object> map, Metadata metadata) { for (int i = 0; i < metadata.size(); i++) { - FloggerMetadataKey key = metadata.getKey(i); + JvmMetadataKey key = metadata.getKey(i); Object value = map.get(key); if (key.canRepeat()) { @SuppressWarnings("unchecked") @@ -444,13 +444,13 @@ private static void addTo(Map, Object> map, Metadata metad @Override public void process(MetadataHandler handler, C context) { - for (Map.Entry, Object> e : map.entrySet()) { + for (Map.Entry, Object> e : map.entrySet()) { dispatch(e.getKey(), e.getValue(), handler, context); } } @Override - public void handle(FloggerMetadataKey key, MetadataHandler handler, C context) { + public void handle(JvmMetadataKey key, MetadataHandler handler, C context) { Object value = map.get(key); if (value != null) { dispatch(key, value, handler, context); @@ -460,7 +460,7 @@ public void handle(FloggerMetadataKey key, MetadataHandler handler, C // It's safe to ignore warnings since single keys are only ever 'T' when added to the map. @Override @SuppressWarnings("unchecked") - public T getSingleValue(FloggerMetadataKey key) { + public T getSingleValue(JvmMetadataKey key) { checkArgument(!key.canRepeat(), "key must be single valued"); Object value = map.get(key); return (value != null) ? (T) value : null; @@ -472,7 +472,7 @@ public int keyCount() { } @Override - public Set> keySet() { + public Set> keySet() { return map.keySet(); } @@ -480,7 +480,7 @@ public Set> keySet() { // and single keys are only ever 'T' when added to the map. @SuppressWarnings("unchecked") private static void dispatch( - FloggerMetadataKey key, Object value, MetadataHandler handler, C context) { + JvmMetadataKey key, Object value, MetadataHandler handler, C context) { if (key.canRepeat()) { handler.handleRepeated(key, ((List) value).iterator(), context); } else { diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/backend/Platform.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/Platform.java similarity index 96% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/backend/Platform.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/backend/Platform.java index 15edf68be..0bd50c49a 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/backend/Platform.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/Platform.java @@ -24,13 +24,13 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.backend; +package io.spine.logging.jvm.backend; -import io.spine.logging.flogger.AbstractLogger; -import io.spine.logging.flogger.FloggerLogSite; -import io.spine.logging.flogger.context.ContextDataProvider; -import io.spine.logging.flogger.context.Tags; -import io.spine.logging.flogger.util.RecursionDepth; +import io.spine.logging.jvm.AbstractLogger; +import io.spine.logging.jvm.JvmLogSite; +import io.spine.logging.jvm.context.ContextDataProvider; +import io.spine.logging.jvm.context.Tags; +import io.spine.logging.jvm.util.RecursionDepth; import org.jspecify.annotations.Nullable; import java.lang.reflect.InvocationTargetException; @@ -189,10 +189,10 @@ public abstract static class LogCallerFinder { * @param loggerApi the class containing the log() methods whose caller we need to find. * @param stackFramesToSkip the number of method calls which exist on the stack between the * {@code log()} method and the point at which this method is invoked. - * @return A log site inferred from the stack, or {@link FloggerLogSite#INVALID} if no log site + * @return A log site inferred from the stack, or {@link JvmLogSite#INVALID} if no log site * can be determined. */ - public abstract FloggerLogSite findLogSite(Class loggerApi, int stackFramesToSkip); + public abstract JvmLogSite findLogSite(Class loggerApi, int stackFramesToSkip); } /** @@ -255,7 +255,7 @@ public static boolean shouldForceLogging(String loggerName, Level level, boolean /** * Obtains a custom logging level set for the logger with the given name via - * a {@link io.spine.logging.flogger.context.LogLevelMap} set in the current logging context. + * a {@link io.spine.logging.jvm.context.LogLevelMap} set in the current logging context. * *

    The method returns {@code null} if: *

      diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/backend/SimpleMessageFormatter.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/SimpleMessageFormatter.java similarity index 92% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/backend/SimpleMessageFormatter.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/backend/SimpleMessageFormatter.java index 0c32cea87..463783b06 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/backend/SimpleMessageFormatter.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/SimpleMessageFormatter.java @@ -24,11 +24,11 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.backend; +package io.spine.logging.jvm.backend; -import io.spine.logging.flogger.LogContext; -import io.spine.logging.flogger.FloggerMetadataKey; -import io.spine.logging.flogger.FloggerMetadataKey.KeyValueHandler; +import io.spine.logging.jvm.LogContext; +import io.spine.logging.jvm.JvmMetadataKey; +import io.spine.logging.jvm.JvmMetadataKey.KeyValueHandler; import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.util.Collections; import java.util.HashSet; @@ -58,7 +58,7 @@ * } * *

      If additional metadata keys, other than the {@code cause} are to be omitted, then {@link - * #getSimpleFormatterIgnoring(FloggerMetadataKey...)} can be used to obtain a static formatter, + * #getSimpleFormatterIgnoring(JvmMetadataKey...)} can be used to obtain a static formatter, * instead of using the default. * * @see @@ -66,8 +66,8 @@ */ public final class SimpleMessageFormatter { @SuppressWarnings("ConstantCaseForConstants") - private static final Set> DEFAULT_KEYS_TO_IGNORE = - Collections.>singleton(LogContext.Key.LOG_CAUSE); + private static final Set> DEFAULT_KEYS_TO_IGNORE = + Collections.>singleton(LogContext.Key.LOG_CAUSE); private static final LogMessageFormatter DEFAULT_FORMATTER = newFormatter(DEFAULT_KEYS_TO_IGNORE); @@ -107,11 +107,11 @@ public static LogMessageFormatter getDefaultFormatter() { * almost never expected to be part of the formatted message. Other internal metadata keys may * also be suppressed. */ - public static LogMessageFormatter getSimpleFormatterIgnoring(FloggerMetadataKey... extraIgnoredKeys) { + public static LogMessageFormatter getSimpleFormatterIgnoring(JvmMetadataKey... extraIgnoredKeys) { if (extraIgnoredKeys.length == 0) { return getDefaultFormatter(); } - Set> ignored = new HashSet>(DEFAULT_KEYS_TO_IGNORE); + Set> ignored = new HashSet>(DEFAULT_KEYS_TO_IGNORE); Collections.addAll(ignored, extraIgnoredKeys); return newFormatter(ignored); } @@ -182,7 +182,7 @@ public static String getLiteralLogMessage(LogData logData) { * message. */ public static boolean mustBeFormatted( - LogData logData, MetadataProcessor metadata, Set> keysToIgnore) { + LogData logData, MetadataProcessor metadata, Set> keysToIgnore) { // If there are logged arguments or more metadata keys than can be ignored, we fail immediately // which avoids the cost of creating the metadata key set (so don't remove the size check). return logData.getTemplateContext() != null @@ -194,7 +194,7 @@ public static boolean mustBeFormatted( * Returns a new "simple" formatter which ignores the given set of metadata keys. The caller must * ensure that the given set is effectively immutable. */ - private static LogMessageFormatter newFormatter(final Set> keysToIgnore) { + private static LogMessageFormatter newFormatter(final Set> keysToIgnore) { return new LogMessageFormatter() { private final MetadataHandler handler = MetadataKeyValueHandlers.getDefaultHandler(keysToIgnore); diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/backend/TemplateContext.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/TemplateContext.java similarity index 94% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/backend/TemplateContext.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/backend/TemplateContext.java index ff736f87a..9163fb4ac 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/backend/TemplateContext.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/TemplateContext.java @@ -24,11 +24,11 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.backend; +package io.spine.logging.jvm.backend; -import static io.spine.logging.flogger.util.Checks.checkNotNull; +import static io.spine.logging.jvm.util.Checks.checkNotNull; -import io.spine.logging.flogger.parser.MessageParser; +import io.spine.logging.jvm.parser.MessageParser; /** * A context object for templates that allows caches to validate existing templates or create new diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/backend/package-info.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/package-info.java similarity index 97% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/backend/package-info.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/backend/package-info.java index 45d35bda1..03b0f65bd 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/backend/package-info.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/package-info.java @@ -31,6 +31,6 @@ * Original Java code of Google Flogger */ @CheckReturnValue -package io.spine.logging.flogger.backend; +package io.spine.logging.jvm.backend; import com.google.errorprone.annotations.CheckReturnValue; diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/context/ContextDataProvider.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/context/ContextDataProvider.java similarity index 96% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/context/ContextDataProvider.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/context/ContextDataProvider.java index f4bf7ab41..0c7ddb62c 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/context/ContextDataProvider.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/context/ContextDataProvider.java @@ -24,11 +24,11 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.context; +package io.spine.logging.jvm.context; -import io.spine.logging.flogger.LoggingScope; -import io.spine.logging.flogger.backend.Metadata; -import io.spine.logging.flogger.backend.Platform; +import io.spine.logging.jvm.LoggingScope; +import io.spine.logging.jvm.backend.Metadata; +import io.spine.logging.jvm.backend.Platform; import java.util.logging.Level; import org.jspecify.annotations.Nullable; @@ -51,7 +51,7 @@ * the jar file containing the implementation. When creating an implementation of this class, you * can provide service metadata (and thereby allow users to get your implementation just by * including your jar file) by either manually including - * a {@code META-INF/services/io.spine.logging.flogger.context.ContextDataProvider} file + * a {@code META-INF/services/io.spine.logging.jvm.context.ContextDataProvider} file * containing the name of your implementation class or by annotating your implementation class * using * {@code @AutoService(ContextDataProvider.class)}. diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/context/ContextMetadata.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/context/ContextMetadata.java similarity index 88% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/context/ContextMetadata.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/context/ContextMetadata.java index a7dbc2e82..6bb14f028 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/context/ContextMetadata.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/context/ContextMetadata.java @@ -24,13 +24,13 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.context; +package io.spine.logging.jvm.context; -import static io.spine.logging.flogger.util.Checks.checkArgument; -import static io.spine.logging.flogger.util.Checks.checkNotNull; +import static io.spine.logging.jvm.util.Checks.checkArgument; +import static io.spine.logging.jvm.util.Checks.checkNotNull; -import io.spine.logging.flogger.FloggerMetadataKey; -import io.spine.logging.flogger.backend.Metadata; +import io.spine.logging.jvm.JvmMetadataKey; +import io.spine.logging.jvm.backend.Metadata; import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.util.ArrayList; import java.util.Arrays; @@ -48,10 +48,10 @@ */ public abstract class ContextMetadata extends Metadata { private static final class Entry { - final FloggerMetadataKey key; + final JvmMetadataKey key; final T value; - Entry(FloggerMetadataKey key, T value) { + Entry(JvmMetadataKey key, T value) { this.key = checkNotNull(key, "key"); this.value = checkNotNull(value, "value"); } @@ -74,7 +74,7 @@ private Builder() {} /** Add a single metadata key/value pair to the builder. */ @CanIgnoreReturnValue - public Builder add(FloggerMetadataKey key, T value) { + public Builder add(JvmMetadataKey key, T value) { // Entries are immutable and get moved into the metadata when it's built, so these get shared // and reduce the size of the metadata storage compared to storing adjacent key/value pairs. entries.add(new Entry(key, value)); @@ -94,7 +94,7 @@ public static Builder builder() { } /** Returns a space efficient {@code ScopeMetadata} containing a single value. */ - public static ContextMetadata singleton(FloggerMetadataKey key, T value) { + public static ContextMetadata singleton(JvmMetadataKey key, T value) { return new SingletonMetadata(key, value); } @@ -113,9 +113,9 @@ private ContextMetadata() {} * *

      Whether this is achieved via copying or chaining of instances is an implementation detail. * - *

      Use {@link io.spine.logging.flogger.backend.MetadataProcessor MetadataProcessor} to process + *

      Use {@link io.spine.logging.jvm.backend.MetadataProcessor MetadataProcessor} to process * metadata consistently with respect to single valued and repeated keys, and use {@link - * Metadata#findValue(FloggerMetadataKey)} to look up the “most recent” value for a single + * Metadata#findValue(JvmMetadataKey)} to look up the “most recent” value for a single * valued key. */ public abstract ContextMetadata concatenate(ContextMetadata metadata); @@ -124,7 +124,7 @@ private ContextMetadata() {} abstract Entry get(int n); @Override - public FloggerMetadataKey getKey(int n) { + public JvmMetadataKey getKey(int n) { return get(n).key; } @@ -153,7 +153,7 @@ Entry get(int n) { @Override @Nullable @SuppressWarnings("unchecked") - public T findValue(FloggerMetadataKey key) { + public T findValue(JvmMetadataKey key) { checkArgument(!key.canRepeat(), "metadata key must be single valued"); for (int n = entries.length - 1; n >= 0; n--) { Entry e = entries[n]; @@ -184,7 +184,7 @@ public ContextMetadata concatenate(ContextMetadata metadata) { private static final class SingletonMetadata extends ContextMetadata { private final Entry entry; - SingletonMetadata(FloggerMetadataKey key, T value) { + SingletonMetadata(JvmMetadataKey key, T value) { this.entry = new Entry(key, value); } @@ -204,7 +204,7 @@ Entry get(int n) { @Override @Nullable @SuppressWarnings("unchecked") - public R findValue(FloggerMetadataKey key) { + public R findValue(JvmMetadataKey key) { checkArgument(!key.canRepeat(), "metadata key must be single valued"); return entry.key.equals(key) ? (R) entry.value : null; } @@ -244,7 +244,7 @@ Entry get(int n) { @Override @Nullable - public T findValue(FloggerMetadataKey key) { + public T findValue(JvmMetadataKey key) { // For consistency, do the same checks as for non-empty instances. checkArgument(!key.canRepeat(), "metadata key must be single valued"); return null; diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/context/LogLevelMap.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/context/LogLevelMap.java similarity index 98% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/context/LogLevelMap.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/context/LogLevelMap.java index 520b950ba..627a18182 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/context/LogLevelMap.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/context/LogLevelMap.java @@ -24,9 +24,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.context; +package io.spine.logging.jvm.context; -import static io.spine.logging.flogger.util.Checks.checkNotNull; +import static io.spine.logging.jvm.util.Checks.checkNotNull; import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.util.Collections; diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/context/NoOpContextDataProvider.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/context/NoOpContextDataProvider.java similarity index 93% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/context/NoOpContextDataProvider.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/context/NoOpContextDataProvider.java index f5b1b22c5..6008bddfc 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/context/NoOpContextDataProvider.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/context/NoOpContextDataProvider.java @@ -24,12 +24,12 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.context; +package io.spine.logging.jvm.context; -import io.spine.logging.flogger.FluentLogger2; -import io.spine.logging.flogger.FloggerMetadataKey; -import io.spine.logging.flogger.StackSize; -import io.spine.logging.flogger.context.ScopedLoggingContext.LoggingContextCloseable; +import io.spine.logging.jvm.FluentLogger2; +import io.spine.logging.jvm.JvmMetadataKey; +import io.spine.logging.jvm.StackSize; +import io.spine.logging.jvm.context.ScopedLoggingContext.LoggingContextCloseable; import java.util.concurrent.atomic.AtomicBoolean; @@ -104,7 +104,7 @@ public boolean addTags(Tags tags) { } @Override - public boolean addMetadata(FloggerMetadataKey key, T value) { + public boolean addMetadata(JvmMetadataKey key, T value) { logWarningOnceOnly(); return super.addMetadata(key, value); } diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/context/ScopeType.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/context/ScopeType.java similarity index 94% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/context/ScopeType.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/context/ScopeType.java index 08fa94d29..94a1b06eb 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/context/ScopeType.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/context/ScopeType.java @@ -24,12 +24,12 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.context; +package io.spine.logging.jvm.context; -import static io.spine.logging.flogger.util.Checks.checkNotNull; +import static io.spine.logging.jvm.util.Checks.checkNotNull; -import io.spine.logging.flogger.LoggingScope; -import io.spine.logging.flogger.LoggingScopeProvider; +import io.spine.logging.jvm.LoggingScope; +import io.spine.logging.jvm.LoggingScopeProvider; import org.jspecify.annotations.Nullable; /** diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/context/ScopedLoggingContext.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContext.java similarity index 97% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/context/ScopedLoggingContext.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContext.java index cccae95bc..49f29f384 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/context/ScopedLoggingContext.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContext.java @@ -24,20 +24,20 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.context; +package io.spine.logging.jvm.context; -import static io.spine.logging.flogger.util.Checks.checkNotNull; -import static io.spine.logging.flogger.util.Checks.checkState; +import static io.spine.logging.jvm.util.Checks.checkNotNull; +import static io.spine.logging.jvm.util.Checks.checkState; -import io.spine.logging.flogger.FloggerApi; -import io.spine.logging.flogger.LoggingScope; -import io.spine.logging.flogger.FloggerMetadataKey; +import io.spine.logging.jvm.JvmApi; +import io.spine.logging.jvm.LoggingScope; +import io.spine.logging.jvm.JvmMetadataKey; import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.MustBeClosed; import java.io.Closeable; import java.util.concurrent.Callable; -import io.spine.logging.flogger.LoggingScopeProvider; +import io.spine.logging.jvm.LoggingScopeProvider; import org.jspecify.annotations.Nullable; /** @@ -172,7 +172,7 @@ public final Builder withTags(Tags tags) { * times on a builder. */ @CanIgnoreReturnValue - public final Builder withMetadata(FloggerMetadataKey key, T value) { + public final Builder withMetadata(JvmMetadataKey key, T value) { if (metadata == null) { metadata = ContextMetadata.builder(); } @@ -370,7 +370,7 @@ protected ScopedLoggingContext() {} *

      This method is the same as {@link #newContext()} except it additionally binds a new * {@link ScopeType} instance to the newly created context. * This allows log statements to control stateful logging operations (e.g., rate limiting) using - * {@link FloggerApi#per(LoggingScopeProvider) per(ScopeType)} method. + * {@link JvmApi#per(LoggingScopeProvider) per(ScopeType)} method. * *

      Note for users: if you don't need an instance of {@code ScopedLoggingContext} for some * reason such as testability (injecting it, for example), consider using the static methods in @@ -419,7 +419,7 @@ public boolean addTags(Tags tags) { * new context, rather than adding it to context visible to multiple threads. */ @CanIgnoreReturnValue - public boolean addMetadata(FloggerMetadataKey key, T value) { + public boolean addMetadata(JvmMetadataKey key, T value) { checkNotNull(key, "key"); checkNotNull(value, "value"); return false; diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/context/ScopedLoggingContexts.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContexts.java similarity index 96% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/context/ScopedLoggingContexts.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContexts.java index 604937d39..f3d4598a1 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/context/ScopedLoggingContexts.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContexts.java @@ -24,13 +24,13 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.context; +package io.spine.logging.jvm.context; import static java.util.concurrent.TimeUnit.MINUTES; -import io.spine.logging.flogger.FluentLogger2; -import io.spine.logging.flogger.FloggerMetadataKey; -import io.spine.logging.flogger.StackSize; +import io.spine.logging.jvm.FluentLogger2; +import io.spine.logging.jvm.JvmMetadataKey; +import io.spine.logging.jvm.StackSize; import com.google.errorprone.annotations.CanIgnoreReturnValue; /** @@ -130,7 +130,7 @@ public static boolean addTags(Tags tags) { * new context, rather than adding it to context visible to multiple threads. */ @CanIgnoreReturnValue - public static boolean addMetadata(FloggerMetadataKey key, T value) { + public static boolean addMetadata(JvmMetadataKey key, T value) { return warnOnFailure(ScopedLoggingContext.getInstance().addMetadata(key, value)); } diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/context/SegmentTrie.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/context/SegmentTrie.java similarity index 99% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/context/SegmentTrie.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/context/SegmentTrie.java index 626ea1ac6..01fde70ad 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/context/SegmentTrie.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/context/SegmentTrie.java @@ -24,9 +24,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.context; +package io.spine.logging.jvm.context; -import static io.spine.logging.flogger.util.Checks.checkNotNull; +import static io.spine.logging.jvm.util.Checks.checkNotNull; import static java.lang.Math.min; import java.util.ArrayList; diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/context/Tags.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/context/Tags.java similarity index 99% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/context/Tags.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/context/Tags.java index f4f69f97b..751b3aaad 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/context/Tags.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/context/Tags.java @@ -24,11 +24,11 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.context; +package io.spine.logging.jvm.context; -import static io.spine.logging.flogger.util.Checks.checkArgument; -import static io.spine.logging.flogger.util.Checks.checkMetadataIdentifier; -import static io.spine.logging.flogger.util.Checks.checkNotNull; +import static io.spine.logging.jvm.util.Checks.checkArgument; +import static io.spine.logging.jvm.util.Checks.checkMetadataIdentifier; +import static io.spine.logging.jvm.util.Checks.checkNotNull; import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.util.AbstractMap; diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/context/package-info.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/context/package-info.java similarity index 97% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/context/package-info.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/context/package-info.java index 21877fa56..65f617540 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/context/package-info.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/context/package-info.java @@ -31,6 +31,6 @@ * Original Java code of Google Flogger */ @CheckReturnValue -package io.spine.logging.flogger.context; +package io.spine.logging.jvm.context; import com.google.errorprone.annotations.CheckReturnValue; diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/package-info.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/package-info.java similarity index 97% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/package-info.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/package-info.java index d0ef9c266..43e252cbb 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/package-info.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/package-info.java @@ -31,6 +31,6 @@ * Original Java code of Google Flogger */ @CheckReturnValue -package io.spine.logging.flogger; +package io.spine.logging.jvm; import com.google.errorprone.annotations.CheckReturnValue; diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/parameter/BraceStyleParameter.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/BraceStyleParameter.java similarity index 95% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/parameter/BraceStyleParameter.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/BraceStyleParameter.java index aa460b7f8..c583df8c2 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/parameter/BraceStyleParameter.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/BraceStyleParameter.java @@ -24,11 +24,11 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.parameter; +package io.spine.logging.jvm.parameter; -import io.spine.logging.flogger.backend.FormatChar; -import io.spine.logging.flogger.backend.FormatOptions; -import io.spine.logging.flogger.backend.FormatType; +import io.spine.logging.jvm.backend.FormatChar; +import io.spine.logging.jvm.backend.FormatOptions; +import io.spine.logging.jvm.backend.FormatType; import java.text.MessageFormat; import java.util.Calendar; import java.util.Date; diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/parameter/DateTimeFormat.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeFormat.java similarity index 99% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/parameter/DateTimeFormat.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeFormat.java index f23ed387a..dd8b344c0 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/parameter/DateTimeFormat.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeFormat.java @@ -24,7 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.parameter; +package io.spine.logging.jvm.parameter; import java.util.Collections; import java.util.HashMap; diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/parameter/DateTimeParameter.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeParameter.java similarity index 96% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/parameter/DateTimeParameter.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeParameter.java index bf5636618..f1143cffa 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/parameter/DateTimeParameter.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeParameter.java @@ -24,9 +24,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.parameter; +package io.spine.logging.jvm.parameter; -import io.spine.logging.flogger.backend.FormatOptions; +import io.spine.logging.jvm.backend.FormatOptions; /** * A parameter for formatting date/time arguments. diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/parameter/Parameter.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/Parameter.java similarity index 97% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/parameter/Parameter.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/Parameter.java index 78c05bbb3..53bfb21e7 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/parameter/Parameter.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/Parameter.java @@ -24,9 +24,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.parameter; +package io.spine.logging.jvm.parameter; -import io.spine.logging.flogger.backend.FormatOptions; +import io.spine.logging.jvm.backend.FormatOptions; /** * An abstract representation of a parameter for a message template. diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/parameter/ParameterVisitor.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/ParameterVisitor.java similarity index 96% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/parameter/ParameterVisitor.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/ParameterVisitor.java index 291a316a0..dce687fd0 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/parameter/ParameterVisitor.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/ParameterVisitor.java @@ -24,10 +24,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.parameter; +package io.spine.logging.jvm.parameter; -import io.spine.logging.flogger.backend.FormatChar; -import io.spine.logging.flogger.backend.FormatOptions; +import io.spine.logging.jvm.backend.FormatChar; +import io.spine.logging.jvm.backend.FormatOptions; /** * A visitor of log message arguments, dispatched by {@code Parameter} instances. diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/parameter/SimpleParameter.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/SimpleParameter.java similarity index 95% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/parameter/SimpleParameter.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/SimpleParameter.java index 69919f55f..01236c3da 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/parameter/SimpleParameter.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/SimpleParameter.java @@ -24,12 +24,12 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.parameter; +package io.spine.logging.jvm.parameter; -import static io.spine.logging.flogger.util.Checks.checkNotNull; +import static io.spine.logging.jvm.util.Checks.checkNotNull; -import io.spine.logging.flogger.backend.FormatChar; -import io.spine.logging.flogger.backend.FormatOptions; +import io.spine.logging.jvm.backend.FormatChar; +import io.spine.logging.jvm.backend.FormatOptions; import java.util.Collections; import java.util.EnumMap; import java.util.Map; diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/parameter/package-info.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/package-info.java similarity index 97% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/parameter/package-info.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/package-info.java index a08befd89..d9fd78d28 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/parameter/package-info.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/package-info.java @@ -31,6 +31,6 @@ * Original Java code of Google Flogger */ @CheckReturnValue -package io.spine.logging.flogger.parameter; +package io.spine.logging.jvm.parameter; import com.google.errorprone.annotations.CheckReturnValue; diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/parser/BraceStyleMessageParser.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/parser/BraceStyleMessageParser.java similarity index 99% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/parser/BraceStyleMessageParser.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/parser/BraceStyleMessageParser.java index ae186c8ad..0f605a868 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/parser/BraceStyleMessageParser.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/parser/BraceStyleMessageParser.java @@ -24,7 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.parser; +package io.spine.logging.jvm.parser; /** * A specialized {@link MessageParser} for processing log messages in the "brace style", as used by diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/parser/DefaultBraceStyleMessageParser.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultBraceStyleMessageParser.java similarity index 96% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/parser/DefaultBraceStyleMessageParser.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultBraceStyleMessageParser.java index 188038418..bf9773f79 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/parser/DefaultBraceStyleMessageParser.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultBraceStyleMessageParser.java @@ -24,9 +24,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.parser; +package io.spine.logging.jvm.parser; -import io.spine.logging.flogger.parameter.BraceStyleParameter; +import io.spine.logging.jvm.parameter.BraceStyleParameter; /** * Default implementation of the brace style message parser. Note that while the underlying parsing diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/parser/DefaultPrintfMessageParser.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultPrintfMessageParser.java similarity index 89% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/parser/DefaultPrintfMessageParser.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultPrintfMessageParser.java index 485d0933e..e3f1a3852 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/parser/DefaultPrintfMessageParser.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultPrintfMessageParser.java @@ -24,18 +24,18 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.parser; +package io.spine.logging.jvm.parser; -import static io.spine.logging.flogger.backend.FormatOptions.FLAG_LEFT_ALIGN; -import static io.spine.logging.flogger.backend.FormatOptions.FLAG_UPPER_CASE; +import static io.spine.logging.jvm.backend.FormatOptions.FLAG_LEFT_ALIGN; +import static io.spine.logging.jvm.backend.FormatOptions.FLAG_UPPER_CASE; -import io.spine.logging.flogger.backend.FormatChar; -import io.spine.logging.flogger.backend.FormatOptions; -import io.spine.logging.flogger.parameter.DateTimeFormat; -import io.spine.logging.flogger.parameter.DateTimeParameter; -import io.spine.logging.flogger.parameter.Parameter; -import io.spine.logging.flogger.parameter.ParameterVisitor; -import io.spine.logging.flogger.parameter.SimpleParameter; +import io.spine.logging.jvm.backend.FormatChar; +import io.spine.logging.jvm.backend.FormatOptions; +import io.spine.logging.jvm.parameter.DateTimeFormat; +import io.spine.logging.jvm.parameter.DateTimeParameter; +import io.spine.logging.jvm.parameter.Parameter; +import io.spine.logging.jvm.parameter.ParameterVisitor; +import io.spine.logging.jvm.parameter.SimpleParameter; /** * Default implementation of the printf message parser. This parser supports all the place-holders diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/parser/MessageBuilder.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/parser/MessageBuilder.java similarity index 96% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/parser/MessageBuilder.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/parser/MessageBuilder.java index 74d100a8d..a2a77e9ec 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/parser/MessageBuilder.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/parser/MessageBuilder.java @@ -24,11 +24,11 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.parser; +package io.spine.logging.jvm.parser; -import io.spine.logging.flogger.backend.TemplateContext; -import io.spine.logging.flogger.parameter.Parameter; -import io.spine.logging.flogger.util.Checks; +import io.spine.logging.jvm.backend.TemplateContext; +import io.spine.logging.jvm.parameter.Parameter; +import io.spine.logging.jvm.util.Checks; /** * A builder which is used during message parsing to create a message object which encapsulates diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/parser/MessageParser.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/parser/MessageParser.java similarity index 96% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/parser/MessageParser.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/parser/MessageParser.java index 92a2f48a8..557a63653 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/parser/MessageParser.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/parser/MessageParser.java @@ -24,7 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.parser; +package io.spine.logging.jvm.parser; /** * Base class from which any specific message parsers are derived (e.g. {@link PrintfMessageParser} @@ -36,7 +36,7 @@ public abstract class MessageParser { /** * The maximum allowed index (this should correspond to the MAX_ALLOWED_WIDTH - * in {@link io.spine.logging.flogger.backend.FormatOptions FormatOptions} + * in {@link io.spine.logging.jvm.backend.FormatOptions FormatOptions} * because at times it is ambiguous as to which is being parsed). */ public static final int MAX_ARG_COUNT = 1000000; diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/parser/ParseException.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/parser/ParseException.java similarity index 99% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/parser/ParseException.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/parser/ParseException.java index 402f2ec20..24b28888c 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/parser/ParseException.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/parser/ParseException.java @@ -24,7 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.parser; +package io.spine.logging.jvm.parser; /** * The exception that should be thrown whenever parsing of a log message fails. This exception must diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/parser/PrintfMessageParser.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/parser/PrintfMessageParser.java similarity index 99% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/parser/PrintfMessageParser.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/parser/PrintfMessageParser.java index 6647eab25..36668c3c0 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/parser/PrintfMessageParser.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/parser/PrintfMessageParser.java @@ -24,7 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.parser; +package io.spine.logging.jvm.parser; /** * A specialized {@link MessageParser} for processing log messages in printf style, as used by diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/parser/package-info.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/parser/package-info.java similarity index 97% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/parser/package-info.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/parser/package-info.java index 83d16a570..4f81af60d 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/parser/package-info.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/parser/package-info.java @@ -31,6 +31,6 @@ * Original Java code of Google Flogger */ @CheckReturnValue -package io.spine.logging.flogger.parser; +package io.spine.logging.jvm.parser; import com.google.errorprone.annotations.CheckReturnValue; diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/util/Checks.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/util/Checks.java similarity index 98% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/util/Checks.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/util/Checks.java index 51776c4bb..f71b2bd51 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/util/Checks.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/util/Checks.java @@ -24,7 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.util; +package io.spine.logging.jvm.util; import com.google.errorprone.annotations.CanIgnoreReturnValue; diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/util/RecursionDepth.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/util/RecursionDepth.java similarity index 98% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/util/RecursionDepth.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/util/RecursionDepth.java index b67165110..5c29136e3 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/util/RecursionDepth.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/util/RecursionDepth.java @@ -24,7 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.util; +package io.spine.logging.jvm.util; import java.io.Closeable; diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/util/StaticMethodCaller.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/util/StaticMethodCaller.java similarity index 99% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/util/StaticMethodCaller.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/util/StaticMethodCaller.java index f0fc360e8..5873f63d7 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/util/StaticMethodCaller.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/util/StaticMethodCaller.java @@ -24,7 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.util; +package io.spine.logging.jvm.util; import java.lang.reflect.Method; import org.jspecify.annotations.Nullable; diff --git a/flogger/middleware/src/main/java/io/spine/logging/flogger/util/package-info.java b/flogger/middleware/src/main/java/io/spine/logging/jvm/util/package-info.java similarity index 97% rename from flogger/middleware/src/main/java/io/spine/logging/flogger/util/package-info.java rename to flogger/middleware/src/main/java/io/spine/logging/jvm/util/package-info.java index 732a3b5ba..3ce947439 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/flogger/util/package-info.java +++ b/flogger/middleware/src/main/java/io/spine/logging/jvm/util/package-info.java @@ -31,6 +31,6 @@ * Original Java code of Google Flogger */ @CheckReturnValue -package io.spine.logging.flogger.util; +package io.spine.logging.jvm.util; import com.google.errorprone.annotations.CheckReturnValue; diff --git a/flogger/middleware/src/main/kotlin/io/spine/logging/flogger/FloggerMetadataKeys.kt b/flogger/middleware/src/main/kotlin/io/spine/logging/jvm/JvmMetadataKeys.kt similarity index 82% rename from flogger/middleware/src/main/kotlin/io/spine/logging/flogger/FloggerMetadataKeys.kt rename to flogger/middleware/src/main/kotlin/io/spine/logging/jvm/JvmMetadataKeys.kt index d02c8c135..f8ed7a453 100644 --- a/flogger/middleware/src/main/kotlin/io/spine/logging/flogger/FloggerMetadataKeys.kt +++ b/flogger/middleware/src/main/kotlin/io/spine/logging/jvm/JvmMetadataKeys.kt @@ -24,10 +24,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger +package io.spine.logging.jvm /** - * Creates a new single [FloggerMetadataKey] with the given [label]. + * Creates a new single [JvmMetadataKey] with the given [label]. * * In JVM, if the given type [T] describes a Java primitive, * this method would use a type of the corresponding object wrapper. @@ -36,11 +36,11 @@ package io.spine.logging.flogger * * @param T type of values that can be associated with this key */ -public inline fun singleKey(label: String): FloggerMetadataKey = - FloggerMetadataKey.single(label, T::class.javaObjectType) +public inline fun singleKey(label: String): JvmMetadataKey = + JvmMetadataKey.single(label, T::class.javaObjectType) /** - * Creates a new repeated [FloggerMetadataKey] with the given [label]. + * Creates a new repeated [JvmMetadataKey] with the given [label]. * * In JVM, if the given type [T] describes a Java primitive, * this method would use a type of the corresponding object wrapper. @@ -49,5 +49,5 @@ public inline fun singleKey(label: String): FloggerMetadataKey * * @param T type of values that can be associated with this key */ -public inline fun repeatedKey(label: String): FloggerMetadataKey = - FloggerMetadataKey.repeated(label, T::class.javaObjectType) +public inline fun repeatedKey(label: String): JvmMetadataKey = + JvmMetadataKey.repeated(label, T::class.javaObjectType) diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/AbstractLoggerSpec.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/AbstractLoggerSpec.kt similarity index 96% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/AbstractLoggerSpec.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/AbstractLoggerSpec.kt index 10ac151d8..9ae9329eb 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/AbstractLoggerSpec.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/AbstractLoggerSpec.kt @@ -24,7 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger +package io.spine.logging.jvm import io.kotest.assertions.throwables.shouldThrow import io.kotest.matchers.collections.shouldBeEmpty @@ -33,10 +33,10 @@ import io.kotest.matchers.string.shouldBeEmpty import io.kotest.matchers.string.shouldContain import io.kotest.matchers.string.shouldMatch import io.kotest.matchers.string.shouldNotContain -import io.spine.logging.flogger.backend.LogData -import io.spine.logging.flogger.backend.LoggingException -import io.spine.logging.flogger.given.ConfigurableLogger -import io.spine.logging.flogger.given.FormattingBackend +import io.spine.logging.jvm.backend.LogData +import io.spine.logging.jvm.backend.LoggingException +import io.spine.logging.jvm.given.ConfigurableLogger +import io.spine.logging.jvm.given.FormattingBackend import io.spine.logging.testing.tapConsole import kotlin.text.RegexOption.DOT_MATCHES_ALL import org.junit.jupiter.api.DisplayName diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/CountingRateLimiterSpec.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/CountingRateLimiterSpec.kt similarity index 93% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/CountingRateLimiterSpec.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/CountingRateLimiterSpec.kt index 8458bad06..4a75d4f1b 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/CountingRateLimiterSpec.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/CountingRateLimiterSpec.kt @@ -24,17 +24,17 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger +package io.spine.logging.jvm import io.kotest.matchers.nulls.shouldBeNull import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldNotBe import io.kotest.matchers.types.shouldBeSameInstanceAs -import io.spine.logging.flogger.CountingRateLimiter.check -import io.spine.logging.flogger.LogContext.Key -import io.spine.logging.flogger.RateLimitStatus.DISALLOW -import io.spine.logging.flogger.backend.given.FakeMetadata -import io.spine.logging.flogger.given.FakeLogSite +import io.spine.logging.jvm.CountingRateLimiter.check +import io.spine.logging.jvm.LogContext.Key +import io.spine.logging.jvm.RateLimitStatus.DISALLOW +import io.spine.logging.jvm.backend.given.FakeMetadata +import io.spine.logging.jvm.given.FakeLogSite import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/DurationRateLimiterSpec.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/DurationRateLimiterSpec.kt similarity index 93% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/DurationRateLimiterSpec.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/DurationRateLimiterSpec.kt index 8d47cf2bc..35cd3ed8c 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/DurationRateLimiterSpec.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/DurationRateLimiterSpec.kt @@ -24,19 +24,19 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger +package io.spine.logging.jvm import io.kotest.matchers.nulls.shouldBeNull import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldNotBe import io.kotest.matchers.types.shouldBeSameInstanceAs -import io.spine.logging.flogger.DurationRateLimiter.check -import io.spine.logging.flogger.DurationRateLimiter.newRateLimitPeriod -import io.spine.logging.flogger.LogContext.Key -import io.spine.logging.flogger.RateLimitStatus.DISALLOW -import io.spine.logging.flogger.RateLimitStatus.checkStatus -import io.spine.logging.flogger.backend.given.FakeMetadata -import io.spine.logging.flogger.given.FakeLogSite +import io.spine.logging.jvm.DurationRateLimiter.check +import io.spine.logging.jvm.DurationRateLimiter.newRateLimitPeriod +import io.spine.logging.jvm.LogContext.Key +import io.spine.logging.jvm.RateLimitStatus.DISALLOW +import io.spine.logging.jvm.RateLimitStatus.checkStatus +import io.spine.logging.jvm.backend.given.FakeMetadata +import io.spine.logging.jvm.given.FakeLogSite import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit.MILLISECONDS import org.junit.jupiter.api.DisplayName diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/FluentLogger2Spec.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/FluentLogger2Spec.kt similarity index 84% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/FluentLogger2Spec.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/FluentLogger2Spec.kt index 87774be14..88d6e06d7 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/FluentLogger2Spec.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/FluentLogger2Spec.kt @@ -24,13 +24,13 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger +package io.spine.logging.jvm import io.kotest.matchers.shouldBe import io.kotest.matchers.types.shouldBeInstanceOf import io.kotest.matchers.types.shouldNotBeInstanceOf -import io.spine.logging.flogger.FluentLogger2.forEnclosingClass -import io.spine.logging.flogger.backend.given.MemoizingLoggerBackend +import io.spine.logging.jvm.FluentLogger2.forEnclosingClass +import io.spine.logging.jvm.backend.given.MemoizingLoggerBackend import java.util.logging.Level import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test @@ -73,18 +73,18 @@ internal class FluentLogger2Spec { backend.setLevel(Level.INFO) // Down to and including the configured log level are not no-op instances. - logger.atSevere().shouldNotBeInstanceOf>() - logger.atWarning().shouldNotBeInstanceOf>() - logger.atInfo().shouldNotBeInstanceOf>() + logger.atSevere().shouldNotBeInstanceOf>() + logger.atWarning().shouldNotBeInstanceOf>() + logger.atInfo().shouldNotBeInstanceOf>() logger.atSevere().shouldBeInstanceOf() logger.atWarning().shouldBeInstanceOf() logger.atInfo().shouldBeInstanceOf() // Below the configured log level, you only get no-op instances. - logger.atFine().shouldBeInstanceOf>() - logger.atFiner().shouldBeInstanceOf>() - logger.atFinest().shouldBeInstanceOf>() + logger.atFine().shouldBeInstanceOf>() + logger.atFiner().shouldBeInstanceOf>() + logger.atFinest().shouldBeInstanceOf>() // Just verify that logs below the current log level are discarded. logger.atFine().log("DISCARDED") @@ -96,8 +96,8 @@ internal class FluentLogger2Spec { logger.atInfo().log("LOGGED") backend.loggedCount shouldBe 1 backend.setLevel(Level.OFF) - logger.atSevere().shouldBeInstanceOf>() + logger.atSevere().shouldBeInstanceOf>() backend.setLevel(Level.ALL) - logger.atFinest().shouldNotBeInstanceOf>() + logger.atFinest().shouldNotBeInstanceOf>() } } diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/FloggerLogSitesSpec.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/JvmLogSitesSpec.kt similarity index 82% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/FloggerLogSitesSpec.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/JvmLogSitesSpec.kt index e7b832008..7bec2a0d0 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/FloggerLogSitesSpec.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/JvmLogSitesSpec.kt @@ -24,25 +24,25 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger +package io.spine.logging.jvm -import io.spine.logging.flogger.FloggerLogSites.callerOf -import io.spine.logging.flogger.FloggerLogSites.logSite -import io.spine.logging.flogger.FloggerLogSites.logSiteFrom -import io.spine.logging.flogger.MyLogUtil.callerLogSite -import io.spine.logging.flogger.MyLogUtil.callerLogSiteWrapped +import io.spine.logging.jvm.JvmLogSites.callerOf +import io.spine.logging.jvm.JvmLogSites.logSite +import io.spine.logging.jvm.JvmLogSites.logSiteFrom +import io.spine.logging.jvm.MyLogUtil.callerLogSite +import io.spine.logging.jvm.MyLogUtil.callerLogSiteWrapped import io.kotest.matchers.shouldBe import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test /** - * Tests for [FloggerLogSites]. + * Tests for [JvmLogSites]. * * @see * Original Java code of Google Flogger */ -@DisplayName("`FloggerLogSites` should") -internal class FloggerLogSitesSpec { +@DisplayName("`JvmLogSites` should") +internal class JvmLogSitesSpec { @Test fun `return log site for the current line of code`() { @@ -59,7 +59,7 @@ internal class FloggerLogSitesSpec { @Test fun `return 'INVALID' log site if the caller not found`() { - callerOf(String::class.java) shouldBe FloggerLogSite.INVALID + callerOf(String::class.java) shouldBe JvmLogSite.INVALID } @Test @@ -74,8 +74,8 @@ internal class FloggerLogSitesSpec { } private object MyLogUtil { - val callerLogSite: FloggerLogSite + val callerLogSite: JvmLogSite get() = callerOf(MyLogUtil::class.java) - val callerLogSiteWrapped: FloggerLogSite + val callerLogSiteWrapped: JvmLogSite get() = callerLogSite } diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/FloggerMetadataKeySpec.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/JvmMetadataKeySpec.kt similarity index 90% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/FloggerMetadataKeySpec.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/JvmMetadataKeySpec.kt index 73a0b532a..1ff293918 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/FloggerMetadataKeySpec.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/JvmMetadataKeySpec.kt @@ -24,14 +24,14 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger - -import io.spine.logging.flogger.FloggerMetadataKey.repeated -import io.spine.logging.flogger.FloggerMetadataKey.single -import io.spine.logging.flogger.backend.Platform -import io.spine.logging.flogger.given.MemoizingKvHandler -import io.spine.logging.flogger.given.iterate -import io.spine.logging.flogger.util.RecursionDepth +package io.spine.logging.jvm + +import io.spine.logging.jvm.JvmMetadataKey.repeated +import io.spine.logging.jvm.JvmMetadataKey.single +import io.spine.logging.jvm.backend.Platform +import io.spine.logging.jvm.given.MemoizingKvHandler +import io.spine.logging.jvm.given.iterate +import io.spine.logging.jvm.util.RecursionDepth import io.kotest.assertions.throwables.shouldThrow import io.kotest.matchers.collections.shouldContain import io.kotest.matchers.collections.shouldContainExactly @@ -41,13 +41,13 @@ import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test /** - * Tests for [FloggerMetadataKey]. + * Tests for [JvmMetadataKey]. * * @see * Original Java code of Google Flogger */ -@DisplayName("`FloggerMetadataKey` should") -internal class FloggerMetadataKeySpec { +@DisplayName("`JvmMetadataKey` should") +internal class JvmMetadataKeySpec { @Test fun `create a key for a single piece of metadata`() { @@ -63,7 +63,7 @@ internal class FloggerMetadataKeySpec { val badLabels = mutableListOf("", "foo bar", "_FOO") badLabels.forEach { label -> shouldThrow { - FloggerMetadataKey(label, String::class.java, false) + JvmMetadataKey(label, String::class.java, false) } } } @@ -154,8 +154,8 @@ internal class FloggerMetadataKeySpec { @Test fun `throw on 'null's`() { val badInstantiations = listOf( - { FloggerMetadataKey(null, String::class.java, false) }, - { FloggerMetadataKey("label", null, false) }, + { JvmMetadataKey(null, String::class.java, false) }, + { JvmMetadataKey("label", null, false) }, { single(null, String::class.java) }, { single("label", null) }, { repeated(null, String::class.java) }, @@ -175,7 +175,7 @@ internal class FloggerMetadataKeySpec { * include that key, even in code, which has no explicit knowledge of it. */ private class ReenteringKey(label: String) : - FloggerMetadataKey(label, Any::class.java, true) { + JvmMetadataKey(label, Any::class.java, true) { override fun emit(value: Any, kvh: KeyValueHandler) { val currentDepth = Platform.getCurrentRecursionDepth() diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/LogContextSpec.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/LogContextSpec.kt similarity index 96% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/LogContextSpec.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/LogContextSpec.kt index 01b30bdcb..eaaadd01e 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/LogContextSpec.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/LogContextSpec.kt @@ -24,7 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger +package io.spine.logging.jvm import io.kotest.assertions.throwables.shouldThrow import io.kotest.matchers.booleans.shouldBeFalse @@ -36,23 +36,23 @@ import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldNotBe import io.kotest.matchers.throwable.shouldHaveMessage import io.kotest.matchers.types.shouldNotBeSameInstanceAs -import io.spine.logging.flogger.DurationRateLimiter.newRateLimitPeriod -import io.spine.logging.flogger.LazyArgs.lazy -import io.spine.logging.flogger.LogContext.Key -import io.spine.logging.flogger.LogContext.specializeLogSiteKeyFromMetadata -import io.spine.logging.flogger.backend.given.FakeMetadata -import io.spine.logging.flogger.backend.given.MemoizingLoggerBackend -import io.spine.logging.flogger.backend.given.shouldContain -import io.spine.logging.flogger.backend.given.shouldContainInOrder -import io.spine.logging.flogger.backend.given.shouldHaveSize -import io.spine.logging.flogger.backend.given.shouldNotContain -import io.spine.logging.flogger.backend.given.shouldUniquelyContain -import io.spine.logging.flogger.context.Tags -import io.spine.logging.flogger.given.ConfigurableLogger -import io.spine.logging.flogger.given.FakeLogSite -import io.spine.logging.flogger.given.iterate -import io.spine.logging.flogger.given.shouldHaveArguments -import io.spine.logging.flogger.given.shouldHaveMessage +import io.spine.logging.jvm.DurationRateLimiter.newRateLimitPeriod +import io.spine.logging.jvm.LazyArgs.lazy +import io.spine.logging.jvm.LogContext.Key +import io.spine.logging.jvm.LogContext.specializeLogSiteKeyFromMetadata +import io.spine.logging.jvm.backend.given.FakeMetadata +import io.spine.logging.jvm.backend.given.MemoizingLoggerBackend +import io.spine.logging.jvm.backend.given.shouldContain +import io.spine.logging.jvm.backend.given.shouldContainInOrder +import io.spine.logging.jvm.backend.given.shouldHaveSize +import io.spine.logging.jvm.backend.given.shouldNotContain +import io.spine.logging.jvm.backend.given.shouldUniquelyContain +import io.spine.logging.jvm.context.Tags +import io.spine.logging.jvm.given.ConfigurableLogger +import io.spine.logging.jvm.given.FakeLogSite +import io.spine.logging.jvm.given.iterate +import io.spine.logging.jvm.given.shouldHaveArguments +import io.spine.logging.jvm.given.shouldHaveMessage import java.lang.System.currentTimeMillis import java.util.concurrent.TimeUnit.MILLISECONDS import java.util.concurrent.TimeUnit.SECONDS @@ -94,7 +94,7 @@ internal class LogContextSpec { // and you'd use `logVarargs()`. private fun logHelper( logger: FluentLogger2, - logSite: FloggerLogSite, + logSite: JvmLogSite, n: Int, message: String ) { @@ -211,7 +211,7 @@ internal class LogContextSpec { /** * For testing log-site tags are correctly merged with metadata, - * see [AbstractContextDataProviderSpec][io.spine.logging.flogger.context.AbstractContextDataProviderSpec]. + * see [AbstractContextDataProviderSpec][io.spine.logging.jvm.context.AbstractContextDataProviderSpec]. */ @Test fun `accept tags`() { @@ -871,9 +871,9 @@ internal class LogContextSpec { // We don't expect this to ever happen in real code though. for (i in 0..6) { // Log every 2nd (0, 2, 4, 6) - logHelper(logger, FloggerLogSites.logSite(), 2, "Foo: $i") + logHelper(logger, JvmLogSites.logSite(), 2, "Foo: $i") // Log every 3rd (0, 3, 6) - logHelper(logger, FloggerLogSites.logSite(), 3, "Bar: $i") + logHelper(logger, JvmLogSites.logSite(), 3, "Bar: $i") } backend.loggedCount shouldBe 7 backend.firstLogged.shouldHaveArguments("Foo: 0") @@ -892,17 +892,17 @@ internal class LogContextSpec { @Test fun `suppress an invalid log site analysis`() { logger.atInfo() - .withInjectedLogSite(FloggerLogSite.INVALID) + .withInjectedLogSite(JvmLogSite.INVALID) .log("No log site here") logger.atInfo() .withInjectedLogSite(null) .log("No-op injection") backend.loggedCount shouldBe 2 - backend.firstLogged.logSite shouldBe FloggerLogSite.INVALID + backend.firstLogged.logSite shouldBe JvmLogSite.INVALID backend.logged[1].logSite.shouldNotBeNull() - backend.logged[1].logSite shouldNotBe FloggerLogSite.INVALID + backend.logged[1].logSite shouldNotBe JvmLogSite.INVALID } @Nested inner class diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/LogPerBucketingStrategySpec.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/LogPerBucketingStrategySpec.kt similarity index 99% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/LogPerBucketingStrategySpec.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/LogPerBucketingStrategySpec.kt index 28c4a7991..e4dcf2548 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/LogPerBucketingStrategySpec.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/LogPerBucketingStrategySpec.kt @@ -24,7 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger +package io.spine.logging.jvm import io.kotest.matchers.nulls.shouldBeNull import io.kotest.matchers.shouldBe diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/LogSiteMapSpec.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/LogSiteMapSpec.kt similarity index 96% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/LogSiteMapSpec.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/LogSiteMapSpec.kt index 4155dc1f8..516c0b3ae 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/LogSiteMapSpec.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/LogSiteMapSpec.kt @@ -24,7 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger +package io.spine.logging.jvm import io.kotest.matchers.booleans.shouldBeFalse import io.kotest.matchers.booleans.shouldBeTrue @@ -32,9 +32,9 @@ import io.kotest.matchers.nulls.shouldNotBeNull import io.kotest.matchers.shouldBe import io.kotest.matchers.types.shouldBeSameInstanceAs import io.kotest.matchers.types.shouldNotBeSameInstanceAs -import io.spine.logging.flogger.backend.Metadata -import io.spine.logging.flogger.backend.given.FakeMetadata -import io.spine.logging.flogger.given.FakeLogSite +import io.spine.logging.jvm.backend.Metadata +import io.spine.logging.jvm.backend.given.FakeMetadata +import io.spine.logging.jvm.given.FakeLogSite import java.lang.Thread.sleep import java.util.concurrent.Callable import java.util.concurrent.atomic.AtomicInteger diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/LogSiteStackTraceSpec.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/LogSiteStackTraceSpec.kt similarity index 98% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/LogSiteStackTraceSpec.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/LogSiteStackTraceSpec.kt index 509d5a6f5..10a45e844 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/LogSiteStackTraceSpec.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/LogSiteStackTraceSpec.kt @@ -24,7 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger +package io.spine.logging.jvm import io.kotest.matchers.nulls.shouldBeNull import io.kotest.matchers.shouldBe diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/LoggingScopeSpec.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/LoggingScopeSpec.kt similarity index 95% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/LoggingScopeSpec.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/LoggingScopeSpec.kt index 5fa26222e..2164011ca 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/LoggingScopeSpec.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/LoggingScopeSpec.kt @@ -24,10 +24,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger +package io.spine.logging.jvm import io.kotest.matchers.shouldNotBe -import io.spine.logging.flogger.LoggingScope.create +import io.spine.logging.jvm.LoggingScope.create import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/RateLimitStatusSpec.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/RateLimitStatusSpec.kt similarity index 93% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/RateLimitStatusSpec.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/RateLimitStatusSpec.kt index 11f12340c..30419d4f5 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/RateLimitStatusSpec.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/RateLimitStatusSpec.kt @@ -24,7 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger +package io.spine.logging.jvm import io.kotest.assertions.throwables.shouldThrow import io.kotest.matchers.booleans.shouldBeFalse @@ -32,12 +32,12 @@ import io.kotest.matchers.booleans.shouldBeTrue import io.kotest.matchers.nulls.shouldBeNull import io.kotest.matchers.shouldBe import io.kotest.matchers.types.shouldBeSameInstanceAs -import io.spine.logging.flogger.RateLimitStatus.ALLOW -import io.spine.logging.flogger.RateLimitStatus.DISALLOW -import io.spine.logging.flogger.RateLimitStatus.checkStatus -import io.spine.logging.flogger.RateLimitStatus.combine -import io.spine.logging.flogger.backend.given.FakeMetadata -import io.spine.logging.flogger.given.FakeLogSite +import io.spine.logging.jvm.RateLimitStatus.ALLOW +import io.spine.logging.jvm.RateLimitStatus.DISALLOW +import io.spine.logging.jvm.RateLimitStatus.checkStatus +import io.spine.logging.jvm.RateLimitStatus.combine +import io.spine.logging.jvm.backend.given.FakeMetadata +import io.spine.logging.jvm.given.FakeLogSite import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/SamplingRateLimiterSpec.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/SamplingRateLimiterSpec.kt similarity index 90% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/SamplingRateLimiterSpec.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/SamplingRateLimiterSpec.kt index 0269cf0b8..cf22166aa 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/SamplingRateLimiterSpec.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/SamplingRateLimiterSpec.kt @@ -24,20 +24,20 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger +package io.spine.logging.jvm import io.kotest.matchers.ints.shouldBeGreaterThan import io.kotest.matchers.ints.shouldBeInRange import io.kotest.matchers.nulls.shouldBeNull import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldNotBe -import io.spine.logging.flogger.LogContext.Key -import io.spine.logging.flogger.RateLimitStatus.DISALLOW -import io.spine.logging.flogger.RateLimitStatus.checkStatus -import io.spine.logging.flogger.SamplingRateLimiter.check -import io.spine.logging.flogger.backend.Metadata -import io.spine.logging.flogger.backend.given.FakeMetadata -import io.spine.logging.flogger.given.FakeLogSite +import io.spine.logging.jvm.LogContext.Key +import io.spine.logging.jvm.RateLimitStatus.DISALLOW +import io.spine.logging.jvm.RateLimitStatus.checkStatus +import io.spine.logging.jvm.SamplingRateLimiter.check +import io.spine.logging.jvm.backend.Metadata +import io.spine.logging.jvm.backend.given.FakeMetadata +import io.spine.logging.jvm.given.FakeLogSite import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/SpecializedLogSiteKeySpec.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/SpecializedLogSiteKeySpec.kt similarity index 97% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/SpecializedLogSiteKeySpec.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/SpecializedLogSiteKeySpec.kt index ea0ae4f28..ccfdded7a 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/SpecializedLogSiteKeySpec.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/SpecializedLogSiteKeySpec.kt @@ -24,11 +24,11 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger +package io.spine.logging.jvm import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldNotBe -import io.spine.logging.flogger.given.FakeLogSite +import io.spine.logging.jvm.given.FakeLogSite import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/StackBasedLogSiteSpec.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/StackBasedLogSiteSpec.kt similarity index 97% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/StackBasedLogSiteSpec.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/StackBasedLogSiteSpec.kt index 5d7a86e64..6150449c6 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/StackBasedLogSiteSpec.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/StackBasedLogSiteSpec.kt @@ -24,7 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger +package io.spine.logging.jvm import io.kotest.assertions.throwables.shouldThrow import io.kotest.matchers.collections.shouldHaveSize @@ -77,7 +77,7 @@ internal class StackBasedLogSiteSpec { val lineNumber = -3 // Can also be unknown, represented with a negative value. val logSite = stackBasedLogSite(CLASS_NAME, METHOD_NAME, fileName, lineNumber) logSite.fileName.shouldBeNull() - logSite.lineNumber shouldBe FloggerLogSite.UNKNOWN_LINE + logSite.lineNumber shouldBe JvmLogSite.UNKNOWN_LINE } @Test diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/BaseMessageFormatterSpec.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/BaseMessageFormatterSpec.kt similarity index 98% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/BaseMessageFormatterSpec.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/BaseMessageFormatterSpec.kt index b089f8565..841202d70 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/BaseMessageFormatterSpec.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/BaseMessageFormatterSpec.kt @@ -24,12 +24,12 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.backend +package io.spine.logging.jvm.backend import io.kotest.assertions.throwables.shouldThrow import io.kotest.matchers.shouldBe -import io.spine.logging.flogger.backend.given.FakeLogData -import io.spine.logging.flogger.parser.ParseException +import io.spine.logging.jvm.backend.given.FakeLogData +import io.spine.logging.jvm.parser.ParseException import java.math.BigDecimal import java.math.BigInteger import java.util.* diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/FormatCharSpec.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatCharSpec.kt similarity index 85% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/FormatCharSpec.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatCharSpec.kt index 8efe1bf8b..017252231 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/FormatCharSpec.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatCharSpec.kt @@ -24,20 +24,20 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.backend +package io.spine.logging.jvm.backend -import io.spine.logging.flogger.backend.FormatChar.BOOLEAN -import io.spine.logging.flogger.backend.FormatChar.CHAR -import io.spine.logging.flogger.backend.FormatChar.DECIMAL -import io.spine.logging.flogger.backend.FormatChar.EXPONENT -import io.spine.logging.flogger.backend.FormatChar.EXPONENT_HEX -import io.spine.logging.flogger.backend.FormatChar.FLOAT -import io.spine.logging.flogger.backend.FormatChar.GENERAL -import io.spine.logging.flogger.backend.FormatChar.HEX -import io.spine.logging.flogger.backend.FormatChar.OCTAL -import io.spine.logging.flogger.backend.FormatChar.STRING -import io.spine.logging.flogger.backend.FormatOptions.parse -import io.spine.logging.flogger.backend.FormatOptions.parseValidFlags +import io.spine.logging.jvm.backend.FormatChar.BOOLEAN +import io.spine.logging.jvm.backend.FormatChar.CHAR +import io.spine.logging.jvm.backend.FormatChar.DECIMAL +import io.spine.logging.jvm.backend.FormatChar.EXPONENT +import io.spine.logging.jvm.backend.FormatChar.EXPONENT_HEX +import io.spine.logging.jvm.backend.FormatChar.FLOAT +import io.spine.logging.jvm.backend.FormatChar.GENERAL +import io.spine.logging.jvm.backend.FormatChar.HEX +import io.spine.logging.jvm.backend.FormatChar.OCTAL +import io.spine.logging.jvm.backend.FormatChar.STRING +import io.spine.logging.jvm.backend.FormatOptions.parse +import io.spine.logging.jvm.backend.FormatOptions.parseValidFlags import io.kotest.matchers.shouldBe import io.kotest.matchers.types.shouldBeSameInstanceAs import org.junit.jupiter.api.DisplayName diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/FormatOptionsSpec.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatOptionsSpec.kt similarity index 92% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/FormatOptionsSpec.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatOptionsSpec.kt index 003dfcde2..8ac2b7825 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/FormatOptionsSpec.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatOptionsSpec.kt @@ -24,19 +24,19 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.backend - -import io.spine.logging.flogger.backend.FormatOptions.ALL_FLAGS -import io.spine.logging.flogger.backend.FormatOptions.FLAG_LEFT_ALIGN -import io.spine.logging.flogger.backend.FormatOptions.FLAG_PREFIX_PLUS_FOR_POSITIVE_VALUES -import io.spine.logging.flogger.backend.FormatOptions.FLAG_PREFIX_SPACE_FOR_POSITIVE_VALUES -import io.spine.logging.flogger.backend.FormatOptions.FLAG_SHOW_ALT_FORM -import io.spine.logging.flogger.backend.FormatOptions.FLAG_SHOW_GROUPING -import io.spine.logging.flogger.backend.FormatOptions.FLAG_SHOW_LEADING_ZEROS -import io.spine.logging.flogger.backend.FormatOptions.FLAG_UPPER_CASE -import io.spine.logging.flogger.backend.FormatOptions.UNSET -import io.spine.logging.flogger.backend.FormatOptions.parse -import io.spine.logging.flogger.parser.ParseException +package io.spine.logging.jvm.backend + +import io.spine.logging.jvm.backend.FormatOptions.ALL_FLAGS +import io.spine.logging.jvm.backend.FormatOptions.FLAG_LEFT_ALIGN +import io.spine.logging.jvm.backend.FormatOptions.FLAG_PREFIX_PLUS_FOR_POSITIVE_VALUES +import io.spine.logging.jvm.backend.FormatOptions.FLAG_PREFIX_SPACE_FOR_POSITIVE_VALUES +import io.spine.logging.jvm.backend.FormatOptions.FLAG_SHOW_ALT_FORM +import io.spine.logging.jvm.backend.FormatOptions.FLAG_SHOW_GROUPING +import io.spine.logging.jvm.backend.FormatOptions.FLAG_SHOW_LEADING_ZEROS +import io.spine.logging.jvm.backend.FormatOptions.FLAG_UPPER_CASE +import io.spine.logging.jvm.backend.FormatOptions.UNSET +import io.spine.logging.jvm.backend.FormatOptions.parse +import io.spine.logging.jvm.parser.ParseException import io.kotest.assertions.throwables.shouldNotThrow import io.kotest.assertions.throwables.shouldThrow import io.kotest.matchers.booleans.shouldBeFalse diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/FormatTypeSpec.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatTypeSpec.kt similarity index 92% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/FormatTypeSpec.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatTypeSpec.kt index 0a977f9ce..47b7b98d9 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/FormatTypeSpec.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatTypeSpec.kt @@ -24,13 +24,13 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.backend +package io.spine.logging.jvm.backend -import io.spine.logging.flogger.backend.FormatType.GENERAL -import io.spine.logging.flogger.backend.FormatType.BOOLEAN -import io.spine.logging.flogger.backend.FormatType.CHARACTER -import io.spine.logging.flogger.backend.FormatType.INTEGRAL -import io.spine.logging.flogger.backend.FormatType.FLOAT +import io.spine.logging.jvm.backend.FormatType.GENERAL +import io.spine.logging.jvm.backend.FormatType.BOOLEAN +import io.spine.logging.jvm.backend.FormatType.CHARACTER +import io.spine.logging.jvm.backend.FormatType.INTEGRAL +import io.spine.logging.jvm.backend.FormatType.FLOAT import io.kotest.matchers.booleans.shouldBeFalse import io.kotest.matchers.booleans.shouldBeTrue import java.math.BigDecimal diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/KeyValueFormatterSpec.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/KeyValueFormatterSpec.kt similarity index 99% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/KeyValueFormatterSpec.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/KeyValueFormatterSpec.kt index 9c0272e54..bb4fb8cb8 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/KeyValueFormatterSpec.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/KeyValueFormatterSpec.kt @@ -24,7 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.backend +package io.spine.logging.jvm.backend import io.kotest.matchers.shouldBe import io.kotest.matchers.string.shouldBeEmpty diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/LightweightProcessorSpec.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/LightweightProcessorSpec.kt similarity index 97% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/LightweightProcessorSpec.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/LightweightProcessorSpec.kt index ea5abe351..00a3b706e 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/LightweightProcessorSpec.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/LightweightProcessorSpec.kt @@ -24,7 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.backend +package io.spine.logging.jvm.backend import org.junit.jupiter.api.DisplayName diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/MessageUtilsSpec.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MessageUtilsSpec.kt similarity index 88% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/MessageUtilsSpec.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MessageUtilsSpec.kt index 8fb1ffded..7567f6130 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/MessageUtilsSpec.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MessageUtilsSpec.kt @@ -24,7 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.backend +package io.spine.logging.jvm.backend import io.kotest.matchers.booleans.shouldBeFalse import io.kotest.matchers.booleans.shouldBeTrue @@ -34,16 +34,16 @@ import io.kotest.matchers.string.shouldContain import io.kotest.matchers.string.shouldNotContain import io.kotest.matchers.types.shouldBeSameInstanceAs import io.spine.logging.backend.given.BadToString -import io.spine.logging.flogger.FloggerLogSite -import io.spine.logging.flogger.backend.FormatOptions.FLAG_SHOW_ALT_FORM -import io.spine.logging.flogger.backend.FormatOptions.FLAG_SHOW_LEADING_ZEROS -import io.spine.logging.flogger.backend.FormatOptions.FLAG_UPPER_CASE -import io.spine.logging.flogger.backend.FormatOptions.UNSET -import io.spine.logging.flogger.backend.MessageUtils.appendHex -import io.spine.logging.flogger.backend.MessageUtils.appendLogSite -import io.spine.logging.flogger.backend.MessageUtils.safeFormatTo -import io.spine.logging.flogger.backend.MessageUtils.safeToString -import io.spine.logging.flogger.given.FakeLogSite +import io.spine.logging.jvm.JvmLogSite +import io.spine.logging.jvm.backend.FormatOptions.FLAG_SHOW_ALT_FORM +import io.spine.logging.jvm.backend.FormatOptions.FLAG_SHOW_LEADING_ZEROS +import io.spine.logging.jvm.backend.FormatOptions.FLAG_UPPER_CASE +import io.spine.logging.jvm.backend.FormatOptions.UNSET +import io.spine.logging.jvm.backend.MessageUtils.appendHex +import io.spine.logging.jvm.backend.MessageUtils.appendLogSite +import io.spine.logging.jvm.backend.MessageUtils.safeFormatTo +import io.spine.logging.jvm.backend.MessageUtils.safeToString +import io.spine.logging.jvm.given.FakeLogSite import java.util.* import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Nested @@ -141,7 +141,7 @@ internal class MessageUtilsSpec { "$out" shouldBe ".:32" out.setLength(0) - appendLogSite(FloggerLogSite.INVALID, out).shouldBeFalse() + appendLogSite(JvmLogSite.INVALID, out).shouldBeFalse() "$out".shouldBeEmpty() } diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/MetadataHandlerSpec.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataHandlerSpec.kt similarity index 91% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/MetadataHandlerSpec.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataHandlerSpec.kt index 34be07013..846634620 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/MetadataHandlerSpec.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataHandlerSpec.kt @@ -24,15 +24,15 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.backend +package io.spine.logging.jvm.backend import com.google.common.base.Joiner import com.google.common.collect.Iterators import io.kotest.matchers.shouldBe -import io.spine.logging.flogger.FloggerMetadataKey -import io.spine.logging.flogger.backend.given.FakeMetadata -import io.spine.logging.flogger.repeatedKey -import io.spine.logging.flogger.singleKey +import io.spine.logging.jvm.JvmMetadataKey +import io.spine.logging.jvm.backend.given.FakeMetadata +import io.spine.logging.jvm.repeatedKey +import io.spine.logging.jvm.singleKey import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test @@ -192,7 +192,7 @@ private fun process( * * @see MetadataHandler.builder */ -private fun appendUnknownValue(key: FloggerMetadataKey<*>, value: Any, out: StringBuilder) { +private fun appendUnknownValue(key: JvmMetadataKey<*>, value: Any, out: StringBuilder) { out.append("${key.label}=<<$value>> ") } @@ -202,7 +202,7 @@ private fun appendUnknownValue(key: FloggerMetadataKey<*>, value: Any, out: Stri * @see MetadataHandler.builder */ private fun appendUnknownValues( - key: FloggerMetadataKey<*>, + key: JvmMetadataKey<*>, values: Iterator<*>, out: StringBuilder ) { @@ -210,16 +210,16 @@ private fun appendUnknownValues( appendUnknownValue(key, joinedValues, out) } -private fun appendValue(key: FloggerMetadataKey<*>, value: Any, out: StringBuilder) { +private fun appendValue(key: JvmMetadataKey<*>, value: Any, out: StringBuilder) { out.append("${key.label}=$value ") } -private fun appendValues(key: FloggerMetadataKey<*>, values: Iterator<*>, out: StringBuilder) { +private fun appendValues(key: JvmMetadataKey<*>, values: Iterator<*>, out: StringBuilder) { val joinedValues = Iterators.toString(values) appendValue(key, joinedValues, out) } -private fun appendSum(key: FloggerMetadataKey, values: Iterator, out: StringBuilder) { +private fun appendSum(key: JvmMetadataKey, values: Iterator, out: StringBuilder) { var sum = 0 values.forEach { sum += it } out.append("sum(${key.label})=$sum ") diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/MetadataKeyValueHandlersSpec.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataKeyValueHandlersSpec.kt similarity index 87% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/MetadataKeyValueHandlersSpec.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataKeyValueHandlersSpec.kt index 5d7e39cdc..807c4144b 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/MetadataKeyValueHandlersSpec.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataKeyValueHandlersSpec.kt @@ -24,17 +24,17 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.backend +package io.spine.logging.jvm.backend -import io.spine.logging.flogger.backend.MetadataKeyValueHandlers.getDefaultHandler -import io.spine.logging.flogger.backend.MetadataKeyValueHandlers.getDefaultRepeatedValueHandler -import io.spine.logging.flogger.backend.MetadataKeyValueHandlers.getDefaultValueHandler -import io.spine.logging.flogger.given.MemoizingKvHandler -import io.spine.logging.flogger.given.iterate +import io.spine.logging.jvm.backend.MetadataKeyValueHandlers.getDefaultHandler +import io.spine.logging.jvm.backend.MetadataKeyValueHandlers.getDefaultRepeatedValueHandler +import io.spine.logging.jvm.backend.MetadataKeyValueHandlers.getDefaultValueHandler +import io.spine.logging.jvm.given.MemoizingKvHandler +import io.spine.logging.jvm.given.iterate import io.kotest.matchers.collections.shouldContainExactly import io.kotest.matchers.collections.shouldContainExactlyInAnyOrder -import io.spine.logging.flogger.repeatedKey -import io.spine.logging.flogger.singleKey +import io.spine.logging.jvm.repeatedKey +import io.spine.logging.jvm.singleKey import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/MetadataProcessorSpec.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataProcessorSpec.kt similarity index 93% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/MetadataProcessorSpec.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataProcessorSpec.kt index 71276d141..27de8f442 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/MetadataProcessorSpec.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataProcessorSpec.kt @@ -24,7 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.backend +package io.spine.logging.jvm.backend import com.google.common.collect.Iterators import io.kotest.assertions.throwables.shouldThrow @@ -33,10 +33,10 @@ import io.kotest.matchers.collections.shouldContainExactly import io.kotest.matchers.ints.shouldBeLessThanOrEqual import io.kotest.matchers.nulls.shouldBeNull import io.kotest.matchers.shouldBe -import io.spine.logging.flogger.FloggerMetadataKey -import io.spine.logging.flogger.backend.given.FakeMetadata -import io.spine.logging.flogger.repeatedKey -import io.spine.logging.flogger.singleKey +import io.spine.logging.jvm.JvmMetadataKey +import io.spine.logging.jvm.backend.given.FakeMetadata +import io.spine.logging.jvm.repeatedKey +import io.spine.logging.jvm.singleKey import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test @@ -185,8 +185,8 @@ internal abstract class MetadataProcessorSpec(private val factory: ProcessorFact .add(REP_1, "two") val metadata = factory.processorFor(scope, Metadata.empty()) val handler: MetadataHandler = object : MetadataHandler() { - override fun handle(key: FloggerMetadataKey, value: T, context: Void) = Unit - override fun handleRepeated(key: FloggerMetadataKey, + override fun handle(key: JvmMetadataKey, value: T, context: Void) = Unit + override fun handleRepeated(key: JvmMetadataKey, values: MutableIterator, context: Void?) { values.hasNext().shouldBeTrue() @@ -221,7 +221,7 @@ private fun entries(metadata: MetadataProcessor): List { * Processes the given [metadata] for a single metadata [key], * returning the formatted entry. */ -private fun handleEntry(metadata: MetadataProcessor, key: FloggerMetadataKey<*>): String? { +private fun handleEntry(metadata: MetadataProcessor, key: JvmMetadataKey<*>): String? { val entries = arrayListOf() metadata.handle(key, COLLECTING_HANDLER, entries) entries.size shouldBeLessThanOrEqual 1 @@ -230,12 +230,12 @@ private fun handleEntry(metadata: MetadataProcessor, key: FloggerMetadataKey<*>) private object COLLECTING_HANDLER : MetadataHandler>() { - override fun handle(key: FloggerMetadataKey, value: T, out: MutableList) { + override fun handle(key: JvmMetadataKey, value: T, out: MutableList) { val stringified = "%s=%s".format(key.label, value) out.add(stringified) } - override fun handleRepeated(key: FloggerMetadataKey, + override fun handleRepeated(key: JvmMetadataKey, values: MutableIterator, out: MutableList) { val stringified = "%s=%s".format(key.label, Iterators.toString(values)) diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/SimpleMessageFormatterSpec.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/SimpleMessageFormatterSpec.kt similarity index 95% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/SimpleMessageFormatterSpec.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/SimpleMessageFormatterSpec.kt index 94b150391..561fae3a8 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/SimpleMessageFormatterSpec.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/SimpleMessageFormatterSpec.kt @@ -24,16 +24,16 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.backend +package io.spine.logging.jvm.backend import io.kotest.matchers.shouldBe import io.kotest.matchers.types.shouldBeSameInstanceAs -import io.spine.logging.flogger.LogContext.Key -import io.spine.logging.flogger.backend.given.FakeLogData -import io.spine.logging.flogger.backend.given.FakeMetadata -import io.spine.logging.flogger.context.Tags -import io.spine.logging.flogger.repeatedKey -import io.spine.logging.flogger.singleKey +import io.spine.logging.jvm.LogContext.Key +import io.spine.logging.jvm.backend.given.FakeLogData +import io.spine.logging.jvm.backend.given.FakeMetadata +import io.spine.logging.jvm.context.Tags +import io.spine.logging.jvm.repeatedKey +import io.spine.logging.jvm.singleKey import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/SimpleProcessorSpec.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/SimpleProcessorSpec.kt similarity index 97% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/SimpleProcessorSpec.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/SimpleProcessorSpec.kt index f69b698d1..e3d1a8089 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/SimpleProcessorSpec.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/SimpleProcessorSpec.kt @@ -24,7 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.backend +package io.spine.logging.jvm.backend import org.junit.jupiter.api.DisplayName diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/given/FakeLogData.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/FakeLogData.kt similarity index 85% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/given/FakeLogData.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/FakeLogData.kt index e6c7b5550..895ee0c7a 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/given/FakeLogData.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/FakeLogData.kt @@ -24,19 +24,19 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.backend.given +package io.spine.logging.jvm.backend.given import com.google.errorprone.annotations.CanIgnoreReturnValue -import io.spine.logging.flogger.FloggerLogSite -import io.spine.logging.flogger.FloggerMetadataKey -import io.spine.logging.flogger.LogContext -import io.spine.logging.flogger.backend.LogData -import io.spine.logging.flogger.backend.Metadata -import io.spine.logging.flogger.backend.TemplateContext -import io.spine.logging.flogger.given.FakeLogSite -import io.spine.logging.flogger.parser.DefaultBraceStyleMessageParser -import io.spine.logging.flogger.parser.DefaultPrintfMessageParser -import io.spine.logging.flogger.parser.MessageParser +import io.spine.logging.jvm.JvmLogSite +import io.spine.logging.jvm.JvmMetadataKey +import io.spine.logging.jvm.LogContext +import io.spine.logging.jvm.backend.LogData +import io.spine.logging.jvm.backend.Metadata +import io.spine.logging.jvm.backend.TemplateContext +import io.spine.logging.jvm.given.FakeLogSite +import io.spine.logging.jvm.parser.DefaultBraceStyleMessageParser +import io.spine.logging.jvm.parser.DefaultPrintfMessageParser +import io.spine.logging.jvm.parser.MessageParser import java.util.concurrent.TimeUnit import java.util.logging.Level @@ -54,7 +54,7 @@ class FakeLogData : LogData { private var literalArgument: Any? = null private var timestampNanos = 0L private val metadata = FakeMetadata() - private var logSite: FloggerLogSite = LOG_SITE + private var logSite: JvmLogSite = LOG_SITE companion object { private const val LOGGER_NAME = "io.spine.LoggerName" @@ -106,13 +106,13 @@ class FakeLogData : LogData { } @CanIgnoreReturnValue - fun setLogSite(logSite: FloggerLogSite): FakeLogData { + fun setLogSite(logSite: JvmLogSite): FakeLogData { this.logSite = logSite return this } @CanIgnoreReturnValue - fun addMetadata(key: FloggerMetadataKey, value: Any?): FakeLogData { + fun addMetadata(key: JvmMetadataKey, value: Any?): FakeLogData { metadata.add(key, key.cast(value)) return this } @@ -134,7 +134,7 @@ class FakeLogData : LogData { return LOGGER_NAME } - override fun getLogSite(): FloggerLogSite { + override fun getLogSite(): JvmLogSite { return logSite } diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/given/FakeMetadata.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/FakeMetadata.kt similarity index 82% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/given/FakeMetadata.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/FakeMetadata.kt index 911c16ac0..966608ec0 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/given/FakeMetadata.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/FakeMetadata.kt @@ -24,11 +24,11 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.backend.given +package io.spine.logging.jvm.backend.given import com.google.errorprone.annotations.CanIgnoreReturnValue -import io.spine.logging.flogger.FloggerMetadataKey -import io.spine.logging.flogger.backend.Metadata +import io.spine.logging.jvm.JvmMetadataKey +import io.spine.logging.jvm.backend.Metadata /** * A mutable [Metadata] implementation for testing logging backends @@ -38,7 +38,7 @@ import io.spine.logging.flogger.backend.Metadata */ class FakeMetadata : Metadata() { - private class KeyValuePair(val key: FloggerMetadataKey, val value: T) + private class KeyValuePair(val key: JvmMetadataKey, val value: T) private val entries = mutableListOf>() @@ -46,18 +46,18 @@ class FakeMetadata : Metadata() { * Adds a key/value pair to this [Metadata]. */ @CanIgnoreReturnValue - fun add(key: FloggerMetadataKey, value: T): FakeMetadata { + fun add(key: JvmMetadataKey, value: T): FakeMetadata { entries.add(KeyValuePair(key, value)) return this } override fun size(): Int = entries.size - override fun getKey(n: Int): FloggerMetadataKey<*> = entries[n].key + override fun getKey(n: Int): JvmMetadataKey<*> = entries[n].key override fun getValue(n: Int): Any = entries[n].value!! - override fun findValue(key: FloggerMetadataKey): T? { + override fun findValue(key: JvmMetadataKey): T? { val entry = entries.firstOrNull { it.key == key } val casted = key.cast(entry?.value) // It is safe to pass `null` here. return casted diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/given/MemoizingLoggerBackend.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/MemoizingLoggerBackend.kt similarity index 94% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/given/MemoizingLoggerBackend.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/MemoizingLoggerBackend.kt index 358a1d715..5727f2324 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/given/MemoizingLoggerBackend.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/MemoizingLoggerBackend.kt @@ -24,10 +24,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.backend.given +package io.spine.logging.jvm.backend.given -import io.spine.logging.flogger.backend.LogData -import io.spine.logging.flogger.backend.LoggerBackend +import io.spine.logging.jvm.backend.LogData +import io.spine.logging.jvm.backend.LoggerBackend import java.util.logging.Level /** diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/given/MetadataAssertions.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/MetadataAssertions.kt similarity index 82% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/given/MetadataAssertions.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/MetadataAssertions.kt index 2093933e4..a851ee4ac 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/backend/given/MetadataAssertions.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/MetadataAssertions.kt @@ -24,10 +24,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.backend.given +package io.spine.logging.jvm.backend.given -import io.spine.logging.flogger.FloggerMetadataKey -import io.spine.logging.flogger.backend.Metadata +import io.spine.logging.jvm.JvmMetadataKey +import io.spine.logging.jvm.backend.Metadata import io.kotest.matchers.collections.shouldContainInOrder import io.kotest.matchers.ints.shouldBeExactly import io.kotest.matchers.nulls.shouldBeNull @@ -60,7 +60,7 @@ internal infix fun Metadata.shouldHaveSize(number: Int) { /** * Asserts that this [Metadata] has a [key] with the mapped [values]. */ -internal fun Metadata.shouldContainInOrder(key: FloggerMetadataKey, vararg values: T) { +internal fun Metadata.shouldContainInOrder(key: JvmMetadataKey, vararg values: T) { valuesOf(key) shouldContainInOrder values.asList() } @@ -69,34 +69,34 @@ internal fun Metadata.shouldContainInOrder(key: FloggerMetadataKey, varar * * The given [value] should be the first one, which was mapped to the [key]. */ -internal fun Metadata.shouldHaveFirstValue(key: FloggerMetadataKey, value: T) { +internal fun Metadata.shouldHaveFirstValue(key: JvmMetadataKey, value: T) { findValue(key) shouldBe value } /** * Asserts that this [Metadata] does NOT HAVE a value for the given [key]. */ -internal infix fun Metadata.shouldNotContain(key: FloggerMetadataKey) { +internal infix fun Metadata.shouldNotContain(key: JvmMetadataKey) { findValue(key).shouldBeNull() } /** * Asserts that this [Metadata] has one or more values for the given [key] */ -internal infix fun Metadata.shouldContain(key: FloggerMetadataKey) { +internal infix fun Metadata.shouldContain(key: JvmMetadataKey) { findValue(key).shouldNotBeNull() } /** * Asserts that this [Metadata] has a [key] to which only a single [value] is mapped. */ -internal fun Metadata.shouldUniquelyContain(key: FloggerMetadataKey, value: T) { +internal fun Metadata.shouldUniquelyContain(key: JvmMetadataKey, value: T) { findValue(key) shouldBe value val allKeys = (0.. getKey(i) }.toList() allKeys.indexOf(key) shouldBe allKeys.lastIndexOf(key) } -private fun Metadata.valuesOf(key: FloggerMetadataKey): List { +private fun Metadata.valuesOf(key: JvmMetadataKey): List { val values: MutableList = ArrayList() for (n in 0.. + interface Api : JvmApi /** * Logs at the given level with the fixed [DEFAULT_TIMESTAMP_NANOS]. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/given/FakeLogSite.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/given/FakeLogSite.kt similarity index 94% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/given/FakeLogSite.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/given/FakeLogSite.kt index 5ffe80382..5697b11f9 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/given/FakeLogSite.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/given/FakeLogSite.kt @@ -24,14 +24,14 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.given +package io.spine.logging.jvm.given -import io.spine.logging.flogger.FloggerLogSite +import io.spine.logging.jvm.JvmLogSite import java.util.* import java.util.concurrent.atomic.AtomicInteger /** - * A simplified implementation of [FloggerLogSite] for testing. + * A simplified implementation of [JvmLogSite] for testing. * * @see Original Java code of Google Flogger */ @@ -40,7 +40,7 @@ class FakeLogSite( private val methodName: String, private val lineNumber: Int, private val sourcePath: String? -) : FloggerLogSite() { +) : JvmLogSite() { companion object { private const val LOGGING_CLASS = "com.example.ClassName" diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/given/FormattingBackend.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/given/FormattingBackend.kt similarity index 95% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/given/FormattingBackend.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/given/FormattingBackend.kt index 2175a7d19..29d76ba37 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/given/FormattingBackend.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/given/FormattingBackend.kt @@ -24,10 +24,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.given +package io.spine.logging.jvm.given -import io.spine.logging.flogger.backend.LogData -import io.spine.logging.flogger.backend.LoggerBackend +import io.spine.logging.jvm.backend.LogData +import io.spine.logging.jvm.backend.LoggerBackend import java.util.* import java.util.logging.Level diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/given/LogDataAssertions.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/given/LogDataAssertions.kt similarity index 96% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/given/LogDataAssertions.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/given/LogDataAssertions.kt index 3da1004c1..c60aeade4 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/given/LogDataAssertions.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/given/LogDataAssertions.kt @@ -24,9 +24,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.given +package io.spine.logging.jvm.given -import io.spine.logging.flogger.backend.LogData +import io.spine.logging.jvm.backend.LogData import io.kotest.matchers.collections.shouldContainExactly import io.kotest.matchers.shouldBe diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/given/MemoizingKvHandler.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/given/MemoizingKvHandler.kt similarity index 89% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/given/MemoizingKvHandler.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/given/MemoizingKvHandler.kt index 4af386119..76274694c 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/given/MemoizingKvHandler.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/given/MemoizingKvHandler.kt @@ -24,14 +24,14 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.given +package io.spine.logging.jvm.given -import io.spine.logging.flogger.FloggerMetadataKey +import io.spine.logging.jvm.JvmMetadataKey /** * Remembers all handled key/value pairs. */ -internal class MemoizingKvHandler : FloggerMetadataKey.KeyValueHandler { +internal class MemoizingKvHandler : JvmMetadataKey.KeyValueHandler { val entries = ArrayList() diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/parameter/ParameterSpec.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parameter/ParameterSpec.kt similarity index 96% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/parameter/ParameterSpec.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parameter/ParameterSpec.kt index 09adf63e7..6f4c4775e 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/parameter/ParameterSpec.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parameter/ParameterSpec.kt @@ -24,9 +24,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.parameter +package io.spine.logging.jvm.parameter -import io.spine.logging.flogger.backend.FormatOptions +import io.spine.logging.jvm.backend.FormatOptions import io.kotest.matchers.shouldBe import io.kotest.matchers.types.shouldBeSameInstanceAs import org.junit.jupiter.api.DisplayName diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/parameter/SimpleParameterSpec.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parameter/SimpleParameterSpec.kt similarity index 88% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/parameter/SimpleParameterSpec.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parameter/SimpleParameterSpec.kt index e4b2d2fb6..4b1f5fc93 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/parameter/SimpleParameterSpec.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parameter/SimpleParameterSpec.kt @@ -24,18 +24,18 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.parameter +package io.spine.logging.jvm.parameter -import io.spine.logging.flogger.backend.FormatChar -import io.spine.logging.flogger.backend.FormatOptions +import io.spine.logging.jvm.backend.FormatChar +import io.spine.logging.jvm.backend.FormatOptions import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test -import io.spine.logging.flogger.backend.FormatChar.DECIMAL -import io.spine.logging.flogger.backend.FormatChar.FLOAT -import io.spine.logging.flogger.backend.FormatChar.HEX -import io.spine.logging.flogger.backend.FormatChar.STRING -import io.spine.logging.flogger.parameter.SimpleParameter.buildFormatString -import io.spine.logging.flogger.parser.ParseException +import io.spine.logging.jvm.backend.FormatChar.DECIMAL +import io.spine.logging.jvm.backend.FormatChar.FLOAT +import io.spine.logging.jvm.backend.FormatChar.HEX +import io.spine.logging.jvm.backend.FormatChar.STRING +import io.spine.logging.jvm.parameter.SimpleParameter.buildFormatString +import io.spine.logging.jvm.parser.ParseException import io.kotest.matchers.shouldBe import io.kotest.matchers.types.shouldBeSameInstanceAs import io.kotest.matchers.types.shouldNotBeSameInstanceAs diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/parser/BraceStyleMessageParserSpec.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parser/BraceStyleMessageParserSpec.kt similarity index 95% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/parser/BraceStyleMessageParserSpec.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parser/BraceStyleMessageParserSpec.kt index 53cadb205..1b33589af 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/parser/BraceStyleMessageParserSpec.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parser/BraceStyleMessageParserSpec.kt @@ -24,12 +24,12 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.parser +package io.spine.logging.jvm.parser -import io.spine.logging.flogger.parser.BraceStyleMessageParser.nextBraceFormatTerm -import io.spine.logging.flogger.parser.given.FakeParameter -import io.spine.logging.flogger.parser.given.assertParse -import io.spine.logging.flogger.parser.given.assertParseError +import io.spine.logging.jvm.parser.BraceStyleMessageParser.nextBraceFormatTerm +import io.spine.logging.jvm.parser.given.FakeParameter +import io.spine.logging.jvm.parser.given.assertParse +import io.spine.logging.jvm.parser.given.assertParseError import io.kotest.matchers.shouldBe import io.kotest.matchers.string.shouldContain import org.junit.jupiter.api.DisplayName diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/parser/DefaultBraceStyleMessageParserSpec.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parser/DefaultBraceStyleMessageParserSpec.kt similarity index 88% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/parser/DefaultBraceStyleMessageParserSpec.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parser/DefaultBraceStyleMessageParserSpec.kt index 9bbd2cbea..98bb96eac 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/parser/DefaultBraceStyleMessageParserSpec.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parser/DefaultBraceStyleMessageParserSpec.kt @@ -24,14 +24,14 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.parser +package io.spine.logging.jvm.parser -import io.spine.logging.flogger.backend.FormatChar -import io.spine.logging.flogger.backend.FormatOptions -import io.spine.logging.flogger.backend.FormatOptions.FLAG_SHOW_GROUPING -import io.spine.logging.flogger.backend.FormatOptions.UNSET -import io.spine.logging.flogger.parser.given.MemoizingMessageBuilder -import io.spine.logging.flogger.parser.given.MemoizingParameterVisitor +import io.spine.logging.jvm.backend.FormatChar +import io.spine.logging.jvm.backend.FormatOptions +import io.spine.logging.jvm.backend.FormatOptions.FLAG_SHOW_GROUPING +import io.spine.logging.jvm.backend.FormatOptions.UNSET +import io.spine.logging.jvm.parser.given.MemoizingMessageBuilder +import io.spine.logging.jvm.parser.given.MemoizingParameterVisitor import io.kotest.matchers.shouldBe import io.kotest.matchers.string.shouldContain import org.junit.jupiter.api.DisplayName diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/parser/DefaultPrintfMessageParserSpec.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parser/DefaultPrintfMessageParserSpec.kt similarity index 93% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/parser/DefaultPrintfMessageParserSpec.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parser/DefaultPrintfMessageParserSpec.kt index a8d357a46..3ef45d422 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/parser/DefaultPrintfMessageParserSpec.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parser/DefaultPrintfMessageParserSpec.kt @@ -24,11 +24,11 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.parser +package io.spine.logging.jvm.parser -import io.spine.logging.flogger.backend.FormatChar -import io.spine.logging.flogger.parser.given.MemoizingMessageBuilder -import io.spine.logging.flogger.parser.given.MemoizingParameterVisitor +import io.spine.logging.jvm.backend.FormatChar +import io.spine.logging.jvm.parser.given.MemoizingMessageBuilder +import io.spine.logging.jvm.parser.given.MemoizingParameterVisitor import io.kotest.matchers.shouldBe import io.kotest.matchers.string.shouldContain import org.junit.jupiter.api.DisplayName diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/parser/PrintfMessageParserSpec.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parser/PrintfMessageParserSpec.kt similarity index 95% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/parser/PrintfMessageParserSpec.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parser/PrintfMessageParserSpec.kt index 30ef32ac3..89f1a6ea4 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/parser/PrintfMessageParserSpec.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parser/PrintfMessageParserSpec.kt @@ -24,12 +24,12 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.parser +package io.spine.logging.jvm.parser -import io.spine.logging.flogger.parser.PrintfMessageParser.nextPrintfTerm -import io.spine.logging.flogger.parser.given.FakeParameter -import io.spine.logging.flogger.parser.given.assertParse -import io.spine.logging.flogger.parser.given.assertParseError +import io.spine.logging.jvm.parser.PrintfMessageParser.nextPrintfTerm +import io.spine.logging.jvm.parser.given.FakeParameter +import io.spine.logging.jvm.parser.given.assertParse +import io.spine.logging.jvm.parser.given.assertParseError import io.kotest.matchers.collections.shouldBeIn import io.kotest.matchers.shouldBe diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/parser/given/ParserTestEnv.kt b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parser/given/ParserTestEnv.kt similarity index 90% rename from flogger/middleware/src/test/kotlin/io/spine/logging/flogger/parser/given/ParserTestEnv.kt rename to flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parser/given/ParserTestEnv.kt index 2b57791b7..1e0abe4c8 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/flogger/parser/given/ParserTestEnv.kt +++ b/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parser/given/ParserTestEnv.kt @@ -24,17 +24,17 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.logging.flogger.parser.given - -import io.spine.logging.flogger.backend.FormatChar -import io.spine.logging.flogger.backend.FormatOptions -import io.spine.logging.flogger.backend.TemplateContext -import io.spine.logging.flogger.parameter.DateTimeFormat -import io.spine.logging.flogger.parameter.Parameter -import io.spine.logging.flogger.parameter.ParameterVisitor -import io.spine.logging.flogger.parser.MessageBuilder -import io.spine.logging.flogger.parser.MessageParser -import io.spine.logging.flogger.parser.ParseException +package io.spine.logging.jvm.parser.given + +import io.spine.logging.jvm.backend.FormatChar +import io.spine.logging.jvm.backend.FormatOptions +import io.spine.logging.jvm.backend.TemplateContext +import io.spine.logging.jvm.parameter.DateTimeFormat +import io.spine.logging.jvm.parameter.Parameter +import io.spine.logging.jvm.parameter.ParameterVisitor +import io.spine.logging.jvm.parser.MessageBuilder +import io.spine.logging.jvm.parser.MessageParser +import io.spine.logging.jvm.parser.ParseException import io.kotest.matchers.collections.shouldContainExactly import io.kotest.matchers.string.shouldContain import kotlin.properties.Delegates.notNull diff --git a/flogger/platform-generator/src/main/java/io/spine/logging/backend/generator/PlatformProviderGenerator.java b/flogger/platform-generator/src/main/java/io/spine/logging/backend/generator/PlatformProviderGenerator.java index 3e8056125..21f000abb 100644 --- a/flogger/platform-generator/src/main/java/io/spine/logging/backend/generator/PlatformProviderGenerator.java +++ b/flogger/platform-generator/src/main/java/io/spine/logging/backend/generator/PlatformProviderGenerator.java @@ -60,7 +60,7 @@ /** * Generates {@code PlatformProvider} class from scratch. * - *

      The generated class discovers {@code io.spine.logging.flogger.backend.Platform} + *

      The generated class discovers {@code io.spine.logging.jvm.backend.Platform} * implementations, and creates their instances. * *

      This generator is necessary to create a class, which explicitly @@ -83,7 +83,7 @@ public final class PlatformProviderGenerator { private static final String[] PLATFORM_CLASSES = { - "Lio/spine/logging/flogger/backend/system/DefaultPlatform;", + "Lio/spine/logging/jvm/backend/system/DefaultPlatform;", }; /** @@ -99,7 +99,7 @@ public static void main(String[] args) throws IOException { classWriter.visit( V1_6, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, - "io/spine/logging/flogger/backend/PlatformProvider", + "io/spine/logging/jvm/backend/PlatformProvider", null, "java/lang/Object", null) @@ -118,7 +118,7 @@ public static void main(String[] args) throws IOException { methodVisitor = classWriter.visitMethod( ACC_PUBLIC + ACC_STATIC, "getPlatform", - "()Lio/spine/logging/flogger/backend/Platform;", + "()Lio/spine/logging/jvm/backend/Platform;", null, null ); @@ -141,7 +141,7 @@ public static void main(String[] args) throws IOException { var path = Paths.get(args[0]); Files.createDirectories(path.getParent()); try (var jar = new JarOutputStream(newOutputStream(path, StandardOpenOption.CREATE_NEW))) { - var entry = new ZipEntry("io/spine/logging/flogger/backend/PlatformProvider.class"); + var entry = new ZipEntry("io/spine/logging/jvm/backend/PlatformProvider.class"); // Clear timestamp to ensure JAR is deterministic for build cache. entry.setTime(0); jar.putNextEntry(entry); @@ -231,7 +231,7 @@ the class not being present. "newInstance", "([Ljava/lang/Object;)Ljava/lang/Object;", false); - methodVisitor.visitTypeInsn(CHECKCAST, "io/spine/logging/flogger/backend/Platform"); + methodVisitor.visitTypeInsn(CHECKCAST, "io/spine/logging/jvm/backend/Platform"); methodVisitor.visitLabel(endLabel); methodVisitor.visitInsn(ARETURN); diff --git a/logging/src/jvmMain/kotlin/io/spine/logging/JvmLogger.kt b/logging/src/jvmMain/kotlin/io/spine/logging/JvmLogger.kt index b371fec7d..561a7182d 100644 --- a/logging/src/jvmMain/kotlin/io/spine/logging/JvmLogger.kt +++ b/logging/src/jvmMain/kotlin/io/spine/logging/JvmLogger.kt @@ -26,10 +26,10 @@ package io.spine.logging -import io.spine.logging.flogger.FluentLogger2 -import io.spine.logging.flogger.FloggerLogSites.callerOf +import io.spine.logging.jvm.FluentLogger2 +import io.spine.logging.jvm.JvmLogSites.callerOf import com.google.errorprone.annotations.CheckReturnValue -import io.spine.logging.flogger.FloggerLogSite +import io.spine.logging.jvm.JvmLogSite import kotlin.reflect.KClass import kotlin.time.DurationUnit import kotlin.time.toTimeUnit @@ -159,20 +159,20 @@ public operator fun JLevel.compareTo(other: JLevel): Int = intValue().compareTo(other.intValue()) /** - * Converts this [LogSite] to Flogger's counterpart. + * Converts this [LogSite] to the JVM logging counterpart. */ -private fun LogSite.toFloggerSite(): FloggerLogSite { +private fun LogSite.toFloggerSite(): JvmLogSite { if (this == LogSite.INVALID) { - return FloggerLogSite.INVALID + return JvmLogSite.INVALID } - return object : FloggerLogSite() { + return object : JvmLogSite() { override fun getClassName(): String = this@toFloggerSite.className override fun getMethodName(): String = this@toFloggerSite.methodName override fun getLineNumber(): Int = this@toFloggerSite.lineNumber override fun getFileName(): String? = null override fun hashCode(): Int = this@toFloggerSite.hashCode() override fun equals(other: Any?): Boolean { - if (other !is FloggerLogSite) { + if (other !is JvmLogSite) { return false } return lineNumber == other.lineNumber && diff --git a/logging/src/jvmMain/kotlin/io/spine/logging/JvmMetadataKey.kt b/logging/src/jvmMain/kotlin/io/spine/logging/JvmMetadataKey.kt index 6a3d2fd4a..5242f7153 100644 --- a/logging/src/jvmMain/kotlin/io/spine/logging/JvmMetadataKey.kt +++ b/logging/src/jvmMain/kotlin/io/spine/logging/JvmMetadataKey.kt @@ -26,7 +26,7 @@ package io.spine.logging -import io.spine.logging.flogger.FloggerMetadataKey +import io.spine.logging.jvm.JvmMetadataKey as FloggerMetadataKey import kotlin.reflect.KClass import kotlin.reflect.cast diff --git a/logging/src/jvmMain/kotlin/io/spine/logging/LogSiteLookup.kt b/logging/src/jvmMain/kotlin/io/spine/logging/LogSiteLookup.kt index 59b6b3855..42353be2e 100644 --- a/logging/src/jvmMain/kotlin/io/spine/logging/LogSiteLookup.kt +++ b/logging/src/jvmMain/kotlin/io/spine/logging/LogSiteLookup.kt @@ -26,10 +26,10 @@ package io.spine.logging -import io.spine.logging.flogger.backend.Platform +import io.spine.logging.jvm.backend.Platform import kotlin.reflect.KClass -import io.spine.logging.flogger.FloggerLogSite -import io.spine.logging.flogger.FloggerLogSites +import io.spine.logging.jvm.JvmLogSite +import io.spine.logging.jvm.JvmLogSites /** * Determines log sites for the current line of code using Flogger utils. @@ -43,7 +43,7 @@ public actual object LogSiteLookup { * the [LogSite.INVALID] instance. */ public actual fun callerOf(loggingApi: KClass<*>): LogSite { - val floggerSite = FloggerLogSites.callerOf(loggingApi.java) + val floggerSite = JvmLogSites.callerOf(loggingApi.java) val logSite = floggerSite.toLogSite() return logSite } @@ -64,8 +64,8 @@ public actual object LogSiteLookup { } } -private fun FloggerLogSite.toLogSite(): LogSite { - if (this == FloggerLogSite.INVALID) { +private fun JvmLogSite.toLogSite(): LogSite { + if (this == JvmLogSite.INVALID) { return LogSite.INVALID } return InjectedLogSite( diff --git a/logging/src/jvmMain/kotlin/io/spine/logging/LoggingFactory.kt b/logging/src/jvmMain/kotlin/io/spine/logging/LoggingFactory.kt index bae8a45b0..883f74434 100644 --- a/logging/src/jvmMain/kotlin/io/spine/logging/LoggingFactory.kt +++ b/logging/src/jvmMain/kotlin/io/spine/logging/LoggingFactory.kt @@ -26,8 +26,8 @@ package io.spine.logging -import io.spine.logging.flogger.FluentLogger2 -import io.spine.logging.flogger.backend.Platform +import io.spine.logging.jvm.FluentLogger2 +import io.spine.logging.jvm.backend.Platform import io.spine.reflect.CallerFinder import kotlin.reflect.KClass diff --git a/logging/src/jvmMain/kotlin/io/spine/logging/context/LoggingContextFactory.kt b/logging/src/jvmMain/kotlin/io/spine/logging/context/LoggingContextFactory.kt index 3cb182f04..7ee2a3e7b 100644 --- a/logging/src/jvmMain/kotlin/io/spine/logging/context/LoggingContextFactory.kt +++ b/logging/src/jvmMain/kotlin/io/spine/logging/context/LoggingContextFactory.kt @@ -35,9 +35,9 @@ import io.spine.logging.toJavaLogging import io.spine.logging.toLevel import io.spine.logging.toLoggerName import kotlin.reflect.KClass -import io.spine.logging.flogger.context.ContextDataProvider as FContextDataProvider -import io.spine.logging.flogger.context.LogLevelMap as FLogLevelMap -import io.spine.logging.flogger.context.ScopedLoggingContext as FScopedLoggingContext +import io.spine.logging.jvm.context.ContextDataProvider as FContextDataProvider +import io.spine.logging.jvm.context.LogLevelMap as FLogLevelMap +import io.spine.logging.jvm.context.ScopedLoggingContext as FScopedLoggingContext /** * A JVM implementation of `LoggingContextFactory`. diff --git a/platforms/jvm-default-platform/src/main/java/io/spine/logging/backend/system/DefaultPlatform.java b/platforms/jvm-default-platform/src/main/java/io/spine/logging/backend/system/DefaultPlatform.java index 0c3427a3c..0e6c0f0b5 100644 --- a/platforms/jvm-default-platform/src/main/java/io/spine/logging/backend/system/DefaultPlatform.java +++ b/platforms/jvm-default-platform/src/main/java/io/spine/logging/backend/system/DefaultPlatform.java @@ -27,18 +27,18 @@ package io.spine.logging.backend.system; import io.spine.logging.backend.jul.JulBackendFactory; -import io.spine.logging.flogger.backend.BackendFactory; -import io.spine.logging.flogger.backend.Clock; -import io.spine.logging.flogger.backend.LoggerBackend; -import io.spine.logging.flogger.backend.Platform; -import io.spine.logging.flogger.context.ContextDataProvider; +import io.spine.logging.jvm.backend.BackendFactory; +import io.spine.logging.jvm.backend.Clock; +import io.spine.logging.jvm.backend.LoggerBackend; +import io.spine.logging.jvm.backend.Platform; +import io.spine.logging.jvm.context.ContextDataProvider; import org.jspecify.annotations.Nullable; import java.util.ArrayList; import java.util.List; import java.util.ServiceLoader; -import static io.spine.logging.flogger.util.StaticMethodCaller.getInstanceFromSystemProperty; +import static io.spine.logging.jvm.util.StaticMethodCaller.getInstanceFromSystemProperty; /** * The default logger platform for a server-side Java environment. diff --git a/platforms/jvm-default-platform/src/main/java/io/spine/logging/backend/system/StackBasedCallerFinder.java b/platforms/jvm-default-platform/src/main/java/io/spine/logging/backend/system/StackBasedCallerFinder.java index 86d34a67f..86d38dc23 100644 --- a/platforms/jvm-default-platform/src/main/java/io/spine/logging/backend/system/StackBasedCallerFinder.java +++ b/platforms/jvm-default-platform/src/main/java/io/spine/logging/backend/system/StackBasedCallerFinder.java @@ -26,10 +26,10 @@ package io.spine.logging.backend.system; -import io.spine.logging.flogger.AbstractLogger; -import io.spine.logging.flogger.FloggerLogSite; -import io.spine.logging.flogger.FloggerLogSites; -import io.spine.logging.flogger.backend.Platform.LogCallerFinder; +import io.spine.logging.jvm.AbstractLogger; +import io.spine.logging.jvm.JvmLogSite; +import io.spine.logging.jvm.JvmLogSites; +import io.spine.logging.jvm.backend.Platform.LogCallerFinder; import static io.spine.reflect.CallerFinder.findCallerOf; @@ -61,13 +61,13 @@ public String findLoggingClass(Class> loggerClass) { } @Override - public FloggerLogSite findLogSite(Class loggerApi, int stackFramesToSkip) { + public JvmLogSite findLogSite(Class loggerApi, int stackFramesToSkip) { // Skip an additional stack frame because we create the Throwable inside this method, not at // the point that this method was invoked (which allows completely alternate implementations // to avoid even constructing the Throwable instance). var caller = findCallerOf(loggerApi, stackFramesToSkip + 1); // Returns INVALID if "caller" is null (no caller found for given API class). - return FloggerLogSites.logSiteFrom(caller); + return JvmLogSites.logSiteFrom(caller); } @Override diff --git a/platforms/jvm-default-platform/src/main/java/io/spine/logging/backend/system/SystemClock.java b/platforms/jvm-default-platform/src/main/java/io/spine/logging/backend/system/SystemClock.java index 1990778d9..76d109b45 100644 --- a/platforms/jvm-default-platform/src/main/java/io/spine/logging/backend/system/SystemClock.java +++ b/platforms/jvm-default-platform/src/main/java/io/spine/logging/backend/system/SystemClock.java @@ -26,7 +26,7 @@ package io.spine.logging.backend.system; -import io.spine.logging.flogger.backend.Clock; +import io.spine.logging.jvm.backend.Clock; import static java.util.concurrent.TimeUnit.MILLISECONDS; diff --git a/platforms/jvm-default-platform/src/test/kotlin/io/spine/logging/backend/system/DefaultPlatformSpec.kt b/platforms/jvm-default-platform/src/test/kotlin/io/spine/logging/backend/system/DefaultPlatformSpec.kt index c6d56a9c2..469a13cac 100644 --- a/platforms/jvm-default-platform/src/test/kotlin/io/spine/logging/backend/system/DefaultPlatformSpec.kt +++ b/platforms/jvm-default-platform/src/test/kotlin/io/spine/logging/backend/system/DefaultPlatformSpec.kt @@ -35,8 +35,8 @@ import io.spine.logging.backend.system.given.NoOpCallerFinder import io.spine.logging.backend.system.given.StubBackendFactoryService import io.spine.logging.backend.system.given.StubClockService import io.spine.logging.backend.system.given.StubContextDataProviderService -import io.spine.logging.flogger.backend.given.MemoizingLoggerBackend -import io.spine.logging.flogger.context.ContextDataProvider +import io.spine.logging.jvm.backend.given.MemoizingLoggerBackend +import io.spine.logging.jvm.context.ContextDataProvider import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test diff --git a/platforms/jvm-default-platform/src/test/kotlin/io/spine/logging/backend/system/given/DefaultPlatformTestEnv.kt b/platforms/jvm-default-platform/src/test/kotlin/io/spine/logging/backend/system/given/DefaultPlatformTestEnv.kt index f3c864fba..3d45f9fa8 100644 --- a/platforms/jvm-default-platform/src/test/kotlin/io/spine/logging/backend/system/given/DefaultPlatformTestEnv.kt +++ b/platforms/jvm-default-platform/src/test/kotlin/io/spine/logging/backend/system/given/DefaultPlatformTestEnv.kt @@ -26,13 +26,13 @@ package io.spine.logging.backend.system.given -import io.spine.logging.flogger.backend.BackendFactory -import io.spine.logging.flogger.backend.Clock -import io.spine.logging.flogger.AbstractLogger -import io.spine.logging.flogger.FloggerLogSite -import io.spine.logging.flogger.backend.LoggerBackend -import io.spine.logging.flogger.backend.Platform -import io.spine.logging.flogger.backend.given.MemoizingLoggerBackend +import io.spine.logging.jvm.backend.BackendFactory +import io.spine.logging.jvm.backend.Clock +import io.spine.logging.jvm.AbstractLogger +import io.spine.logging.jvm.JvmLogSite +import io.spine.logging.jvm.backend.LoggerBackend +import io.spine.logging.jvm.backend.Platform +import io.spine.logging.jvm.backend.given.MemoizingLoggerBackend /** * A primitive factory of [MemoizingLoggerBackend]. @@ -72,6 +72,6 @@ internal class NoOpCallerFinder : Platform.LogCallerFinder() { /** * Throws [IllegalStateException]. */ - override fun findLogSite(loggerApi: Class<*>?, stackFramesToSkip: Int): FloggerLogSite = + override fun findLogSite(loggerApi: Class<*>?, stackFramesToSkip: Int): JvmLogSite = throw UnsupportedOperationException() } diff --git a/platforms/jvm-default-platform/src/test/kotlin/io/spine/logging/backend/system/given/JavaServices.kt b/platforms/jvm-default-platform/src/test/kotlin/io/spine/logging/backend/system/given/JavaServices.kt index b0f2c1f4c..d2c81c4bc 100644 --- a/platforms/jvm-default-platform/src/test/kotlin/io/spine/logging/backend/system/given/JavaServices.kt +++ b/platforms/jvm-default-platform/src/test/kotlin/io/spine/logging/backend/system/given/JavaServices.kt @@ -27,11 +27,11 @@ package io.spine.logging.backend.system.given import com.google.auto.service.AutoService -import io.spine.logging.flogger.backend.LoggerBackend -import io.spine.logging.flogger.backend.BackendFactory -import io.spine.logging.flogger.backend.Clock -import io.spine.logging.flogger.context.ContextDataProvider -import io.spine.logging.flogger.context.ScopedLoggingContext +import io.spine.logging.jvm.backend.LoggerBackend +import io.spine.logging.jvm.backend.BackendFactory +import io.spine.logging.jvm.backend.Clock +import io.spine.logging.jvm.context.ContextDataProvider +import io.spine.logging.jvm.context.ScopedLoggingContext /** * This file contains Java services that are used to test how diff --git a/tests/jvm-jul-backend-std-context/src/test/kotlin/LogLevelMapITest.kt b/tests/jvm-jul-backend-std-context/src/test/kotlin/LogLevelMapITest.kt index 0f02c09ba..a85fdc782 100644 --- a/tests/jvm-jul-backend-std-context/src/test/kotlin/LogLevelMapITest.kt +++ b/tests/jvm-jul-backend-std-context/src/test/kotlin/LogLevelMapITest.kt @@ -24,7 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import io.spine.logging.flogger.backend.Platform +import io.spine.logging.jvm.backend.Platform import io.kotest.matchers.shouldBe import io.spine.logging.backend.jul.JulBackendFactory import io.spine.logging.context.JulLogLevelMapTest diff --git a/tests/jvm-log4j2-backend-std-context/src/test/kotlin/LogLevelMapITest.kt b/tests/jvm-log4j2-backend-std-context/src/test/kotlin/LogLevelMapITest.kt index 219af4a4a..29f55abd7 100644 --- a/tests/jvm-log4j2-backend-std-context/src/test/kotlin/LogLevelMapITest.kt +++ b/tests/jvm-log4j2-backend-std-context/src/test/kotlin/LogLevelMapITest.kt @@ -24,7 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import io.spine.logging.flogger.backend.Platform +import io.spine.logging.jvm.backend.Platform import io.kotest.matchers.shouldBe import io.spine.logging.Level import io.spine.logging.backend.log4j2.Log4j2BackendFactory From df3e2378c3ac53eab7f06ad9e467d3070244949e Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Wed, 25 Jun 2025 16:58:24 +0100 Subject: [PATCH 02/28] Rename the `flogger` directory --- .idea/kotlinc.xml | 6 +--- config | 2 +- dependencies.md | 34 +++++++++---------- {flogger => jvm}/README.md | 0 {flogger => jvm}/middleware/build.gradle.kts | 0 .../io/spine/logging/jvm/AbstractLogger.java | 2 +- .../logging/jvm/CountingRateLimiter.java | 2 +- .../logging/jvm/DurationRateLimiter.java | 2 +- .../io/spine/logging/jvm/FluentLogger2.java | 2 +- .../java/io/spine/logging/jvm/JvmApi.java | 2 +- .../java/io/spine/logging/jvm/JvmLogSite.java | 2 +- .../io/spine/logging/jvm/JvmLogSites.java | 2 +- .../io/spine/logging/jvm/JvmMetadataKey.java | 2 +- .../java/io/spine/logging/jvm/LazyArg.java | 2 +- .../java/io/spine/logging/jvm/LazyArgs.java | 2 +- .../java/io/spine/logging/jvm/LogContext.java | 2 +- .../logging/jvm/LogPerBucketingStrategy.java | 2 +- .../java/io/spine/logging/jvm/LogSiteKey.java | 2 +- .../java/io/spine/logging/jvm/LogSiteMap.java | 2 +- .../spine/logging/jvm/LogSiteStackTrace.java | 2 +- .../io/spine/logging/jvm/LoggingScope.java | 2 +- .../logging/jvm/LoggingScopeProvider.java | 2 +- .../io/spine/logging/jvm/RateLimitStatus.java | 2 +- .../logging/jvm/SamplingRateLimiter.java | 2 +- .../logging/jvm/SpecializedLogSiteKey.java | 2 +- .../spine/logging/jvm/StackBasedLogSite.java | 2 +- .../java/io/spine/logging/jvm/StackSize.java | 2 +- .../logging/jvm/backend/BackendFactory.java | 2 +- .../jvm/backend/BaseMessageFormatter.java | 2 +- .../io/spine/logging/jvm/backend/Clock.java | 2 +- .../spine/logging/jvm/backend/FormatChar.java | 2 +- .../logging/jvm/backend/FormatOptions.java | 2 +- .../spine/logging/jvm/backend/FormatType.java | 2 +- .../jvm/backend/KeyValueFormatter.java | 2 +- .../io/spine/logging/jvm/backend/LogData.java | 2 +- .../jvm/backend/LogMessageFormatter.java | 2 +- .../logging/jvm/backend/LoggerBackend.java | 2 +- .../logging/jvm/backend/LoggingException.java | 2 +- .../logging/jvm/backend/MessageUtils.java | 2 +- .../spine/logging/jvm/backend/Metadata.java | 2 +- .../logging/jvm/backend/MetadataHandler.java | 2 +- .../jvm/backend/MetadataKeyValueHandlers.java | 2 +- .../jvm/backend/MetadataProcessor.java | 2 +- .../spine/logging/jvm/backend/Platform.java | 2 +- .../jvm/backend/SimpleMessageFormatter.java | 2 +- .../logging/jvm/backend/TemplateContext.java | 2 +- .../logging/jvm/backend/package-info.java | 2 +- .../jvm/context/ContextDataProvider.java | 2 +- .../logging/jvm/context/ContextMetadata.java | 2 +- .../logging/jvm/context/LogLevelMap.java | 2 +- .../jvm/context/NoOpContextDataProvider.java | 2 +- .../spine/logging/jvm/context/ScopeType.java | 2 +- .../jvm/context/ScopedLoggingContext.java | 2 +- .../jvm/context/ScopedLoggingContexts.java | 2 +- .../logging/jvm/context/SegmentTrie.java | 2 +- .../io/spine/logging/jvm/context/Tags.java | 2 +- .../logging/jvm/context/package-info.java | 2 +- .../io/spine/logging/jvm/package-info.java | 2 +- .../jvm/parameter/BraceStyleParameter.java | 2 +- .../logging/jvm/parameter/DateTimeFormat.java | 2 +- .../jvm/parameter/DateTimeParameter.java | 2 +- .../logging/jvm/parameter/Parameter.java | 2 +- .../jvm/parameter/ParameterVisitor.java | 2 +- .../jvm/parameter/SimpleParameter.java | 2 +- .../logging/jvm/parameter/package-info.java | 2 +- .../jvm/parser/BraceStyleMessageParser.java | 2 +- .../DefaultBraceStyleMessageParser.java | 2 +- .../parser/DefaultPrintfMessageParser.java | 2 +- .../logging/jvm/parser/MessageBuilder.java | 2 +- .../logging/jvm/parser/MessageParser.java | 2 +- .../logging/jvm/parser/ParseException.java | 2 +- .../jvm/parser/PrintfMessageParser.java | 2 +- .../logging/jvm/parser/package-info.java | 2 +- .../io/spine/logging/jvm/util/Checks.java | 2 +- .../logging/jvm/util/RecursionDepth.java | 2 +- .../logging/jvm/util/StaticMethodCaller.java | 2 +- .../spine/logging/jvm/util/package-info.java | 2 +- .../io/spine/logging/jvm/JvmMetadataKeys.kt | 2 +- .../logging/backend/given/BadToString.java | 2 +- .../logging/backend/given/package-info.java | 4 +-- .../spine/logging/jvm/AbstractLoggerSpec.kt | 2 +- .../logging/jvm/CountingRateLimiterSpec.kt | 2 +- .../logging/jvm/DurationRateLimiterSpec.kt | 2 +- .../io/spine/logging/jvm/FluentLogger2Spec.kt | 2 +- .../io/spine/logging/jvm/JvmLogSitesSpec.kt | 2 +- .../spine/logging/jvm/JvmMetadataKeySpec.kt | 2 +- .../io/spine/logging/jvm/LogContextSpec.kt | 2 +- .../jvm/LogPerBucketingStrategySpec.kt | 2 +- .../io/spine/logging/jvm/LogSiteMapSpec.kt | 2 +- .../logging/jvm/LogSiteStackTraceSpec.kt | 2 +- .../io/spine/logging/jvm/LoggingScopeSpec.kt | 2 +- .../spine/logging/jvm/RateLimitStatusSpec.kt | 2 +- .../logging/jvm/SamplingRateLimiterSpec.kt | 2 +- .../logging/jvm/SpecializedLogSiteKeySpec.kt | 2 +- .../logging/jvm/StackBasedLogSiteSpec.kt | 2 +- .../jvm/backend/BaseMessageFormatterSpec.kt | 2 +- .../logging/jvm/backend/FormatCharSpec.kt | 2 +- .../logging/jvm/backend/FormatOptionsSpec.kt | 2 +- .../logging/jvm/backend/FormatTypeSpec.kt | 2 +- .../jvm/backend/KeyValueFormatterSpec.kt | 2 +- .../jvm/backend/LightweightProcessorSpec.kt | 2 +- .../logging/jvm/backend/MessageUtilsSpec.kt | 2 +- .../jvm/backend/MetadataHandlerSpec.kt | 2 +- .../backend/MetadataKeyValueHandlersSpec.kt | 2 +- .../jvm/backend/MetadataProcessorSpec.kt | 2 +- .../jvm/backend/SimpleMessageFormatterSpec.kt | 2 +- .../jvm/backend/SimpleProcessorSpec.kt | 2 +- .../logging/jvm/backend/given/FakeLogData.kt | 2 +- .../logging/jvm/backend/given/FakeMetadata.kt | 2 +- .../backend/given/MemoizingLoggerBackend.kt | 2 +- .../jvm/backend/given/MetadataAssertions.kt | 2 +- .../AbstractContextDataProviderSpec.kt | 2 +- .../jvm/context/ContextMetadataSpec.kt | 2 +- .../logging/jvm/context/LogLevelMapSpec.kt | 2 +- .../jvm/context/ScopedLoggingContextSpec.kt | 2 +- .../logging/jvm/context/SegmentTrieSpec.kt | 2 +- .../io/spine/logging/jvm/context/TagsSpec.kt | 2 +- .../spine/logging/jvm/given/BackendTestEnv.kt | 2 +- .../logging/jvm/given/ConfigurableLogger.kt | 2 +- .../io/spine/logging/jvm/given/FakeLogSite.kt | 2 +- .../logging/jvm/given/FormattingBackend.kt | 2 +- .../logging/jvm/given/LogDataAssertions.kt | 2 +- .../logging/jvm/given/MemoizingKvHandler.kt | 2 +- .../logging/jvm/parameter/ParameterSpec.kt | 2 +- .../jvm/parameter/SimpleParameterSpec.kt | 2 +- .../jvm/parser/BraceStyleMessageParserSpec.kt | 2 +- .../DefaultBraceStyleMessageParserSpec.kt | 2 +- .../parser/DefaultPrintfMessageParserSpec.kt | 2 +- .../jvm/parser/PrintfMessageParserSpec.kt | 2 +- .../logging/jvm/parser/given/ParserTestEnv.kt | 2 +- .../platform-generator/build.gradle.kts | 0 .../generator/PlatformProviderGenerator.java | 4 +-- .../backend/generator/package-info.java | 4 +-- settings.gradle.kts | 6 ++-- version.gradle.kts | 2 +- 135 files changed, 153 insertions(+), 157 deletions(-) rename {flogger => jvm}/README.md (100%) rename {flogger => jvm}/middleware/build.gradle.kts (100%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/AbstractLogger.java (99%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/CountingRateLimiter.java (98%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/DurationRateLimiter.java (98%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/FluentLogger2.java (98%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/JvmApi.java (99%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/JvmLogSite.java (99%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/JvmLogSites.java (99%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/JvmMetadataKey.java (99%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/LazyArg.java (96%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/LazyArgs.java (97%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/LogContext.java (99%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/LogPerBucketingStrategy.java (99%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/LogSiteKey.java (96%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/LogSiteMap.java (98%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/LogSiteStackTrace.java (97%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/LoggingScope.java (99%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/LoggingScopeProvider.java (96%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/RateLimitStatus.java (99%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/SamplingRateLimiter.java (98%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/SpecializedLogSiteKey.java (97%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/StackBasedLogSite.java (97%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/StackSize.java (98%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/backend/BackendFactory.java (98%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/backend/BaseMessageFormatter.java (99%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/backend/Clock.java (98%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/backend/FormatChar.java (99%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/backend/FormatOptions.java (99%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/backend/FormatType.java (98%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/backend/KeyValueFormatter.java (98%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/backend/LogData.java (98%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/backend/LogMessageFormatter.java (97%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/backend/LoggerBackend.java (98%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/backend/LoggingException.java (96%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/backend/MessageUtils.java (99%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/backend/Metadata.java (98%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataHandler.java (99%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataKeyValueHandlers.java (98%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataProcessor.java (99%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/backend/Platform.java (99%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/backend/SimpleMessageFormatter.java (99%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/backend/TemplateContext.java (97%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/backend/package-info.java (95%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/context/ContextDataProvider.java (99%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/context/ContextMetadata.java (99%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/context/LogLevelMap.java (98%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/context/NoOpContextDataProvider.java (98%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/context/ScopeType.java (98%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContext.java (99%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContexts.java (99%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/context/SegmentTrie.java (99%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/context/Tags.java (99%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/context/package-info.java (95%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/package-info.java (95%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/parameter/BraceStyleParameter.java (98%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeFormat.java (98%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeParameter.java (97%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/parameter/Parameter.java (97%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/parameter/ParameterVisitor.java (98%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/parameter/SimpleParameter.java (98%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/parameter/package-info.java (95%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/parser/BraceStyleMessageParser.java (99%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultBraceStyleMessageParser.java (97%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultPrintfMessageParser.java (98%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/parser/MessageBuilder.java (98%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/parser/MessageParser.java (97%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/parser/ParseException.java (98%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/parser/PrintfMessageParser.java (99%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/parser/package-info.java (95%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/util/Checks.java (98%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/util/RecursionDepth.java (97%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/util/StaticMethodCaller.java (98%) rename {flogger => jvm}/middleware/src/main/java/io/spine/logging/jvm/util/package-info.java (95%) rename {flogger => jvm}/middleware/src/main/kotlin/io/spine/logging/jvm/JvmMetadataKeys.kt (96%) rename {flogger => jvm}/middleware/src/test/java/io/spine/logging/backend/given/BadToString.java (95%) rename {flogger => jvm}/middleware/src/test/java/io/spine/logging/backend/given/package-info.java (91%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/AbstractLoggerSpec.kt (98%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/CountingRateLimiterSpec.kt (98%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/DurationRateLimiterSpec.kt (98%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/FluentLogger2Spec.kt (98%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/JvmLogSitesSpec.kt (97%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/JvmMetadataKeySpec.kt (99%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/LogContextSpec.kt (99%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/LogPerBucketingStrategySpec.kt (98%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/LogSiteMapSpec.kt (98%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/LogSiteStackTraceSpec.kt (97%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/LoggingScopeSpec.kt (96%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/RateLimitStatusSpec.kt (98%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/SamplingRateLimiterSpec.kt (98%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/SpecializedLogSiteKeySpec.kt (97%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/StackBasedLogSiteSpec.kt (98%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/backend/BaseMessageFormatterSpec.kt (99%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatCharSpec.kt (98%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatOptionsSpec.kt (99%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatTypeSpec.kt (98%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/backend/KeyValueFormatterSpec.kt (98%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/backend/LightweightProcessorSpec.kt (94%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MessageUtilsSpec.kt (98%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataHandlerSpec.kt (99%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataKeyValueHandlersSpec.kt (98%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataProcessorSpec.kt (99%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/backend/SimpleMessageFormatterSpec.kt (99%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/backend/SimpleProcessorSpec.kt (94%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/FakeLogData.kt (98%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/FakeMetadata.kt (96%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/MemoizingLoggerBackend.kt (97%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/MetadataAssertions.kt (97%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/context/AbstractContextDataProviderSpec.kt (99%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/context/ContextMetadataSpec.kt (98%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/context/LogLevelMapSpec.kt (98%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/context/ScopedLoggingContextSpec.kt (97%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/context/SegmentTrieSpec.kt (98%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/context/TagsSpec.kt (99%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/given/BackendTestEnv.kt (94%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/given/ConfigurableLogger.kt (97%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/given/FakeLogSite.kt (97%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/given/FormattingBackend.kt (97%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/given/LogDataAssertions.kt (96%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/given/MemoizingKvHandler.kt (95%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/parameter/ParameterSpec.kt (97%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/parameter/SimpleParameterSpec.kt (98%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/parser/BraceStyleMessageParserSpec.kt (98%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/parser/DefaultBraceStyleMessageParserSpec.kt (97%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/parser/DefaultPrintfMessageParserSpec.kt (97%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/parser/PrintfMessageParserSpec.kt (98%) rename {flogger => jvm}/middleware/src/test/kotlin/io/spine/logging/jvm/parser/given/ParserTestEnv.kt (98%) rename {flogger => jvm}/platform-generator/build.gradle.kts (100%) rename {flogger => jvm}/platform-generator/src/main/java/io/spine/logging/backend/generator/PlatformProviderGenerator.java (98%) rename {flogger => jvm}/platform-generator/src/main/java/io/spine/logging/backend/generator/package-info.java (91%) diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index df1c163af..c515672dd 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -3,11 +3,7 @@ - - - + \ No newline at end of file diff --git a/config b/config index fab231bb9..e60974948 160000 --- a/config +++ b/config @@ -1 +1 @@ -Subproject commit fab231bb932cf3ea2d51b89373f06dcb1e06cbc5 +Subproject commit e60974948530988efae6f63237b47e19dba80773 diff --git a/dependencies.md b/dependencies.md index abbb2e7b3..1385b5a59 100644 --- a/dependencies.md +++ b/dependencies.md @@ -724,7 +724,7 @@ The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 12:49:51 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 16:41:12 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -1553,7 +1553,7 @@ This report was generated on **Wed Jun 25 12:49:51 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 12:49:52 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 16:41:12 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -2366,7 +2366,7 @@ This report was generated on **Wed Jun 25 12:49:52 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 12:49:52 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 16:41:12 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -3187,7 +3187,7 @@ This report was generated on **Wed Jun 25 12:49:52 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 12:49:52 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 16:41:12 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -4035,7 +4035,7 @@ This report was generated on **Wed Jun 25 12:49:52 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 12:49:52 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 16:41:13 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -4875,7 +4875,7 @@ This report was generated on **Wed Jun 25 12:49:52 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 12:49:53 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 16:41:13 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -5715,7 +5715,7 @@ This report was generated on **Wed Jun 25 12:49:53 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 12:49:53 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 16:41:13 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -6563,7 +6563,7 @@ This report was generated on **Wed Jun 25 12:49:53 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 12:49:53 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 16:41:13 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -7415,7 +7415,7 @@ This report was generated on **Wed Jun 25 12:49:53 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 12:49:53 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 16:41:13 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -8244,7 +8244,7 @@ This report was generated on **Wed Jun 25 12:49:53 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 12:49:53 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 16:41:12 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -8981,7 +8981,7 @@ This report was generated on **Wed Jun 25 12:49:53 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 12:49:54 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 16:41:12 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -9706,7 +9706,7 @@ This report was generated on **Wed Jun 25 12:49:54 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 12:49:54 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 16:41:12 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -10519,7 +10519,7 @@ This report was generated on **Wed Jun 25 12:49:54 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 12:49:54 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 16:41:12 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -11308,7 +11308,7 @@ This report was generated on **Wed Jun 25 12:49:54 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 12:49:54 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 16:41:12 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -12296,7 +12296,7 @@ This report was generated on **Wed Jun 25 12:49:54 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 12:49:54 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 16:41:12 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -13169,7 +13169,7 @@ This report was generated on **Wed Jun 25 12:49:54 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 12:49:55 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 16:41:12 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -13986,4 +13986,4 @@ This report was generated on **Wed Jun 25 12:49:55 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 12:49:55 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). \ No newline at end of file +This report was generated on **Wed Jun 25 16:41:12 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). \ No newline at end of file diff --git a/flogger/README.md b/jvm/README.md similarity index 100% rename from flogger/README.md rename to jvm/README.md diff --git a/flogger/middleware/build.gradle.kts b/jvm/middleware/build.gradle.kts similarity index 100% rename from flogger/middleware/build.gradle.kts rename to jvm/middleware/build.gradle.kts diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/AbstractLogger.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/AbstractLogger.java similarity index 99% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/AbstractLogger.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/AbstractLogger.java index 02afd0655..2e1d66b64 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/AbstractLogger.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/AbstractLogger.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/CountingRateLimiter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/CountingRateLimiter.java similarity index 98% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/CountingRateLimiter.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/CountingRateLimiter.java index 4a77931aa..0cfe2eace 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/CountingRateLimiter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/CountingRateLimiter.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/DurationRateLimiter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/DurationRateLimiter.java similarity index 98% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/DurationRateLimiter.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/DurationRateLimiter.java index da908d31f..b6e781108 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/DurationRateLimiter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/DurationRateLimiter.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/FluentLogger2.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/FluentLogger2.java similarity index 98% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/FluentLogger2.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/FluentLogger2.java index 086681da1..4e8f9788f 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/FluentLogger2.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/FluentLogger2.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/JvmApi.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmApi.java similarity index 99% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/JvmApi.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/JvmApi.java index db8bdfb65..474150e2c 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/JvmApi.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmApi.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/JvmLogSite.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmLogSite.java similarity index 99% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/JvmLogSite.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/JvmLogSite.java index 2fd68850c..6c7c12b6b 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/JvmLogSite.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmLogSite.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/JvmLogSites.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmLogSites.java similarity index 99% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/JvmLogSites.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/JvmLogSites.java index 7e9b24480..62cb2d250 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/JvmLogSites.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmLogSites.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/JvmMetadataKey.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmMetadataKey.java similarity index 99% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/JvmMetadataKey.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/JvmMetadataKey.java index 8050016c4..1804a5e0d 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/JvmMetadataKey.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmMetadataKey.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/LazyArg.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/LazyArg.java similarity index 96% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/LazyArg.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/LazyArg.java index 9e59ddf42..47100f705 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/LazyArg.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/LazyArg.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/LazyArgs.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/LazyArgs.java similarity index 97% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/LazyArgs.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/LazyArgs.java index 8fac1aa5f..f87bacd29 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/LazyArgs.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/LazyArgs.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/LogContext.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/LogContext.java similarity index 99% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/LogContext.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/LogContext.java index f4f7f326d..1dda1af1f 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/LogContext.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/LogContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/LogPerBucketingStrategy.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/LogPerBucketingStrategy.java similarity index 99% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/LogPerBucketingStrategy.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/LogPerBucketingStrategy.java index 6f68edb69..ef20f858b 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/LogPerBucketingStrategy.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/LogPerBucketingStrategy.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/LogSiteKey.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/LogSiteKey.java similarity index 96% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/LogSiteKey.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/LogSiteKey.java index ac7807aa1..574768b41 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/LogSiteKey.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/LogSiteKey.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/LogSiteMap.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/LogSiteMap.java similarity index 98% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/LogSiteMap.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/LogSiteMap.java index f252c84e6..588c69a77 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/LogSiteMap.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/LogSiteMap.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/LogSiteStackTrace.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/LogSiteStackTrace.java similarity index 97% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/LogSiteStackTrace.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/LogSiteStackTrace.java index bbc293306..ff8ccf038 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/LogSiteStackTrace.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/LogSiteStackTrace.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/LoggingScope.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/LoggingScope.java similarity index 99% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/LoggingScope.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/LoggingScope.java index e9bf41966..520503af8 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/LoggingScope.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/LoggingScope.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/LoggingScopeProvider.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/LoggingScopeProvider.java similarity index 96% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/LoggingScopeProvider.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/LoggingScopeProvider.java index e9c9b6e6a..67c4a94a1 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/LoggingScopeProvider.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/LoggingScopeProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/RateLimitStatus.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/RateLimitStatus.java similarity index 99% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/RateLimitStatus.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/RateLimitStatus.java index a5ed6db14..37dfdb85c 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/RateLimitStatus.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/RateLimitStatus.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/SamplingRateLimiter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/SamplingRateLimiter.java similarity index 98% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/SamplingRateLimiter.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/SamplingRateLimiter.java index 944510f5f..6fc731eac 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/SamplingRateLimiter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/SamplingRateLimiter.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/SpecializedLogSiteKey.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/SpecializedLogSiteKey.java similarity index 97% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/SpecializedLogSiteKey.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/SpecializedLogSiteKey.java index 58e5292d9..02dc9197d 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/SpecializedLogSiteKey.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/SpecializedLogSiteKey.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/StackBasedLogSite.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/StackBasedLogSite.java similarity index 97% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/StackBasedLogSite.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/StackBasedLogSite.java index f1592589f..8171156d2 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/StackBasedLogSite.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/StackBasedLogSite.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/StackSize.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/StackSize.java similarity index 98% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/StackSize.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/StackSize.java index cdbb147c7..a1f7f8f02 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/StackSize.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/StackSize.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/BackendFactory.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/BackendFactory.java similarity index 98% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/backend/BackendFactory.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/backend/BackendFactory.java index 2d657469c..a96eb376c 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/BackendFactory.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/BackendFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/BaseMessageFormatter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/BaseMessageFormatter.java similarity index 99% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/backend/BaseMessageFormatter.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/backend/BaseMessageFormatter.java index f65cef5ca..3fdb90d5e 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/BaseMessageFormatter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/BaseMessageFormatter.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/Clock.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/Clock.java similarity index 98% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/backend/Clock.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/backend/Clock.java index 534ebb3ac..e2477c182 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/Clock.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/Clock.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/FormatChar.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatChar.java similarity index 99% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/backend/FormatChar.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatChar.java index 67c473f21..0b2271a1c 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/FormatChar.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatChar.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/FormatOptions.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatOptions.java similarity index 99% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/backend/FormatOptions.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatOptions.java index 138c827fe..ae24f2601 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/FormatOptions.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatOptions.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/FormatType.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatType.java similarity index 98% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/backend/FormatType.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatType.java index 3dfd89caa..cb75cfd99 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/FormatType.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatType.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/KeyValueFormatter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/KeyValueFormatter.java similarity index 98% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/backend/KeyValueFormatter.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/backend/KeyValueFormatter.java index 5537e1b44..894167e4a 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/KeyValueFormatter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/KeyValueFormatter.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/LogData.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LogData.java similarity index 98% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/backend/LogData.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LogData.java index 7fbd8d9ad..23e86a25f 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/LogData.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LogData.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/LogMessageFormatter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LogMessageFormatter.java similarity index 97% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/backend/LogMessageFormatter.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LogMessageFormatter.java index 15a8f59cd..709aa4476 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/LogMessageFormatter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LogMessageFormatter.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/LoggerBackend.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LoggerBackend.java similarity index 98% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/backend/LoggerBackend.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LoggerBackend.java index c72daa731..1f882f05a 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/LoggerBackend.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LoggerBackend.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/LoggingException.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LoggingException.java similarity index 96% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/backend/LoggingException.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LoggingException.java index acd55e57f..06690e260 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/LoggingException.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LoggingException.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/MessageUtils.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MessageUtils.java similarity index 99% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/backend/MessageUtils.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MessageUtils.java index 89a5ff801..7e33e4c97 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/MessageUtils.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MessageUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/Metadata.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/Metadata.java similarity index 98% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/backend/Metadata.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/backend/Metadata.java index d140db0ca..f8ef22ea6 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/Metadata.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/Metadata.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataHandler.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataHandler.java similarity index 99% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataHandler.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataHandler.java index c532ce0fe..91af9c6fd 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataHandler.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataKeyValueHandlers.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataKeyValueHandlers.java similarity index 98% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataKeyValueHandlers.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataKeyValueHandlers.java index 5da8761bc..a509520f6 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataKeyValueHandlers.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataKeyValueHandlers.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataProcessor.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataProcessor.java similarity index 99% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataProcessor.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataProcessor.java index 6b7b38320..8579e5567 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataProcessor.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/Platform.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/Platform.java similarity index 99% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/backend/Platform.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/backend/Platform.java index 0bd50c49a..a04cace8b 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/Platform.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/Platform.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/SimpleMessageFormatter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/SimpleMessageFormatter.java similarity index 99% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/backend/SimpleMessageFormatter.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/backend/SimpleMessageFormatter.java index 463783b06..b1df7abff 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/SimpleMessageFormatter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/SimpleMessageFormatter.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/TemplateContext.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/TemplateContext.java similarity index 97% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/backend/TemplateContext.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/backend/TemplateContext.java index 9163fb4ac..f6dadf98e 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/TemplateContext.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/TemplateContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/package-info.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/package-info.java similarity index 95% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/backend/package-info.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/backend/package-info.java index 03b0f65bd..03a34eb36 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/backend/package-info.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/context/ContextDataProvider.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ContextDataProvider.java similarity index 99% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/context/ContextDataProvider.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/context/ContextDataProvider.java index 0c7ddb62c..4d12684b4 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/context/ContextDataProvider.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ContextDataProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/context/ContextMetadata.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ContextMetadata.java similarity index 99% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/context/ContextMetadata.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/context/ContextMetadata.java index 6bb14f028..0c2126385 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/context/ContextMetadata.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ContextMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/context/LogLevelMap.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/LogLevelMap.java similarity index 98% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/context/LogLevelMap.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/context/LogLevelMap.java index 627a18182..9b106fece 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/context/LogLevelMap.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/LogLevelMap.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/context/NoOpContextDataProvider.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/NoOpContextDataProvider.java similarity index 98% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/context/NoOpContextDataProvider.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/context/NoOpContextDataProvider.java index 6008bddfc..d42b3b0c0 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/context/NoOpContextDataProvider.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/NoOpContextDataProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/context/ScopeType.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopeType.java similarity index 98% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/context/ScopeType.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopeType.java index 94a1b06eb..d63aa4b53 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/context/ScopeType.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopeType.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContext.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContext.java similarity index 99% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContext.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContext.java index 49f29f384..deca440bd 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContext.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContexts.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContexts.java similarity index 99% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContexts.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContexts.java index f3d4598a1..b27386146 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContexts.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContexts.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/context/SegmentTrie.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/SegmentTrie.java similarity index 99% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/context/SegmentTrie.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/context/SegmentTrie.java index 01fde70ad..fba8357a0 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/context/SegmentTrie.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/SegmentTrie.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/context/Tags.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/Tags.java similarity index 99% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/context/Tags.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/context/Tags.java index 751b3aaad..71beba48b 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/context/Tags.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/Tags.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/context/package-info.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/package-info.java similarity index 95% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/context/package-info.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/context/package-info.java index 65f617540..492d078cf 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/context/package-info.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/package-info.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/package-info.java similarity index 95% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/package-info.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/package-info.java index 43e252cbb..25a8dd839 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/package-info.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/BraceStyleParameter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/BraceStyleParameter.java similarity index 98% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/BraceStyleParameter.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/BraceStyleParameter.java index c583df8c2..5c13bbe08 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/BraceStyleParameter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/BraceStyleParameter.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeFormat.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeFormat.java similarity index 98% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeFormat.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeFormat.java index dd8b344c0..617a60d4a 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeFormat.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeFormat.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeParameter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeParameter.java similarity index 97% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeParameter.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeParameter.java index f1143cffa..1315be135 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeParameter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeParameter.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/Parameter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/Parameter.java similarity index 97% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/Parameter.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/Parameter.java index 53bfb21e7..b2a0bf7ac 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/Parameter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/Parameter.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/ParameterVisitor.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/ParameterVisitor.java similarity index 98% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/ParameterVisitor.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/ParameterVisitor.java index dce687fd0..74e622194 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/ParameterVisitor.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/ParameterVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/SimpleParameter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/SimpleParameter.java similarity index 98% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/SimpleParameter.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/SimpleParameter.java index 01236c3da..83f57ef19 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/SimpleParameter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/SimpleParameter.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/package-info.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/package-info.java similarity index 95% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/package-info.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/package-info.java index d9fd78d28..97b4dfd21 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/parameter/package-info.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/parser/BraceStyleMessageParser.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/BraceStyleMessageParser.java similarity index 99% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/parser/BraceStyleMessageParser.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/parser/BraceStyleMessageParser.java index 0f605a868..09a82d32c 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/parser/BraceStyleMessageParser.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/BraceStyleMessageParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultBraceStyleMessageParser.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultBraceStyleMessageParser.java similarity index 97% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultBraceStyleMessageParser.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultBraceStyleMessageParser.java index bf9773f79..94635729f 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultBraceStyleMessageParser.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultBraceStyleMessageParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultPrintfMessageParser.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultPrintfMessageParser.java similarity index 98% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultPrintfMessageParser.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultPrintfMessageParser.java index e3f1a3852..bcd46b1bd 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultPrintfMessageParser.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultPrintfMessageParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/parser/MessageBuilder.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/MessageBuilder.java similarity index 98% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/parser/MessageBuilder.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/parser/MessageBuilder.java index a2a77e9ec..c03a24787 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/parser/MessageBuilder.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/MessageBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/parser/MessageParser.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/MessageParser.java similarity index 97% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/parser/MessageParser.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/parser/MessageParser.java index 557a63653..d25bb312d 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/parser/MessageParser.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/MessageParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/parser/ParseException.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/ParseException.java similarity index 98% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/parser/ParseException.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/parser/ParseException.java index 24b28888c..778f62994 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/parser/ParseException.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/ParseException.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/parser/PrintfMessageParser.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/PrintfMessageParser.java similarity index 99% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/parser/PrintfMessageParser.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/parser/PrintfMessageParser.java index 36668c3c0..4a44b62f9 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/parser/PrintfMessageParser.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/PrintfMessageParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/parser/package-info.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/package-info.java similarity index 95% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/parser/package-info.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/parser/package-info.java index 4f81af60d..462bc4f07 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/parser/package-info.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/util/Checks.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/util/Checks.java similarity index 98% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/util/Checks.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/util/Checks.java index f71b2bd51..d16a6f629 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/util/Checks.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/util/Checks.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/util/RecursionDepth.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/util/RecursionDepth.java similarity index 97% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/util/RecursionDepth.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/util/RecursionDepth.java index 5c29136e3..8f22bf36a 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/util/RecursionDepth.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/util/RecursionDepth.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/util/StaticMethodCaller.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/util/StaticMethodCaller.java similarity index 98% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/util/StaticMethodCaller.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/util/StaticMethodCaller.java index 5873f63d7..104f1a1ee 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/util/StaticMethodCaller.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/util/StaticMethodCaller.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/java/io/spine/logging/jvm/util/package-info.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/util/package-info.java similarity index 95% rename from flogger/middleware/src/main/java/io/spine/logging/jvm/util/package-info.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/util/package-info.java index 3ce947439..262edc079 100644 --- a/flogger/middleware/src/main/java/io/spine/logging/jvm/util/package-info.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/util/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/main/kotlin/io/spine/logging/jvm/JvmMetadataKeys.kt b/jvm/middleware/src/main/kotlin/io/spine/logging/jvm/JvmMetadataKeys.kt similarity index 96% rename from flogger/middleware/src/main/kotlin/io/spine/logging/jvm/JvmMetadataKeys.kt rename to jvm/middleware/src/main/kotlin/io/spine/logging/jvm/JvmMetadataKeys.kt index f8ed7a453..54dc579df 100644 --- a/flogger/middleware/src/main/kotlin/io/spine/logging/jvm/JvmMetadataKeys.kt +++ b/jvm/middleware/src/main/kotlin/io/spine/logging/jvm/JvmMetadataKeys.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/java/io/spine/logging/backend/given/BadToString.java b/jvm/middleware/src/test/java/io/spine/logging/backend/given/BadToString.java similarity index 95% rename from flogger/middleware/src/test/java/io/spine/logging/backend/given/BadToString.java rename to jvm/middleware/src/test/java/io/spine/logging/backend/given/BadToString.java index 60de36131..9f95481e5 100644 --- a/flogger/middleware/src/test/java/io/spine/logging/backend/given/BadToString.java +++ b/jvm/middleware/src/test/java/io/spine/logging/backend/given/BadToString.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/java/io/spine/logging/backend/given/package-info.java b/jvm/middleware/src/test/java/io/spine/logging/backend/given/package-info.java similarity index 91% rename from flogger/middleware/src/test/java/io/spine/logging/backend/given/package-info.java rename to jvm/middleware/src/test/java/io/spine/logging/backend/given/package-info.java index 0092a372b..1ae6ce248 100644 --- a/flogger/middleware/src/test/java/io/spine/logging/backend/given/package-info.java +++ b/jvm/middleware/src/test/java/io/spine/logging/backend/given/package-info.java @@ -1,11 +1,11 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * https://www.apache.org/licenses/LICENSE-2.0 * * Redistribution and use in source and/or binary forms, with or without * modification, must retain the above copyright notice and the following diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/AbstractLoggerSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/AbstractLoggerSpec.kt similarity index 98% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/AbstractLoggerSpec.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/AbstractLoggerSpec.kt index 9ae9329eb..921ebf166 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/AbstractLoggerSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/AbstractLoggerSpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/CountingRateLimiterSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/CountingRateLimiterSpec.kt similarity index 98% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/CountingRateLimiterSpec.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/CountingRateLimiterSpec.kt index 4a75d4f1b..d1b490568 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/CountingRateLimiterSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/CountingRateLimiterSpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/DurationRateLimiterSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/DurationRateLimiterSpec.kt similarity index 98% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/DurationRateLimiterSpec.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/DurationRateLimiterSpec.kt index 35cd3ed8c..147de1291 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/DurationRateLimiterSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/DurationRateLimiterSpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/FluentLogger2Spec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/FluentLogger2Spec.kt similarity index 98% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/FluentLogger2Spec.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/FluentLogger2Spec.kt index 88d6e06d7..93687d710 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/FluentLogger2Spec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/FluentLogger2Spec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/JvmLogSitesSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/JvmLogSitesSpec.kt similarity index 97% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/JvmLogSitesSpec.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/JvmLogSitesSpec.kt index 7bec2a0d0..e1b659513 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/JvmLogSitesSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/JvmLogSitesSpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/JvmMetadataKeySpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/JvmMetadataKeySpec.kt similarity index 99% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/JvmMetadataKeySpec.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/JvmMetadataKeySpec.kt index 1ff293918..842574a8b 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/JvmMetadataKeySpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/JvmMetadataKeySpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/LogContextSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LogContextSpec.kt similarity index 99% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/LogContextSpec.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LogContextSpec.kt index eaaadd01e..aa4445e5b 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/LogContextSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LogContextSpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/LogPerBucketingStrategySpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LogPerBucketingStrategySpec.kt similarity index 98% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/LogPerBucketingStrategySpec.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LogPerBucketingStrategySpec.kt index e4dcf2548..d4d141689 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/LogPerBucketingStrategySpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LogPerBucketingStrategySpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/LogSiteMapSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LogSiteMapSpec.kt similarity index 98% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/LogSiteMapSpec.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LogSiteMapSpec.kt index 516c0b3ae..be49a09d8 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/LogSiteMapSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LogSiteMapSpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/LogSiteStackTraceSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LogSiteStackTraceSpec.kt similarity index 97% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/LogSiteStackTraceSpec.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LogSiteStackTraceSpec.kt index 10a45e844..a4ebb41c6 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/LogSiteStackTraceSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LogSiteStackTraceSpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/LoggingScopeSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LoggingScopeSpec.kt similarity index 96% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/LoggingScopeSpec.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LoggingScopeSpec.kt index 2164011ca..fe40c7934 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/LoggingScopeSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LoggingScopeSpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/RateLimitStatusSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/RateLimitStatusSpec.kt similarity index 98% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/RateLimitStatusSpec.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/RateLimitStatusSpec.kt index 30419d4f5..658dfb137 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/RateLimitStatusSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/RateLimitStatusSpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/SamplingRateLimiterSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/SamplingRateLimiterSpec.kt similarity index 98% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/SamplingRateLimiterSpec.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/SamplingRateLimiterSpec.kt index cf22166aa..c9e3065f6 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/SamplingRateLimiterSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/SamplingRateLimiterSpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/SpecializedLogSiteKeySpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/SpecializedLogSiteKeySpec.kt similarity index 97% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/SpecializedLogSiteKeySpec.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/SpecializedLogSiteKeySpec.kt index ccfdded7a..a063ecb89 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/SpecializedLogSiteKeySpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/SpecializedLogSiteKeySpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/StackBasedLogSiteSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/StackBasedLogSiteSpec.kt similarity index 98% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/StackBasedLogSiteSpec.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/StackBasedLogSiteSpec.kt index 6150449c6..3bf7bdcb2 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/StackBasedLogSiteSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/StackBasedLogSiteSpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/BaseMessageFormatterSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/BaseMessageFormatterSpec.kt similarity index 99% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/BaseMessageFormatterSpec.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/BaseMessageFormatterSpec.kt index 841202d70..f3a88f9d2 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/BaseMessageFormatterSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/BaseMessageFormatterSpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatCharSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatCharSpec.kt similarity index 98% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatCharSpec.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatCharSpec.kt index 017252231..3a0d121b0 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatCharSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatCharSpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatOptionsSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatOptionsSpec.kt similarity index 99% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatOptionsSpec.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatOptionsSpec.kt index 8ac2b7825..cedb1faa5 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatOptionsSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatOptionsSpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatTypeSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatTypeSpec.kt similarity index 98% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatTypeSpec.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatTypeSpec.kt index 47b7b98d9..58bec63a3 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatTypeSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatTypeSpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/KeyValueFormatterSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/KeyValueFormatterSpec.kt similarity index 98% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/KeyValueFormatterSpec.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/KeyValueFormatterSpec.kt index bb4fb8cb8..a7c0bf16b 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/KeyValueFormatterSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/KeyValueFormatterSpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/LightweightProcessorSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/LightweightProcessorSpec.kt similarity index 94% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/LightweightProcessorSpec.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/LightweightProcessorSpec.kt index 00a3b706e..ca1777f66 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/LightweightProcessorSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/LightweightProcessorSpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MessageUtilsSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MessageUtilsSpec.kt similarity index 98% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MessageUtilsSpec.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MessageUtilsSpec.kt index 7567f6130..ee4f95004 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MessageUtilsSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MessageUtilsSpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataHandlerSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataHandlerSpec.kt similarity index 99% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataHandlerSpec.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataHandlerSpec.kt index 846634620..d78b39d47 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataHandlerSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataHandlerSpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataKeyValueHandlersSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataKeyValueHandlersSpec.kt similarity index 98% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataKeyValueHandlersSpec.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataKeyValueHandlersSpec.kt index 807c4144b..e59c22ae1 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataKeyValueHandlersSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataKeyValueHandlersSpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataProcessorSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataProcessorSpec.kt similarity index 99% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataProcessorSpec.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataProcessorSpec.kt index 27de8f442..b35da9975 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataProcessorSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataProcessorSpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/SimpleMessageFormatterSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/SimpleMessageFormatterSpec.kt similarity index 99% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/SimpleMessageFormatterSpec.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/SimpleMessageFormatterSpec.kt index 561fae3a8..55f1363ee 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/SimpleMessageFormatterSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/SimpleMessageFormatterSpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/SimpleProcessorSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/SimpleProcessorSpec.kt similarity index 94% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/SimpleProcessorSpec.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/SimpleProcessorSpec.kt index e3d1a8089..efe15ff3d 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/SimpleProcessorSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/SimpleProcessorSpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/FakeLogData.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/FakeLogData.kt similarity index 98% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/FakeLogData.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/FakeLogData.kt index 895ee0c7a..6b0c8ea20 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/FakeLogData.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/FakeLogData.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/FakeMetadata.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/FakeMetadata.kt similarity index 96% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/FakeMetadata.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/FakeMetadata.kt index 966608ec0..fc3ed6128 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/FakeMetadata.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/FakeMetadata.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/MemoizingLoggerBackend.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/MemoizingLoggerBackend.kt similarity index 97% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/MemoizingLoggerBackend.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/MemoizingLoggerBackend.kt index 5727f2324..ed872ec1c 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/MemoizingLoggerBackend.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/MemoizingLoggerBackend.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/MetadataAssertions.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/MetadataAssertions.kt similarity index 97% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/MetadataAssertions.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/MetadataAssertions.kt index a851ee4ac..87803b627 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/MetadataAssertions.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/MetadataAssertions.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/context/AbstractContextDataProviderSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/AbstractContextDataProviderSpec.kt similarity index 99% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/context/AbstractContextDataProviderSpec.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/AbstractContextDataProviderSpec.kt index 2d3c88703..bfc5171a1 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/context/AbstractContextDataProviderSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/AbstractContextDataProviderSpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/context/ContextMetadataSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/ContextMetadataSpec.kt similarity index 98% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/context/ContextMetadataSpec.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/ContextMetadataSpec.kt index 647d9e49e..787b0fa7c 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/context/ContextMetadataSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/ContextMetadataSpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/context/LogLevelMapSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/LogLevelMapSpec.kt similarity index 98% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/context/LogLevelMapSpec.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/LogLevelMapSpec.kt index beea6db93..fbf3b531f 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/context/LogLevelMapSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/LogLevelMapSpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/context/ScopedLoggingContextSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/ScopedLoggingContextSpec.kt similarity index 97% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/context/ScopedLoggingContextSpec.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/ScopedLoggingContextSpec.kt index b7bf4eb9b..8baa6b308 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/context/ScopedLoggingContextSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/ScopedLoggingContextSpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/context/SegmentTrieSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/SegmentTrieSpec.kt similarity index 98% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/context/SegmentTrieSpec.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/SegmentTrieSpec.kt index 7f692ee42..ddd826337 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/context/SegmentTrieSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/SegmentTrieSpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/context/TagsSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/TagsSpec.kt similarity index 99% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/context/TagsSpec.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/TagsSpec.kt index 764c8fdbf..a7037d4a8 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/context/TagsSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/TagsSpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/given/BackendTestEnv.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/given/BackendTestEnv.kt similarity index 94% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/given/BackendTestEnv.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/given/BackendTestEnv.kt index 77787323c..98a6614a2 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/given/BackendTestEnv.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/given/BackendTestEnv.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/given/ConfigurableLogger.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/given/ConfigurableLogger.kt similarity index 97% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/given/ConfigurableLogger.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/given/ConfigurableLogger.kt index 3e361cfd8..d3b728151 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/given/ConfigurableLogger.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/given/ConfigurableLogger.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/given/FakeLogSite.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/given/FakeLogSite.kt similarity index 97% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/given/FakeLogSite.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/given/FakeLogSite.kt index 5697b11f9..ac7bf47c4 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/given/FakeLogSite.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/given/FakeLogSite.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/given/FormattingBackend.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/given/FormattingBackend.kt similarity index 97% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/given/FormattingBackend.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/given/FormattingBackend.kt index 29d76ba37..23716838b 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/given/FormattingBackend.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/given/FormattingBackend.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/given/LogDataAssertions.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/given/LogDataAssertions.kt similarity index 96% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/given/LogDataAssertions.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/given/LogDataAssertions.kt index c60aeade4..45727f389 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/given/LogDataAssertions.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/given/LogDataAssertions.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/given/MemoizingKvHandler.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/given/MemoizingKvHandler.kt similarity index 95% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/given/MemoizingKvHandler.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/given/MemoizingKvHandler.kt index 76274694c..03c4ab0cf 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/given/MemoizingKvHandler.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/given/MemoizingKvHandler.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parameter/ParameterSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parameter/ParameterSpec.kt similarity index 97% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parameter/ParameterSpec.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parameter/ParameterSpec.kt index 6f4c4775e..ada4503b4 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parameter/ParameterSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parameter/ParameterSpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parameter/SimpleParameterSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parameter/SimpleParameterSpec.kt similarity index 98% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parameter/SimpleParameterSpec.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parameter/SimpleParameterSpec.kt index 4b1f5fc93..243043d62 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parameter/SimpleParameterSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parameter/SimpleParameterSpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parser/BraceStyleMessageParserSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parser/BraceStyleMessageParserSpec.kt similarity index 98% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parser/BraceStyleMessageParserSpec.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parser/BraceStyleMessageParserSpec.kt index 1b33589af..c13421953 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parser/BraceStyleMessageParserSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parser/BraceStyleMessageParserSpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parser/DefaultBraceStyleMessageParserSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parser/DefaultBraceStyleMessageParserSpec.kt similarity index 97% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parser/DefaultBraceStyleMessageParserSpec.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parser/DefaultBraceStyleMessageParserSpec.kt index 98bb96eac..45dc8e12f 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parser/DefaultBraceStyleMessageParserSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parser/DefaultBraceStyleMessageParserSpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parser/DefaultPrintfMessageParserSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parser/DefaultPrintfMessageParserSpec.kt similarity index 97% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parser/DefaultPrintfMessageParserSpec.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parser/DefaultPrintfMessageParserSpec.kt index 3ef45d422..d34f25718 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parser/DefaultPrintfMessageParserSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parser/DefaultPrintfMessageParserSpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parser/PrintfMessageParserSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parser/PrintfMessageParserSpec.kt similarity index 98% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parser/PrintfMessageParserSpec.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parser/PrintfMessageParserSpec.kt index 89f1a6ea4..a3c726961 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parser/PrintfMessageParserSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parser/PrintfMessageParserSpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parser/given/ParserTestEnv.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parser/given/ParserTestEnv.kt similarity index 98% rename from flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parser/given/ParserTestEnv.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parser/given/ParserTestEnv.kt index 1e0abe4c8..c1a26a71c 100644 --- a/flogger/middleware/src/test/kotlin/io/spine/logging/jvm/parser/given/ParserTestEnv.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parser/given/ParserTestEnv.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/flogger/platform-generator/build.gradle.kts b/jvm/platform-generator/build.gradle.kts similarity index 100% rename from flogger/platform-generator/build.gradle.kts rename to jvm/platform-generator/build.gradle.kts diff --git a/flogger/platform-generator/src/main/java/io/spine/logging/backend/generator/PlatformProviderGenerator.java b/jvm/platform-generator/src/main/java/io/spine/logging/backend/generator/PlatformProviderGenerator.java similarity index 98% rename from flogger/platform-generator/src/main/java/io/spine/logging/backend/generator/PlatformProviderGenerator.java rename to jvm/platform-generator/src/main/java/io/spine/logging/backend/generator/PlatformProviderGenerator.java index 21f000abb..71d31501f 100644 --- a/flogger/platform-generator/src/main/java/io/spine/logging/backend/generator/PlatformProviderGenerator.java +++ b/jvm/platform-generator/src/main/java/io/spine/logging/backend/generator/PlatformProviderGenerator.java @@ -1,11 +1,11 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * https://www.apache.org/licenses/LICENSE-2.0 * * Redistribution and use in source and/or binary forms, with or without * modification, must retain the above copyright notice and the following diff --git a/flogger/platform-generator/src/main/java/io/spine/logging/backend/generator/package-info.java b/jvm/platform-generator/src/main/java/io/spine/logging/backend/generator/package-info.java similarity index 91% rename from flogger/platform-generator/src/main/java/io/spine/logging/backend/generator/package-info.java rename to jvm/platform-generator/src/main/java/io/spine/logging/backend/generator/package-info.java index 0a628f6ea..f284ccede 100644 --- a/flogger/platform-generator/src/main/java/io/spine/logging/backend/generator/package-info.java +++ b/jvm/platform-generator/src/main/java/io/spine/logging/backend/generator/package-info.java @@ -1,11 +1,11 @@ /* - * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * https://www.apache.org/licenses/LICENSE-2.0 * * Redistribution and use in source and/or binary forms, with or without * modification, must retain the above copyright notice and the following diff --git a/settings.gradle.kts b/settings.gradle.kts index 91370a21e..56fe3b51e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,5 +1,5 @@ /* - * Copyright 2024, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -63,7 +63,7 @@ includeTest( "smoke-test", ) -includeFlogger( +includeJvm( "middleware", "platform-generator", ) @@ -76,7 +76,7 @@ fun includePlatform(vararg modules: String) = includeTo("platforms", modules) fun includeTest(vararg modules: String) = includeTo("tests", modules) -fun includeFlogger(vararg modules: String) = includeTo("flogger", modules) +fun includeJvm(vararg modules: String) = includeTo("jvm", modules) fun includeTo(directory: String, modules: Array) = modules.forEach { name -> include(name) diff --git a/version.gradle.kts b/version.gradle.kts index 9f9ee6fe0..6a6a8787a 100644 --- a/version.gradle.kts +++ b/version.gradle.kts @@ -24,4 +24,4 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -val versionToPublish: String by extra("2.0.0-SNAPSHOT.250") +val versionToPublish: String by extra("2.0.0-SNAPSHOT.251") From 521de757b77326754cc5d362d4bb58526934bfe3 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Wed, 25 Jun 2025 17:25:25 +0100 Subject: [PATCH 03/28] Restore (c) statements --- jvm/middleware/build.gradle.kts | 2 +- .../src/main/java/io/spine/logging/jvm/AbstractLogger.java | 2 +- .../main/java/io/spine/logging/jvm/CountingRateLimiter.java | 2 +- .../main/java/io/spine/logging/jvm/DurationRateLimiter.java | 2 +- .../src/main/java/io/spine/logging/jvm/FluentLogger2.java | 2 +- .../src/main/java/io/spine/logging/jvm/JvmLogSite.java | 2 +- .../src/main/java/io/spine/logging/jvm/JvmLogSites.java | 2 +- jvm/middleware/src/main/java/io/spine/logging/jvm/LazyArg.java | 2 +- .../src/main/java/io/spine/logging/jvm/LazyArgs.java | 2 +- .../src/main/java/io/spine/logging/jvm/LogContext.java | 2 +- .../java/io/spine/logging/jvm/LogPerBucketingStrategy.java | 2 +- .../src/main/java/io/spine/logging/jvm/LogSiteKey.java | 3 +-- .../src/main/java/io/spine/logging/jvm/LogSiteMap.java | 2 +- .../src/main/java/io/spine/logging/jvm/LogSiteStackTrace.java | 2 +- .../main/java/io/spine/logging/jvm/LoggingScopeProvider.java | 2 +- .../src/main/java/io/spine/logging/jvm/RateLimitStatus.java | 2 +- .../main/java/io/spine/logging/jvm/SamplingRateLimiter.java | 2 +- .../main/java/io/spine/logging/jvm/SpecializedLogSiteKey.java | 2 +- .../src/main/java/io/spine/logging/jvm/StackBasedLogSite.java | 2 +- .../src/main/java/io/spine/logging/jvm/StackSize.java | 2 +- .../io/spine/logging/jvm/backend/BaseMessageFormatter.java | 2 +- .../src/main/java/io/spine/logging/jvm/backend/Clock.java | 2 +- .../src/main/java/io/spine/logging/jvm/backend/FormatChar.java | 2 +- .../main/java/io/spine/logging/jvm/backend/FormatOptions.java | 2 +- .../src/main/java/io/spine/logging/jvm/backend/FormatType.java | 2 +- .../src/main/java/io/spine/logging/jvm/backend/LogData.java | 2 +- .../java/io/spine/logging/jvm/backend/LogMessageFormatter.java | 2 +- .../main/java/io/spine/logging/jvm/backend/LoggerBackend.java | 2 +- .../java/io/spine/logging/jvm/backend/LoggingException.java | 2 +- .../src/main/java/io/spine/logging/jvm/backend/Metadata.java | 2 +- .../java/io/spine/logging/jvm/backend/MetadataHandler.java | 2 +- .../io/spine/logging/jvm/backend/MetadataKeyValueHandlers.java | 2 +- .../java/io/spine/logging/jvm/backend/MetadataProcessor.java | 2 +- .../src/main/java/io/spine/logging/jvm/backend/Platform.java | 2 +- .../io/spine/logging/jvm/backend/SimpleMessageFormatter.java | 2 +- .../main/java/io/spine/logging/jvm/backend/package-info.java | 2 +- .../java/io/spine/logging/jvm/context/ContextMetadata.java | 2 +- .../main/java/io/spine/logging/jvm/context/LogLevelMap.java | 2 +- .../io/spine/logging/jvm/context/NoOpContextDataProvider.java | 2 +- .../src/main/java/io/spine/logging/jvm/context/ScopeType.java | 2 +- .../io/spine/logging/jvm/context/ScopedLoggingContext.java | 2 +- .../io/spine/logging/jvm/context/ScopedLoggingContexts.java | 2 +- .../main/java/io/spine/logging/jvm/context/SegmentTrie.java | 2 +- .../src/main/java/io/spine/logging/jvm/context/Tags.java | 2 +- .../main/java/io/spine/logging/jvm/context/package-info.java | 2 +- .../src/main/java/io/spine/logging/jvm/package-info.java | 2 +- .../io/spine/logging/jvm/parameter/BraceStyleParameter.java | 2 +- .../java/io/spine/logging/jvm/parameter/DateTimeFormat.java | 2 +- .../java/io/spine/logging/jvm/parameter/DateTimeParameter.java | 2 +- .../main/java/io/spine/logging/jvm/parameter/Parameter.java | 2 +- .../java/io/spine/logging/jvm/parameter/ParameterVisitor.java | 2 +- .../java/io/spine/logging/jvm/parameter/SimpleParameter.java | 2 +- .../main/java/io/spine/logging/jvm/parameter/package-info.java | 2 +- .../logging/jvm/parser/DefaultBraceStyleMessageParser.java | 2 +- .../spine/logging/jvm/parser/DefaultPrintfMessageParser.java | 2 +- .../main/java/io/spine/logging/jvm/parser/MessageBuilder.java | 2 +- .../main/java/io/spine/logging/jvm/parser/ParseException.java | 2 +- .../java/io/spine/logging/jvm/parser/PrintfMessageParser.java | 2 +- .../main/java/io/spine/logging/jvm/parser/package-info.java | 2 +- .../src/main/java/io/spine/logging/jvm/util/Checks.java | 2 +- .../main/java/io/spine/logging/jvm/util/RecursionDepth.java | 2 +- .../java/io/spine/logging/jvm/util/StaticMethodCaller.java | 2 +- .../src/main/java/io/spine/logging/jvm/util/package-info.java | 2 +- .../src/main/kotlin/io/spine/logging/jvm/JvmMetadataKeys.kt | 2 +- .../test/java/io/spine/logging/backend/given/BadToString.java | 2 +- .../test/java/io/spine/logging/backend/given/package-info.java | 2 +- .../src/test/kotlin/io/spine/logging/jvm/AbstractLoggerSpec.kt | 2 +- .../src/test/kotlin/io/spine/logging/jvm/FluentLogger2Spec.kt | 2 +- .../src/test/kotlin/io/spine/logging/jvm/JvmMetadataKeySpec.kt | 2 +- .../src/test/kotlin/io/spine/logging/jvm/LogContextSpec.kt | 2 +- .../io/spine/logging/jvm/backend/BaseMessageFormatterSpec.kt | 2 +- .../io/spine/logging/jvm/backend/MetadataProcessorSpec.kt | 2 +- .../kotlin/io/spine/logging/jvm/context/LogLevelMapSpec.kt | 2 +- .../test/kotlin/io/spine/logging/jvm/given/BackendTestEnv.kt | 2 +- .../logging/jvm/parser/DefaultBraceStyleMessageParserSpec.kt | 2 +- jvm/platform-generator/build.gradle.kts | 2 +- .../logging/backend/generator/PlatformProviderGenerator.java | 2 +- .../java/io/spine/logging/backend/generator/package-info.java | 2 +- 78 files changed, 78 insertions(+), 79 deletions(-) diff --git a/jvm/middleware/build.gradle.kts b/jvm/middleware/build.gradle.kts index 05cc6bda5..3351c8175 100644 --- a/jvm/middleware/build.gradle.kts +++ b/jvm/middleware/build.gradle.kts @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/AbstractLogger.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/AbstractLogger.java index 2e1d66b64..02afd0655 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/AbstractLogger.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/AbstractLogger.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/CountingRateLimiter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/CountingRateLimiter.java index 0cfe2eace..4a77931aa 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/CountingRateLimiter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/CountingRateLimiter.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/DurationRateLimiter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/DurationRateLimiter.java index b6e781108..da908d31f 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/DurationRateLimiter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/DurationRateLimiter.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/FluentLogger2.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/FluentLogger2.java index 4e8f9788f..086681da1 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/FluentLogger2.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/FluentLogger2.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmLogSite.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmLogSite.java index 6c7c12b6b..2fd68850c 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmLogSite.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmLogSite.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmLogSites.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmLogSites.java index 62cb2d250..7e9b24480 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmLogSites.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmLogSites.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/LazyArg.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/LazyArg.java index 47100f705..9e59ddf42 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/LazyArg.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/LazyArg.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/LazyArgs.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/LazyArgs.java index f87bacd29..8fac1aa5f 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/LazyArgs.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/LazyArgs.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/LogContext.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/LogContext.java index 1dda1af1f..f4f7f326d 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/LogContext.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/LogContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/LogPerBucketingStrategy.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/LogPerBucketingStrategy.java index ef20f858b..6f68edb69 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/LogPerBucketingStrategy.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/LogPerBucketingStrategy.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/LogSiteKey.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/LogSiteKey.java index 574768b41..239f503f7 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/LogSiteKey.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/LogSiteKey.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -38,4 +38,3 @@ * Original Java code of Google Flogger */ public interface LogSiteKey {} - diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/LogSiteMap.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/LogSiteMap.java index 588c69a77..f252c84e6 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/LogSiteMap.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/LogSiteMap.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/LogSiteStackTrace.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/LogSiteStackTrace.java index ff8ccf038..bbc293306 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/LogSiteStackTrace.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/LogSiteStackTrace.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/LoggingScopeProvider.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/LoggingScopeProvider.java index 67c4a94a1..e9c9b6e6a 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/LoggingScopeProvider.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/LoggingScopeProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/RateLimitStatus.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/RateLimitStatus.java index 37dfdb85c..a5ed6db14 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/RateLimitStatus.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/RateLimitStatus.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/SamplingRateLimiter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/SamplingRateLimiter.java index 6fc731eac..944510f5f 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/SamplingRateLimiter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/SamplingRateLimiter.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/SpecializedLogSiteKey.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/SpecializedLogSiteKey.java index 02dc9197d..58e5292d9 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/SpecializedLogSiteKey.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/SpecializedLogSiteKey.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/StackBasedLogSite.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/StackBasedLogSite.java index 8171156d2..f1592589f 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/StackBasedLogSite.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/StackBasedLogSite.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/StackSize.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/StackSize.java index a1f7f8f02..cdbb147c7 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/StackSize.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/StackSize.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/BaseMessageFormatter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/BaseMessageFormatter.java index 3fdb90d5e..f65cef5ca 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/BaseMessageFormatter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/BaseMessageFormatter.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/Clock.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/Clock.java index e2477c182..534ebb3ac 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/Clock.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/Clock.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatChar.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatChar.java index 0b2271a1c..67c473f21 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatChar.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatChar.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatOptions.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatOptions.java index ae24f2601..138c827fe 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatOptions.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatOptions.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatType.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatType.java index cb75cfd99..3dfd89caa 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatType.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatType.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LogData.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LogData.java index 23e86a25f..7fbd8d9ad 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LogData.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LogData.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LogMessageFormatter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LogMessageFormatter.java index 709aa4476..15a8f59cd 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LogMessageFormatter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LogMessageFormatter.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LoggerBackend.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LoggerBackend.java index 1f882f05a..c72daa731 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LoggerBackend.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LoggerBackend.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LoggingException.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LoggingException.java index 06690e260..acd55e57f 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LoggingException.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LoggingException.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/Metadata.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/Metadata.java index f8ef22ea6..d140db0ca 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/Metadata.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/Metadata.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataHandler.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataHandler.java index 91af9c6fd..c532ce0fe 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataHandler.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataKeyValueHandlers.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataKeyValueHandlers.java index a509520f6..5da8761bc 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataKeyValueHandlers.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataKeyValueHandlers.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataProcessor.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataProcessor.java index 8579e5567..6b7b38320 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataProcessor.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/Platform.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/Platform.java index a04cace8b..0bd50c49a 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/Platform.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/Platform.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/SimpleMessageFormatter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/SimpleMessageFormatter.java index b1df7abff..463783b06 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/SimpleMessageFormatter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/SimpleMessageFormatter.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/package-info.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/package-info.java index 03a34eb36..03b0f65bd 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/package-info.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ContextMetadata.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ContextMetadata.java index 0c2126385..6bb14f028 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ContextMetadata.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ContextMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/LogLevelMap.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/LogLevelMap.java index 9b106fece..627a18182 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/LogLevelMap.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/LogLevelMap.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/NoOpContextDataProvider.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/NoOpContextDataProvider.java index d42b3b0c0..6008bddfc 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/NoOpContextDataProvider.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/NoOpContextDataProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopeType.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopeType.java index d63aa4b53..94a1b06eb 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopeType.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopeType.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContext.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContext.java index deca440bd..49f29f384 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContext.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContexts.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContexts.java index b27386146..f3d4598a1 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContexts.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContexts.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/SegmentTrie.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/SegmentTrie.java index fba8357a0..01fde70ad 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/SegmentTrie.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/SegmentTrie.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/Tags.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/Tags.java index 71beba48b..751b3aaad 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/Tags.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/Tags.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/package-info.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/package-info.java index 492d078cf..65f617540 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/package-info.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/package-info.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/package-info.java index 25a8dd839..43e252cbb 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/package-info.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/BraceStyleParameter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/BraceStyleParameter.java index 5c13bbe08..c583df8c2 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/BraceStyleParameter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/BraceStyleParameter.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeFormat.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeFormat.java index 617a60d4a..dd8b344c0 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeFormat.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeFormat.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeParameter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeParameter.java index 1315be135..f1143cffa 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeParameter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeParameter.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/Parameter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/Parameter.java index b2a0bf7ac..53bfb21e7 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/Parameter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/Parameter.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/ParameterVisitor.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/ParameterVisitor.java index 74e622194..dce687fd0 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/ParameterVisitor.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/ParameterVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/SimpleParameter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/SimpleParameter.java index 83f57ef19..01236c3da 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/SimpleParameter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/SimpleParameter.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/package-info.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/package-info.java index 97b4dfd21..d9fd78d28 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/package-info.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultBraceStyleMessageParser.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultBraceStyleMessageParser.java index 94635729f..bf9773f79 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultBraceStyleMessageParser.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultBraceStyleMessageParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultPrintfMessageParser.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultPrintfMessageParser.java index bcd46b1bd..e3f1a3852 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultPrintfMessageParser.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultPrintfMessageParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/MessageBuilder.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/MessageBuilder.java index c03a24787..a2a77e9ec 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/MessageBuilder.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/MessageBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/ParseException.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/ParseException.java index 778f62994..24b28888c 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/ParseException.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/ParseException.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/PrintfMessageParser.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/PrintfMessageParser.java index 4a44b62f9..36668c3c0 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/PrintfMessageParser.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/PrintfMessageParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/package-info.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/package-info.java index 462bc4f07..4f81af60d 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/package-info.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/util/Checks.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/util/Checks.java index d16a6f629..f71b2bd51 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/util/Checks.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/util/Checks.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/util/RecursionDepth.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/util/RecursionDepth.java index 8f22bf36a..5c29136e3 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/util/RecursionDepth.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/util/RecursionDepth.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/util/StaticMethodCaller.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/util/StaticMethodCaller.java index 104f1a1ee..5873f63d7 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/util/StaticMethodCaller.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/util/StaticMethodCaller.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/util/package-info.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/util/package-info.java index 262edc079..3ce947439 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/util/package-info.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/util/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/main/kotlin/io/spine/logging/jvm/JvmMetadataKeys.kt b/jvm/middleware/src/main/kotlin/io/spine/logging/jvm/JvmMetadataKeys.kt index 54dc579df..f8ed7a453 100644 --- a/jvm/middleware/src/main/kotlin/io/spine/logging/jvm/JvmMetadataKeys.kt +++ b/jvm/middleware/src/main/kotlin/io/spine/logging/jvm/JvmMetadataKeys.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/test/java/io/spine/logging/backend/given/BadToString.java b/jvm/middleware/src/test/java/io/spine/logging/backend/given/BadToString.java index 9f95481e5..60de36131 100644 --- a/jvm/middleware/src/test/java/io/spine/logging/backend/given/BadToString.java +++ b/jvm/middleware/src/test/java/io/spine/logging/backend/given/BadToString.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/test/java/io/spine/logging/backend/given/package-info.java b/jvm/middleware/src/test/java/io/spine/logging/backend/given/package-info.java index 1ae6ce248..a7e57284c 100644 --- a/jvm/middleware/src/test/java/io/spine/logging/backend/given/package-info.java +++ b/jvm/middleware/src/test/java/io/spine/logging/backend/given/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/AbstractLoggerSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/AbstractLoggerSpec.kt index 921ebf166..9ae9329eb 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/AbstractLoggerSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/AbstractLoggerSpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/FluentLogger2Spec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/FluentLogger2Spec.kt index 93687d710..88d6e06d7 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/FluentLogger2Spec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/FluentLogger2Spec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/JvmMetadataKeySpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/JvmMetadataKeySpec.kt index 842574a8b..1ff293918 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/JvmMetadataKeySpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/JvmMetadataKeySpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LogContextSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LogContextSpec.kt index aa4445e5b..eaaadd01e 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LogContextSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LogContextSpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/BaseMessageFormatterSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/BaseMessageFormatterSpec.kt index f3a88f9d2..841202d70 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/BaseMessageFormatterSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/BaseMessageFormatterSpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataProcessorSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataProcessorSpec.kt index b35da9975..27de8f442 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataProcessorSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataProcessorSpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/LogLevelMapSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/LogLevelMapSpec.kt index fbf3b531f..beea6db93 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/LogLevelMapSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/LogLevelMapSpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/given/BackendTestEnv.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/given/BackendTestEnv.kt index 98a6614a2..77787323c 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/given/BackendTestEnv.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/given/BackendTestEnv.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parser/DefaultBraceStyleMessageParserSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parser/DefaultBraceStyleMessageParserSpec.kt index 45dc8e12f..98bb96eac 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parser/DefaultBraceStyleMessageParserSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parser/DefaultBraceStyleMessageParserSpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/platform-generator/build.gradle.kts b/jvm/platform-generator/build.gradle.kts index 5629b643d..df5285e50 100644 --- a/jvm/platform-generator/build.gradle.kts +++ b/jvm/platform-generator/build.gradle.kts @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/platform-generator/src/main/java/io/spine/logging/backend/generator/PlatformProviderGenerator.java b/jvm/platform-generator/src/main/java/io/spine/logging/backend/generator/PlatformProviderGenerator.java index 71d31501f..69c80c0de 100644 --- a/jvm/platform-generator/src/main/java/io/spine/logging/backend/generator/PlatformProviderGenerator.java +++ b/jvm/platform-generator/src/main/java/io/spine/logging/backend/generator/PlatformProviderGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/jvm/platform-generator/src/main/java/io/spine/logging/backend/generator/package-info.java b/jvm/platform-generator/src/main/java/io/spine/logging/backend/generator/package-info.java index f284ccede..c2546cd85 100644 --- a/jvm/platform-generator/src/main/java/io/spine/logging/backend/generator/package-info.java +++ b/jvm/platform-generator/src/main/java/io/spine/logging/backend/generator/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From 3b4bf8e45b10e867e7076865b962e49ab708887d Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Wed, 25 Jun 2025 19:40:46 +0100 Subject: [PATCH 04/28] Address inspection warnings Also: * Improve code layout. --- dependencies.md | 68 +- .../io/spine/logging/jvm/AbstractLogger.java | 377 +-- .../logging/jvm/CountingRateLimiter.java | 105 +- .../logging/jvm/DurationRateLimiter.java | 236 +- .../java/io/spine/logging/jvm/JvmLogSite.java | 9 +- .../java/io/spine/logging/jvm/LogContext.java | 2851 +++++++++-------- .../logging/jvm/LogPerBucketingStrategy.java | 402 +-- .../java/io/spine/logging/jvm/LogSiteMap.java | 127 +- .../spine/logging/jvm/LogSiteStackTrace.java | 11 +- .../io/spine/logging/jvm/RateLimitStatus.java | 294 +- .../logging/jvm/SamplingRateLimiter.java | 91 +- .../logging/jvm/SpecializedLogSiteKey.java | 2 +- .../spine/logging/jvm/StackBasedLogSite.java | 78 +- .../jvm/backend/BaseMessageFormatter.java | 386 +-- .../spine/logging/jvm/backend/FormatChar.java | 334 +- .../logging/jvm/backend/FormatOptions.java | 939 +++--- .../spine/logging/jvm/backend/FormatType.java | 178 +- .../io/spine/logging/jvm/backend/LogData.java | 155 +- .../logging/jvm/backend/LoggerBackend.java | 38 +- .../logging/jvm/backend/LoggingException.java | 19 +- .../logging/jvm/backend/MetadataHandler.java | 564 ++-- .../jvm/backend/MetadataKeyValueHandlers.java | 100 +- .../jvm/backend/MetadataProcessor.java | 784 ++--- .../spine/logging/jvm/backend/Platform.java | 521 +-- .../jvm/backend/SimpleMessageFormatter.java | 389 ++- .../logging/jvm/context/ContextMetadata.java | 391 +-- .../logging/jvm/context/LogLevelMap.java | 258 +- .../jvm/context/NoOpContextDataProvider.java | 170 +- .../jvm/context/ScopedLoggingContext.java | 742 +++-- .../logging/jvm/context/SegmentTrie.java | 517 +-- .../io/spine/logging/jvm/context/Tags.java | 1304 ++++---- .../jvm/parameter/BraceStyleParameter.java | 122 +- .../logging/jvm/parameter/DateTimeFormat.java | 283 +- .../logging/jvm/parameter/Parameter.java | 90 +- .../jvm/parameter/SimpleParameter.java | 132 +- .../parser/DefaultPrintfMessageParser.java | 152 +- .../logging/jvm/parser/MessageBuilder.java | 180 +- .../logging/jvm/parser/ParseException.java | 198 +- .../io/spine/logging/jvm/util/Checks.java | 92 +- .../logging/jvm/util/StaticMethodCaller.java | 193 +- .../spine/logging/jvm/AbstractLoggerSpec.kt | 1 + .../{FluentLogger2Spec.kt => LoggerSpec.kt} | 2 +- .../jvm/backend/MetadataProcessorSpec.kt | 1 + .../logging/jvm/backend/given/FakeLogData.kt | 6 - .../kotlin/io/spine/logging/JvmLogger.kt | 2 +- pom.xml | 2 +- 46 files changed, 7212 insertions(+), 6684 deletions(-) rename jvm/middleware/src/test/kotlin/io/spine/logging/jvm/{FluentLogger2Spec.kt => LoggerSpec.kt} (99%) diff --git a/dependencies.md b/dependencies.md index 1385b5a59..a10a522b8 100644 --- a/dependencies.md +++ b/dependencies.md @@ -1,6 +1,6 @@ -# Dependencies of `io.spine:spine-logging-fixtures:2.0.0-SNAPSHOT.250` +# Dependencies of `io.spine:spine-logging-fixtures:2.0.0-SNAPSHOT.251` ## Runtime ## Compile, tests, and tooling @@ -724,12 +724,12 @@ The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 16:41:12 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 19:34:15 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine:spine-logging-grpc-context:2.0.0-SNAPSHOT.250` +# Dependencies of `io.spine:spine-logging-grpc-context:2.0.0-SNAPSHOT.251` ## Runtime 1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2. @@ -1553,12 +1553,12 @@ This report was generated on **Wed Jun 25 16:41:12 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 16:41:12 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 19:34:16 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine:spine-logging-jul-backend:2.0.0-SNAPSHOT.250` +# Dependencies of `io.spine:spine-logging-jul-backend:2.0.0-SNAPSHOT.251` ## Runtime 1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2. @@ -2366,12 +2366,12 @@ This report was generated on **Wed Jun 25 16:41:12 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 16:41:12 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 19:34:16 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine:spine-logging-jvm-default-platform:2.0.0-SNAPSHOT.250` +# Dependencies of `io.spine:spine-logging-jvm-default-platform:2.0.0-SNAPSHOT.251` ## Runtime 1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2. @@ -3187,12 +3187,12 @@ This report was generated on **Wed Jun 25 16:41:12 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 16:41:12 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 19:34:16 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine:spine-logging-jvm-jul-backend-grpc-context:2.0.0-SNAPSHOT.250` +# Dependencies of `io.spine:spine-logging-jvm-jul-backend-grpc-context:2.0.0-SNAPSHOT.251` ## Runtime 1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2. @@ -4035,12 +4035,12 @@ This report was generated on **Wed Jun 25 16:41:12 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 16:41:13 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 19:34:16 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine:spine-logging-jvm-jul-backend-std-context:2.0.0-SNAPSHOT.250` +# Dependencies of `io.spine:spine-logging-jvm-jul-backend-std-context:2.0.0-SNAPSHOT.251` ## Runtime 1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2. @@ -4875,12 +4875,12 @@ This report was generated on **Wed Jun 25 16:41:13 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 16:41:13 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 19:34:17 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine:spine-logging-jvm-log4j2-backend-std-context:2.0.0-SNAPSHOT.250` +# Dependencies of `io.spine:spine-logging-jvm-log4j2-backend-std-context:2.0.0-SNAPSHOT.251` ## Runtime 1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2. @@ -5715,12 +5715,12 @@ This report was generated on **Wed Jun 25 16:41:13 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 16:41:13 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 19:34:17 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine:spine-logging-jvm-slf4j-jdk14-backend-std-context:2.0.0-SNAPSHOT.250` +# Dependencies of `io.spine:spine-logging-jvm-slf4j-jdk14-backend-std-context:2.0.0-SNAPSHOT.251` ## Runtime 1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2. @@ -6563,12 +6563,12 @@ This report was generated on **Wed Jun 25 16:41:13 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 16:41:13 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 19:34:17 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine:spine-logging-jvm-slf4j-reload4j-backend-std-context:2.0.0-SNAPSHOT.250` +# Dependencies of `io.spine:spine-logging-jvm-slf4j-reload4j-backend-std-context:2.0.0-SNAPSHOT.251` ## Runtime 1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2. @@ -7415,12 +7415,12 @@ This report was generated on **Wed Jun 25 16:41:13 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 16:41:13 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 19:34:17 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine:spine-logging-log4j2-backend:2.0.0-SNAPSHOT.250` +# Dependencies of `io.spine:spine-logging-log4j2-backend:2.0.0-SNAPSHOT.251` ## Runtime 1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2. @@ -8244,12 +8244,12 @@ This report was generated on **Wed Jun 25 16:41:13 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 16:41:12 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 19:34:18 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine:spine-logging:2.0.0-SNAPSHOT.250` +# Dependencies of `io.spine:spine-logging:2.0.0-SNAPSHOT.251` ## Runtime ## Compile, tests, and tooling @@ -8981,12 +8981,12 @@ This report was generated on **Wed Jun 25 16:41:12 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 16:41:12 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 19:34:18 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine.tools:spine-logging-testlib:2.0.0-SNAPSHOT.250` +# Dependencies of `io.spine.tools:spine-logging-testlib:2.0.0-SNAPSHOT.251` ## Runtime ## Compile, tests, and tooling @@ -9706,12 +9706,12 @@ This report was generated on **Wed Jun 25 16:41:12 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 16:41:12 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 19:34:18 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine:spine-logging-middleware:2.0.0-SNAPSHOT.250` +# Dependencies of `io.spine:spine-logging-middleware:2.0.0-SNAPSHOT.251` ## Runtime 1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2. @@ -10519,12 +10519,12 @@ This report was generated on **Wed Jun 25 16:41:12 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 16:41:12 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 19:34:18 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine:spine-logging-platform-generator:2.0.0-SNAPSHOT.250` +# Dependencies of `io.spine:spine-logging-platform-generator:2.0.0-SNAPSHOT.251` ## Runtime 1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2. @@ -11308,12 +11308,12 @@ This report was generated on **Wed Jun 25 16:41:12 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 16:41:12 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 19:34:19 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine:spine-logging-probe-backend:2.0.0-SNAPSHOT.250` +# Dependencies of `io.spine:spine-logging-probe-backend:2.0.0-SNAPSHOT.251` ## Runtime 1. **Group** : com.google.auto.service. **Name** : auto-service-annotations. **Version** : 1.1.1. @@ -12296,12 +12296,12 @@ This report was generated on **Wed Jun 25 16:41:12 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 16:41:12 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 19:34:19 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine:spine-logging-smoke-test:2.0.0-SNAPSHOT.250` +# Dependencies of `io.spine:spine-logging-smoke-test:2.0.0-SNAPSHOT.251` ## Runtime 1. **Group** : com.fasterxml.jackson. **Name** : jackson-bom. **Version** : 2.18.3. @@ -13169,12 +13169,12 @@ This report was generated on **Wed Jun 25 16:41:12 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 16:41:12 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 19:34:19 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine:spine-logging-std-context:2.0.0-SNAPSHOT.250` +# Dependencies of `io.spine:spine-logging-std-context:2.0.0-SNAPSHOT.251` ## Runtime 1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2. @@ -13986,4 +13986,4 @@ This report was generated on **Wed Jun 25 16:41:12 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 16:41:12 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). \ No newline at end of file +This report was generated on **Wed Jun 25 19:34:19 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). \ No newline at end of file diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/AbstractLogger.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/AbstractLogger.java index 02afd0655..6c391fce7 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/AbstractLogger.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/AbstractLogger.java @@ -26,205 +26,212 @@ package io.spine.logging.jvm; -import static io.spine.logging.jvm.util.Checks.checkNotNull; -import static java.util.concurrent.TimeUnit.NANOSECONDS; - import io.spine.logging.jvm.backend.LogData; import io.spine.logging.jvm.backend.LoggerBackend; import io.spine.logging.jvm.backend.LoggingException; import io.spine.logging.jvm.backend.MessageUtils; import io.spine.logging.jvm.util.RecursionDepth; -import java.text.SimpleDateFormat; -import java.util.Date; + +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; import java.util.logging.Level; +import static io.spine.logging.jvm.util.Checks.checkNotNull; +import static java.util.concurrent.TimeUnit.NANOSECONDS; + /** * Base class for the fluent logger API. This class is a factory for instances of a fluent logging * API, used to build log statements via method chaining. * - * @param the logging API provided by this logger. - * + * @param + * the logging API provided by this logger. * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger */ public abstract class AbstractLogger> { - /** - * An upper bound on the depth of reentrant logging allowed by Flogger. Logger backends may choose - * to react to reentrant logging sooner than this, but once this value is reached, a warning is - * is emitted to stderr, which will not include any user provided arguments or metadata (in an - * attempt to halt recursion). - */ - private static final int MAX_ALLOWED_RECURSION_DEPTH = 100; - - private final LoggerBackend backend; - - /** - * Constructs a new logger for the specified backend. - * - * @param backend the logger backend which ultimately writes the log statements out. - */ - protected AbstractLogger(LoggerBackend backend) { - this.backend = checkNotNull(backend, "backend"); - } - - // ---- PUBLIC API ---- - - /** - * Returns a fluent logging API appropriate for the specified log level. - *

      - * If a logger implementation determines that logging is definitely disabled at this point then - * this method is expected to return a "no-op" implementation of that logging API, which will - * result in all further calls made for the log statement to being silently ignored. - *

      - * A simple implementation of this method in a concrete subclass might look like: - *

      {@code
      -   * boolean isLoggable = isLoggable(level);
      -   * boolean isForced = Platform.shouldForceLogging(getName(), level, isLoggable);
      -   * return (isLoggable | isForced) ? new SubContext(level, isForced) : NO_OP;
      -   * }
      - * where {@code NO_OP} is a singleton, no-op instance of the logging API whose methods do nothing - * and just {@code return noOp()}. - */ - public abstract API at(Level level); - - /** A convenience method for at({@link Level#SEVERE}). */ - public final API atSevere() { - return at(Level.SEVERE); - } - - /** A convenience method for at({@link Level#WARNING}). */ - public final API atWarning() { - return at(Level.WARNING); - } - - /** A convenience method for at({@link Level#INFO}). */ - public final API atInfo() { - return at(Level.INFO); - } - - /** A convenience method for at({@link Level#CONFIG}). */ - public final API atConfig() { - return at(Level.CONFIG); - } - - /** A convenience method for at({@link Level#FINE}). */ - public final API atFine() { - return at(Level.FINE); - } - - /** A convenience method for at({@link Level#FINER}). */ - public final API atFiner() { - return at(Level.FINER); - } - - /** A convenience method for at({@link Level#FINEST}). */ - public final API atFinest() { - return at(Level.FINEST); - } - - // ---- HELPER METHODS (useful during sub-class initialization) ---- - - /** - * Returns the non-null name of this logger (Flogger does not currently support anonymous - * loggers). - */ - // IMPORTANT: Flogger does not currently support the idea of an anonymous logger instance - // (but probably should). The issue here is that in order to allow the FluentLogger instance - // and the LoggerConfig instance to share the same underlying logger, while allowing the - // backend API to be flexible enough _not_ to admit the existence of the JDK logger, we will - // need to push the LoggerConfig API down into the backend and expose it from there. - // See b/14878562 - // TODO(dbeaumont): Make anonymous loggers work with the config() method and the LoggerConfig API. - protected String getName() { - return backend.getLoggerName(); - } - - /** - * Returns whether the given level is enabled for this logger. Users wishing to guard code with a - * check for "loggability" should use {@code logger.atLevel().isEnabled()} instead. - */ - protected final boolean isLoggable(Level level) { - return backend.isLoggable(level); - } - - // ---- IMPLEMENTATION DETAIL (only visible to the base logging context) ---- - - /** - * Returns the logging backend (not visible to logger subclasses to discourage tightly coupled - * implementations). - */ - final LoggerBackend getBackend() { - return backend; - } - - /** - * Invokes the logging backend to write a log statement, ensuring that all exceptions which could - * be caused during logging, including any subsequent error handling, are handled. This method can - * only fail due to instances of {@link LoggingException} or {@link java.lang.Error} being thrown. - * - *

      This method also guards against unbounded reentrant logging, and will suppress further - * logging if it detects significant recursion has occurred. - */ - final void write(LogData data) { - checkNotNull(data, "data"); - // Note: Recursion checking should not be in the LoggerBackend. There are many backends and they - // can call into other backends. We only want the counter incremented per log statement. - try (RecursionDepth depth = RecursionDepth.enterLogStatement()) { - if (depth.getValue() <= MAX_ALLOWED_RECURSION_DEPTH) { - backend.log(data); - } else { - reportError("unbounded recursion in log statement", data); - } - } catch (RuntimeException logError) { - handleErrorRobustly(logError, data); + + /** + * An upper bound on the depth of reentrant logging allowed by Flogger. Logger backends may + * choose + * to react to reentrant logging sooner than this, but once this value is reached, a warning is + * is emitted to stderr, which will not include any user provided arguments or metadata (in an + * attempt to halt recursion). + */ + private static final int MAX_ALLOWED_RECURSION_DEPTH = 100; + + @SuppressWarnings("SimpleDateFormatWithoutLocale") + public static final DateTimeFormatter FORMATTER = + DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ") + .withZone(ZoneId.systemDefault()); + + private final LoggerBackend backend; + + /** + * Constructs a new logger for the specified backend. + * + * @param backend + * the logger backend which ultimately writes the log statements out. + */ + protected AbstractLogger(LoggerBackend backend) { + this.backend = checkNotNull(backend, "backend"); + } + + // ---- PUBLIC API ---- + + /** + * Returns a fluent logging API appropriate for the specified log level. + *

      + * If a logger implementation determines that logging is definitely disabled at this point then + * this method is expected to return a "no-op" implementation of that logging API, which will + * result in all further calls made for the log statement to being silently ignored. + *

      + * A simple implementation of this method in a concrete subclass might look like: + *

      {@code
      +     * boolean isLoggable = isLoggable(level);
      +     * boolean isForced = Platform.shouldForceLogging(getName(), level, isLoggable);
      +     * return (isLoggable | isForced) ? new SubContext(level, isForced) : NO_OP;
      +     * }
      + * where {@code NO_OP} is a singleton, no-op instance of the logging API whose methods do + * nothing + * and just {@code return noOp()}. + */ + public abstract API at(Level level); + + /** A convenience method for at({@link Level#SEVERE}). */ + public final API atSevere() { + return at(Level.SEVERE); + } + + /** A convenience method for at({@link Level#WARNING}). */ + public final API atWarning() { + return at(Level.WARNING); + } + + /** A convenience method for at({@link Level#INFO}). */ + public final API atInfo() { + return at(Level.INFO); + } + + /** A convenience method for at({@link Level#CONFIG}). */ + @SuppressWarnings("unused") + public final API atConfig() { + return at(Level.CONFIG); + } + + /** A convenience method for at({@link Level#FINE}). */ + public final API atFine() { + return at(Level.FINE); } - } - - /** Only allow LoggingException and Errors to escape this method. */ - private void handleErrorRobustly(RuntimeException logError, LogData data) { - try { - backend.handleError(logError, data); - } catch (LoggingException allowed) { - // Bypass the catch-all if the exception is deliberately created during error handling. - throw allowed; - } catch (RuntimeException badError) { - // Don't trust exception toString() method here. - reportError(badError.getClass().getName() + ": " + badError.getMessage(), data); - // However printStackTrace() will invoke toString() on the exception and its causes. - try { - badError.printStackTrace(System.err); - } catch (RuntimeException ignored) { - // We already printed the base error so it doesn't seem worth doing anything more here. - } + + /** A convenience method for at({@link Level#FINER}). */ + public final API atFiner() { + return at(Level.FINER); + } + + /** A convenience method for at({@link Level#FINEST}). */ + public final API atFinest() { + return at(Level.FINEST); + } + + // ---- HELPER METHODS (useful during sub-class initialization) ---- + + /** + * Returns the non-null name of this logger (Flogger does not currently support anonymous + * loggers). + */ + // IMPORTANT: Flogger does not currently support the idea of an anonymous logger instance + // (but probably should). The issue here is that in order to allow the FluentLogger instance + // and the LoggerConfig instance to share the same underlying logger, while allowing the + // backend API to be flexible enough _not_ to admit the existence of the JDK logger, we will + // need to push the LoggerConfig API down into the backend and expose it from there. + // See b/14878562 + // TODO(dbeaumont): Make anonymous loggers work with the config() method and the LoggerConfig API. + protected String getName() { + return backend.getLoggerName(); + } + + /** + * Returns whether the given level is enabled for this logger. Users wishing to guard code with + * a + * check for "loggability" should use {@code logger.atLevel().isEnabled()} instead. + */ + protected final boolean isLoggable(Level level) { + return backend.isLoggable(level); + } + + // ---- IMPLEMENTATION DETAIL (only visible to the base logging context) ---- + + /** + * Returns the logging backend (not visible to logger subclasses to discourage tightly coupled + * implementations). + */ + final LoggerBackend getBackend() { + return backend; + } + + /** + * Invokes the logging backend to write a log statement, ensuring that all exceptions which + * could + * be caused during logging, including any subsequent error handling, are handled. This method + * can + * only fail due to instances of {@link LoggingException} or {@link java.lang.Error} being + * thrown. + * + *

      This method also guards against unbounded reentrant logging, and will suppress further + * logging if it detects significant recursion has occurred. + */ + final void write(LogData data) { + checkNotNull(data, "data"); + // Note: Recursion checking should not be in the LoggerBackend. There are many backends and they + // can call into other backends. We only want the counter incremented per log statement. + try (RecursionDepth depth = RecursionDepth.enterLogStatement()) { + if (depth.getValue() <= MAX_ALLOWED_RECURSION_DEPTH) { + backend.log(data); + } else { + reportError("unbounded recursion in log statement", data); + } + } catch (RuntimeException logError) { + handleErrorRobustly(logError, data); + } + } + + /** Only allow LoggingException and Errors to escape this method. */ + private void handleErrorRobustly(RuntimeException logError, LogData data) { + try { + backend.handleError(logError, data); + } catch (LoggingException allowed) { + // Bypass the catch-all if the exception is deliberately created during error handling. + throw allowed; + } catch (RuntimeException badError) { + // Don't trust exception toString() method here. + reportError(badError.getClass() + .getName() + ": " + badError.getMessage(), data); + // However printStackTrace() will invoke toString() on the exception and its causes. + try { + badError.printStackTrace(System.err); + } catch (RuntimeException ignored) { + // We already printed the base error so it doesn't seem worth doing anything more here. + } + } + } + + // It is important that this code never risk calling back to a user supplied value (e.g. logged + // arguments or metadata) since that could trigger a recursive error state. + private static void reportError(String message, LogData data) { + StringBuilder out = new StringBuilder(); + out.append(formatTimestampIso8601(data)) + .append(": logging error ["); + MessageUtils.appendLogSite(data.getLogSite(), out); + out.append("]: ") + .append(message); + System.err.println(out); + // We expect System.err to be an auto-flushing stream, but let's be sure. + System.err.flush(); + } + + private static String formatTimestampIso8601(LogData data) { + var instant = Instant.ofEpochMilli(NANOSECONDS.toMillis(data.getTimestampNanos())); + return FORMATTER.format(instant); } - } - - // It is important that this code never risk calling back to a user supplied value (e.g. logged - // arguments or metadata) since that could trigger a recursive error state. - private static void reportError(String message, LogData data) { - StringBuilder out = new StringBuilder(); - out.append(formatTimestampIso8601(data)).append(": logging error ["); - MessageUtils.appendLogSite(data.getLogSite(), out); - out.append("]: ").append(message); - System.err.println(out); - // We expect System.err to be an auto-flushing stream, but let's be sure. - System.err.flush(); - } - - @SuppressWarnings({"GoodTime", "JavaUtilDate", "SimpleDateFormat"}) // JDK7, no Joda-Time. - private static String formatTimestampIso8601(LogData data) { - // Sadly in JDK7, we don't have access to java.time and can't depend on things like Joda-Time. - Date timestamp = new Date(NANOSECONDS.toMillis(data.getTimestampNanos())); - // Use the system timezone here since we don't know how logger backends want to format dates. - // The only alternative is to always use UTC, but that may cause confusion to some users, and - // if users really want UTC, they can set that as the system timezone. - // - // ISO format from https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html. - // Note that ending with "SSSXXX" would be more correct, but Android does not support this until - // v24+ (https://developer.android.com/reference/java/text/SimpleDateFormat.html). - // - // DO NOT attempt to cache the formatter instance as it's not thread safe, and this code is not - // performance sensitive. - return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ").format(timestamp); - } } diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/CountingRateLimiter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/CountingRateLimiter.java index 4a77931aa..d91214bcb 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/CountingRateLimiter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/CountingRateLimiter.java @@ -26,12 +26,14 @@ package io.spine.logging.jvm; -import static io.spine.logging.jvm.LogContext.Key.LOG_EVERY_N; - +import com.google.common.annotations.VisibleForTesting; import io.spine.logging.jvm.backend.Metadata; -import java.util.concurrent.atomic.AtomicLong; import org.jspecify.annotations.Nullable; +import java.util.concurrent.atomic.AtomicLong; + +import static io.spine.logging.jvm.LogContext.Key.LOG_EVERY_N; + /** * Rate limiter to support {@code every(N)} functionality. * @@ -41,58 +43,63 @@ * *

      Instances of this class are thread safe. * - * @see - * Original Java code of Google Flogger + * @see + * Original Java code of Google Flogger */ final class CountingRateLimiter extends RateLimitStatus { - private static final LogSiteMap map = - new LogSiteMap() { - @Override - protected CountingRateLimiter initialValue() { - return new CountingRateLimiter(); - } - }; - /** - * Returns the status of the rate limiter, or {@code null} if the {@code LOG_EVERY_N} metadata was - * not present. - * - *

      The rate limiter status is {@code DISALLOW} until the log count exceeds the specified limit, - * and then the limiter switches to its pending state and returns an allow status until it is - * reset. - */ - @Nullable - static RateLimitStatus check(Metadata metadata, LogSiteKey logSiteKey) { - Integer rateLimitCount = metadata.findValue(LOG_EVERY_N); - if (rateLimitCount == null) { - // Without rate limiter specific metadata, this limiter has no effect. - return null; + private static final LogSiteMap map = + new LogSiteMap<>() { + @Override + protected CountingRateLimiter initialValue() { + return new CountingRateLimiter(); + } + }; + + /** + * Returns the status of the rate limiter, or {@code null} if the {@code LOG_EVERY_N} metadata + * was not present. + * + *

      The rate limiter status is {@code DISALLOW} until the log count exceeds the specified + * limit, and then the limiter switches to its pending state and returns an allow status until + * it is reset. + */ + @Nullable + static RateLimitStatus check(Metadata metadata, LogSiteKey logSiteKey) { + var rateLimitCount = metadata.findValue(LOG_EVERY_N); + if (rateLimitCount == null) { + // Without rate limiter specific metadata, this limiter has no effect. + return null; + } + return map.get(logSiteKey, metadata) + .incrementAndCheckLogCount(rateLimitCount); } - return map.get(logSiteKey, metadata).incrementAndCheckLogCount(rateLimitCount); - } - // By setting the initial value as Integer#MAX_VALUE we ensure that the first time rate limiting - // is checked, the rate limit count (which is only an Integer) must be reached, placing the - // limiter into its pending state immediately. If this is the only limiter used, this corresponds - // to the first log statement always being emitted. - private final AtomicLong invocationCount = new AtomicLong(Integer.MAX_VALUE); + // By setting the initial value as Integer#MAX_VALUE we ensure that the first time rate limiting + // is checked, the rate limit count (which is only an Integer) must be reached, placing the + // limiter into its pending state immediately. If this is the only limiter used, + // this corresponds to the first log statement always being emitted. + private final AtomicLong invocationCount = new AtomicLong(Integer.MAX_VALUE); - // Visible for testing. - CountingRateLimiter() {} + @VisibleForTesting + CountingRateLimiter() { + } - /** - * Increments the invocation count and returns true if it reached the specified rate limit count. - * This is invoked during post-processing if a rate limiting count was set via {@link - * JvmApi#every(int)}. - */ - // Visible for testing. - RateLimitStatus incrementAndCheckLogCount(int rateLimitCount) { - return invocationCount.incrementAndGet() >= rateLimitCount ? this : DISALLOW; - } + /** + * Increments the invocation count and returns true if it reached the specified + * rate limit count. + * This is invoked during post-processing if a rate limiting count was set via {@link + * JvmApi#every(int)}. + */ + @VisibleForTesting + RateLimitStatus incrementAndCheckLogCount(int rateLimitCount) { + return invocationCount.incrementAndGet() >= rateLimitCount ? this : DISALLOW; + } - // Reset function called to move the limiter out of the "pending" state after a log occurs. - @Override - public void reset() { - invocationCount.set(0); - } + // Reset function called to move the limiter out of the "pending" state after a log occurs. + @Override + public void reset() { + invocationCount.set(0); + } } diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/DurationRateLimiter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/DurationRateLimiter.java index da908d31f..6dc5c097c 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/DurationRateLimiter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/DurationRateLimiter.java @@ -26,16 +26,17 @@ package io.spine.logging.jvm; -import static io.spine.logging.jvm.LogContext.Key.LOG_AT_MOST_EVERY; -import static io.spine.logging.jvm.util.Checks.checkArgument; -import static io.spine.logging.jvm.util.Checks.checkNotNull; -import static java.lang.Math.max; - import io.spine.logging.jvm.backend.LogData; import io.spine.logging.jvm.backend.Metadata; +import org.jspecify.annotations.Nullable; + import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; -import org.jspecify.annotations.Nullable; + +import static io.spine.logging.jvm.LogContext.Key.LOG_AT_MOST_EVERY; +import static io.spine.logging.jvm.util.Checks.checkArgument; +import static io.spine.logging.jvm.util.Checks.checkNotNull; +import static java.lang.Math.max; /** * Rate limiter to support {@code atMostEvery(N, units)} functionality. @@ -46,128 +47,135 @@ * *

      Instances of this class are thread safe. * - * @see - * Original Java code of Google Flogger + * @see + * Original Java code of Google Flogger */ final class DurationRateLimiter extends RateLimitStatus { - private static final LogSiteMap map = - new LogSiteMap() { + + private static final LogSiteMap map = new LogSiteMap<>() { @Override protected DurationRateLimiter initialValue() { - return new DurationRateLimiter(); + return new DurationRateLimiter(); } - }; - - /** - * Creates a period for rate limiting for the specified duration. This is invoked by the {@link - * LogContext#atMostEvery(int, TimeUnit)} method to create a metadata value. - */ - static RateLimitPeriod newRateLimitPeriod(int n, TimeUnit unit) { - // We could cache commonly used values here if we wanted. - return new RateLimitPeriod(n, unit); - } - - /** - * Returns whether the log site should log based on the value of the {@code LOG_AT_MOST_EVERY} - * metadata value and the current log site timestamp. - */ - @Nullable - static RateLimitStatus check(Metadata metadata, LogSiteKey logSiteKey, long timestampNanos) { - RateLimitPeriod rateLimitPeriod = metadata.findValue(LOG_AT_MOST_EVERY); - if (rateLimitPeriod == null) { - // Without rate limiter specific metadata, this limiter has no effect. - return null; + }; + + /** + * Creates a period for rate limiting for the specified duration. This is invoked by the {@link + * LogContext#atMostEvery(int, TimeUnit)} method to create a metadata value. + */ + static RateLimitPeriod newRateLimitPeriod(int n, TimeUnit unit) { + // We could cache commonly used values here if we wanted. + return new RateLimitPeriod(n, unit); } - return map.get(logSiteKey, metadata).checkLastTimestamp(timestampNanos, rateLimitPeriod); - } - - /** - * Immutable metadata for rate limiting based on a fixed count. This corresponds to the - * LOG_AT_MOST_EVERY metadata key in {@link LogData}. Unlike the metadata for {@code every(N)}, we - * need to use a wrapper class here to preserve the time unit information. - */ - static final class RateLimitPeriod { - private final int n; - private final TimeUnit unit; - - private RateLimitPeriod(int n, TimeUnit unit) { - // This code will work with a zero length time period, but it's nonsensical to try. - if (n <= 0) { - throw new IllegalArgumentException("time period must be positive: " + n); - } - this.n = n; - this.unit = checkNotNull(unit, "time unit"); + + /** + * Returns whether the log site should log based on the value of the {@code LOG_AT_MOST_EVERY} + * metadata value and the current log site timestamp. + */ + @Nullable + static RateLimitStatus check(Metadata metadata, LogSiteKey logSiteKey, long timestampNanos) { + RateLimitPeriod rateLimitPeriod = metadata.findValue(LOG_AT_MOST_EVERY); + if (rateLimitPeriod == null) { + // Without rate limiter specific metadata, this limiter has no effect. + return null; + } + return map.get(logSiteKey, metadata) + .checkLastTimestamp(timestampNanos, rateLimitPeriod); } - private long toNanos() { - // Since nanoseconds are the smallest level of precision a TimeUnit can express, we are - // guaranteed that "unit.toNanos(n) >= n > 0". This is important for correctness (see comment - // in checkLastTimestamp()) because it ensures the new timestamp that indicates when logging - // should occur always differs from the previous timestamp. - return unit.toNanos(n); + /** + * Immutable metadata for rate limiting based on a fixed count. This corresponds to the + * LOG_AT_MOST_EVERY metadata key in {@link LogData}. Unlike the metadata for {@code every(N)}, + * we + * need to use a wrapper class here to preserve the time unit information. + */ + static final class RateLimitPeriod { + + private final int n; + private final TimeUnit unit; + + private RateLimitPeriod(int n, TimeUnit unit) { + // This code will work with a zero length time period, but it's nonsensical to try. + if (n <= 0) { + throw new IllegalArgumentException("time period must be positive: " + n); + } + this.n = n; + this.unit = checkNotNull(unit, "time unit"); + } + + private long toNanos() { + // Since nanoseconds are the smallest level of precision a TimeUnit can express, we are + // guaranteed that "unit.toNanos(n) >= n > 0". This is important for correctness (see comment + // in checkLastTimestamp()) because it ensures the new timestamp that indicates when logging + // should occur always differs from the previous timestamp. + return unit.toNanos(n); + } + + @Override + public String toString() { + return n + " " + unit; + } + + @Override + public int hashCode() { + // Rough and ready. We don't expect this be be needed much at all. + return (n * 37) ^ unit.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof RateLimitPeriod) { + RateLimitPeriod that = (RateLimitPeriod) obj; + return this.n == that.n && this.unit == that.unit; + } + return false; + } } - @Override - public String toString() { - return n + " " + unit; + private final AtomicLong lastTimestampNanos = new AtomicLong(-1L); + + // Visible for testing. + DurationRateLimiter() { } - @Override - public int hashCode() { - // Rough and ready. We don't expect this be be needed much at all. - return (n * 37) ^ unit.hashCode(); + /** + * Checks whether the current time stamp is after the rate limiting period and if so, updates + * the + * time stamp and returns true. This is invoked during post-processing if a rate limiting + * duration + * was set via {@link JvmApi#atMostEvery(int, TimeUnit)}. + */ + // Visible for testing. + RateLimitStatus checkLastTimestamp(long timestampNanos, RateLimitPeriod period) { + checkArgument(timestampNanos >= 0, "timestamp cannot be negative"); + // If this is negative, we are in the pending state and will return "allow" until we are reset. + // The value held here is updated to be the most recent negated timestamp, and is negated again + // (making it positive and setting us into the rate limiting state) when we are reset. + long lastNanos = lastTimestampNanos.get(); + if (lastNanos >= 0) { + long deadlineNanos = lastNanos + period.toNanos(); + // Check for negative deadline to avoid overflow for ridiculous durations. Assume overflow + // always means "no logging". + if (deadlineNanos < 0 || timestampNanos < deadlineNanos) { + return DISALLOW; + } + } + // When logging is triggered, negate the timestamp to move us into the "pending" state and + // return our reset status. + // We don't want to race with the reset function (which may have already set a new timestamp). + lastTimestampNanos.compareAndSet(lastNanos, -timestampNanos); + return this; } + // Reset function called to move the limiter out of the "pending" state. We do this by negating + // the timestamp (which was already negated when we entered the pending state, so we restore it + // to a positive value which moves us back into the "limiting" state). @Override - public boolean equals(Object obj) { - if (obj instanceof RateLimitPeriod) { - RateLimitPeriod that = (RateLimitPeriod) obj; - return this.n == that.n && this.unit == that.unit; - } - return false; - } - } - - private final AtomicLong lastTimestampNanos = new AtomicLong(-1L); - - // Visible for testing. - DurationRateLimiter() {} - - /** - * Checks whether the current time stamp is after the rate limiting period and if so, updates the - * time stamp and returns true. This is invoked during post-processing if a rate limiting duration - * was set via {@link JvmApi#atMostEvery(int, TimeUnit)}. - */ - // Visible for testing. - RateLimitStatus checkLastTimestamp(long timestampNanos, RateLimitPeriod period) { - checkArgument(timestampNanos >= 0, "timestamp cannot be negative"); - // If this is negative, we are in the pending state and will return "allow" until we are reset. - // The value held here is updated to be the most recent negated timestamp, and is negated again - // (making it positive and setting us into the rate limiting state) when we are reset. - long lastNanos = lastTimestampNanos.get(); - if (lastNanos >= 0) { - long deadlineNanos = lastNanos + period.toNanos(); - // Check for negative deadline to avoid overflow for ridiculous durations. Assume overflow - // always means "no logging". - if (deadlineNanos < 0 || timestampNanos < deadlineNanos) { - return DISALLOW; - } + public void reset() { + // Only one thread at a time can reset a rate limiter, so this can be unconditional. We should + // only be able to get here if the timestamp was set to a negative value above. However use + // max() to make sure we always move out of the pending state. + lastTimestampNanos.set(max(-lastTimestampNanos.get(), 0)); } - // When logging is triggered, negate the timestamp to move us into the "pending" state and - // return our reset status. - // We don't want to race with the reset function (which may have already set a new timestamp). - lastTimestampNanos.compareAndSet(lastNanos, -timestampNanos); - return this; - } - - // Reset function called to move the limiter out of the "pending" state. We do this by negating - // the timestamp (which was already negated when we entered the pending state, so we restore it - // to a positive value which moves us back into the "limiting" state). - @Override - public void reset() { - // Only one thread at a time can reset a rate limiter, so this can be unconditional. We should - // only be able to get here if the timestamp was set to a negative value above. However use - // max() to make sure we always move out of the pending state. - lastTimestampNanos.set(max(-lastTimestampNanos.get(), 0)); - } } diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmLogSite.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmLogSite.java index 2fd68850c..ff2ee9dc3 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmLogSite.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmLogSite.java @@ -65,8 +65,7 @@ public abstract class JvmLogSite implements LogSiteKey { * methods which rely on being able to look up site specific metadata will be disabled and * essentially become "no ops". */ - public static final JvmLogSite INVALID = - new JvmLogSite() { + public static final JvmLogSite INVALID = new JvmLogSite() { @Override public String getClassName() { return ""; @@ -83,7 +82,7 @@ public int getLineNumber() { } @Override - public String getFileName() { + public @Nullable String getFileName() { return null; } // No need to implement equals() or hashCode() for a singleton instance. @@ -98,8 +97,8 @@ public String getFileName() { /** * Returns a valid line number for the log statement in the range 1 - 65535, or * {@link #UNKNOWN_LINE} if not known. - *

      - * There is a limit of 16 bits for line numbers in a class. See + * + *

      There is a limit of 16 bits for line numbers in a class. See * here * for more details. */ diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/LogContext.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/LogContext.java index f4f7f326d..e408b0f1a 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/LogContext.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/LogContext.java @@ -33,6 +33,7 @@ import io.spine.logging.jvm.backend.TemplateContext; import io.spine.logging.jvm.context.Tags; import io.spine.logging.jvm.parser.MessageParser; +import org.checkerframework.checker.nullness.qual.NonNull; import org.jspecify.annotations.Nullable; import java.util.Arrays; @@ -45,7 +46,6 @@ import static io.spine.logging.jvm.JvmLogSite.injectedLogSite; import static io.spine.logging.jvm.util.Checks.checkNotNull; import static io.spine.reflect.CallerFinder.stackForCallerOf; -import static java.util.concurrent.TimeUnit.NANOSECONDS; /** * The base context for a logging statement, which implements the base logging API. @@ -61,1624 +61,1671 @@ * methods, and this class should be extended to implement them. A new logger class will then be * needed to return the extended context. * - *

      Logging contexts are not thread safe. + *

      Logging contexts are not thread-safe. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger */ public abstract class LogContext, API extends JvmApi> implements JvmApi, LogData { - /** - * The predefined metadata keys used by the default logging API. Backend implementations can use - * these to identify metadata added by the core logging API. - */ - // TODO: Reevaluate this whole strategy before open-sourcing. - public static final class Key { - private Key() {} /** - * The key associated with a {@link Throwable} cause to be associated with the log message. This - * value is set by {@link JvmApi#withCause(Throwable)}. + * The predefined metadata keys used by the default logging API. Backend implementations can use + * these to identify metadata added by the core logging API. */ - public static final JvmMetadataKey LOG_CAUSE = - JvmMetadataKey.single("cause", Throwable.class); + // TODO: Reevaluate this whole strategy before open-sourcing. + public static final class Key { + + private Key() { + } + + /** + * The key associated with a {@link Throwable} cause to be associated with the log message. + * This + * value is set by {@link JvmApi#withCause(Throwable)}. + */ + public static final JvmMetadataKey LOG_CAUSE = + JvmMetadataKey.single("cause", Throwable.class); + + /** + * The key associated with a rate limiting counter for "1-in-N" rate limiting. The value is + * set by {@link JvmApi#every(int)}. + */ + public static final JvmMetadataKey LOG_EVERY_N = + JvmMetadataKey.single("ratelimit_count", Integer.class); + + /** + * The key associated with a rate limiting counter for "1-in-N" randomly sampled rate + * limiting. The value is set by {@link JvmApi#onAverageEvery(int)}. + */ + public static final JvmMetadataKey LOG_SAMPLE_EVERY_N = + JvmMetadataKey.single("sampling_count", Integer.class); + + /** + * The key associated with a rate limiting period for "at most once every N" rate limiting. + * The value is set by {@link JvmApi#atMostEvery(int, TimeUnit)}. + */ + public static final JvmMetadataKey LOG_AT_MOST_EVERY = + JvmMetadataKey.single("ratelimit_period", RateLimitPeriod.class); + + /** + * The key associated with a count of rate limited logs. This is only public so backends can + * reference the key to control formatting. + */ + public static final JvmMetadataKey SKIPPED_LOG_COUNT = + JvmMetadataKey.single("skipped", Integer.class); + + /** + * The key associated with a sequence of log site "grouping keys". These serve to specialize + * the log site key to group the behaviour of stateful operations like rate limiting. This is + * used by the {@code per()} methods and is only public so backends can reference the key to + * control formatting. + */ + public static final JvmMetadataKey LOG_SITE_GROUPING_KEY = + new JvmMetadataKey<>("group_by", Object.class, true) { + @Override + public void emitRepeated(Iterator keys, KeyValueHandler out) { + if (keys.hasNext()) { + var first = keys.next(); + if (!keys.hasNext()) { + out.handle(getLabel(), first); + } else { + // In the very unlikely case there's more than one aggregation key, emit a list. + var buf = new StringBuilder(); + buf.append('[') + .append(first); + do { + buf.append(',') + .append(keys.next()); + } while (keys.hasNext()); + out.handle(getLabel(), buf.append(']') + .toString()); + } + } + } + }; + + /** + * The key associated with a {@code Boolean} value used to specify that the log statement + * must be emitted. + * + *

      Forcing a log statement ensures that the {@code LoggerBackend} is passed the + * {@code LogData} for this log statement regardless of the backend's log level or any other + * filtering or rate limiting which might normally occur. + * + *

      If a log statement is forced, this key will be set immediately on creation of the + * logging context and will be visible to both fluent methods and post-processing. + * + *

      Filtering and rate-limiting methods must check for this value and should treat forced + * log statements as not having had any filtering or rate limiting applied. For example, if + * the following log statement was forced: + * + *

      {@code
      +         * logger.atInfo().withCause(e).atMostEvery(1, MINUTES).log("Message...");
      +         * }
      + * + * it should behave as if the rate-limiting methods were never called, such as: + * + *
      {@code
      +         * logger.atInfo().withCause(e).log("Message...");
      +         * }
      + * + * As well as no longer including any rate-limiting metadata for the forced log statement, + * this also has the effect of never interfering with the rate-limiting of this log + * statement for other callers. + * + *

      The decision of whether to force a log statement is expected to be made based upon + * debug values provided by the logger which come from a scope greater than the log + * statement itself. Thus it makes no sense to provide a public method to set this value + * programmatically for a log statement. + */ + public static final JvmMetadataKey WAS_FORCED = + JvmMetadataKey.single("forced", Boolean.class); + + /** + * The key associated with any injected {@link Tags}. + * + *

      If tags are injected, they are added after post-processing if the log site is enabled. + * Thus they are not available to the {@code postProcess()} method itself. The rationale is + * that a log statement's behavior should only be affected by code at the log site (other + * than "forcing" log statements, which is slightly a special case). + * + *

      Tags can be added at the log site, although this should rarely be necessary and using + * normal log message arguments is always the preferred way to indicate unstructured log + * data. Users should never build new {@link Tags} instances just to pass them into a log + * statement. + */ + public static final JvmMetadataKey TAGS = + new JvmMetadataKey<>("tags", Tags.class, false) { + @Override + public void emit(Tags tags, KeyValueHandler out) { + for (Map.Entry> e : tags.asMap() + .entrySet()) { + var values = e.getValue(); + if (!values.isEmpty()) { + for (var v : e.getValue()) { + out.handle(e.getKey(), v); + } + } else { + out.handle(e.getKey(), null); + } + } + } + }; + + /** + * Key associated with the metadata for specifying additional stack information with a log + * statement. + */ + public static final JvmMetadataKey CONTEXT_STACK_SIZE = + JvmMetadataKey.single("stack_size", StackSize.class); + } + + static final class MutableMetadata extends Metadata { + + /** + * The default number of key/value pairs we initially allocate space for when someone adds + * metadata to this context. + * + *

      Note: As of 10/12 the VM allocates small object arrays very linearly with respect to + * the number of elements (an array has a 12 byte header with 4 bytes/element for object + * references). The allocation size is always rounded up to the next 8 bytes which means we + * can just pick a small value for the initial size and grow from there without too much + * waste. + * + *

      For 4 key/value pairs, we will need 8 elements in the array, which will take up 48 + * bytes {@code (12 + (8 * 4) = 44}, which when rounded up is 48. + */ + private static final int INITIAL_KEY_VALUE_CAPACITY = 4; + + /** + * The array of key/value pairs to hold any metadata that might be added by the logger or any + * of the fluent methods on our API. This is an array so it is as space efficient as possible. + */ + private Object[] keyValuePairs = new Object[2 * INITIAL_KEY_VALUE_CAPACITY]; + /** The number of key/value pairs currently stored in the array. */ + private int keyValueCount = 0; + + @Override + public int size() { + return keyValueCount; + } + + @Override + public JvmMetadataKey getKey(int n) { + if (n >= keyValueCount) { + throw new IndexOutOfBoundsException(); + } + return (JvmMetadataKey) keyValuePairs[2 * n]; + } + + @Override + public Object getValue(int n) { + if (n >= keyValueCount) { + throw new IndexOutOfBoundsException(); + } + return keyValuePairs[(2 * n) + 1]; + } + + private int indexOf(JvmMetadataKey key) { + for (var index = 0; index < keyValueCount; index++) { + if (keyValuePairs[2 * index].equals(key)) { + return index; + } + } + return -1; + } + + @Override + @Nullable + public T findValue(JvmMetadataKey key) { + var index = indexOf(key); + return index != -1 ? key.cast(keyValuePairs[(2 * index) + 1]) : null; + } + + /** + * Adds the key/value pair to the metadata (growing the internal array as necessary). If the + * key + * cannot be repeated, and there is already a value for the key in the metadata, then the + * existing value is replaced, otherwise the value is added at the end of the metadata. + */ + void addValue(JvmMetadataKey key, T value) { + if (!key.canRepeat()) { + var index = indexOf(key); + if (index != -1) { + keyValuePairs[(2 * index) + 1] = checkValue(value); + return; + } + } + // Check that the array is big enough for one more element. + if (2 * (keyValueCount + 1) > keyValuePairs.length) { + // Use doubling here (this code should almost never be hit in normal usage and the total + // number of items should always stay relatively small. If this resizing algorithm is ever + // modified it is vital that the new value is always an even number. + keyValuePairs = Arrays.copyOf(keyValuePairs, 2 * keyValuePairs.length); + } + keyValuePairs[2 * keyValueCount] = checkKey(key); + keyValuePairs[(2 * keyValueCount) + 1] = checkValue(value); + keyValueCount += 1; + } + + private static @NonNull JvmMetadataKey checkKey(JvmMetadataKey key) { + return checkNotNull(key, "metadata key"); + } + + private static @NonNull T checkValue(T value) { + return checkNotNull(value, "metadata value"); + } + + /** Removes all key/value pairs for a given key. */ + private void removeAllValues(JvmMetadataKey key) { + var index = indexOf(key); + if (index >= 0) { + var dest = 2 * index; + var src = dest + 2; + while (src < (2 * keyValueCount)) { + var nextKey = keyValuePairs[src]; + if (!nextKey.equals(key)) { + keyValuePairs[dest] = nextKey; + keyValuePairs[dest + 1] = keyValuePairs[src + 1]; + dest += 2; + } + src += 2; + } + // We know src & dest are +ve and (src > dest), so shifting is safe here. + keyValueCount -= (src - dest) >> 1; + while (dest < src) { + keyValuePairs[dest++] = null; + } + } + } + + /** Strictly for debugging. */ + @Override + public String toString() { + var out = new StringBuilder("Metadata{"); + for (var n = 0; n < size(); n++) { + out.append(" '") + .append(getKey(n)) + .append("': ") + .append(getValue(n)); + } + return out.append(" }") + .toString(); + } + } /** - * The key associated with a rate limiting counter for "1-in-N" rate limiting. The value is set - * by {@link JvmApi#every(int)}. + * A simple token used to identify cases where a single literal value is logged. Note that this + * instance must be unique, and it is important not to replace this with {@code ""} or any other + * value than might be interned and be accessible to code outside this class. */ - public static final JvmMetadataKey LOG_EVERY_N = - JvmMetadataKey.single("ratelimit_count", Integer.class); + @SuppressWarnings("StringOperationCanBeSimplified") + private static final String LITERAL_VALUE_MESSAGE = new String(); + + // TODO: Aggressively attempt to reduce the number of fields in this instance. + + /** The log level of the log statement that this context was created for. */ + private final Level level; + /** The timestamp of the log statement that this context is associated with. */ + private final long timestampNanos; + + /** Additional metadata for this log statement (added via fluent API methods). */ + private MutableMetadata metadata = null; + /** The log site information for this log statement (set immediately prior to post-processing). */ + private JvmLogSite logSite = null; + /** Rate limit status (only set if rate limiting occurs). */ + private RateLimitStatus rateLimitStatus = null; + /** The template context if formatting is required (set only after post-processing). */ + private TemplateContext templateContext = null; + /** The log arguments (set only after post-processing). */ + private Object[] args = null; /** - * The key associated with a rate limiting counter for "1-in-N" randomly sampled rate limiting. - * The value is set by {@link JvmApi#onAverageEvery(int)}. + * Creates a logging context with the specified level, and with a timestamp obtained from the + * configured logging {@link Platform}. + * + * @param level + * the log level for this log statement. + * @param isForced + * whether to force this log statement (see {@link #wasForced()} for details). */ - public static final JvmMetadataKey LOG_SAMPLE_EVERY_N = - JvmMetadataKey.single("sampling_count", Integer.class); + protected LogContext(Level level, boolean isForced) { + this(level, isForced, Platform.getCurrentTimeNanos()); + } /** - * The key associated with a rate limiting period for "at most once every N" rate limiting. The - * value is set by {@link JvmApi#atMostEvery(int, TimeUnit)}. + * Creates a logging context with the specified level and timestamp. This constructor is + * provided + * only for testing when timestamps need to be injected. In general, subclasses would only need + * to + * call this constructor when testing additional API methods which require timestamps (e.g. + * additional rate limiting functionality). Most unit tests for logger subclasses should not + * test + * the value of the timestamp at all, since this is already well tested elsewhere. + * + * @param level + * the log level for this log statement. + * @param isForced + * whether to force this log statement (see {@link #wasForced()} for details). + * @param timestampNanos + * the nanosecond timestamp for this log statement. */ - public static final JvmMetadataKey LOG_AT_MOST_EVERY = - JvmMetadataKey.single("ratelimit_period", RateLimitPeriod.class); + protected LogContext(Level level, boolean isForced, long timestampNanos) { + this.level = checkNotNull(level, "level"); + this.timestampNanos = timestampNanos; + if (isForced) { + addMetadata(Key.WAS_FORCED, Boolean.TRUE); + } + } /** - * The key associated with a count of rate limited logs. This is only public so backends can - * reference the key to control formatting. + * Returns the current API (which is just the concrete sub-type of this instance). This is + * returned by fluent methods to continue the fluent call chain. */ - public static final JvmMetadataKey SKIPPED_LOG_COUNT = - JvmMetadataKey.single("skipped", Integer.class); + protected abstract API api(); + + // ---- Logging Context Constants ---- /** - * The key associated with a sequence of log site "grouping keys". These serve to specialize the - * log site key to group the behaviour of stateful operations like rate limiting. This is used - * by the {@code per()} methods and is only public so backends can reference the key to control - * formatting. + * Returns the logger which created this context. This is implemented as an abstract method to + * save a field in every context. */ - public static final JvmMetadataKey LOG_SITE_GROUPING_KEY = - new JvmMetadataKey<>("group_by", Object.class, true) { - @Override - public void emitRepeated(Iterator keys, KeyValueHandler out) { - if (keys.hasNext()) { - var first = keys.next(); - if (!keys.hasNext()) { - out.handle(getLabel(), first); - } else { - // In the very unlikely case there's more than one aggregation key, emit a list. - var buf = new StringBuilder(); - buf.append('[').append(first); - do { - buf.append(',') - .append(keys.next()); - } while (keys.hasNext()); - out.handle(getLabel(), buf.append(']').toString()); - } - } - } - }; + protected abstract LOGGER getLogger(); /** - * The key associated with a {@code Boolean} value used to specify that the log statement must - * be emitted. + * Returns the constant no-op logging API, which can be returned by fluent methods in extended + * logging contexts to efficiently disable logging. This is implemented as an abstract method to + * save a field in every context. + */ + protected abstract API noOp(); + + /** Returns the message parser used for all log statements made through this logger. */ + protected abstract MessageParser getMessageParser(); + + // ---- LogData API ---- + + @Override + public final Level getLevel() { + return level; + } + + @Override + public final long getTimestampNanos() { + return timestampNanos; + } + + @Override + public final String getLoggerName() { + return getLogger().getBackend() + .getLoggerName(); + } + + @Override + public final JvmLogSite getLogSite() { + if (logSite == null) { + throw new IllegalStateException( + "cannot request log site information prior to postProcess()"); + } + return logSite; + } + + @Override + public final TemplateContext getTemplateContext() { + return templateContext; + } + + @Override + public final Object[] getArguments() { + if (templateContext == null) { + throw new IllegalStateException( + "cannot get arguments unless a template context exists"); + } + return args; + } + + @Override + public final Object getLiteralArgument() { + if (templateContext != null) { + throw new IllegalStateException( + "cannot get literal argument if a template context exists"); + } + return args[0]; + } + + @Override + public final boolean wasForced() { + // Check explicit TRUE here because findValue() can return null (which would fail unboxing). + return metadata != null && Boolean.TRUE.equals(metadata.findValue(Key.WAS_FORCED)); + } + + /** + * Returns any additional metadata for this log statement. * - *

      Forcing a log statement ensures that the {@code LoggerBackend} is passed the {@code - * LogData} for this log statement regardless of the backend's log level or any other filtering - * or rate limiting which might normally occur. If a log statement is forced, this key will be - * set immediately on creation of the logging context and will be visible to both fluent methods - * and post-processing. + *

      When called outside of the logging backend, this method may return different values at + * different times (ie, it may initially return a shared static "empty" metadata object and + * later + * return a different implementation). As such it is not safe to cache the instance returned by + * this method or to attempt to cast it to any particular implementation. + */ + @Override + public final Metadata getMetadata() { + return metadata != null ? metadata : Metadata.empty(); + } + + // ---- Mutable Metadata ---- + + /** + * Adds the given key/value pair to this logging context. If the key cannot be repeated, and + * there + * is already a value for the key in the metadata, then the existing value is replaced, + * otherwise + * the value is added at the end of the metadata. * - *

      Filtering and rate-limiting methods must check for this value and should treat forced log - * statements as not having had any filtering or rate limiting applied. For example, if the - * following log statement was forced: + * @param key + * the metadata key (see {@link LogData}). + * @param value + * the metadata value. + */ + protected final void addMetadata(JvmMetadataKey key, T value) { + if (metadata == null) { + metadata = new MutableMetadata(); + } + metadata.addValue(key, value); + } + + /** + * Removes all key/value pairs with the specified key. Note that this method does not resize + * any + * underlying backing arrays or other storage as logging contexts are expected to be short + * lived. * - *

      {@code
      -     * logger.atInfo().withCause(e).atMostEvery(1, MINUTES).log("Message...");
      -     * }
      + * @param key + * the metadata key (see {@link LogData}). + */ + protected final void removeMetadata(JvmMetadataKey key) { + if (metadata != null) { + metadata.removeAllValues(key); + } + } + + // ---- Post processing ---- + + /** + * A callback which can be overridden to implement post processing of logging contexts prior to + * passing them to the backend. * - * it should behave as if the rate-limiting methods were never called, such as: + *

      Basic Responsibilities

      * - *
      {@code
      -     * logger.atInfo().withCause(e).log("Message...");
      -     * }
      + *

      This method is responsible for: * - * As well as no longer including any rate-limiting metadata for the forced log statement, this - * also has the effect of never interfering with the rate-limiting of this log statement for - * other callers. + *

        + *
      1. Performing any rate limiting operations specific to the extended API. + *
      2. Updating per log-site information (e.g. for debug metrics). + *
      3. Adding any additional metadata to this context. + *
      4. Returning whether logging should be attempted. + *
      * - *

      The decision of whether to force a log statement is expected to be made based upon debug - * values provded by the logger which come from a scope greater than the log statement itself. - * Thus it makes no sense to provide a public method to set this value programmatically for a - * log statement. - */ - public static final JvmMetadataKey WAS_FORCED = - JvmMetadataKey.single("forced", Boolean.class); - - /** - * The key associated with any injected {@link Tags}. + *

      Implementations of this method must always call {@code super.postProcess()} first with the + * given log site key: + * + *

      {@code protected boolean postProcess(@Nullable LogSiteKey logSiteKey) {
      +     *   boolean shouldLog = super.postProcess(logSiteKey);
      +     *   // Handle rate limiting if present.
      +     *   // Add additional metadata etc.
      +     *   return shouldLog;
      +     * }}
      + * + *

      Log Site Keys

      + * + *

      If per log-site information is needed during post-processing, it should be stored using a + * {@link LogSiteMap}. This will correctly handle "specialized" log-site keys and remove the risk + * of memory leaks due to retaining unused log site data indefinitely. + * + *

      Note that the given {@code logSiteKey} can be more specific than the {@link JvmLogSite} + * of a log statement (i.e. a single log statement can have multiple distinct versions of + * its state). See {@link #per(Enum)} for more information. + * + *

      If a log statement cannot be identified uniquely, then {@code logSiteKey} will be {@code + * null}, and this method must behave exactly as if the corresponding fluent method had not been + * invoked. On a system in which log site information is unavailable: + * + *

      {@code logger.atInfo().every(100).withCause(e).log("Some message"); }
      + * + * should behave exactly the same as: + * + *
      {@code logger.atInfo().withCause(e).log("Some message"); }
      + * + *

      Rate Limiting and Skipped Logs

      + * + *

      When handling rate limiting, {@link #updateRateLimiterStatus(RateLimitStatus)} should be + * called for each active rate limiter. This ensures that even if logging does not occur, the + * number of "skipped" log statements is recorded correctly and emitted for the next allowed log. * - *

      If tags are injected, they are added after post-processing if the log site is enabled. - * Thus they are not available to the {@code postProcess()} method itself. The rationale is that - * a log statement's behavior should only be affected by code at the log site (other than - * "forcing" log statements, which is slightly a special case). + *

      If {@code postProcess()} returns {@code false} without updating the rate limit status, the + * log statement may not be counted as skipped. In some situations this is desired, but either way + * the extended logging API should make it clear to the user (via documentation) what will happen. + * However, in most cases {@code postProcess()} is only expected to return {@code false} due to + * rate limiting. * - *

      Tags can be added at the log site, although this should rarely be necessary and using - * normal log message arguments is always the preferred way to indicate unstrctured log data. - * Users should never build new {@link Tags} instances just to pass them into a log statement. + *

      If rate limiters are used there are still situations in which {@code postProcess()} can + * return {@code true}, but logging will not occur. This is due to race conditions around the + * resetting of rate limiter state. A {@code postProcess()} method can "early exit" as soon as + * {@code shouldLog} is false, but should assume logging will occur while it remains {@code true}. + * + *

      If a method in the logging chain determines that logging should definitely not occur, it may + * choose to return the {@code NoOp} logging API at that point. However this will bypass any + * post-processing, and no rate limiter state will be updated. This is sometimes desirable, but + * the API documentation should make it clear to the user as to which behaviour occurs. + * + *

      For example, level selector methods (such as {@code atInfo()}) return the {@code NoOp} API + * for "disabled" log statements, and these have no effect on rate limiter state, and will not + * update the "skipped" count. This is fine because controlling logging via log level selection is + * not conceptually a form of "rate limiting". + * + *

      The default implementation of this method enforces the rate limits as set by {@link + * #every(int)} and {@link #atMostEvery(int, TimeUnit)}. + * + * @param logSiteKey + * used to lookup persistent, per log statement, state. + * @return true if logging should be attempted (usually based on rate limiter state). */ - public static final JvmMetadataKey TAGS = - new JvmMetadataKey<>("tags", Tags.class, false) { - @Override - public void emit(Tags tags, KeyValueHandler out) { - for (Map.Entry> e : tags.asMap().entrySet()) { - var values = e.getValue(); - if (!values.isEmpty()) { - for (var v : e.getValue()) { - out.handle(e.getKey(), v); + protected boolean postProcess(@Nullable LogSiteKey logSiteKey) { + // Without metadata there's nothing to post-process. + if (metadata != null) { + // Without a log site we ignore any log-site specific behaviour. + if (logSiteKey != null) { + // Since the base class postProcess() should be invoked before subclass logic, we can set + // the initial status here. Subclasses can combine this with other rate limiter statuses by + // calling updateRateLimiterStatus() before we get back into shouldLog(). + var status = DurationRateLimiter.check(metadata, logSiteKey, timestampNanos); + status = RateLimitStatus.combine(status, + CountingRateLimiter.check(metadata, logSiteKey)); + status = RateLimitStatus.combine(status, + SamplingRateLimiter.check(metadata, logSiteKey)); + this.rateLimitStatus = status; + + // Early exit as soon as we know the log statement is disallowed. + // A subclass may still do post processing but should never re-enable the log. + if (status == RateLimitStatus.DISALLOW) { + return false; } - } else { - out.handle(e.getKey(), null); - } } - } - }; + + // This does not affect whether logging will occur, only what additional data it contains. + var stackSize = metadata.findValue(Key.CONTEXT_STACK_SIZE); + if (stackSize != null) { + // We add this information to the stack trace exception, + // so it doesn't need to go here. + removeMetadata(Key.CONTEXT_STACK_SIZE); + // IMPORTANT: Skipping at least 1 stack frame below is essential for correctness, + // since postProcess() can be overridden, so the stack could look like: + // + // ^ UserCode::someMethod << we want to start here and skip everything below + // | LogContext::log + // | LogContext::shouldLog + // | OtherChildContext::postProcess + // | ChildContext::postProcess << this is *not* the caller of LogContext we're after + // \- LogContext::postProcess << we are here + // + // By skipping the initial code inside this method, we don't trigger any stack + // capture until after the "log" method. + var context = + new LogSiteStackTrace( + getMetadata().findValue(Key.LOG_CAUSE), + stackSize, + stackForCallerOf(LogContext.class, stackSize.getMaxDepth(), 1)); + // The "cause" is a unique metadata key, we must replace any existing value. + addMetadata(Key.LOG_CAUSE, context); + } + } + // By default, no restrictions apply so we should log. + return true; + } /** - * Key associated with the metadata for specifying additional stack information with a log - * statement. + * Callback to allow custom log contexts to apply additional rate limiting behaviour. + * This should be called from within an overriden {@code postProcess()} method. + * Typically, this is invoked after calling {@code super.postProcess(logSiteKey)}, such as: + * + *

      {@code protected boolean postProcess(@Nullable LogSiteKey logSiteKey) {
      +     *   boolean shouldLog = super.postProcess(logSiteKey);
      +     *   // Even if `shouldLog` is false, we still call the rate limiter to update its state.
      +     *   shouldLog &= updateRateLimiterStatus(CustomRateLimiter.check(...));
      +     *   if (shouldLog) {
      +     *     // Maybe add additional metadata here...
      +     *   }
      +     *   return shouldLog;
      +     * }}
      + * + *

      See {@link RateLimitStatus} for more information on how to implement custom rate + * limiting in Flogger. + * + * @param status + * a rate limiting status, or {@code null} if the rate limiter was not active. + * @return whether logging will occur based on the current combined state of + * active rate limiters. */ - public static final JvmMetadataKey CONTEXT_STACK_SIZE = - JvmMetadataKey.single("stack_size", StackSize.class); - } + protected final boolean updateRateLimiterStatus(@Nullable RateLimitStatus status) { + rateLimitStatus = RateLimitStatus.combine(rateLimitStatus, status); + return rateLimitStatus != RateLimitStatus.DISALLOW; + } - static final class MutableMetadata extends Metadata { /** - * The default number of key/value pairs we initially allocate space for when someone adds - * metadata to this context. - * - *

      Note: As of 10/12 the VM allocates small object arrays very linearly with respect to the - * number of elements (an array has a 12 byte header with 4 bytes/element for object - * references). The allocation size is always rounded up to the next 8 bytes which means we can - * just pick a small value for the initial size and grow from there without too much waste. + * Pre-processes log metadata and determines whether we should make the pending logging call. * - *

      For 4 key/value pairs, we will need 8 elements in the array, which will take up 48 bytes - * {@code (12 + (8 * 4) = 44}, which when rounded up is 48. + *

      Note that this call is made inside each of the individual log methods (rather than in + * {@code logImpl()}) because it is better to decide whether we are actually going to do the + * logging before we pay the price of creating a varargs array and doing things like + * auto-boxing of arguments. */ - private static final int INITIAL_KEY_VALUE_CAPACITY = 4; + private boolean shouldLog() { + // The log site may have already been injected via "withInjectedLogSite()" or similar. + if (logSite == null) { + // From the point at which we call inferLogSite() we can skip 1 additional method (the + // shouldLog() method itself) when looking up the stack to find the log() method. + logSite = + checkNotNull( + Platform.getCallerFinder() + .findLogSite(LogContext.class, 1), + "logger backend must not return a null LogSite"); + } + LogSiteKey logSiteKey = null; + if (logSite != JvmLogSite.INVALID) { + logSiteKey = logSite; + // Log site keys are only modified when we have metadata in the log statement. + if (metadata != null && metadata.size() > 0) { + logSiteKey = specializeLogSiteKeyFromMetadata(logSiteKey, metadata); + } + } + var shouldLog = postProcess(logSiteKey); + if (rateLimitStatus != null) { + // We check rate limit status even if it is "DISALLOW" to update the skipped logs count. + var skippedLogs = RateLimitStatus.checkStatus(rateLimitStatus, logSiteKey, metadata); + if (shouldLog && skippedLogs > 0) { + metadata.addValue(Key.SKIPPED_LOG_COUNT, skippedLogs); + } + // checkStatus() returns -1 in two cases: + // 1. We passed it the DISALLOW status. + // 2. We passed it an "allow" status, but multiple threads were racing to try and reset the + // rate limiters, and this thread lost. + // Either way we should suppress logging. + shouldLog &= (skippedLogs >= 0); + } + return shouldLog; + } + + // WARNING: If we ever start to use combined log-site and scoped context metadata here via + // MetadataProcessor, there's an issue. It's possible that the same scope can appear in both + // the context and the log-site, and multiplicity should not matter; BUT IT DOES! This means + // that a log statement executed both in and outside of the context would currently see + // different keys, when they should be the same. To fix this, specialization must be changed + // to ignore repeated scopes. For now we only see log site metadata so this is not an issue. + // + // TODO: Ignore repeated scopes (e.g. use a Bloom Filter mask on each scope). + // TODO: Make a proper iterator on Metadata or use MetadataProcessor. + // + // Visible for testing + static LogSiteKey specializeLogSiteKeyFromMetadata(LogSiteKey logSiteKey, Metadata metadata) { + checkNotNull(logSiteKey, "logSiteKey"); // For package null checker only. + for (int n = 0, size = metadata.size(); n < size; n++) { + if (Key.LOG_SITE_GROUPING_KEY.equals(metadata.getKey(n))) { + Object groupByQualifier = metadata.getValue(n); + // Logging scopes need special treatment to handle tidying up when closed. + if (groupByQualifier instanceof LoggingScope) { + logSiteKey = ((LoggingScope) groupByQualifier).specialize(logSiteKey); + } else { + logSiteKey = SpecializedLogSiteKey.of(logSiteKey, groupByQualifier); + } + } + } + return logSiteKey; + } /** - * The array of key/value pairs to hold any metadata the might be added by the logger or any of - * the fluent methods on our API. This is an array so it is as space efficient as possible. + * Make the backend logging call. This is the point at which we have paid the price of creating + * a + * varargs array and doing any necessary auto-boxing. */ - private Object[] keyValuePairs = new Object[2 * INITIAL_KEY_VALUE_CAPACITY]; - /** The number of key/value pairs currently stored in the array. */ - private int keyValueCount = 0; + @SuppressWarnings("ReferenceEquality") + private void logImpl(String message, Object... args) { + this.args = args; + // Evaluate any (rare) LazyArg instances early. This may throw exceptions from user code, but + // it seems reasonable to propagate them in this case (they would have been thrown if the + // argument was evaluated at the call site anyway). + for (var n = 0; n < args.length; n++) { + if (args[n] instanceof LazyArg) { + args[n] = ((LazyArg) args[n]).evaluate(); + } + } + // Using "!=" is fast and sufficient here because the only real case this should be skipping + // is when we called log(String) or log(), which should not result in a template being created. + // DO NOT replace this with a string instance which can be interned, or use equals() here, + // since that could mistakenly treat other calls to log(String, Object...) incorrectly. + if (message != LITERAL_VALUE_MESSAGE) { + this.templateContext = new TemplateContext(getMessageParser(), message); + } + // Right at the end of processing add any tags injected by the platform. Any tags supplied at + // the log site are merged with the injected tags (though this should be very rare). + var tags = Platform.getInjectedTags(); + if (!tags.isEmpty()) { + var logSiteTags = getMetadata().findValue(Key.TAGS); + if (logSiteTags != null) { + tags = tags.merge(logSiteTags); + } + addMetadata(Key.TAGS, tags); + } + // Pass the completed log data to the backend (it should not be modified after this point). + getLogger().write(this); + } + + // ---- Log site injection (used by pre-processors and special cases) ---- @Override - public int size() { - return keyValueCount; + public final API withInjectedLogSite(JvmLogSite logSite) { + // First call wins (since auto-injection will typically target the log() method at the end of + // the chain and might not check for previous explicit injection). In particular it MUST be + // allowed for a caller to specify the "INVALID" log site, and have that set the field here to + // disable log site lookup at this log statement (though passing "null" is a no-op). + if (this.logSite == null && logSite != null) { + this.logSite = logSite; + } + return api(); } + @SuppressWarnings("deprecation") @Override - public JvmMetadataKey getKey(int n) { - if (n >= keyValueCount) { - throw new IndexOutOfBoundsException(); - } - return (JvmMetadataKey) keyValuePairs[2 * n]; + public final API withInjectedLogSite( + String internalClassName, + String methodName, + int encodedLineNumber, + @Nullable String sourceFileName) { + var logSite = injectedLogSite(internalClassName, methodName, encodedLineNumber, + sourceFileName); + return withInjectedLogSite(logSite); } + // ---- Public logging API ---- + @Override - public Object getValue(int n) { - if (n >= keyValueCount) { - throw new IndexOutOfBoundsException(); - } - return keyValuePairs[(2 * n) + 1]; + public final boolean isEnabled() { + // We can't guarantee that all logger implementations will return instances of this class + // _only_ when logging is enabled, so if would be potentially unsafe to just return true here. + // It's not worth caching this result in the instance because calls to this method should be + // rare and they are only going to be made once per instance anyway. + return wasForced() || getLogger().isLoggable(level); } - private int indexOf(JvmMetadataKey key) { - for (var index = 0; index < keyValueCount; index++) { - if (keyValuePairs[2 * index].equals(key)) { - return index; + @Override + public final API with(JvmMetadataKey key, @Nullable T value) { + // Null keys are always bad (even if the value is also null). This is one of the few places + // where the logger API will throw a runtime exception (and as such it's important to ensure + // the NoOp implementation also does the check). The reasoning for this is that the metadata + // key is never expected to be passed user data, and should always be a static constant. + // Because of this it's always going to be an obvious code error if we get a null here. + checkNotNull(key, "metadata key"); + if (value != null) { + addMetadata(key, value); } - } - return -1; + return api(); } @Override - @Nullable - public T findValue(JvmMetadataKey key) { - var index = indexOf(key); - return index != -1 ? key.cast(keyValuePairs[(2 * index) + 1]) : null; + public final API with(JvmMetadataKey key) { + return with(key, Boolean.TRUE); } - /** - * Adds the key/value pair to the metadata (growing the internal array as necessary). If the key - * cannot be repeated, and there is already a value for the key in the metadata, then the - * existing value is replaced, otherwise the value is added at the end of the metadata. + @Override + public API per(@Nullable T key, LogPerBucketingStrategy strategy) { + // Skip calling the bucketer for null so implementations don't need to check. + return key != null ? with(Key.LOG_SITE_GROUPING_KEY, strategy.apply(key)) : api(); + } + + @Override + public final API per(Enum key) { + return with(Key.LOG_SITE_GROUPING_KEY, key); + } + + @Override + public API per(LoggingScopeProvider scopeProvider) { + return with(Key.LOG_SITE_GROUPING_KEY, scopeProvider.getCurrentScope()); + } + + @Override + public final API withCause(Throwable cause) { + return with(Key.LOG_CAUSE, cause); + } + + @Override + public API withStackTrace(StackSize size) { + // Unlike other metadata methods, the "no-op" value is not null. + if (checkNotNull(size, "stack size") != StackSize.NONE) { + addMetadata(Key.CONTEXT_STACK_SIZE, size); + } + return api(); + } + + @Override + public final API every(int n) { + return everyImpl(Key.LOG_EVERY_N, n, "rate limit"); + } + + @Override + public final API onAverageEvery(int n) { + return everyImpl(Key.LOG_SAMPLE_EVERY_N, n, "sampling"); + } + + private API everyImpl(JvmMetadataKey key, int n, String label) { + // See wasForced() for discussion as to why this occurs before argument checking. + if (wasForced()) { + return api(); + } + if (n <= 0) { + throw new IllegalArgumentException(label + " count must be positive"); + } + // 1-in-1 rate limiting is a no-op. + if (n > 1) { + addMetadata(key, n); + } + return api(); + } + + @Override + public final API atMostEvery(int n, TimeUnit unit) { + // See wasForced() for discussion as to why this occurs before argument checking. + if (wasForced()) { + return api(); + } + if (n < 0) { + throw new IllegalArgumentException("rate limit period cannot be negative"); + } + // Rate limiting with a zero length period is a no-op, but if the time unit is nanoseconds then + // the value is rounded up inside the rate limit object. + if (n > 0) { + addMetadata(Key.LOG_AT_MOST_EVERY, DurationRateLimiter.newRateLimitPeriod(n, unit)); + } + return api(); + } + + /* + * Note that while all log statements look almost identical to each other, it is vital that we + * keep the 'shouldLog()' call outside of the call to 'logImpl()' so we can decide whether or not + * to abort logging before we do any varargs creation. */ - void addValue(JvmMetadataKey key, T value) { - if (!key.canRepeat()) { - var index = indexOf(key); - if (index != -1) { - keyValuePairs[(2 * index) + 1] = checkNotNull(value, "metadata value"); - return; - } - } - // Check that the array is big enough for one more element. - if (2 * (keyValueCount + 1) > keyValuePairs.length) { - // Use doubling here (this code should almost never be hit in normal usage and the total - // number of items should always stay relatively small. If this resizing algorithm is ever - // modified it is vital that the new value is always an even number. - keyValuePairs = Arrays.copyOf(keyValuePairs, 2 * keyValuePairs.length); - } - keyValuePairs[2 * keyValueCount] = checkNotNull(key, "metadata key"); - keyValuePairs[(2 * keyValueCount) + 1] = checkNotNull(value, "metadata value"); - keyValueCount += 1; - } - - /** Removes all key/value pairs for a given key. */ - void removeAllValues(JvmMetadataKey key) { - var index = indexOf(key); - if (index >= 0) { - var dest = 2 * index; - var src = dest + 2; - while (src < (2 * keyValueCount)) { - var nextKey = keyValuePairs[src]; - if (!nextKey.equals(key)) { - keyValuePairs[dest] = nextKey; - keyValuePairs[dest + 1] = keyValuePairs[src + 1]; - dest += 2; - } - src += 2; - } - // We know src & dest are +ve and (src > dest), so shifting is safe here. - keyValueCount -= (src - dest) >> 1; - while (dest < src) { - keyValuePairs[dest++] = null; - } - } - } - - /** Strictly for debugging. */ - @Override - public String toString() { - var out = new StringBuilder("Metadata{"); - for (var n = 0; n < size(); n++) { - out.append(" '").append(getKey(n)).append("': ").append(getValue(n)); - } - return out.append(" }").toString(); - } - } - - /** - * A simple token used to identify cases where a single literal value is logged. Note that this - * instance must be unique and it is important not to replace this with {@code ""} or any other - * value than might be interned and be accessible to code outside this class. - */ - @SuppressWarnings("StringOperationCanBeSimplified") - private static final String LITERAL_VALUE_MESSAGE = new String(); - - // TODO: Aggressively attempt to reduce the number of fields in this instance. - - /** The log level of the log statement that this context was created for. */ - private final Level level; - /** The timestamp of the log statement that this context is associated with. */ - private final long timestampNanos; - - /** Additional metadata for this log statement (added via fluent API methods). */ - private MutableMetadata metadata = null; - /** The log site information for this log statement (set immediately prior to post-processing). */ - private JvmLogSite logSite = null; - /** Rate limit status (only set if rate limiting occurs). */ - private RateLimitStatus rateLimitStatus = null; - /** The template context if formatting is required (set only after post-processing). */ - private TemplateContext templateContext = null; - /** The log arguments (set only after post-processing). */ - private Object[] args = null; - - /** - * Creates a logging context with the specified level, and with a timestamp obtained from the - * configured logging {@link Platform}. - * - * @param level the log level for this log statement. - * @param isForced whether to force this log statement (see {@link #wasForced()} for details). - */ - protected LogContext(Level level, boolean isForced) { - this(level, isForced, Platform.getCurrentTimeNanos()); - } - - /** - * Creates a logging context with the specified level and timestamp. This constructor is provided - * only for testing when timestamps need to be injected. In general, subclasses would only need to - * call this constructor when testing additional API methods which require timestamps (e.g. - * additional rate limiting functionality). Most unit tests for logger subclasses should not test - * the value of the timestamp at all, since this is already well tested elsewhere. - * - * @param level the log level for this log statement. - * @param isForced whether to force this log statement (see {@link #wasForced()} for details). - * @param timestampNanos the nanosecond timestamp for this log statement. - */ - protected LogContext(Level level, boolean isForced, long timestampNanos) { - this.level = checkNotNull(level, "level"); - this.timestampNanos = timestampNanos; - if (isForced) { - addMetadata(Key.WAS_FORCED, Boolean.TRUE); - } - } - - /** - * Returns the current API (which is just the concrete sub-type of this instance). This is - * returned by fluent methods to continue the fluent call chain. - */ - protected abstract API api(); - - // ---- Logging Context Constants ---- - - /** - * Returns the logger which created this context. This is implemented as an abstract method to - * save a field in every context. - */ - protected abstract LOGGER getLogger(); - - /** - * Returns the constant no-op logging API, which can be returned by fluent methods in extended - * logging contexts to efficiently disable logging. This is implemented as an abstract method to - * save a field in every context. - */ - protected abstract API noOp(); - - /** Returns the message parser used for all log statements made through this logger. */ - protected abstract MessageParser getMessageParser(); - - // ---- LogData API ---- - - @Override - public final Level getLevel() { - return level; - } - - @Deprecated - @Override - public final long getTimestampMicros() { - return NANOSECONDS.toMicros(timestampNanos); - } - - @Override - public final long getTimestampNanos() { - return timestampNanos; - } - - @Override - public final String getLoggerName() { - return getLogger().getBackend().getLoggerName(); - } - - @Override - public final JvmLogSite getLogSite() { - if (logSite == null) { - throw new IllegalStateException("cannot request log site information prior to postProcess()"); - } - return logSite; - } - - @Override - public final TemplateContext getTemplateContext() { - return templateContext; - } - - @Override - public final Object[] getArguments() { - if (templateContext == null) { - throw new IllegalStateException("cannot get arguments unless a template context exists"); - } - return args; - } - - @Override - public final Object getLiteralArgument() { - if (templateContext != null) { - throw new IllegalStateException("cannot get literal argument if a template context exists"); - } - return args[0]; - } - - @Override - public final boolean wasForced() { - // Check explicit TRUE here because findValue() can return null (which would fail unboxing). - return metadata != null && Boolean.TRUE.equals(metadata.findValue(Key.WAS_FORCED)); - } - - /** - * Returns any additional metadata for this log statement. - * - *

      When called outside of the logging backend, this method may return different values at - * different times (ie, it may initially return a shared static "empty" metadata object and later - * return a different implementation). As such it is not safe to cache the instance returned by - * this method or to attempt to cast it to any particular implementation. - */ - @Override - public final Metadata getMetadata() { - return metadata != null ? metadata : Metadata.empty(); - } - - // ---- Mutable Metadata ---- - - /** - * Adds the given key/value pair to this logging context. If the key cannot be repeated, and there - * is already a value for the key in the metadata, then the existing value is replaced, otherwise - * the value is added at the end of the metadata. - * - * @param key the metadata key (see {@link LogData}). - * @param value the metadata value. - */ - protected final void addMetadata(JvmMetadataKey key, T value) { - if (metadata == null) { - metadata = new MutableMetadata(); - } - metadata.addValue(key, value); - } - - /** - * Removes all key/value pairs with the specified key. Note that this method does not resize any - * underlying backing arrays or other storage as logging contexts are expected to be short lived. - * - * @param key the metadata key (see {@link LogData}). - */ - protected final void removeMetadata(JvmMetadataKey key) { - if (metadata != null) { - metadata.removeAllValues(key); - } - } - - // ---- Post processing ---- - - /** - * A callback which can be overridden to implement post processing of logging contexts prior to - * passing them to the backend. - * - *

      Basic Responsibilities

      - * - *

      This method is responsible for: - * - *

        - *
      1. Performing any rate limiting operations specific to the extended API. - *
      2. Updating per log-site information (e.g. for debug metrics). - *
      3. Adding any additional metadata to this context. - *
      4. Returning whether logging should be attempted. - *
      - * - *

      Implementations of this method must always call {@code super.postProcess()} first with the - * given log site key: - * - *

      {@code protected boolean postProcess(@Nullable LogSiteKey logSiteKey) {
      -   *   boolean shouldLog = super.postProcess(logSiteKey);
      -   *   // Handle rate limiting if present.
      -   *   // Add additional metadata etc.
      -   *   return shouldLog;
      -   * }}
      - * - *

      Log Site Keys

      - * - *

      If per log-site information is needed during post-processing, it should be stored using a - * {@link LogSiteMap}. This will correctly handle "specialized" log-site keys and remove the risk - * of memory leaks due to retaining unused log site data indefinitely. - * - *

      Note that the given {@code logSiteKey} can be more specific than the {@link JvmLogSite} - * of a log statement (i.e. a single log statement can have multiple distinct versions of - * its state). See {@link #per(Enum)} for more information. - * - *

      If a log statement cannot be identified uniquely, then {@code logSiteKey} will be {@code - * null}, and this method must behave exactly as if the corresponding fluent method had not been - * invoked. On a system in which log site information is unavailable: - * - *

      {@code logger.atInfo().every(100).withCause(e).log("Some message"); }
      - * - * should behave exactly the same as: - * - *
      {@code logger.atInfo().withCause(e).log("Some message"); }
      - * - *

      Rate Limiting and Skipped Logs

      - * - *

      When handling rate limiting, {@link #updateRateLimiterStatus(RateLimitStatus)} should be - * called for each active rate limiter. This ensures that even if logging does not occur, the - * number of "skipped" log statements is recorded correctly and emitted for the next allowed log. - * - *

      If {@code postProcess()} returns {@code false} without updating the rate limit status, the - * log statement may not be counted as skipped. In some situations this is desired, but either way - * the extended logging API should make it clear to the user (via documentation) what will happen. - * However, in most cases {@code postProcess()} is only expected to return {@code false} due to - * rate limiting. - * - *

      If rate limiters are used there are still situations in which {@code postProcess()} can - * return {@code true}, but logging will not occur. This is due to race conditions around the - * resetting of rate limiter state. A {@code postProcess()} method can "early exit" as soon as - * {@code shouldLog} is false, but should assume logging will occur while it remains {@code true}. - * - *

      If a method in the logging chain determines that logging should definitely not occur, it may - * choose to return the {@code NoOp} logging API at that point. However this will bypass any - * post-processing, and no rate limiter state will be updated. This is sometimes desirable, but - * the API documentation should make it clear to the user as to which behaviour occurs. - * - *

      For example, level selector methods (such as {@code atInfo()}) return the {@code NoOp} API - * for "disabled" log statements, and these have no effect on rate limiter state, and will not - * update the "skipped" count. This is fine because controlling logging via log level selection is - * not conceptually a form of "rate limiting". - * - *

      The default implementation of this method enforces the rate limits as set by {@link - * #every(int)} and {@link #atMostEvery(int, TimeUnit)}. - * - * @param logSiteKey used to lookup persistent, per log statement, state. - * @return true if logging should be attempted (usually based on rate limiter state). - */ - protected boolean postProcess(@Nullable LogSiteKey logSiteKey) { - // Without metadata there's nothing to post-process. - if (metadata != null) { - // Without a log site we ignore any log-site specific behaviour. - if (logSiteKey != null) { - // Since the base class postProcess() should be invoked before subclass logic, we can set - // the initial status here. Subclasses can combine this with other rate limiter statuses by - // calling updateRateLimiterStatus() before we get back into shouldLog(). - var status = DurationRateLimiter.check(metadata, logSiteKey, timestampNanos); - status = RateLimitStatus.combine(status, CountingRateLimiter.check(metadata, logSiteKey)); - status = RateLimitStatus.combine(status, SamplingRateLimiter.check(metadata, logSiteKey)); - this.rateLimitStatus = status; - - // Early exit as soon as we know the log statement is disallowed. A subclass may still do - // post processing but should never re-enable the log. - if (status == RateLimitStatus.DISALLOW) { - return false; - } - } - - // This does not affect whether logging will occur, only what additional data it contains. - var stackSize = metadata.findValue(Key.CONTEXT_STACK_SIZE); - if (stackSize != null) { - // We add this information to the stack trace exception so it doesn't need to go here. - removeMetadata(Key.CONTEXT_STACK_SIZE); - // IMPORTANT: Skipping at least 1 stack frame below is essential for correctness, since - // postProcess() can be overridden, so the stack could look like: - // - // ^ UserCode::someMethod << we want to start here and skip everything below - // | LogContext::log - // | LogContext::shouldLog - // | OtherChildContext::postProcess - // | ChildContext::postProcess << this is *not* the caller of LogContext we're after - // \- LogContext::postProcess << we are here - // - // By skipping the initial code inside this method, we don't trigger any stack capture until - // after the "log" method. - var context = - new LogSiteStackTrace( - getMetadata().findValue(Key.LOG_CAUSE), - stackSize, - stackForCallerOf(LogContext.class, stackSize.getMaxDepth(), 1)); - // The "cause" is a unique metadata key, we must replace any existing value. - addMetadata(Key.LOG_CAUSE, context); - } - } - // By default, no restrictions apply so we should log. - return true; - } - - /** - * Callback to allow custom log contexts to apply additional rate limiting behaviour. This should - * be called from within an overriden {@code postProcess()} method. Typically this is invoked - * after calling {@code super.postProcess(logSiteKey)}, such as: - * - *

      {@code protected boolean postProcess(@Nullable LogSiteKey logSiteKey) {
      -   *   boolean shouldLog = super.postProcess(logSiteKey);
      -   *   // Even if `shouldLog` is false, we still call the rate limiter to update its state.
      -   *   shouldLog &= updateRateLimiterStatus(CustomRateLimiter.check(...));
      -   *   if (shouldLog) {
      -   *     // Maybe add additional metadata here...
      -   *   }
      -   *   return shouldLog;
      -   * }}
      - * - *

      See {@link RateLimitStatus} for more information on how to implement custom rate limiting in - * Flogger. - * - * @param status a rate limiting status, or {@code null} if the rate limiter was not active. - * @return whether logging will occur based on the current combined state of active rate limiters. - */ - protected final boolean updateRateLimiterStatus(@Nullable RateLimitStatus status) { - rateLimitStatus = RateLimitStatus.combine(rateLimitStatus, status); - return rateLimitStatus != RateLimitStatus.DISALLOW; - } - - /** - * Pre-processes log metadata and determines whether we should make the pending logging call. - * - *

      Note that this call is made inside each of the individual log methods (rather than in {@code - * logImpl()}) because it is better to decide whether we are actually going to do the logging - * before we pay the price of creating a varargs array and doing things like auto-boxing of - * arguments. - */ - private boolean shouldLog() { - // The log site may have already been injected via "withInjectedLogSite()" or similar. - if (logSite == null) { - // From the point at which we call inferLogSite() we can skip 1 additional method (the - // shouldLog() method itself) when looking up the stack to find the log() method. - logSite = - checkNotNull( - Platform.getCallerFinder().findLogSite(LogContext.class, 1), - "logger backend must not return a null LogSite"); - } - LogSiteKey logSiteKey = null; - if (logSite != JvmLogSite.INVALID) { - logSiteKey = logSite; - // Log site keys are only modified when we have metadata in the log statement. - if (metadata != null && metadata.size() > 0) { - logSiteKey = specializeLogSiteKeyFromMetadata(logSiteKey, metadata); - } - } - var shouldLog = postProcess(logSiteKey); - if (rateLimitStatus != null) { - // We check rate limit status even if it is "DISALLOW" to update the skipped logs count. - var skippedLogs = RateLimitStatus.checkStatus(rateLimitStatus, logSiteKey, metadata); - if (shouldLog && skippedLogs > 0) { - metadata.addValue(Key.SKIPPED_LOG_COUNT, skippedLogs); - } - // checkStatus() returns -1 in two cases: - // 1. We passed it the DISALLOW status. - // 2. We passed it an "allow" status, but multiple threads were racing to try and reset the - // rate limiters, and this thread lost. - // Either way we should suppress logging. - shouldLog &= (skippedLogs >= 0); - } - return shouldLog; - } - - // WARNING: If we ever start to use combined log-site and scoped context metadata here via - // MetadataProcessor, there's an issue. It's possible that the same scope can appear in both - // the context and the log-site, and multiplicity should not matter; BUT IT DOES! This means - // that a log statement executed both in and outside of the context would currently see - // different keys, when they should be the same. To fix this, specialization must be changed - // to ignore repeated scopes. For now we only see log site metadata so this is not an issue. - // - // TODO: Ignore repeated scopes (e.g. use a Bloom Filter mask on each scope). - // TODO: Make a proper iterator on Metadata or use MetadataProcessor. - // - // Visible for testing - static LogSiteKey specializeLogSiteKeyFromMetadata(LogSiteKey logSiteKey, Metadata metadata) { - checkNotNull(logSiteKey, "logSiteKey"); // For package null checker only. - for (int n = 0, size = metadata.size(); n < size; n++) { - if (Key.LOG_SITE_GROUPING_KEY.equals(metadata.getKey(n))) { - Object groupByQualifier = metadata.getValue(n); - // Logging scopes need special treatment to handle tidying up when closed. - if (groupByQualifier instanceof LoggingScope) { - logSiteKey = ((LoggingScope) groupByQualifier).specialize(logSiteKey); - } else { - logSiteKey = SpecializedLogSiteKey.of(logSiteKey, groupByQualifier); - } - } - } - return logSiteKey; - } - - /** - * Make the backend logging call. This is the point at which we have paid the price of creating a - * varargs array and doing any necessary auto-boxing. - */ - @SuppressWarnings("ReferenceEquality") - private void logImpl(String message, Object... args) { - this.args = args; - // Evaluate any (rare) LazyArg instances early. This may throw exceptions from user code, but - // it seems reasonable to propagate them in this case (they would have been thrown if the - // argument was evaluated at the call site anyway). - for (var n = 0; n < args.length; n++) { - if (args[n] instanceof LazyArg) { - args[n] = ((LazyArg) args[n]).evaluate(); - } - } - // Using "!=" is fast and sufficient here because the only real case this should be skipping - // is when we called log(String) or log(), which should not result in a template being created. - // DO NOT replace this with a string instance which can be interned, or use equals() here, - // since that could mistakenly treat other calls to log(String, Object...) incorrectly. - if (message != LITERAL_VALUE_MESSAGE) { - this.templateContext = new TemplateContext(getMessageParser(), message); - } - // Right at the end of processing add any tags injected by the platform. Any tags supplied at - // the log site are merged with the injected tags (though this should be very rare). - var tags = Platform.getInjectedTags(); - if (!tags.isEmpty()) { - var logSiteTags = getMetadata().findValue(Key.TAGS); - if (logSiteTags != null) { - tags = tags.merge(logSiteTags); - } - addMetadata(Key.TAGS, tags); - } - // Pass the completed log data to the backend (it should not be modified after this point). - getLogger().write(this); - } - - // ---- Log site injection (used by pre-processors and special cases) ---- - - @Override - public final API withInjectedLogSite(JvmLogSite logSite) { - // First call wins (since auto-injection will typically target the log() method at the end of - // the chain and might not check for previous explicit injection). In particular it MUST be - // allowed for a caller to specify the "INVALID" log site, and have that set the field here to - // disable log site lookup at this log statement (though passing "null" is a no-op). - if (this.logSite == null && logSite != null) { - this.logSite = logSite; - } - return api(); - } - - @SuppressWarnings("deprecation") - @Override - public final API withInjectedLogSite( - String internalClassName, - String methodName, - int encodedLineNumber, - @Nullable String sourceFileName) { - var logSite = injectedLogSite(internalClassName, methodName, encodedLineNumber, sourceFileName); - return withInjectedLogSite(logSite); - } - - // ---- Public logging API ---- - - @Override - public final boolean isEnabled() { - // We can't guarantee that all logger implementations will return instances of this class - // _only_ when logging is enabled, so if would be potentially unsafe to just return true here. - // It's not worth caching this result in the instance because calls to this method should be - // rare and they are only going to be made once per instance anyway. - return wasForced() || getLogger().isLoggable(level); - } - - @Override - public final API with(JvmMetadataKey key, @Nullable T value) { - // Null keys are always bad (even if the value is also null). This is one of the few places - // where the logger API will throw a runtime exception (and as such it's important to ensure - // the NoOp implementation also does the check). The reasoning for this is that the metadata - // key is never expected to be passed user data, and should always be a static constant. - // Because of this it's always going to be an obvious code error if we get a null here. - checkNotNull(key, "metadata key"); - if (value != null) { - addMetadata(key, value); - } - return api(); - } - - @Override - public final API with(JvmMetadataKey key) { - return with(key, Boolean.TRUE); - } - - @Override - public API per(@Nullable T key, LogPerBucketingStrategy strategy) { - // Skip calling the bucketer for null so implementations don't need to check. - return key != null ? with(Key.LOG_SITE_GROUPING_KEY, strategy.apply(key)) : api(); - } - - @Override - public final API per(Enum key) { - return with(Key.LOG_SITE_GROUPING_KEY, key); - } - - @Override - public API per(LoggingScopeProvider scopeProvider) { - return with(Key.LOG_SITE_GROUPING_KEY, scopeProvider.getCurrentScope()); - } - - @Override - public final API withCause(Throwable cause) { - return with(Key.LOG_CAUSE, cause); - } - - @Override - public API withStackTrace(StackSize size) { - // Unlike other metadata methods, the "no-op" value is not null. - if (checkNotNull(size, "stack size") != StackSize.NONE) { - addMetadata(Key.CONTEXT_STACK_SIZE, size); - } - return api(); - } - - @Override - public final API every(int n) { - return everyImpl(Key.LOG_EVERY_N, n, "rate limit"); - } - - @Override - public final API onAverageEvery(int n) { - return everyImpl(Key.LOG_SAMPLE_EVERY_N, n, "sampling"); - } - - private API everyImpl(JvmMetadataKey key, int n, String label) { - // See wasForced() for discussion as to why this occurs before argument checking. - if (wasForced()) { - return api(); - } - if (n <= 0) { - throw new IllegalArgumentException(label + " count must be positive"); - } - // 1-in-1 rate limiting is a no-op. - if (n > 1) { - addMetadata(key, n); - } - return api(); - } - - @Override - public final API atMostEvery(int n, TimeUnit unit) { - // See wasForced() for discussion as to why this occurs before argument checking. - if (wasForced()) { - return api(); - } - if (n < 0) { - throw new IllegalArgumentException("rate limit period cannot be negative"); - } - // Rate limiting with a zero length period is a no-op, but if the time unit is nanoseconds then - // the value is rounded up inside the rate limit object. - if (n > 0) { - addMetadata(Key.LOG_AT_MOST_EVERY, DurationRateLimiter.newRateLimitPeriod(n, unit)); - } - return api(); - } - - /* - * Note that while all log statements look almost identical to each other, it is vital that we - * keep the 'shouldLog()' call outside of the call to 'logImpl()' so we can decide whether or not - * to abort logging before we do any varargs creation. - */ - - @Override - public final void log() { - if (shouldLog()) { - logImpl(LITERAL_VALUE_MESSAGE, ""); - } - } - - @Override - public final void log(String msg) { - if (shouldLog()) { - logImpl(LITERAL_VALUE_MESSAGE, msg); - } - } - - @Override - public final void log(String message, @Nullable Object p1) { - if (shouldLog()) { - logImpl(message, p1); - } - } - - @Override - public final void log(String message, @Nullable Object p1, @Nullable Object p2) { - if (shouldLog()) { - logImpl(message, p1, p2); - } - } - - @Override - public final void log( - String message, @Nullable Object p1, @Nullable Object p2, @Nullable Object p3) { - if (shouldLog()) { - logImpl(message, p1, p2, p3); - } - } - - @Override - public final void log( - String message, - @Nullable Object p1, - @Nullable Object p2, - @Nullable Object p3, - @Nullable Object p4) { - if (shouldLog()) { - logImpl(message, p1, p2, p3, p4); - } - } - - @Override - public final void log( - String msg, - @Nullable Object p1, - @Nullable Object p2, - @Nullable Object p3, - @Nullable Object p4, - @Nullable Object p5) { - if (shouldLog()) { - logImpl(msg, p1, p2, p3, p4, p5); - } - } - - @Override - public final void log( - String msg, - @Nullable Object p1, - @Nullable Object p2, - @Nullable Object p3, - @Nullable Object p4, - @Nullable Object p5, - @Nullable Object p6) { - if (shouldLog()) { - logImpl(msg, p1, p2, p3, p4, p5, p6); - } - } - - @Override - public final void log( - String msg, - @Nullable Object p1, - @Nullable Object p2, - @Nullable Object p3, - @Nullable Object p4, - @Nullable Object p5, - @Nullable Object p6, - @Nullable Object p7) { - if (shouldLog()) { - logImpl(msg, p1, p2, p3, p4, p5, p6, p7); - } - } - - @Override - public final void log( - String msg, - @Nullable Object p1, - @Nullable Object p2, - @Nullable Object p3, - @Nullable Object p4, - @Nullable Object p5, - @Nullable Object p6, - @Nullable Object p7, - @Nullable Object p8) { - if (shouldLog()) { - logImpl(msg, p1, p2, p3, p4, p5, p6, p7, p8); - } - } - - @Override - public final void log( - String msg, - @Nullable Object p1, - @Nullable Object p2, - @Nullable Object p3, - @Nullable Object p4, - @Nullable Object p5, - @Nullable Object p6, - @Nullable Object p7, - @Nullable Object p8, - @Nullable Object p9) { - if (shouldLog()) { - logImpl(msg, p1, p2, p3, p4, p5, p6, p7, p8, p9); - } - } - - @Override - public final void log( - String msg, - @Nullable Object p1, - @Nullable Object p2, - @Nullable Object p3, - @Nullable Object p4, - @Nullable Object p5, - @Nullable Object p6, - @Nullable Object p7, - @Nullable Object p8, - @Nullable Object p9, - @Nullable Object p10) { - if (shouldLog()) { - logImpl(msg, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); - } - } - - @Override - public final void log( - String msg, - @Nullable Object p1, - @Nullable Object p2, - @Nullable Object p3, - @Nullable Object p4, - @Nullable Object p5, - @Nullable Object p6, - @Nullable Object p7, - @Nullable Object p8, - @Nullable Object p9, - @Nullable Object p10, - Object... rest) { - if (shouldLog()) { - // Manually create a new varargs array and copy the parameters in. - var params = new Object[rest.length + 10]; - params[0] = p1; - params[1] = p2; - params[2] = p3; - params[3] = p4; - params[4] = p5; - params[5] = p6; - params[6] = p7; - params[7] = p8; - params[8] = p9; - params[9] = p10; - System.arraycopy(rest, 0, params, 10, rest.length); - logImpl(msg, params); - } - } - - @Override - public final void log(String message, char p1) { - if (shouldLog()) { - logImpl(message, p1); - } - } - - @Override - public final void log(String message, byte p1) { - if (shouldLog()) { - logImpl(message, p1); - } - } - - @Override - public final void log(String message, short p1) { - if (shouldLog()) { - logImpl(message, p1); - } - } - - @Override - public final void log(String message, int p1) { - if (shouldLog()) { - logImpl(message, p1); - } - } - - @Override - public final void log(String message, long p1) { - if (shouldLog()) { - logImpl(message, p1); - } - } - - @Override - public final void log(String message, @Nullable Object p1, boolean p2) { - if (shouldLog()) { - logImpl(message, p1, p2); - } - } - - @Override - public final void log(String message, @Nullable Object p1, char p2) { - if (shouldLog()) { - logImpl(message, p1, p2); - } - } - - @Override - public final void log(String message, @Nullable Object p1, byte p2) { - if (shouldLog()) { - logImpl(message, p1, p2); - } - } - - @Override - public final void log(String message, @Nullable Object p1, short p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + + @Override + public final void log() { + if (shouldLog()) { + logImpl(LITERAL_VALUE_MESSAGE, ""); + } + } + + @Override + public final void log(String msg) { + if (shouldLog()) { + logImpl(LITERAL_VALUE_MESSAGE, msg); + } + } + + @Override + public final void log(String message, @Nullable Object p1) { + if (shouldLog()) { + logImpl(message, p1); + } + } + + @Override + public final void log(String message, @Nullable Object p1, @Nullable Object p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } + } + + @Override + public final void log( + String message, @Nullable Object p1, @Nullable Object p2, @Nullable Object p3) { + if (shouldLog()) { + logImpl(message, p1, p2, p3); + } + } + + @Override + public final void log( + String message, + @Nullable Object p1, + @Nullable Object p2, + @Nullable Object p3, + @Nullable Object p4) { + if (shouldLog()) { + logImpl(message, p1, p2, p3, p4); + } + } + + @Override + public final void log( + String msg, + @Nullable Object p1, + @Nullable Object p2, + @Nullable Object p3, + @Nullable Object p4, + @Nullable Object p5) { + if (shouldLog()) { + logImpl(msg, p1, p2, p3, p4, p5); + } + } + + @Override + public final void log( + String msg, + @Nullable Object p1, + @Nullable Object p2, + @Nullable Object p3, + @Nullable Object p4, + @Nullable Object p5, + @Nullable Object p6) { + if (shouldLog()) { + logImpl(msg, p1, p2, p3, p4, p5, p6); + } + } + + @Override + public final void log( + String msg, + @Nullable Object p1, + @Nullable Object p2, + @Nullable Object p3, + @Nullable Object p4, + @Nullable Object p5, + @Nullable Object p6, + @Nullable Object p7) { + if (shouldLog()) { + logImpl(msg, p1, p2, p3, p4, p5, p6, p7); + } + } + + @Override + public final void log( + String msg, + @Nullable Object p1, + @Nullable Object p2, + @Nullable Object p3, + @Nullable Object p4, + @Nullable Object p5, + @Nullable Object p6, + @Nullable Object p7, + @Nullable Object p8) { + if (shouldLog()) { + logImpl(msg, p1, p2, p3, p4, p5, p6, p7, p8); + } } - } - @Override - public final void log(String message, @Nullable Object p1, int p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log( + String msg, + @Nullable Object p1, + @Nullable Object p2, + @Nullable Object p3, + @Nullable Object p4, + @Nullable Object p5, + @Nullable Object p6, + @Nullable Object p7, + @Nullable Object p8, + @Nullable Object p9) { + if (shouldLog()) { + logImpl(msg, p1, p2, p3, p4, p5, p6, p7, p8, p9); + } } - } - @Override - public final void log(String message, @Nullable Object p1, long p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log( + String msg, + @Nullable Object p1, + @Nullable Object p2, + @Nullable Object p3, + @Nullable Object p4, + @Nullable Object p5, + @Nullable Object p6, + @Nullable Object p7, + @Nullable Object p8, + @Nullable Object p9, + @Nullable Object p10) { + if (shouldLog()) { + logImpl(msg, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); + } } - } - @Override - public final void log(String message, @Nullable Object p1, float p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log( + String msg, + @Nullable Object p1, + @Nullable Object p2, + @Nullable Object p3, + @Nullable Object p4, + @Nullable Object p5, + @Nullable Object p6, + @Nullable Object p7, + @Nullable Object p8, + @Nullable Object p9, + @Nullable Object p10, + Object... rest) { + if (shouldLog()) { + // Manually create a new varargs array and copy the parameters in. + var params = new Object[rest.length + 10]; + params[0] = p1; + params[1] = p2; + params[2] = p3; + params[3] = p4; + params[4] = p5; + params[5] = p6; + params[6] = p7; + params[7] = p8; + params[8] = p9; + params[9] = p10; + System.arraycopy(rest, 0, params, 10, rest.length); + logImpl(msg, params); + } } - } - @Override - public final void log(String message, @Nullable Object p1, double p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, char p1) { + if (shouldLog()) { + logImpl(message, p1); + } } - } - @Override - public final void log(String message, boolean p1, @Nullable Object p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, byte p1) { + if (shouldLog()) { + logImpl(message, p1); + } } - } - @Override - public final void log(String message, char p1, @Nullable Object p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, short p1) { + if (shouldLog()) { + logImpl(message, p1); + } } - } - @Override - public final void log(String message, byte p1, @Nullable Object p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, int p1) { + if (shouldLog()) { + logImpl(message, p1); + } } - } - @Override - public final void log(String message, short p1, @Nullable Object p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, long p1) { + if (shouldLog()) { + logImpl(message, p1); + } } - } - @Override - public final void log(String message, int p1, @Nullable Object p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, @Nullable Object p1, boolean p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, long p1, @Nullable Object p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, @Nullable Object p1, char p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, float p1, @Nullable Object p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, @Nullable Object p1, byte p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, double p1, @Nullable Object p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, @Nullable Object p1, short p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, boolean p1, boolean p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, @Nullable Object p1, int p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, char p1, boolean p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, @Nullable Object p1, long p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, byte p1, boolean p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, @Nullable Object p1, float p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, short p1, boolean p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, @Nullable Object p1, double p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, int p1, boolean p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, boolean p1, @Nullable Object p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, long p1, boolean p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, char p1, @Nullable Object p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, float p1, boolean p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, byte p1, @Nullable Object p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, double p1, boolean p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, short p1, @Nullable Object p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, boolean p1, char p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, int p1, @Nullable Object p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, char p1, char p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, long p1, @Nullable Object p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, byte p1, char p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, float p1, @Nullable Object p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, short p1, char p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, double p1, @Nullable Object p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, int p1, char p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, boolean p1, boolean p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, long p1, char p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, char p1, boolean p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, float p1, char p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, byte p1, boolean p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, double p1, char p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, short p1, boolean p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, boolean p1, byte p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, int p1, boolean p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, char p1, byte p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, long p1, boolean p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, byte p1, byte p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, float p1, boolean p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, short p1, byte p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, double p1, boolean p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, int p1, byte p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, boolean p1, char p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, long p1, byte p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, char p1, char p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, float p1, byte p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, byte p1, char p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, double p1, byte p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, short p1, char p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, boolean p1, short p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, int p1, char p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, char p1, short p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, long p1, char p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, byte p1, short p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, float p1, char p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, short p1, short p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, double p1, char p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, int p1, short p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, boolean p1, byte p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, long p1, short p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, char p1, byte p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, float p1, short p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, byte p1, byte p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, double p1, short p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, short p1, byte p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, boolean p1, int p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, int p1, byte p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, char p1, int p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, long p1, byte p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, byte p1, int p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, float p1, byte p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, short p1, int p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, double p1, byte p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, int p1, int p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, boolean p1, short p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, long p1, int p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, char p1, short p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, float p1, int p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, byte p1, short p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } + } + + @Override + public final void log(String message, short p1, short p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } + } + + @Override + public final void log(String message, int p1, short p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } + } + + @Override + public final void log(String message, long p1, short p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } + } + + @Override + public final void log(String message, float p1, short p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } + } + + @Override + public final void log(String message, double p1, short p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } + } + + @Override + public final void log(String message, boolean p1, int p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, double p1, int p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, char p1, int p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } + } + + @Override + public final void log(String message, byte p1, int p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } + } + + @Override + public final void log(String message, short p1, int p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } + } + + @Override + public final void log(String message, int p1, int p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } + } + + @Override + public final void log(String message, long p1, int p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } + } + + @Override + public final void log(String message, float p1, int p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } + } + + @Override + public final void log(String message, double p1, int p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, boolean p1, long p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, boolean p1, long p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, char p1, long p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, char p1, long p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, byte p1, long p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, byte p1, long p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, short p1, long p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, short p1, long p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, int p1, long p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, int p1, long p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, long p1, long p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, long p1, long p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, float p1, long p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, float p1, long p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, double p1, long p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, double p1, long p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, boolean p1, float p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, boolean p1, float p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, char p1, float p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, char p1, float p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, byte p1, float p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, byte p1, float p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, short p1, float p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, short p1, float p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, int p1, float p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, int p1, float p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, long p1, float p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, long p1, float p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, float p1, float p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, float p1, float p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, double p1, float p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, double p1, float p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, boolean p1, double p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, boolean p1, double p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, char p1, double p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, char p1, double p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, byte p1, double p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, byte p1, double p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, short p1, double p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, short p1, double p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, int p1, double p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, int p1, double p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, long p1, double p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, long p1, double p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, float p1, double p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, float p1, double p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void log(String message, double p1, double p2) { - if (shouldLog()) { - logImpl(message, p1, p2); + @Override + public final void log(String message, double p1, double p2) { + if (shouldLog()) { + logImpl(message, p1, p2); + } } - } - @Override - public final void logVarargs(String message, @Nullable Object[] params) { - if (shouldLog()) { - // Copy the varargs array (because we didn't create it and this is quite a rare case). - logImpl(message, Arrays.copyOf(params, params.length)); + @Override + public final void logVarargs(String message, @Nullable Object[] params) { + if (shouldLog()) { + // Copy the varargs array (because we didn't create it and this is quite a rare case). + logImpl(message, Arrays.copyOf(params, params.length)); + } } - } } diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/LogPerBucketingStrategy.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/LogPerBucketingStrategy.java index 6f68edb69..6b4dcd0a9 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/LogPerBucketingStrategy.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/LogPerBucketingStrategy.java @@ -26,11 +26,12 @@ package io.spine.logging.jvm; -import static io.spine.logging.jvm.util.Checks.checkArgument; -import static io.spine.logging.jvm.util.Checks.checkNotNull; +import org.jspecify.annotations.Nullable; import java.util.HashMap; -import org.jspecify.annotations.Nullable; + +import static io.spine.logging.jvm.util.Checks.checkArgument; +import static io.spine.logging.jvm.util.Checks.checkNotNull; /** * Provides a strategy for "bucketing" a potentially unbounded set of log aggregation keys used by @@ -43,203 +44,226 @@ * different log sites. If a different instance is returned each time {@code apply()} is called, a * different instance will be held in each log site. This multiplies the amount of memory that is * retained indefinitely by any use of {@code LoggingApi.per(T, LogPerBucketingStrategy)}. - * + * *

      One way to handle arbitrary key types would be to create a strategy which "interns" instances * in some way, to produce singleton identifiers. Unfortunately interning can itself be a cause of * unbounded memory leaks, so a bucketing strategy wishing to perform interning should probably * support a user defined maximum capacity to limit the overall risk. If too many instances are * seen, the strategy should begin to return {@code null} (and log an appropriate warning). - * + * *

      The additional complexity created by this approach really tells us that types which require * interning in order to be used as aggregation keys should be considered unsuitable, and callers * should seek alternatives. * - * @see - * Original Java code of Google Flogger + * @see + * Original Java code of Google Flogger */ public abstract class LogPerBucketingStrategy { - private static final LogPerBucketingStrategy KNOWN_BOUNDED = - new LogPerBucketingStrategy("KnownBounded") { - @Override - protected Object apply(Object key) { - return key; - } - }; - - // The is a "safe" strategy as far as memory use is concerned since class objects are effectively - // singletons. - private static final LogPerBucketingStrategy BY_CLASS = - new LogPerBucketingStrategy("ByClass") { - @Override - protected Object apply(Object key) { - return key.getClass(); - } - }; - - // The is a "safe" strategy as far as memory use is concerned, because a class object returns the - // same string instance every time its called, and class objects are effectively singletons. - private static final LogPerBucketingStrategy BY_CLASS_NAME = - new LogPerBucketingStrategy("ByClassName") { - @Override - protected Object apply(Object key) { - // This is a naturally interned value, so no need to call intern(). - return key.getClass().getName(); + + private static final LogPerBucketingStrategy KNOWN_BOUNDED = + new LogPerBucketingStrategy<>("KnownBounded") { + @Override + protected Object apply(Object key) { + return key; + } + }; + + // The is a "safe" strategy as far as memory use is concerned since class objects + // are effectively singletons. + private static final LogPerBucketingStrategy BY_CLASS = + new LogPerBucketingStrategy<>("ByClass") { + @Override + protected Object apply(Object key) { + return key.getClass(); + } + }; + + // The is a "safe" strategy as far as memory use is concerned, because a class object returns the + // same string instance every time its called, and class objects are effectively singletons. + private static final LogPerBucketingStrategy BY_CLASS_NAME = + new LogPerBucketingStrategy<>("ByClassName") { + @Override + protected Object apply(Object key) { + // This is a naturally interned value, so no need to call intern(). + return key.getClass() + .getName(); + } + }; + + /** + * A strategy to use only if the set of log aggregation keys is known to be a strictly bounded + * set + * of instances with singleton semantics. + * + *

      WARNING: When using this strategy, keys passed to + * {@code LoggingApi.per(T, LogPerBucketingStrategy)} + * are used as-is by the log aggregation code, and held indefinitely by internal static data + * structures. + * As such it is vital that key instances used with this strategy have singleton semantics + * (i.e. if {@code k1.equals(k2)} then {@code k1== k2}). Failure to adhere to this requirement + * is likely to result in hard to detect memory leaks. + * + *

      If keys do not have singleton semantics then you should use a different strategy, such as + * {@link #byHashCode(int)} or {@link #byClass()}. + */ + public static final LogPerBucketingStrategy knownBounded() { + return KNOWN_BOUNDED; + } + + /** + * A strategy which uses the {@code Class} of the given key for log aggregation. This is useful + * when you need to aggregate over specific exceptions or similar type-distinguished instances. + * + *

      Note that using this strategy will result in a reference to the {@code Class} object of + * the + * key being retained indefinitely. This will prevent class unloading from occurring for + * affected + * classes, and it is up to the caller to decide if this is acceptable or not. + */ + public static final LogPerBucketingStrategy byClass() { + return BY_CLASS; + } + + /** + * A strategy which uses the {@code Class} name of the given key for log aggregation. This is + * useful when you need to aggregate over specific exceptions or similar type-distinguished + * instances. + * + *

      This is an alternative strategy to {@link #byClass()} which avoids holding onto the class + * instance and avoids any issues with class unloading. However it may conflate classes if + * applications use complex arrangements of custom of class-loaders, but this should be + * extremely rare. + */ + public static final LogPerBucketingStrategy byClassName() { + return BY_CLASS_NAME; + } + + /** + * A strategy defined for some given set of known keys. + * + *

      Unlike {@link #knownBounded()}, this strategy maps keys a bounded set of identifiers, and + * permits the use of non-singleton keys in + * {@code LoggingApi.per(T, LogPerBucketingStrategy)}. + * + *

      If keys outside this set are used this strategy returns {@code null}, and log aggregation + * will not occur. Duplicates in {@code knownKeys} are ignored. + */ + public static final LogPerBucketingStrategy forKnownKeys(Iterable knownKeys) { + final HashMap keyMap = new HashMap<>(); + StringBuilder name = new StringBuilder("ForKnownKeys("); + int index = 0; + for (Object key : knownKeys) { + checkNotNull(key, "key"); + if (!keyMap.containsKey(key)) { + name.append(index > 0 ? ", " : "") + .append(key); + keyMap.put(key, index++); + } } - }; - - /** - * A strategy to use only if the set of log aggregation keys is known to be a strictly bounded set - * of instances with singleton semantics. - * - *

      WARNING: When using this strategy, keys passed to {@code LoggingApi.per(T, LogPerBucketingStrategy)} - * are used as-is by the log aggregation code, and held indefinitely by internal static data structures. - * As such it is vital that key instances used with this strategy have singleton semantics - * (i.e. if {@code k1.equals(k2)} then {@code k1== k2}). Failure to adhere to this requirement - * is likely to result in hard to detect memory leaks. - * - *

      If keys do not have singleton semantics then you should use a different strategy, such as - * {@link #byHashCode(int)} or {@link #byClass()}. - */ - public static final LogPerBucketingStrategy knownBounded() { - return KNOWN_BOUNDED; - } - - /** - * A strategy which uses the {@code Class} of the given key for log aggregation. This is useful - * when you need to aggregate over specific exceptions or similar type-distinguished instances. - * - *

      Note that using this strategy will result in a reference to the {@code Class} object of the - * key being retained indefinitely. This will prevent class unloading from occurring for affected - * classes, and it is up to the caller to decide if this is acceptable or not. - */ - public static final LogPerBucketingStrategy byClass() { - return BY_CLASS; - } - - /** - * A strategy which uses the {@code Class} name of the given key for log aggregation. This is - * useful when you need to aggregate over specific exceptions or similar type-distinguished - * instances. - * - *

      This is an alternative strategy to {@link #byClass()} which avoids holding onto the class - * instance and avoids any issues with class unloading. However it may conflate classes if - * applications use complex arrangements of custom of class-loaders, but this should be extremely - * rare. - */ - public static final LogPerBucketingStrategy byClassName() { - return BY_CLASS_NAME; - } - - /** - * A strategy defined for some given set of known keys. - * - *

      Unlike {@link #knownBounded()}, this strategy maps keys a bounded set of identifiers, and - * permits the use of non-singleton keys in {@code LoggingApi.per(T, LogPerBucketingStrategy)}. - * - *

      If keys outside this set are used this strategy returns {@code null}, and log aggregation - * will not occur. Duplicates in {@code knownKeys} are ignored. - */ - public static final LogPerBucketingStrategy forKnownKeys(Iterable knownKeys) { - final HashMap keyMap = new HashMap(); - StringBuilder name = new StringBuilder("ForKnownKeys("); - int index = 0; - for (Object key : knownKeys) { - checkNotNull(key, "key"); - if (!keyMap.containsKey(key)) { - name.append(index > 0 ? ", " : "").append(key); - keyMap.put(key, index++); - } + checkArgument(!keyMap.isEmpty(), "knownKeys must not be empty"); + name.append(")"); + return new LogPerBucketingStrategy<>(name.toString()) { + @Override + @Nullable + protected Object apply(Object key) { + return keyMap.get(key); + } + }; + } + + /** + * A strategy which uses the {@code hashCode()} of a given key, modulo {@code maxBuckets}, for + * log + * aggregation. + * + *

      This is a fallback strategy for cases where the set of possible values is not known in + * advance, or could be arbirarily large in unusual circumstances. + * + *

      When using this method it is obviously important that the {@code hashCode()} method of + * the + * expected keys is well distributed, since duplicate hash codes, or hash codes congruent to + * {@code maxBuckets} will cause keys to be conflated. + * + *

      The caller is responsible for deciding the number of unique log aggregation keys this + * strategy can return. This choice is a trade-off between memory usage and the risk of + * conflating + * keys when performing log aggregation. Each log site using this strategy will hold up to + * {@code + * maxBuckets} distinct versions of log site information to allow rate limiting and other + * stateful + * operations to be applied separately per bucket. The overall allocation cost depends on the + * type + * of rate limiting used alongside this method, but it scales linearly with {@code maxBuckets}. + * + *

      It is recommended to keep the value of {@code maxBuckets} below 250, since this + * guarantees + * no additional allocations will occur when using this strategy, however the value chosen + * should + * be as small as practically possible for the typical expected number of unique keys. + * + *

      To avoid unwanted allocation at log sites, users are strongly encouraged to assign the + * returned value to a static field, and pass that to any log statements which need it. + */ + public static LogPerBucketingStrategy byHashCode(final int maxBuckets) { + checkArgument(maxBuckets > 0, "maxBuckets must be positive"); + return new LogPerBucketingStrategy<>("ByHashCode(" + maxBuckets + ')') { + @SuppressWarnings("MagicNumber") + @Override + protected Object apply(Object key) { + // Modulo can return -ve values and we want a value in the range (0 <= modulo < maxBuckets). + // Note: Math.floorMod() is Java 8, so cannot be used here (yet) otherwise we would just do: + // return Math.floorMod(key.hashCode(), maxBuckets) - 128; + int modulo = key.hashCode() % maxBuckets; + // Can only be -ve if the hashcode was negative, and if so (-maxBuckets < modulo < 0). + // The following adds maxBuckets if modulo was negative, or zero (saves a branch). + modulo += (modulo >> 31) & maxBuckets; + // Subtract 128 from the modulo in order to take full advantage of the promised Integer + // cache in the JVM (ensuring up to 256 cached values). From java.lang.Integer#valueOf(): + // ""This method will always cache values in the range -128 to 127 ..."" + return modulo - 128; + } + }; + } + + private final String name; + + /** Instantiates a strategy with the specified name (used for debugging). */ + protected LogPerBucketingStrategy(String name) { + this.name = checkNotNull(name, "name"); + } + + /** + * Maps a log aggregation key from a potentially unbounded set of key values to a bounded set + * of + * instances. + * + *

      Implementations of this method should be efficient, and avoid allocating memory wherever + * possible. The returned value must be an immutable identifier with minimal additional + * allocation + * requirements and ideally have singleton semantics (e.g. an {@code Enum} or {@code Integer} + * value). + * + *

      Warning: If keys are not known to have natural singleton semantics + * (e.g. {@code String}) then returning the given key instance is generally a bad idea. + * Even if the set of key values is small, the set of distinct allocated instances passed to + * {@link JvmApi#per(Object, LogPerBucketingStrategy)} can be unbounded, and that's what + * matters. + * As such, it is always better to map keys to some singleton identifier or intern the keys in + * some way. + * + * @param key + * a non-null key from a potentially unbounded set of log aggregation keys. + * @return an immutable value from some known bounded set, which will be held persistently by + * internal Flogger data structures as part of the log aggregation feature. If + * {@code null} is + * returned, the corresponding call to {@code per(key, STRATEGY)} has no effect. + */ + @Nullable + protected abstract Object apply(T key); + + @Override + public final String toString() { + return LogPerBucketingStrategy.class.getSimpleName() + '[' + name + ']'; } - checkArgument(!keyMap.isEmpty(), "knownKeys must not be empty"); - name.append(")"); - return new LogPerBucketingStrategy(name.toString()) { - @Override - @Nullable - protected Object apply(Object key) { - return keyMap.get(key); - } - }; - } - - /** - * A strategy which uses the {@code hashCode()} of a given key, modulo {@code maxBuckets}, for log - * aggregation. - * - *

      This is a fallback strategy for cases where the set of possible values is not known in - * advance, or could be arbirarily large in unusual circumstances. - * - *

      When using this method it is obviously important that the {@code hashCode()} method of the - * expected keys is well distributed, since duplicate hash codes, or hash codes congruent to - * {@code maxBuckets} will cause keys to be conflated. - * - *

      The caller is responsible for deciding the number of unique log aggregation keys this - * strategy can return. This choice is a trade-off between memory usage and the risk of conflating - * keys when performing log aggregation. Each log site using this strategy will hold up to {@code - * maxBuckets} distinct versions of log site information to allow rate limiting and other stateful - * operations to be applied separately per bucket. The overall allocation cost depends on the type - * of rate limiting used alongside this method, but it scales linearly with {@code maxBuckets}. - * - *

      It is recommended to keep the value of {@code maxBuckets} below 250, since this guarantees - * no additional allocations will occur when using this strategy, however the value chosen should - * be as small as practically possible for the typical expected number of unique keys. - * - *

      To avoid unwanted allocation at log sites, users are strongly encouraged to assign the - * returned value to a static field, and pass that to any log statements which need it. - */ - public static LogPerBucketingStrategy byHashCode(final int maxBuckets) { - checkArgument(maxBuckets > 0, "maxBuckets must be positive"); - return new LogPerBucketingStrategy("ByHashCode(" + maxBuckets + ')') { - @SuppressWarnings("MagicNumber") - @Override - protected Object apply(Object key) { - // Modulo can return -ve values and we want a value in the range (0 <= modulo < maxBuckets). - // Note: Math.floorMod() is Java 8, so cannot be used here (yet) otherwise we would just do: - // return Math.floorMod(key.hashCode(), maxBuckets) - 128; - int modulo = key.hashCode() % maxBuckets; - // Can only be -ve if the hashcode was negative, and if so (-maxBuckets < modulo < 0). - // The following adds maxBuckets if modulo was negative, or zero (saves a branch). - modulo += (modulo >> 31) & maxBuckets; - // Subtract 128 from the modulo in order to take full advantage of the promised Integer - // cache in the JVM (ensuring up to 256 cached values). From java.lang.Integer#valueOf(): - // ""This method will always cache values in the range -128 to 127 ..."" - return modulo - 128; - } - }; - } - - private final String name; - - /** Instantiates a strategy with the specified name (used for debugging). */ - protected LogPerBucketingStrategy(String name) { - this.name = checkNotNull(name, "name"); - } - - /** - * Maps a log aggregation key from a potentially unbounded set of key values to a bounded set of - * instances. - * - *

      Implementations of this method should be efficient, and avoid allocating memory wherever - * possible. The returned value must be an immutable identifier with minimal additional allocation - * requirements and ideally have singleton semantics (e.g. an {@code Enum} or {@code Integer} - * value). - * - *

      Warning: If keys are not known to have natural singleton semantics - * (e.g. {@code String}) then returning the given key instance is generally a bad idea. - * Even if the set of key values is small, the set of distinct allocated instances passed to - * {@link JvmApi#per(Object,LogPerBucketingStrategy)} can be unbounded, and that's what matters. - * As such, it is always better to map keys to some singleton identifier or intern the keys in - * some way. - * - * @param key a non-null key from a potentially unbounded set of log aggregation keys. - * @return an immutable value from some known bounded set, which will be held persistently by - * internal Flogger data structures as part of the log aggregation feature. If {@code null} is - * returned, the corresponding call to {@code per(key, STRATEGY)} has no effect. - */ - @Nullable - protected abstract Object apply(T key); - - @Override - public final String toString() { - return LogPerBucketingStrategy.class.getSimpleName() + '[' + name + ']'; - } } diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/LogSiteMap.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/LogSiteMap.java index f252c84e6..0f824d8e8 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/LogSiteMap.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/LogSiteMap.java @@ -26,11 +26,12 @@ package io.spine.logging.jvm; -import static io.spine.logging.jvm.util.Checks.checkNotNull; - import io.spine.logging.jvm.backend.Metadata; + import java.util.concurrent.ConcurrentHashMap; +import static io.spine.logging.jvm.util.Checks.checkNotNull; + /** * Provides per log site state for stateful fluent logging operations (e.g. rate limiting). * @@ -47,74 +48,78 @@ * and only used in the {@link LogContext#postProcess(LogSiteKey)} method, which supplies the key * appropriate for the current log statement. * - * @param The value type in the map. - * + * @param + * The value type in the map. * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger */ public abstract class LogSiteMap { - private final ConcurrentHashMap concurrentMap = - new ConcurrentHashMap(); - protected LogSiteMap() {} + private final ConcurrentHashMap concurrentMap = new ConcurrentHashMap<>(); - /** - * Implemented by subclasses to provide a new value for a newly added keys. This value is mapped - * to the key and cannot be replaced, so it is expected to be mutable and must be thread safe. - * All values in a {@code LogSiteMap} are expected to be the same type and have the same initial - * state. - */ - protected abstract V initialValue(); + protected LogSiteMap() { + } - // This method exists only for testing. Do not make this public. - boolean contains(LogSiteKey key) { - return concurrentMap.containsKey(key); - } + /** + * Implemented by subclasses to provide a new value for a newly added keys. This value is mapped + * to the key and cannot be replaced, so it is expected to be mutable and must be thread safe. + * All values in a {@code LogSiteMap} are expected to be the same type and have the same initial + * state. + */ + protected abstract V initialValue(); - /** - * Returns the mutable, thread safe, log site state for the given key to be read or updated during - * the {@link LogContext#postProcess(LogSiteKey)} method. - * - *

      Note that due to the possibility of log site key specialization, there may be more than one - * value in the map for any given log site. This is intended and allows for things like per scope - * rate limiting. - */ - public final V get(LogSiteKey key, Metadata metadata) { - V value = concurrentMap.get(key); - if (value != null) { - return value; + // This method exists only for testing. Do not make this public. + boolean contains(LogSiteKey key) { + return concurrentMap.containsKey(key); } - // Many threads can get here concurrently and attempt to add an initial value. - value = checkNotNull(initialValue(), "initial map value"); - V race = concurrentMap.putIfAbsent(key, value); - if (race != null) { - return race; + + /** + * Returns the mutable, thread safe, log site state for the given key to be read or updated + * during + * the {@link LogContext#postProcess(LogSiteKey)} method. + * + *

      Note that due to the possibility of log site key specialization, there may be more than + * one + * value in the map for any given log site. This is intended and allows for things like per + * scope + * rate limiting. + */ + public final V get(LogSiteKey key, Metadata metadata) { + V value = concurrentMap.get(key); + if (value != null) { + return value; + } + // Many threads can get here concurrently and attempt to add an initial value. + value = checkNotNull(initialValue(), "initial map value"); + V race = concurrentMap.putIfAbsent(key, value); + if (race != null) { + return race; + } + // Only one thread gets here for each log site key added to this map. + addRemovalHook(key, metadata); + return value; } - // Only one thread gets here for each log site key added to this map. - addRemovalHook(key, metadata); - return value; - } - private void addRemovalHook(final LogSiteKey key, Metadata metadata) { - Runnable removalHook = null; - for (int i = 0, count = metadata.size(); i < count; i++) { - if (!LogContext.Key.LOG_SITE_GROUPING_KEY.equals(metadata.getKey(i))) { - continue; - } - Object groupByKey = metadata.getValue(i); - if (!(groupByKey instanceof LoggingScope)) { - continue; - } - if (removalHook == null) { - // Non-static inner class references the outer LogSiteMap. - removalHook = new Runnable() { - @Override - public void run() { - concurrentMap.remove(key); - } - }; - } - ((LoggingScope) groupByKey).onClose(removalHook); + private void addRemovalHook(final LogSiteKey key, Metadata metadata) { + Runnable removalHook = null; + for (int i = 0, count = metadata.size(); i < count; i++) { + if (!LogContext.Key.LOG_SITE_GROUPING_KEY.equals(metadata.getKey(i))) { + continue; + } + Object groupByKey = metadata.getValue(i); + if (!(groupByKey instanceof LoggingScope)) { + continue; + } + if (removalHook == null) { + // Non-static inner class references the outer LogSiteMap. + removalHook = new Runnable() { + @Override + public void run() { + concurrentMap.remove(key); + } + }; + } + ((LoggingScope) groupByKey).onClose(removalHook); + } } - } } diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/LogSiteStackTrace.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/LogSiteStackTrace.java index bbc293306..c1d558a12 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/LogSiteStackTrace.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/LogSiteStackTrace.java @@ -28,17 +28,24 @@ import org.jspecify.annotations.Nullable; +import java.io.Serial; + /** * A synthetic exception which can be attached to log statements when additional stack trace * information is required in log files or via tools such as ECatcher. - *

      - * The name of this class may become relied upon implicitly by tools such as ECatcher. Do not + * + *

      The name of this class may become relied upon implicitly by tools such as ECatcher. Do not * rename or move this class without checking for implicit in logging tools. * * @see * Original Java code of Google Flogger */ +@SuppressWarnings("ExceptionClassNameDoesntEndWithException") public final class LogSiteStackTrace extends Exception { + + @Serial + private static final long serialVersionUID = 0L; + /** * Creates a synthetic exception to hold a call-stack generated for the log statement itself. *

      diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/RateLimitStatus.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/RateLimitStatus.java index a5ed6db14..46fc674bc 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/RateLimitStatus.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/RateLimitStatus.java @@ -27,9 +27,10 @@ package io.spine.logging.jvm; import io.spine.logging.jvm.backend.Metadata; +import org.jspecify.annotations.Nullable; + import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -import org.jspecify.annotations.Nullable; /** * Status for rate-limiting operations, usable by rate limiters and available to subclasses of @@ -116,159 +117,168 @@ * possible (since using explicit locking can cause unacceptable thread contention in highly * concurrent systems). * - * @see - * Original Java code of Google Flogger + * @see + * Original Java code of Google Flogger */ public abstract class RateLimitStatus { - /** - * The status to return whenever a rate limiter determines that logging should not occur. - * - *

      All other statuses implicity "allow" logging. - */ - public static final RateLimitStatus DISALLOW = sentinel(); - /** - * The status to return whenever a stateless rate limiter determines that logging should occur. - * - *

      Note: Truly stateless rate limiters should be very rare, since they cannot hold - * onto a pending "allow" state. Even a simple "sampling rate limiter" should be stateful if once - * the "allow" state is reached it continues to be returned until logging actually occurs. - */ - public static final RateLimitStatus ALLOW = sentinel(); + /** + * The status to return whenever a rate limiter determines that logging should not occur. + * + *

      All other statuses implicity "allow" logging. + */ + public static final RateLimitStatus DISALLOW = sentinel(); - private static RateLimitStatus sentinel() { - return new RateLimitStatus() { - @Override - public void reset() {} - }; - } + /** + * The status to return whenever a stateless rate limiter determines that logging should occur. + * + *

      Note: Truly stateless rate limiters should be very rare, since they cannot hold + * onto a pending "allow" state. Even a simple "sampling rate limiter" should be stateful if + * once + * the "allow" state is reached it continues to be returned until logging actually occurs. + */ + public static final RateLimitStatus ALLOW = sentinel(); - /** - * A log guard ensures that only one thread can claim "logging rights" for a log statement once an - * "allow" rate limit status is set. It also tracks the number of skipped invocations of the log - * site key. - * - *

      Note that the skipped count is tracked via the "log site key" and there may be several keys - * for a single log site (e.g. due to use of the {@code per(...)} methods). This is consistent - * with everywhere else which handles log site specific state, but does make it a little less - * obvious what the skipped count refers to at first glance. - */ - private static final class LogGuard { - private static final LogSiteMap guardMap = - new LogSiteMap() { - @Override - public LogGuard initialValue() { - return new LogGuard(); - } + private static RateLimitStatus sentinel() { + return new RateLimitStatus() { + @Override + public void reset() { + } }; - - private static int checkAndGetSkippedCount( - RateLimitStatus status, LogSiteKey logSiteKey, Metadata metadata) { - LogGuard guard = guardMap.get(logSiteKey, metadata); - // Pre-increment pendingCount to include this log statement, so (pendingCount > 0). - int pendingCount = guard.pendingLogCount.incrementAndGet(); - if (status == DISALLOW || !guard.shouldReset.compareAndSet(false, true)) { - return -1; - } - // Logging is allowed, and this thread has claimed the right to do it. - try { - status.reset(); - } finally { - guard.shouldReset.set(false); - } - // Subtract the pending count (this might not go to zero if other threads are incrementing). - guard.pendingLogCount.addAndGet(-pendingCount); - // Return the skipped log count (which must be >= 0). - return pendingCount - 1; } - private final AtomicBoolean shouldReset = new AtomicBoolean(); - private final AtomicInteger pendingLogCount = new AtomicInteger(); - } + /** + * A log guard ensures that only one thread can claim "logging rights" for a log statement once + * an + * "allow" rate limit status is set. It also tracks the number of skipped invocations of the + * log + * site key. + * + *

      Note that the skipped count is tracked via the "log site key" and there may be several + * keys + * for a single log site (e.g. due to use of the {@code per(...)} methods). This is consistent + * with everywhere else which handles log site specific state, but does make it a little less + * obvious what the skipped count refers to at first glance. + */ + private static final class LogGuard { - /** - * The rules for combining statuses are (in order): - * - *

        - *
      • If either value is {@code null}, the other value is returned (possibly {@code null}). - *
      • If either value is {@code ALLOW} (the constant), the other non-null value is returned. - *
      • If either value is {@code DISALLOW}, {@code DISALLOW} is returned. - *
      • Otherwise a combined status is returned from the two non-null "allow" statuses. - *
      - * - *

      In {@link LogContext} the {@code rateLimitStatus} field is set to the combined value of all - * rate limiter statuses. - * - *

      This ensures that after rate limit processing: - * - *

        - *
      1. If {@code rateLimitStatus == null} no rate limiters were applied, so logging is allowed. - *
      2. If {@code rateLimitStatus == DISALLOW}, the log was suppressed by rate limiting. - *
      3. Otherwise the log statement was allowed, but rate limiters must now be reset. - *
      - * - *

      This code ensures that in the normal case of having no rate limiting for a log statement, no - * allocations occur. It also ensures that (assuming well-written rate limiters) there are no - * allocations for log statements using a single rate limiter. - */ - @Nullable - static RateLimitStatus combine( - @Nullable final RateLimitStatus a, @Nullable final RateLimitStatus b) { - // In the vast majority of cases this code will be run once per log statement, and at least one - // of 'a' or 'b' will be null. So optimize early exiting for that case. - if (a == null) { - return b; - } - if (b == null) { - return a; - } - // This is already a rare situation where 2 rate limiters are active for the same log statement. - // However, in most of these cases, at least one will likley "disallow" logging. - if (a == DISALLOW || b == ALLOW) { - return a; - } - if (b == DISALLOW || a == ALLOW) { - return b; + private static final LogSiteMap guardMap = new LogSiteMap<>() { + @Override + public LogGuard initialValue() { + return new LogGuard(); + } + }; + + private static int checkAndGetSkippedCount( + RateLimitStatus status, LogSiteKey logSiteKey, Metadata metadata) { + var guard = guardMap.get(logSiteKey, metadata); + // Pre-increment pendingCount to include this log statement, so (pendingCount > 0). + var pendingCount = guard.pendingLogCount.incrementAndGet(); + if (status == DISALLOW || !guard.shouldReset.compareAndSet(false, true)) { + return -1; + } + // Logging is allowed, and this thread has claimed the right to do it. + try { + status.reset(); + } finally { + guard.shouldReset.set(false); + } + // Subtract the pending count (this might not go to zero if other threads are incrementing). + guard.pendingLogCount.addAndGet(-pendingCount); + // Return the skipped log count (which must be >= 0). + return pendingCount - 1; + } + + private final AtomicBoolean shouldReset = new AtomicBoolean(); + private final AtomicInteger pendingLogCount = new AtomicInteger(); } - // Getting here should be very rare and happens only when multiple rate limiters have reached - // the "pending" state and logging should occur. Neither status is null, ALLOW or DISALLOW. - return new RateLimitStatus() { - @Override - public void reset() { - // Make sure both statuses are reset regardless of errors. If both throw errors we only - // expose the 2nd one (we don't track "suppressed" exceptions). This is fine though since - // a reset() method should never risk throwing anything in the first place. - try { - a.reset(); - } finally { - b.reset(); + + /** + * The rules for combining statuses are (in order): + * + *

        + *
      • If either value is {@code null}, the other value is returned (possibly {@code null}). + *
      • If either value is {@code ALLOW} (the constant), the other non-null value is returned. + *
      • If either value is {@code DISALLOW}, {@code DISALLOW} is returned. + *
      • Otherwise a combined status is returned from the two non-null "allow" statuses. + *
      + * + *

      In {@link LogContext} the {@code rateLimitStatus} field is set to the combined value of all + * rate limiter statuses. + * + *

      This ensures that after rate limit processing: + * + *

        + *
      1. If {@code rateLimitStatus == null} no rate limiters were applied, so logging is allowed. + *
      2. If {@code rateLimitStatus == DISALLOW}, the log was suppressed by rate limiting. + *
      3. Otherwise the log statement was allowed, but rate limiters must now be reset. + *
      + * + *

      This code ensures that in the normal case of having no rate limiting for a log statement, no + * allocations occur. It also ensures that (assuming well-written rate limiters) there are no + * allocations for log statements using a single rate limiter. + */ + @Nullable + static RateLimitStatus combine( + @Nullable final RateLimitStatus a, @Nullable final RateLimitStatus b) { + // In the vast majority of cases this code will be run once per log statement, and at least one + // of 'a' or 'b' will be null. So optimize early exiting for that case. + if (a == null) { + return b; + } + if (b == null) { + return a; + } + // This is already a rare situation where 2 rate limiters are active for the same log statement. + // However, in most of these cases, at least one will likley "disallow" logging. + if (a == DISALLOW || b == ALLOW) { + return a; + } + if (b == DISALLOW || a == ALLOW) { + return b; } - } - }; - } + // Getting here should be very rare and happens only when multiple rate limiters have reached + // the "pending" state and logging should occur. Neither status is null, ALLOW or DISALLOW. + return new RateLimitStatus() { + @Override + public void reset() { + // Make sure both statuses are reset regardless of errors. If both throw errors we only + // expose the 2nd one (we don't track "suppressed" exceptions). This is fine though since + // a reset() method should never risk throwing anything in the first place. + try { + a.reset(); + } finally { + b.reset(); + } + } + }; + } - /** - * Checks rate limiter status and returns either the number of skipped log statements for the - * {@code logSiteKey} (indicating that this log statement should be emitted) or {@code -1} if it - * should be skipped. - */ - static int checkStatus(RateLimitStatus status, LogSiteKey logSiteKey, Metadata metadata) { - return LogGuard.checkAndGetSkippedCount(status, logSiteKey, metadata); - } + /** + * Checks rate limiter status and returns either the number of skipped log statements for the + * {@code logSiteKey} (indicating that this log statement should be emitted) or {@code -1} if it + * should be skipped. + */ + static int checkStatus(RateLimitStatus status, LogSiteKey logSiteKey, Metadata metadata) { + return LogGuard.checkAndGetSkippedCount(status, logSiteKey, metadata); + } - /** - * Rate limiters can extend this class directly if their "reset" operation is stateless, or they - * can create and return new instances to capture any necessary state. - */ - protected RateLimitStatus() {} + /** + * Rate limiters can extend this class directly if their "reset" operation is stateless, or they + * can create and return new instances to capture any necessary state. + */ + protected RateLimitStatus() { + } - /** - * Resets an associated rate limiter, moving it out of the "pending" state and back into rate - * limiting mode. - * - *

      Note: This method is never invoked concurrently with another {@code reset()} operation, but - * it can be concurrent with calls to update rate limiter state. Thus it must be thread safe in - * general, but can assume it's the only reset operation active for the limiter which returned it. - */ - protected abstract void reset(); + /** + * Resets an associated rate limiter, moving it out of the "pending" state and back into rate + * limiting mode. + * + *

      Note: This method is never invoked concurrently with another {@code reset()} operation, + * but it can be concurrent with calls to update rate limiter state. + * Thus, it must be thread safe in general, but can assume it is the only reset operation + * active for the limiter which returned it. + */ + protected abstract void reset(); } diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/SamplingRateLimiter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/SamplingRateLimiter.java index 944510f5f..e1fda7e93 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/SamplingRateLimiter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/SamplingRateLimiter.java @@ -26,6 +26,7 @@ package io.spine.logging.jvm; +import com.google.common.annotations.VisibleForTesting; import io.spine.logging.jvm.backend.Metadata; import org.jspecify.annotations.Nullable; @@ -43,59 +44,59 @@ * *

      This class is thread safe. * - * @see - * Original Java code of Google Flogger + * @see + * Original Java code of Google Flogger */ final class SamplingRateLimiter extends RateLimitStatus { - private static final LogSiteMap map = - new LogSiteMap() { - @Override - protected SamplingRateLimiter initialValue() { - return new SamplingRateLimiter(); - } - }; - @Nullable - static RateLimitStatus check(Metadata metadata, LogSiteKey logSiteKey) { - Integer rateLimitCount = metadata.findValue(LOG_SAMPLE_EVERY_N); - if (rateLimitCount == null || rateLimitCount <= 0) { - // Without valid rate limiter specific metadata, this limiter has no effect. - return null; - } - return map.get(logSiteKey, metadata).sampleOneIn(rateLimitCount); - } + private static final LogSiteMap map = + new LogSiteMap<>() { + @Override + protected SamplingRateLimiter initialValue() { + return new SamplingRateLimiter(); + } + }; - // Even though Random is synchonized, we have to put it in a ThreadLocal to avoid thread - // contention. We cannot use ThreadLocalRandom (yet) due to JDK level. - private static final ThreadLocal random = new ThreadLocal() { - @Override - protected Random initialValue() { - return new Random(); + @Nullable + static RateLimitStatus check(Metadata metadata, LogSiteKey logSiteKey) { + Integer rateLimitCount = metadata.findValue(LOG_SAMPLE_EVERY_N); + if (rateLimitCount == null || rateLimitCount <= 0) { + // Without valid rate limiter specific metadata, this limiter has no effect. + return null; + } + return map.get(logSiteKey, metadata) + .sampleOneIn(rateLimitCount); } - }; - // Visible for testing. - final AtomicInteger pendingCount = new AtomicInteger(); + // Even though Random is synchonized, we have to put it in a ThreadLocal to avoid thread + // contention. We cannot use ThreadLocalRandom (yet) due to JDK level. + private static final ThreadLocal random = ThreadLocal.withInitial(Random::new); - // Visible for testing. - SamplingRateLimiter() {} + @VisibleForTesting + final AtomicInteger pendingCount = new AtomicInteger(); - RateLimitStatus sampleOneIn(int rateLimitCount) { - // Always "roll the dice" and adjust the count if necessary (even if we were already - // pending). This means that in the long run we will account for every time we roll a - // zero and the number of logs will end up statistically close to 1-in-N (even if at - // times they can be "bursty" due to the action of other rate limiting mechanisms). - int pending; - if (random.get().nextInt(rateLimitCount) == 0) { - pending = pendingCount.incrementAndGet(); - } else { - pending = pendingCount.get(); + @VisibleForTesting + SamplingRateLimiter() { } - return pending > 0 ? this : DISALLOW; - } - @Override - public void reset() { - pendingCount.decrementAndGet(); - } + RateLimitStatus sampleOneIn(int rateLimitCount) { + // Always "roll the dice" and adjust the count if necessary (even if we were already + // pending). This means that in the long run we will account for every time we roll a + // zero, and the number of logs will end up statistically close to 1-in-N (even if at + // times they can be "bursty" due to the action of other rate limiting mechanisms). + int pending; + if (random.get() + .nextInt(rateLimitCount) == 0) { + pending = pendingCount.incrementAndGet(); + } else { + pending = pendingCount.get(); + } + return pending > 0 ? this : DISALLOW; + } + + @Override + public void reset() { + pendingCount.decrementAndGet(); + } } diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/SpecializedLogSiteKey.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/SpecializedLogSiteKey.java index 58e5292d9..738a39857 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/SpecializedLogSiteKey.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/SpecializedLogSiteKey.java @@ -58,7 +58,7 @@ public boolean equals(@Nullable Object obj) { if (!(obj instanceof SpecializedLogSiteKey)) { return false; } - SpecializedLogSiteKey other = (SpecializedLogSiteKey) obj; + var other = (SpecializedLogSiteKey) obj; return delegate.equals(other.delegate) && qualifier.equals(other.qualifier); } diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/StackBasedLogSite.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/StackBasedLogSite.java index f1592589f..719776fab 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/StackBasedLogSite.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/StackBasedLogSite.java @@ -26,11 +26,11 @@ package io.spine.logging.jvm; +import org.jspecify.annotations.Nullable; + import static io.spine.logging.jvm.util.Checks.checkNotNull; import static java.lang.Math.max; -import org.jspecify.annotations.Nullable; - /** * A stack based log site which uses information from a given {@code StackTraceElement}. * @@ -47,49 +47,51 @@ * generate a {@link JvmLogSite} from a {@link StackTraceElement}, use {@link * JvmLogSites#logSiteFrom(StackTraceElement) LogSites.logSiteFrom(myStackTaceElement)}. * - * @see - * Original Java code of Google Flogger + * @see + * Original Java code of Google Flogger */ final class StackBasedLogSite extends JvmLogSite { - // StackTraceElement is unmodifiable once created. - private final StackTraceElement stackElement; - public StackBasedLogSite(StackTraceElement stackElement) { - this.stackElement = checkNotNull(stackElement, "stack element"); - } + // StackTraceElement is unmodifiable once created. + private final StackTraceElement stackElement; + + public StackBasedLogSite(StackTraceElement stackElement) { + this.stackElement = checkNotNull(stackElement, "stack element"); + } - @Override - public String getClassName() { - return stackElement.getClassName(); - } + @Override + public String getClassName() { + return stackElement.getClassName(); + } - @Override - public String getMethodName() { - return stackElement.getMethodName(); - } + @Override + public String getMethodName() { + return stackElement.getMethodName(); + } - @Override - public int getLineNumber() { - // Prohibit negative numbers (which can appear in stack trace elements) from being returned. - return max(stackElement.getLineNumber(), JvmLogSite.UNKNOWN_LINE); - } + @Override + public int getLineNumber() { + // Prohibit negative numbers (which can appear in stack trace elements) from being returned. + return max(stackElement.getLineNumber(), UNKNOWN_LINE); + } - @Override - public String getFileName() { - return stackElement.getFileName(); - } + @Override + public String getFileName() { + return stackElement.getFileName(); + } - @Override - public boolean equals(@Nullable Object obj) { - return (obj instanceof StackBasedLogSite) - && stackElement.equals(((StackBasedLogSite) obj).stackElement); - } + @Override + public boolean equals(@Nullable Object obj) { + return (obj instanceof StackBasedLogSite) + && stackElement.equals(((StackBasedLogSite) obj).stackElement); + } - @Override - public int hashCode() { - // Note that (unlike other log site implementations) this hash-code appears to include the - // file name when creating a hashcode, but this should be the same every time a stack trace - // element is created, so it shouldn't be a problem. - return stackElement.hashCode(); - } + @Override + public int hashCode() { + // Note that (unlike other log site implementations) this hash-code appears to include the + // file name when creating a hashcode, but this should be the same every time a stack trace + // element is created, so it shouldn't be a problem. + return stackElement.hashCode(); + } } diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/BaseMessageFormatter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/BaseMessageFormatter.java index f65cef5ca..2aa1086eb 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/BaseMessageFormatter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/BaseMessageFormatter.java @@ -26,18 +26,19 @@ package io.spine.logging.jvm.backend; -import static io.spine.logging.jvm.backend.FormatOptions.FLAG_UPPER_CASE; -import static io.spine.logging.jvm.util.Checks.checkNotNull; - +import com.google.errorprone.annotations.CanIgnoreReturnValue; import io.spine.logging.jvm.parameter.DateTimeFormat; import io.spine.logging.jvm.parameter.Parameter; import io.spine.logging.jvm.parameter.ParameterVisitor; import io.spine.logging.jvm.parser.MessageBuilder; -import com.google.errorprone.annotations.CanIgnoreReturnValue; + import java.util.Calendar; import java.util.Date; import java.util.Formattable; +import static io.spine.logging.jvm.backend.FormatOptions.FLAG_UPPER_CASE; +import static io.spine.logging.jvm.util.Checks.checkNotNull; + /** * The default formatter for log messages and arguments. * @@ -46,201 +47,208 @@ * {@link #appendFormattedMessage(LogData, StringBuilder)}. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger */ public class BaseMessageFormatter extends MessageBuilder - implements ParameterVisitor { - - // Literal string to be inlined whenever a placeholder references a non-existent argument. - private static final String MISSING_ARGUMENT_MESSAGE = "[ERROR: MISSING LOG ARGUMENT]"; - - // Literal string to be appended wherever additional unused arguments are provided. - private static final String EXTRA_ARGUMENT_MESSAGE = " [ERROR: UNUSED LOG ARGUMENTS]"; - - /** - * Appends the formatted log message of the given log data to the given buffer. - * - *

      Note that the {@link LogData} need not have a template context or arguments, it might just - * have a literal argument, which will be appended without additional formatting. - * - * @param data the log data with the message to be appended. - * @param out a buffer to append to. - * @return the given buffer (for method chaining). - */ - @CanIgnoreReturnValue - public static StringBuilder appendFormattedMessage(LogData data, StringBuilder out) { - if (data.getTemplateContext() != null) { - BaseMessageFormatter formatter = - new BaseMessageFormatter(data.getTemplateContext(), data.getArguments(), out); - out = formatter.build(); - if (data.getArguments().length > formatter.getExpectedArgumentCount()) { - // TODO(dbeaumont): Do better and look at adding formatted values or maybe just a count? - out.append(EXTRA_ARGUMENT_MESSAGE); - } - } else { - out.append(MessageUtils.safeToString(data.getLiteralArgument())); + implements ParameterVisitor { + + // Literal string to be inlined whenever a placeholder references a non-existent argument. + private static final String MISSING_ARGUMENT_MESSAGE = "[ERROR: MISSING LOG ARGUMENT]"; + + // Literal string to be appended wherever additional unused arguments are provided. + private static final String EXTRA_ARGUMENT_MESSAGE = " [ERROR: UNUSED LOG ARGUMENTS]"; + + /** + * Appends the formatted log message of the given log data to the given buffer. + * + *

      Note that the {@link LogData} need not have a template context or arguments, it might just + * have a literal argument, which will be appended without additional formatting. + * + * @param data + * the log data with the message to be appended. + * @param out + * a buffer to append to. + * @return the given buffer (for method chaining). + */ + @CanIgnoreReturnValue + public static StringBuilder appendFormattedMessage(LogData data, StringBuilder out) { + if (data.getTemplateContext() != null) { + var formatter = + new BaseMessageFormatter(data.getTemplateContext(), data.getArguments(), out); + out = formatter.build(); + if (data.getArguments().length > formatter.getExpectedArgumentCount()) { + // TODO(dbeaumont): Do better and look at adding formatted values or maybe just a count? + out.append(EXTRA_ARGUMENT_MESSAGE); + } + } else { + out.append(MessageUtils.safeToString(data.getLiteralArgument())); + } + return out; } - return out; - } - - // Input argument array reference (not copied). - protected final Object[] args; - // Buffer into which the message is formatted. - protected final StringBuilder out; - // The start of the next literal sub-section of the message that needs processing. - private int literalStart = 0; - - protected BaseMessageFormatter(TemplateContext context, Object[] args, StringBuilder out) { - super(context); - this.args = checkNotNull(args, "arguments"); - this.out = checkNotNull(out, "buffer"); - } - - private static void appendFormatted( - StringBuilder out, Object value, FormatChar format, FormatOptions options) { - // Fast path switch statement for commonest cases (we could handle upper-case as a post - // processing step but it's so uncommon it doesn't seem worth it). - // - // Cases and logic within cases are strictly ordered by likelihood to reduce branching (e.g. - // normal String formatting corresponding to "%s" comes before worrying about Formattable, which - // is hardly ever used). - // - // Case statements should consist of a series of if-statements, with code blocks ordered by - // likelihood (each of which returns with a result) and a single final 'break' statement to fall - // through to the general case logic for anything otherwise unhandled. - // - // Most non-default format options (e.g. "%02d") or rare format specifiers are handled by - // breaking from the switch statement, which falls into the generic formatting logic. Anything - // handled explicitly should return instead. - switch (format) { - case STRING: - // String formatting is by far and away the most common case. - if (!(value instanceof Formattable)) { - if (options.isDefault()) { - // %s on a non-Formattable instance is the single most common case by far. - out.append(MessageUtils.safeToString(value)); - return; - } - break; + + // Input argument array reference (not copied). + protected final Object[] args; + // Buffer into which the message is formatted. + protected final StringBuilder out; + // The start of the next literal sub-section of the message that needs processing. + private int literalStart = 0; + + protected BaseMessageFormatter(TemplateContext context, Object[] args, StringBuilder out) { + super(context); + this.args = checkNotNull(args, "arguments"); + this.out = checkNotNull(out, "buffer"); + } + + private static void appendFormatted( + StringBuilder out, Object value, FormatChar format, FormatOptions options) { + // Fast path switch statement for commonest cases (we could handle upper-case as a post + // processing step but it's so uncommon it doesn't seem worth it). + // + // Cases and logic within cases are strictly ordered by likelihood to reduce branching (e.g. + // normal String formatting corresponding to "%s" comes before worrying about Formattable, which + // is hardly ever used). + // + // Case statements should consist of a series of if-statements, with code blocks ordered by + // likelihood (each of which returns with a result) and a single final 'break' statement to fall + // through to the general case logic for anything otherwise unhandled. + // + // Most non-default format options (e.g. "%02d") or rare format specifiers are handled by + // breaking from the switch statement, which falls into the generic formatting logic. Anything + // handled explicitly should return instead. + switch (format) { + case STRING: + // String formatting is by far and away the most common case. + if (!(value instanceof Formattable)) { + if (options.isDefault()) { + // %s on a non-Formattable instance is the single most common case by far. + out.append(MessageUtils.safeToString(value)); + return; + } + break; + } + // Rare but easy to deal with efficiently, and a can support wrapped arguments nicely. + MessageUtils.safeFormatTo((Formattable) value, out, options); + return; + + // Some other types are really easy when they don't have special format options. + case DECIMAL: + case BOOLEAN: + if (options.isDefault()) { + out.append(value); + return; + } + break; + + case HEX: + // Check that if the format options are compatible with "easy" hex formatting. This could + // be expanded to include width, radix and zero padding (relatively common for hex). + if (options.filter(FLAG_UPPER_CASE, false, false) + .equals(options)) { + // Since canFormat() was called before this method, the value must be a Number. + MessageUtils.appendHex(out, (Number) value, options); + return; + } + break; + + case CHAR: + // %c/%C formatting is a little subtle since an Integer or Long can represent a code-point + // resulting in more than one UTF-16 "char". + if (options.isDefault()) { + if (value instanceof Character) { + out.append(value); + return; + } + // Since canFormat() was called before this method, value must be a non-negative Number. + var codePoint = ((Number) value).intValue(); + if ((codePoint >>> 16) == 0) { + out.append((char) codePoint); + return; + } + out.append(Character.toChars(codePoint)); + return; + } + break; + + default: + // Fall through. } - // Rare but easy to deal with efficiently, and a can support wrapped arguments nicely. - MessageUtils.safeFormatTo((Formattable) value, out, options); - return; - - // Some other types are really easy when they don't have special format options. - case DECIMAL: - case BOOLEAN: - if (options.isDefault()) { - out.append(value); - return; + // Default handle for rare cases that need non-trivial formatting. + var formatString = format.getDefaultFormatString(); + if (!options.isDefault()) { + var chr = format.getChar(); + if (options.shouldUpperCase()) { + // Clear 6th bit to convert lower case ASCII to upper case. + chr &= (char) ~0x20; + } + formatString = options.appendPrintfOptions(new StringBuilder("%")) + .append(chr) + .toString(); } - break; - - case HEX: - // Check that if the format options are compatible with "easy" hex formatting. This could - // be expanded to include width, radix and zero padding (relatively common for hex). - if (options.filter(FLAG_UPPER_CASE, false, false).equals(options)) { - // Since canFormat() was called before this method, the value must be a Number. - MessageUtils.appendHex(out, (Number) value, options); - return; + out.append(String.format(MessageUtils.FORMAT_LOCALE, formatString, value)); + } + + @Override + public void addParameterImpl(int termStart, int termEnd, Parameter param) { + getParser().unescape(out, getMessage(), literalStart, termStart); + param.accept(this, args); + literalStart = termEnd; + } + + @Override + public StringBuilder buildImpl() { + getParser().unescape(out, getMessage(), literalStart, getMessage().length()); + return out; + } + + @Override + public void visit(Object value, FormatChar format, FormatOptions options) { + if (format.getType() + .canFormat(value)) { + appendFormatted(out, value, format, options); + } else { + appendInvalid(out, value, format.getDefaultFormatString()); } - break; - - case CHAR: - // %c/%C formatting is a little subtle since an Integer or Long can represent a code-point - // resulting in more than one UTF-16 "char". - if (options.isDefault()) { - if (value instanceof Character) { - out.append(value); - return; - } - // Since canFormat() was called before this method, value must be a non-negative Number. - int codePoint = ((Number) value).intValue(); - if ((codePoint >>> 16) == 0) { - out.append((char) codePoint); - return; - } - out.append(Character.toChars(codePoint)); - return; + } + + @Override + public void visitDateTime(Object value, DateTimeFormat format, FormatOptions options) { + if (value instanceof Date || value instanceof Calendar || value instanceof Long) { + var formatString = + options + .appendPrintfOptions(new StringBuilder("%")) + .append(options.shouldUpperCase() ? 'T' : 't') + .append(format.getChar()) + .toString(); + out.append(String.format(MessageUtils.FORMAT_LOCALE, formatString, value)); + } else { + appendInvalid(out, value, "%t" + format.getChar()); } - break; + } - default: - // Fall through. + @Override + public void visitPreformatted(Object value, String formatted) { + // For unstructured logging we just use the pre-formatted string. + out.append(formatted); } - // Default handle for rare cases that need non-trivial formatting. - String formatString = format.getDefaultFormatString(); - if (!options.isDefault()) { - char chr = format.getChar(); - if (options.shouldUpperCase()) { - // Clear 6th bit to convert lower case ASCII to upper case. - chr &= (char) ~0x20; - } - formatString = options.appendPrintfOptions(new StringBuilder("%")).append(chr).toString(); + + @Override + public void visitMissing() { + out.append(MISSING_ARGUMENT_MESSAGE); } - out.append(String.format(MessageUtils.FORMAT_LOCALE, formatString, value)); - } - - @Override - public void addParameterImpl(int termStart, int termEnd, Parameter param) { - getParser().unescape(out, getMessage(), literalStart, termStart); - param.accept(this, args); - literalStart = termEnd; - } - - @Override - public StringBuilder buildImpl() { - getParser().unescape(out, getMessage(), literalStart, getMessage().length()); - return out; - } - - @Override - public void visit(Object value, FormatChar format, FormatOptions options) { - if (format.getType().canFormat(value)) { - appendFormatted(out, value, format, options); - } else { - BaseMessageFormatter.appendInvalid(out, value, format.getDefaultFormatString()); + + @Override + public void visitNull() { + out.append("null"); } - } - - @Override - public void visitDateTime(Object value, DateTimeFormat format, FormatOptions options) { - if (value instanceof Date || value instanceof Calendar || value instanceof Long) { - String formatString = - options - .appendPrintfOptions(new StringBuilder("%")) - .append(options.shouldUpperCase() ? 'T' : 't') - .append(format.getChar()) - .toString(); - out.append(String.format(MessageUtils.FORMAT_LOCALE, formatString, value)); - } else { - BaseMessageFormatter.appendInvalid(out, value, "%t" + format.getChar()); + + private static void appendInvalid(StringBuilder out, Object value, String formatString) { + out.append("[INVALID: format=") + .append(formatString) + .append(", type=") + .append(value.getClass() + .getCanonicalName()) + .append(", value=") + .append(MessageUtils.safeToString(value)) + .append(']'); } - } - - @Override - public void visitPreformatted(Object value, String formatted) { - // For unstructured logging we just use the pre-formatted string. - out.append(formatted); - } - - @Override - public void visitMissing() { - out.append(MISSING_ARGUMENT_MESSAGE); - } - - @Override - public void visitNull() { - out.append("null"); - } - - private static void appendInvalid(StringBuilder out, Object value, String formatString) { - out.append("[INVALID: format=") - .append(formatString) - .append(", type=") - .append(value.getClass().getCanonicalName()) - .append(", value=") - .append(MessageUtils.safeToString(value)) - .append("]"); - } } diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatChar.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatChar.java index 67c473f21..756e81e28 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatChar.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatChar.java @@ -26,6 +26,8 @@ package io.spine.logging.jvm.backend; +import org.jspecify.annotations.Nullable; + /** * An enum representing the printf-like formatting characters that must be supported by all logging * backends. It is important to note that while backends must accept any of these format specifiers, @@ -35,171 +37,177 @@ * normal '%X' form (including flags, width and precision). Custom messages parsers must convert * arguments into one of these forms before passing then through to the backend. * - * @see - * Original Java code of Google Flogger + * @see + * Original Java code of Google Flogger */ public enum FormatChar { - /** - * Formats the argument in a manner specific to the chosen logging backend. In many cases this - * will be equivalent to using {@code STRING}, but it allows backend implementations to log more - * structured representations of known types. - *

      - * This is a non-numeric format with an upper-case variant. - */ - STRING('s', FormatType.GENERAL, "-#", true /* upper-case variant */), - - /** - * Formats the argument as a boolean. - *

      - * This is a non-numeric format with an upper-case variant. - */ - BOOLEAN('b', FormatType.BOOLEAN, "-", true /* upper-case variant */), - - /** - * Formats a Unicode code-point. This formatting rule can be applied to any character or integral - * numeric value, providing that {@link Character#isValidCodePoint(int)} returns true. Note that - * if the argument cannot be represented losslessly as an integer, it must be considered invalid. - *

      - * This is a non-numeric format with an upper-case variant. - */ - CHAR('c', FormatType.CHARACTER, "-", true /* upper-case variant */), - - /** - * Formats the argument as a decimal integer. - *

      - * This is a numeric format. - */ - DECIMAL('d', FormatType.INTEGRAL, "-0+ ,(", false /* lower-case only */), - - /** - * Formats the argument as an unsigned octal integer. - *

      - * This is a numeric format. - *

      - * '(' is only supported for {@link java.math.BigInteger} or {@link java.math.BigDecimal} - */ - OCTAL('o', FormatType.INTEGRAL, "-#0(", false /* lower-case only */), - - /** - * Formats the argument as an unsigned hexadecimal integer. - *

      - * This is a numeric format with an upper-case variant. - *

      - * '(' is only supported for {@link java.math.BigInteger} or {@link java.math.BigDecimal} - */ - HEX('x', FormatType.INTEGRAL, "-#0(", true /* upper-case variant */), - - /** - * Formats the argument as a signed decimal floating value. - *

      - * This is a numeric format. - */ - FLOAT('f', FormatType.FLOAT, "-#0+ ,(", false /* lower-case only */), - - /** - * Formats the argument using computerized scientific notation. - *

      - * This is a numeric format with an upper-case variant. - */ - EXPONENT('e', FormatType.FLOAT, "-#0+ (", true /* upper-case variant */), - - /** - * Formats the argument using general scientific notation. - *

      - * This is a numeric format with an upper-case variant. - */ - GENERAL('g', FormatType.FLOAT, "-0+ ,(", true /* upper-case variant */), - - /** - * Formats the argument using hexadecimal exponential form. This formatting option is primarily - * useful when debugging issues with the precise bit-wise representation of doubles because no - * rounding of the value takes place. - *

      - * This is a numeric format with an upper-case variant. - */ - // Note: This could be optimized with Double.toHexString() but this parameter is hardly ever used. - EXPONENT_HEX('a', FormatType.FLOAT, "-#0+ ", true /* upper-case variant */); - - // Returns the numeric index [0-25] of a given ASCII letter (upper or lower case). If the given - // value is not an ASCII letter, the returned value is not in the range 0-25. - private static int indexOf(char letter) { - return (letter | 0x20) - 'a'; - } - - // Returns whether a given ASCII letter is lower case. - private static boolean isLowerCase(char letter) { - return (letter & 0x20) != 0; - } - - // A direct mapping from character offset to FormatChar instance. Have all 26 letters accounted - // for because we know that the caller has already checked that this is an ASCII letter. - // This mapping needs to be fast as it's called for every argument in every log message. - private static final FormatChar[] MAP = new FormatChar[26]; - static { - for (FormatChar fc : values()) { - MAP[indexOf(fc.getChar())] = fc; + /** + * Formats the argument in a manner specific to the chosen logging backend. In many cases this + * will be equivalent to using {@code STRING}, but it allows backend implementations to log more + * structured representations of known types. + *

      + * This is a non-numeric format with an upper-case variant. + */ + STRING('s', FormatType.GENERAL, "-#", true /* upper-case variant */), + + /** + * Formats the argument as a boolean. + *

      + * This is a non-numeric format with an upper-case variant. + */ + BOOLEAN('b', FormatType.BOOLEAN, "-", true /* upper-case variant */), + + /** + * Formats a Unicode code-point. This formatting rule can be applied to any character or + * integral + * numeric value, providing that {@link Character#isValidCodePoint(int)} returns true. Note + * that + * if the argument cannot be represented losslessly as an integer, it must be considered + * invalid. + *

      + * This is a non-numeric format with an upper-case variant. + */ + CHAR('c', FormatType.CHARACTER, "-", true /* upper-case variant */), + + /** + * Formats the argument as a decimal integer. + *

      + * This is a numeric format. + */ + DECIMAL('d', FormatType.INTEGRAL, "-0+ ,(", false /* lower-case only */), + + /** + * Formats the argument as an unsigned octal integer. + *

      + * This is a numeric format. + *

      + * '(' is only supported for {@link java.math.BigInteger} or {@link java.math.BigDecimal} + */ + OCTAL('o', FormatType.INTEGRAL, "-#0(", false /* lower-case only */), + + /** + * Formats the argument as an unsigned hexadecimal integer. + *

      + * This is a numeric format with an upper-case variant. + *

      + * '(' is only supported for {@link java.math.BigInteger} or {@link java.math.BigDecimal} + */ + HEX('x', FormatType.INTEGRAL, "-#0(", true /* upper-case variant */), + + /** + * Formats the argument as a signed decimal floating value. + *

      + * This is a numeric format. + */ + FLOAT('f', FormatType.FLOAT, "-#0+ ,(", false /* lower-case only */), + + /** + * Formats the argument using computerized scientific notation. + *

      + * This is a numeric format with an upper-case variant. + */ + EXPONENT('e', FormatType.FLOAT, "-#0+ (", true /* upper-case variant */), + + /** + * Formats the argument using general scientific notation. + *

      + * This is a numeric format with an upper-case variant. + */ + GENERAL('g', FormatType.FLOAT, "-0+ ,(", true /* upper-case variant */), + + /** + * Formats the argument using hexadecimal exponential form. This formatting option is primarily + * useful when debugging issues with the precise bit-wise representation of doubles because no + * rounding of the value takes place. + *

      + * This is a numeric format with an upper-case variant. + */ + // Note: This could be optimized with Double.toHexString() but this parameter is hardly ever used. + EXPONENT_HEX('a', FormatType.FLOAT, "-#0+ ", true /* upper-case variant */); + + // Returns the numeric index [0-25] of a given ASCII letter (upper or lower case). If the given + // value is not an ASCII letter, the returned value is not in the range 0-25. + private static int indexOf(char letter) { + return (letter | 0x20) - 'a'; + } + + // Returns whether a given ASCII letter is lower case. + private static boolean isLowerCase(char letter) { + return (letter & 0x20) != 0; + } + + // A direct mapping from character offset to FormatChar instance. Have all 26 letters accounted + // for because we know that the caller has already checked that this is an ASCII letter. + // This mapping needs to be fast as it's called for every argument in every log message. + private static final FormatChar[] MAP = new FormatChar[26]; + + static { + for (var fc : values()) { + MAP[indexOf(fc.getChar())] = fc; + } + } + + /** + * Returns the FormatChar instance associated with the given printf format specifier. + * If the given character is not an ASCII letter, a runtime exception is thrown. + */ + public static @Nullable FormatChar of(char c) { + // Get from the map by converting the char to lower-case (which is the most common case by far). + // If the given value wasn't an ASCII letter then the index will be out-of-range, but when + // called by the parser, it's always guaranteed to be an ASCII letter (but perhaps not a valid + // format character). + var fc = MAP[indexOf(c)]; + if (isLowerCase(c)) { + // If we were given a lower case char to find, we're done (even if the result is null). + return fc; + } + // Otherwise handle the case where we found a lower-case format char but no upper-case one. + return (fc != null && fc.hasUpperCaseVariant()) ? fc : null; + } + + private final char formatChar; + private final FormatType type; + private final int allowedFlags; + private final String defaultFormatString; + + FormatChar(char c, FormatType type, String allowedFlagChars, boolean hasUpperCaseVariant) { + this.formatChar = c; + this.type = type; + this.allowedFlags = FormatOptions.parseValidFlags(allowedFlagChars, hasUpperCaseVariant); + this.defaultFormatString = "%" + c; + } + + /** + * Returns the lower-case printf style formatting character. + *

      + * Note that as this enumeration is not a subset of any other common formatting syntax, it is + * not + * safe to assume that this character can be used to construct a formatting string to pass to + * other formatting libraries. + */ + public char getChar() { + return formatChar; + } + + /** Returns the general format type for this character. */ + public FormatType getType() { + return type; } - } - - /** - * Returns the FormatChar instance associated with the given printf format specifier. If the - * given character is not an ASCII letter, a runtime exception is thrown. - */ - public static FormatChar of(char c) { - // Get from the map by converting the char to lower-case (which is the most common case by far). - // If the given value wasn't an ASCII letter then the index will be out-of-range, but when - // called by the parser, it's always guaranteed to be an ASCII letter (but perhaps not a valid - // format character). - FormatChar fc = MAP[indexOf(c)]; - if (isLowerCase(c)) { - // If we were given a lower case char to find, we're done (even if the result is null). - return fc; + + /** + * Returns the allowed flag characters as a string. This is package private to hide the precise + * implementation of how we parse and manage formatting options. + */ + int getAllowedFlags() { + return allowedFlags; + } + + private boolean hasUpperCaseVariant() { + return (allowedFlags & FormatOptions.FLAG_UPPER_CASE) != 0; + } + + public String getDefaultFormatString() { + return defaultFormatString; } - // Otherwise handle the case where we found a lower-case format char but no upper-case one. - return (fc != null && fc.hasUpperCaseVariant()) ? fc : null; - } - - private final char formatChar; - private final FormatType type; - private final int allowedFlags; - private final String defaultFormatString; - - FormatChar(char c, FormatType type, String allowedFlagChars, boolean hasUpperCaseVariant) { - this.formatChar = c; - this.type = type; - this.allowedFlags = FormatOptions.parseValidFlags(allowedFlagChars, hasUpperCaseVariant); - this.defaultFormatString = "%" + c; - } - - /** - * Returns the lower-case printf style formatting character. - *

      - * Note that as this enumeration is not a subset of any other common formatting syntax, it is not - * safe to assume that this character can be used to construct a formatting string to pass to - * other formatting libraries. - */ - public char getChar() { - return formatChar; - } - - /** Returns the general format type for this character. */ - public FormatType getType() { - return type; - } - - /** - * Returns the allowed flag characters as a string. This is package private to hide the precise - * implementation of how we parse and manage formatting options. - */ - int getAllowedFlags() { - return allowedFlags; - } - - private boolean hasUpperCaseVariant() { - return (allowedFlags & FormatOptions.FLAG_UPPER_CASE) != 0; - } - - public String getDefaultFormatString() { - return defaultFormatString; - } } diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatOptions.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatOptions.java index 138c827fe..10002b6ea 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatOptions.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatOptions.java @@ -26,503 +26,526 @@ package io.spine.logging.jvm.backend; -import io.spine.logging.jvm.parser.ParseException; import com.google.errorprone.annotations.CanIgnoreReturnValue; +import io.spine.logging.jvm.parser.ParseException; import org.jspecify.annotations.Nullable; /** * A structured representation of formatting options compatible with printf style formatting. - *

      - * This class is immutable and thread safe. * - * @see - * Original Java code of Google Flogger + *

      This class is immutable and thread-safe. + * + * @see + * Original Java code of Google Flogger */ public final class FormatOptions { - private static final int MAX_ALLOWED_WIDTH = 999999; - private static final int MAX_ALLOWED_PRECISION = 999999; + private static final int MAX_ALLOWED_WIDTH = 999999; + private static final int MAX_ALLOWED_PRECISION = 999999; - // WARNING: Never add any more flags here (flag encoding breaks if > 7 flags). - private static final String FLAG_CHARS_ORDERED = " #(+,-0"; - private static final int MIN_FLAG_VALUE = ' '; - private static final int MAX_FLAG_VALUE = '0'; + // WARNING: Never add any more flags here (flag encoding breaks if > 7 flags). + private static final String FLAG_CHARS_ORDERED = " #(+,-0"; + private static final int MIN_FLAG_VALUE = ' '; + private static final int MAX_FLAG_VALUE = '0'; - // For a flag character 'c' in [MIN_FLAG_VALUE, MAX_FLAG_VALUE] the flag index is stored in 3 bits - // starting at bit-N, where N = (3 * (c - MIN_FLAG_VALUE)). - private static final long ENCODED_FLAG_INDICES; + // For a flag character 'c' in [MIN_FLAG_VALUE, MAX_FLAG_VALUE] the flag index is stored in 3 bits + // starting at bit-N, where N = (3 * (c - MIN_FLAG_VALUE)). + private static final long ENCODED_FLAG_INDICES; + public static final String INVALID_FLAG = "invalid flag"; - static { - long encoded = 0; - for (int i = 0; i < FLAG_CHARS_ORDERED.length(); i++) { - long n = (FLAG_CHARS_ORDERED.charAt(i) - MIN_FLAG_VALUE); - encoded |= (i + 1L) << (3 * n); + static { + long encoded = 0; + for (int i = 0; i < FLAG_CHARS_ORDERED.length(); i++) { + long n = (FLAG_CHARS_ORDERED.charAt(i) - MIN_FLAG_VALUE); + encoded |= (i + 1L) << (3 * n); + } + ENCODED_FLAG_INDICES = encoded; } - ENCODED_FLAG_INDICES = encoded; - } - - // Helper to decode a flag character which has already been determined to be in the range - // [MIN_FLAG_VALUE, MAX_FLAG_VALUE]. For characters in this range, this function is identical to - // "return FLAG_CHARS_ORDERED.indexOf(c)" but without any looping. - private static int indexOfFlagCharacter(char c) { - // TODO: Benchmark against "FLAG_CHARS_ORDERED.indexOf(c)" just to be sure. - return (int) ((ENCODED_FLAG_INDICES >>> (3 * (c - MIN_FLAG_VALUE))) & 0x7L) - 1; - } - - /** - * A formatting flag which specifies that for signed numeric output, positive values should be - * prefixed with an ASCII space ({@code ' '}). This corresponds to the {@code ' '} printf flag and - * is valid for all signed numeric types. - */ - public static final int FLAG_PREFIX_SPACE_FOR_POSITIVE_VALUES = (1 << 0); - - /** - * A formatting flag which specifies that output should be shown in a type dependent alternate - * form. This corresponds to the {@code '#'} printf flag and is valid for: - *

        - *
      • Octal (%o) and hexadecimal (%x, %X) formatting, where it specifies that the radix should be - * shown. - *
      • Floating point (%f) and exponential (%e, %E, %a, %A) formatting, where it specifies that a - * decimal separator should always be shown. - *
      - */ - public static final int FLAG_SHOW_ALT_FORM = (1 << 1); - - /** - * A formatting flag which specifies that for signed numeric output, negative values should be - * surrounded by parentheses. This corresponds to the {@code '('} printf flag and is valid for all - * signed numeric types. - */ - public static final int FLAG_USE_PARENS_FOR_NEGATIVE_VALUES = (1 << 2); - - /** - * A formatting flag which specifies that for signed numeric output, positive values should be - * prefixed with an ASCII plus ({@code '+'}). This corresponds to the {@code '+'} printf flag and - * is valid for all signed numeric types. - */ - public static final int FLAG_PREFIX_PLUS_FOR_POSITIVE_VALUES = (1 << 3); - - /** - * A formatting flag which specifies that for non-exponential, base-10, numeric output a grouping - * separator (often a ',') should be used. This corresponds to the {@code ','} printf flag and - * is valid for: - *
        - *
      • Decimal (%d) and unsigned (%u) formatting. - *
      • Float (%f) and general scientific notation (%g, %G) - *
      - */ - public static final int FLAG_SHOW_GROUPING = (1 << 4); - - /** - * A formatting flag which specifies that output should be left-aligned within the minimum - * available width. This corresponds to the {@code '-'} printf flag and is valid for all - * {@code FormatChar} instances, though it must be specified in conjunction with a width value. - */ - public static final int FLAG_LEFT_ALIGN = (1 << 5); - - /** - * A formatting flag which specifies that numeric output should be padding with leading zeros as - * necessary to fill the minimum width. This corresponds to the {@code '0'} printf flag and is - * valid for all numeric types, though it must be specified in conjunction with a width value. - */ - public static final int FLAG_SHOW_LEADING_ZEROS = (1 << 6); - - /** - * A formatting flag which specifies that output should be upper-cased after all other formatting. - * This corresponds to having an upper-case format character and is valud for any type with an - * upper case variant. - */ - public static final int FLAG_UPPER_CASE = (1 << 7); - - /** A mask of all allowed formatting flags. Useful when filtering options via {@link #filter}. */ - public static final int ALL_FLAGS = 0xFF; - - /** The value used to specify that either width or precision were not specified. */ - public static final int UNSET = -1; - - private static final FormatOptions DEFAULT = new FormatOptions(0, UNSET, UNSET); - - /** Returns the default options singleton instance. */ - public static FormatOptions getDefault() { - return DEFAULT; - } - - /** Creates a options instance with the given values. */ - public static FormatOptions of(int flags, int width, int precision) { - if (!checkFlagConsistency(flags, width != UNSET)) { - throw new IllegalArgumentException("invalid flags: 0x" + Integer.toHexString(flags)); + + // Helper to decode a flag character which has already been determined to be in the range + // [MIN_FLAG_VALUE, MAX_FLAG_VALUE]. For characters in this range, this function is identical to + // "return FLAG_CHARS_ORDERED.indexOf(c)" but without any looping. + private static int indexOfFlagCharacter(char c) { + // TODO: Benchmark against "FLAG_CHARS_ORDERED.indexOf(c)" just to be sure. + return (int) ((ENCODED_FLAG_INDICES >>> (3 * (c - MIN_FLAG_VALUE))) & 0x7L) - 1; } - if ((width < 1 || width > MAX_ALLOWED_WIDTH) && width != UNSET) { - throw new IllegalArgumentException("invalid width: " + width); + + /** + * A formatting flag which specifies that for signed numeric output, positive values should be + * prefixed with an ASCII space ({@code ' '}). This corresponds to the {@code ' '} printf flag + * and is valid for all signed numeric types. + */ + public static final int FLAG_PREFIX_SPACE_FOR_POSITIVE_VALUES = (1 << 0); + + /** + * A formatting flag which specifies that output should be shown in a type dependent alternate + * form. This corresponds to the {@code '#'} printf flag and is valid for: + *
        + *
      • Octal (%o) and hexadecimal (%x, %X) formatting, where it specifies that the radix should be + * shown. + *
      • Floating point (%f) and exponential (%e, %E, %a, %A) formatting, where it specifies that a + * decimal separator should always be shown. + *
      + */ + public static final int FLAG_SHOW_ALT_FORM = (1 << 1); + + /** + * A formatting flag which specifies that for signed numeric output, negative values should be + * surrounded by parentheses. This corresponds to the {@code '('} printf flag and is valid for + * all signed numeric types. + */ + public static final int FLAG_USE_PARENS_FOR_NEGATIVE_VALUES = (1 << 2); + + /** + * A formatting flag which specifies that for signed numeric output, positive values should be + * prefixed with an ASCII plus ({@code '+'}). This corresponds to the {@code '+'} printf flag + * and is valid for all signed numeric types. + */ + public static final int FLAG_PREFIX_PLUS_FOR_POSITIVE_VALUES = (1 << 3); + + /** + * A formatting flag which specifies that for non-exponential, base-10, numeric output a + * grouping separator (often a ',') should be used. This corresponds to the {@code ','} printf + * flag and is valid for: + *
        + *
      • Decimal (%d) and unsigned (%u) formatting. + *
      • Float (%f) and general scientific notation (%g, %G) + *
      + */ + public static final int FLAG_SHOW_GROUPING = (1 << 4); + + /** + * A formatting flag which specifies that output should be left-aligned within the minimum + * available width. This corresponds to the {@code '-'} printf flag and is valid for all + * {@code FormatChar} instances, though it must be specified in conjunction with a width value. + */ + public static final int FLAG_LEFT_ALIGN = (1 << 5); + + /** + * A formatting flag which specifies that numeric output should be padding with leading zeros as + * necessary to fill the minimum width. This corresponds to the {@code '0'} printf flag and is + * valid for all numeric types, though it must be specified in conjunction with a width value. + */ + public static final int FLAG_SHOW_LEADING_ZEROS = (1 << 6); + + /** + * A formatting flag which specifies that output should be upper-cased after all other + * formatting. This corresponds to having an upper-case format character and is valid for any + * type with an upper case variant. + */ + public static final int FLAG_UPPER_CASE = (1 << 7); + + /** A mask of all allowed formatting flags. Useful when filtering options via {@link #filter}. */ + public static final int ALL_FLAGS = 0xFF; + + /** The value used to specify that either width or precision were not specified. */ + public static final int UNSET = -1; + + private static final FormatOptions DEFAULT = new FormatOptions(0, UNSET, UNSET); + + /** Returns the default options singleton instance. */ + public static FormatOptions getDefault() { + return DEFAULT; } - if ((precision < 0 || precision > MAX_ALLOWED_PRECISION) && precision != UNSET) { - throw new IllegalArgumentException("invalid precision: " + precision); + + /** Creates a options instance with the given values. */ + public static FormatOptions of(int flags, int width, int precision) { + if (!checkFlagConsistency(flags, width != UNSET)) { + throw new IllegalArgumentException("invalid flags: 0x" + Integer.toHexString(flags)); + } + if ((width < 1 || width > MAX_ALLOWED_WIDTH) && width != UNSET) { + throw new IllegalArgumentException("invalid width: " + width); + } + if ((precision < 0 || precision > MAX_ALLOWED_PRECISION) && precision != UNSET) { + throw new IllegalArgumentException("invalid precision: " + precision); + } + return new FormatOptions(flags, width, precision); + } + + /** + * Parses a sub-sequence of a log message to extract and return its options. Note that callers + * cannot rely on this method producing new instances each time it is called as caching of + * common option values may occur. + * + * @param message + * the original log message in which the formatting options have been identified. + * @param pos + * the index of the first character to parse. + * @param end + * the index after the last character to be parsed. + * @return the parsed options instance. + * @throws ParseException + * if the specified sub-sequence of the string could not be parsed. + */ + public static FormatOptions parse(String message, int pos, int end, boolean isUpperCase) + throws ParseException { + // It is vital that we shortcut parsing and return the default instance here (rather than just + // creating a new instance with default values) because we check for it using '==' later). + // Also, it saves us thousands of otherwise unnecessary allocations. + if (pos == end && !isUpperCase) { + return DEFAULT; + } + + // STEP 1: Parse flag bits. + int flags = isUpperCase ? FLAG_UPPER_CASE : 0; + char c; + while (true) { + if (pos == end) { + return new FormatOptions(flags, UNSET, UNSET); + } + c = message.charAt(pos++); + if (c < MIN_FLAG_VALUE || c > MAX_FLAG_VALUE) { + break; + } + int flagIdx = indexOfFlagCharacter(c); + if (flagIdx < 0) { + if (c == '.') { + // Edge case of something like "%.2f" (precision but no width). + return new FormatOptions(flags, UNSET, parsePrecision(message, pos, end)); + } + throw ParseException.atPosition(INVALID_FLAG, message, pos - 1); + } + int flagBit = 1 << flagIdx; + if ((flags & flagBit) != 0) { + throw ParseException.atPosition("repeated flag", message, pos - 1); + } + flags |= flagBit; + } + + // STEP 2: Parse width (which must start with [1-9]). + // We know that c > MAX_FLAG_VALUE, which is really just '0', so (c >= 1) + int widthStart = pos - 1; + if (c > '9') { + throw ParseException.atPosition(INVALID_FLAG, message, widthStart); + } + int width = c - '0'; + while (true) { + if (pos == end) { + return new FormatOptions(flags, width, UNSET); + } + c = message.charAt(pos++); + if (c == '.') { + return new FormatOptions(flags, width, parsePrecision(message, pos, end)); + } + int n = (char) (c - '0'); + if (n >= 10) { + throw ParseException.atPosition("invalid width character", message, pos - 1); + } + width = (width * 10) + n; + if (width > MAX_ALLOWED_WIDTH) { + throw ParseException.withBounds("width too large", message, widthStart, end); + } + } } - return new FormatOptions(flags, width, precision); - } - - /** - * Parses a sub-sequence of a log message to extract and return its options. Note that callers - * cannot rely on this method producing new instances each time it is called as caching of common - * option values may occur. - * - * @param message the original log message in which the formatting options have been identified. - * @param pos the index of the first character to parse. - * @param end the index after the last character to be parsed. - * @return the parsed options instance. - * @throws ParseException if the specified sub-sequence of the string could not be parsed. - */ - public static FormatOptions parse(String message, int pos, int end, boolean isUpperCase) - throws ParseException { - // It is vital that we shortcut parsing and return the default instance here (rather than just - // creating a new instance with default values) because we check for it using '==' later). - // Also, it saves us thousands of otherwise unnecessary allocations. - if (pos == end && !isUpperCase) { - return DEFAULT; + + private static int parsePrecision(String message, int start, int end) throws ParseException { + if (start == end) { + throw ParseException.atPosition("missing precision", message, start - 1); + } + int precision = 0; + for (int pos = start; pos < end; pos++) { + int n = (char) (message.charAt(pos) - '0'); + if (n >= 10) { + throw ParseException.atPosition("invalid precision character", message, pos); + } + precision = (precision * 10) + n; + if (precision > MAX_ALLOWED_PRECISION) { + throw ParseException.withBounds("precision too large", message, start, end); + } + } + // Check for many-zeros corner case (eg, "%.000f") + if (precision == 0 && end != (start + 1)) { + throw ParseException.withBounds("invalid precision", message, start, end); + } + return precision; } - // STEP 1: Parse flag bits. - int flags = isUpperCase ? FLAG_UPPER_CASE : 0; - char c; - while (true) { - if (pos == end) { - return new FormatOptions(flags, UNSET, UNSET); - } - c = message.charAt(pos++); - if (c < MIN_FLAG_VALUE || c > MAX_FLAG_VALUE) { - break; - } - int flagIdx = indexOfFlagCharacter(c); - if (flagIdx < 0) { - if (c == '.') { - // Edge case of something like "%.2f" (precision but no width). - return new FormatOptions(flags, UNSET, parsePrecision(message, pos, end)); + /** Internal helper method for creating a bit-mask from a string of valid flag characters. */ + static int parseValidFlags(String flagChars, boolean hasUpperVariant) { + var flags = hasUpperVariant ? FLAG_UPPER_CASE : 0; + for (var i = 0; i < flagChars.length(); i++) { + var flagIdx = indexOfFlagCharacter(flagChars.charAt(i)); + if (flagIdx < 0) { + throw new IllegalArgumentException("invalid flags: " + flagChars); + } + flags |= 1 << flagIdx; } - throw ParseException.atPosition("invalid flag", message, pos - 1); - } - int flagBit = 1 << flagIdx; - if ((flags & flagBit) != 0) { - throw ParseException.atPosition("repeated flag", message, pos - 1); - } - flags |= flagBit; + return flags; + } + + // NOTE: If we really cared about space we could encode everything into a single long. + private final int flags; + private final int width; + private final int precision; + + private FormatOptions(int flags, int width, int precision) { + this.flags = flags; + this.width = width; + this.precision = precision; } - // STEP 2: Parse width (which must start with [1-9]). - // We know that c > MAX_FLAG_VALUE, which is really just '0', so (c >= 1) - int widthStart = pos - 1; - if (c > '9') { - throw ParseException.atPosition("invalid flag", message, widthStart); + /** + * Returns a possibly new FormatOptions instance possibly containing a subset of the formatting + * information. This is useful if a backend implementation wishes to create formatting options + * that ignore some of the specified formatting information. + * + * @param allowedFlags + * A mask of flag values to be retained in the returned instance. Use + * {@link #ALL_FLAGS} to retain all flag values, or {@code 0} to suppress all flags. + * @param allowWidth + * specifies whether to include width in the returned instance. + * @param allowPrecision + * specifies whether to include precision in the returned instance. + */ + public FormatOptions filter(int allowedFlags, boolean allowWidth, boolean allowPrecision) { + if (isDefault()) { + return this; + } + int newFlags = allowedFlags & flags; + int newWidth = allowWidth ? width : UNSET; + int newPrecision = allowPrecision ? precision : UNSET; + // Remember that we must never create a non-canonical default instance. + if (newFlags == 0 && newWidth == UNSET && newPrecision == UNSET) { + return DEFAULT; + } + // This check would be faster if we encoded the entire state into a long value. It's also + // entirely possible we should just allocate a new instance and be damned (especially as + // having anything other than the default instance is rare). + // TODO(dbeaumont): Measure performance and see about removing this code, almost certainly fine. + if (newFlags == flags && newWidth == width && newPrecision == precision) { + return this; + } + return new FormatOptions(newFlags, newWidth, newPrecision); } - int width = c - '0'; - while (true) { - if (pos == end) { - return new FormatOptions(flags, width, UNSET); - } - c = message.charAt(pos++); - if (c == '.') { - return new FormatOptions(flags, width, parsePrecision(message, pos, end)); - } - int n = (char) (c - '0'); - if (n >= 10) { - throw ParseException.atPosition("invalid width character", message, pos - 1); - } - width = (width * 10) + n; - if (width > MAX_ALLOWED_WIDTH) { - throw ParseException.withBounds("width too large", message, widthStart, end); - } + + /** Returns true if this instance has only default formatting options. */ + @SuppressWarnings("ReferenceEquality") + public boolean isDefault() { + return this == getDefault(); } - } - private static int parsePrecision(String message, int start, int end) throws ParseException { - if (start == end) { - throw ParseException.atPosition("missing precision", message, start - 1); + /** + * Returns the width for these options, or {@link #UNSET} if not specified. This is a + * non-negative + * decimal integer which typically indicates the minimum number of characters to be written to + * the + * output, but its precise meaning is dependent on the formatting rule it is applied to. + */ + public int getWidth() { + return width; } - int precision = 0; - for (int pos = start; pos < end; pos++) { - int n = (char) (message.charAt(pos) - '0'); - if (n >= 10) { - throw ParseException.atPosition("invalid precision character", message, pos); - } - precision = (precision * 10) + n; - if (precision > MAX_ALLOWED_PRECISION) { - throw ParseException.withBounds("precision too large", message, start, end); - } + + /** + * Returns the precision for these options, or {@link #UNSET} if not specified. This is a + * non-negative decimal integer, usually used to restrict the number of characters, but its + * precise meaning is dependent on the formatting rule it is applied to. + */ + public int getPrecision() { + return precision; } - // Check for many-zeros corner case (eg, "%.000f") - if (precision == 0 && end != (start + 1)) { - throw ParseException.withBounds("invalid precision", message, start, end); + + /** + * Validates these options according to the allowed criteria and checks for inconsistencies in + * flag values. + *

      + * Note that there is not requirement for options used internally in custom message parsers to + * be + * validated, but any format options passed through the {@code ParameterVisitor} interface must + * be valid with respect to the associated {@link FormatChar} instance. + * + * @param allowedFlags + * a bit mask specifying a subset of the printf flags that are allowed for + * these options. + * @param allowPrecision + * true if these options are allowed to have a precision value specified. + * @return true if these options are valid given the specified constraints. + */ + public boolean validate(int allowedFlags, boolean allowPrecision) { + // The default instance is always valid (commonest case). + if (isDefault()) { + return true; + } + // Check if our flags are a subset of the allowed flags. + if ((flags & ~allowedFlags) != 0) { + return false; + } + // Check we only have precision specified when it is allowed. + if (!allowPrecision && precision != UNSET) { + return false; + } + return checkFlagConsistency(flags, getWidth() != UNSET); } - return precision; - } - - /** Internal helper method for creating a bit-mask from a string of valid flag characters. */ - static int parseValidFlags(String flagChars, boolean hasUpperVariant) { - int flags = hasUpperVariant ? FLAG_UPPER_CASE : 0; - for (int i = 0; i < flagChars.length(); i++) { - int flagIdx = indexOfFlagCharacter(flagChars.charAt(i)); - if (flagIdx < 0) { - throw new IllegalArgumentException("invalid flags: " + flagChars); - } - flags |= 1 << flagIdx; + + // Helper to check for legal combinations of flags. + static boolean checkFlagConsistency(int flags, boolean hasWidth) { + // Check that we specify at most one of 'prefix plus' and 'prefix space'. + if ((flags & (FLAG_PREFIX_PLUS_FOR_POSITIVE_VALUES | FLAG_PREFIX_SPACE_FOR_POSITIVE_VALUES)) + == (FLAG_PREFIX_PLUS_FOR_POSITIVE_VALUES | FLAG_PREFIX_SPACE_FOR_POSITIVE_VALUES)) { + return false; + } + // Check that we specify at most one of 'left align' and 'leading zeros'. + if ((flags & (FLAG_LEFT_ALIGN | FLAG_SHOW_LEADING_ZEROS)) + == (FLAG_LEFT_ALIGN | FLAG_SHOW_LEADING_ZEROS)) { + return false; + } + // Check that if 'left align' or 'leading zeros' is specified, we also have a width value. + if ((flags & (FLAG_LEFT_ALIGN | FLAG_SHOW_LEADING_ZEROS)) != 0 && !hasWidth) { + return false; + } + return true; } - return flags; - } - - // NOTE: If we really cared about space we could encode everything into a single long. - private final int flags; - private final int width; - private final int precision; - - private FormatOptions(int flags, int width, int precision) { - this.flags = flags; - this.width = width; - this.precision = precision; - } - - /** - * Returns a possibly new FormatOptions instance possibly containing a subset of the formatting - * information. This is useful if a backend implementation wishes to create formatting options - * that ignore some of the specified formatting information. - * - * @param allowedFlags A mask of flag values to be retained in the returned instance. Use - * {@link #ALL_FLAGS} to retain all flag values, or {@code 0} to suppress all flags. - * @param allowWidth specifies whether to include width in the returned instance. - * @param allowPrecision specifies whether to include precision in the returned instance. - */ - public FormatOptions filter(int allowedFlags, boolean allowWidth, boolean allowPrecision) { - if (isDefault()) { - return this; + + /** + * Validates these options as if they were being applied to the given {@link FormatChar} and + * checks for inconsistencies in flag values. + *

      + * Note that there is not requirement for options used internally in custom message parsers to + * be + * validated, but any format options passed through the + * {@link io.spine.logging.jvm.parameter.ParameterVisitor ParameterVisitor} interface must + * be valid with respect to the associated {@link FormatChar} instance. + * + * @param formatChar + * the formatting rule to check these options against. + * @return true if these options are valid for the given format. + */ + public boolean areValidFor(FormatChar formatChar) { + return validate(formatChar.getAllowedFlags(), formatChar.getType() + .supportsPrecision()); } - int newFlags = allowedFlags & flags; - int newWidth = allowWidth ? width : UNSET; - int newPrecision = allowPrecision ? precision : UNSET; - // Remember that we must never create a non-canonical default instance. - if (newFlags == 0 && newWidth == UNSET && newPrecision == UNSET) { - return DEFAULT; + + /** + * Returns the flag bits for this options instance. Where possible the per-flag methods + * {@code shouldXxx()} should be preferred for code clarity, but for efficiency and when testing + * multiple flags values at the same time, this method is useful. + */ + public int getFlags() { + return flags; } - // This check would be faster if we encoded the entire state into a long value. It's also - // entirely possible we should just allocate a new instance and be damned (especially as - // having anything other than the default instance is rare). - // TODO(dbeaumont): Measure performance and see about removing this code, almost certainly fine. - if (newFlags == flags && newWidth == width && newPrecision == precision) { - return this; + + /** + * Corresponds to printf flag '-' (incompatible with '0'). + *

      + * Logging backends may ignore this flag, though it does provide some visual clarity when + * aligning + * values. + */ + public boolean shouldLeftAlign() { + return (flags & FLAG_LEFT_ALIGN) != 0; } - return new FormatOptions(newFlags, newWidth, newPrecision); - } - - /** Returns true if this instance has only default formatting options. */ - @SuppressWarnings("ReferenceEquality") - public boolean isDefault() { - return this == getDefault(); - } - - /** - * Returns the width for these options, or {@link #UNSET} if not specified. This is a non-negative - * decimal integer which typically indicates the minimum number of characters to be written to the - * output, but its precise meaning is dependent on the formatting rule it is applied to. - */ - public int getWidth() { - return width; - } - - /** - * Returns the precision for these options, or {@link #UNSET} if not specified. This is a - * non-negative decimal integer, usually used to restrict the number of characters, but its - * precise meaning is dependent on the formatting rule it is applied to. - */ - public int getPrecision() { - return precision; - } - - /** - * Validates these options according to the allowed criteria and checks for inconsistencies in - * flag values. - *

      - * Note that there is not requirement for options used internally in custom message parsers to be - * validated, but any format options passed through the {@code ParameterVisitor} interface must - * be valid with respect to the associated {@link FormatChar} instance. - * - * @param allowedFlags a bit mask specifying a subset of the printf flags that are allowed for - * these options. - * @param allowPrecision true if these options are allowed to have a precision value specified. - * @return true if these options are valid given the specified constraints. - */ - public boolean validate(int allowedFlags, boolean allowPrecision) { - // The default instance is always valid (commonest case). - if (isDefault()) { - return true; + + /** + * Corresponds to printf flag '#'. + *

      + * Logging backends should honor this flag for hex or octal, as it is a common way to avoid + * ambiguity when formatting non-decimal values. + */ + public boolean shouldShowAltForm() { + return (flags & FLAG_SHOW_ALT_FORM) != 0; } - // Check if our flags are a subset of the allowed flags. - if ((flags & ~allowedFlags) != 0) { - return false; + + /** + * Corresponds to printf flag '0'. + *

      + * Logging backends should honor this flag, as it is very commonly used to format hexadecimal or + * octal values to allow specific bit values to be calculated. + */ + public boolean shouldShowLeadingZeros() { + return (flags & FLAG_SHOW_LEADING_ZEROS) != 0; } - // Check we only have precision specified when it is allowed. - if (!allowPrecision && precision != UNSET) { - return false; + + /** + * Corresponds to printf flag '+'. + *

      + * Logging backends are free to ignore this flag, though it does provide some visual clarity + * when + * tabulating certain types of values. + */ + public boolean shouldPrefixPlusForPositiveValues() { + return (flags & FLAG_PREFIX_PLUS_FOR_POSITIVE_VALUES) != 0; } - return checkFlagConsistency(flags, getWidth() != UNSET); - } - - // Helper to check for legal combinations of flags. - static boolean checkFlagConsistency(int flags, boolean hasWidth) { - // Check that we specify at most one of 'prefix plus' and 'prefix space'. - if ((flags & (FLAG_PREFIX_PLUS_FOR_POSITIVE_VALUES | FLAG_PREFIX_SPACE_FOR_POSITIVE_VALUES)) - == (FLAG_PREFIX_PLUS_FOR_POSITIVE_VALUES | FLAG_PREFIX_SPACE_FOR_POSITIVE_VALUES)) { - return false; + + /** + * Corresponds to printf flag ' '. + *

      + * Logging backends are free to ignore this flag, though if they choose to support + * {@link #shouldPrefixPlusForPositiveValues()} then it is advisable to support this as well. + */ + public boolean shouldPrefixSpaceForPositiveValues() { + return (flags & FLAG_PREFIX_SPACE_FOR_POSITIVE_VALUES) != 0; } - // Check that we specify at most one of 'left align' and 'leading zeros'. - if ((flags & (FLAG_LEFT_ALIGN | FLAG_SHOW_LEADING_ZEROS)) - == (FLAG_LEFT_ALIGN | FLAG_SHOW_LEADING_ZEROS)) { - return false; + + /** + * Corresponds to printf flag ','. + *

      + * Logging backends are free to select the locale in which the formatting will occur or ignore + * this flag altogether. + */ + public boolean shouldShowGrouping() { + return (flags & FLAG_SHOW_GROUPING) != 0; } - // Check that if 'left align' or 'leading zeros' is specified, we also have a width value. - if ((flags & (FLAG_LEFT_ALIGN | FLAG_SHOW_LEADING_ZEROS)) != 0 && !hasWidth) { - return false; + + /** + * Corresponds to formatting with an upper-case format character. + *

      + * Logging backends are free to ignore this flag. + */ + public boolean shouldUpperCase() { + return (flags & FLAG_UPPER_CASE) != 0; } - return true; - } - - /** - * Validates these options as if they were being applied to the given {@link FormatChar} and - * checks for inconsistencies in flag values. - *

      - * Note that there is not requirement for options used internally in custom message parsers to be - * validated, but any format options passed through the - * {@link io.spine.logging.jvm.parameter.ParameterVisitor ParameterVisitor} interface must - * be valid with respect to the associated {@link FormatChar} instance. - * - * @param formatChar the formatting rule to check these options against. - * @return true if these options are valid for the given format. - */ - public boolean areValidFor(FormatChar formatChar) { - return validate(formatChar.getAllowedFlags(), formatChar.getType().supportsPrecision()); - } - - /** - * Returns the flag bits for this options instance. Where possible the per-flag methods - * {@code shouldXxx()} should be preferred for code clarity, but for efficiency and when testing - * multiple flags values at the same time, this method is useful. - */ - public int getFlags() { - return flags; - } - - /** - * Corresponds to printf flag '-' (incompatible with '0'). - *

      - * Logging backends may ignore this flag, though it does provide some visual clarity when aligning - * values. - */ - public boolean shouldLeftAlign() { - return (flags & FLAG_LEFT_ALIGN) != 0; - } - - /** - * Corresponds to printf flag '#'. - *

      - * Logging backends should honor this flag for hex or octal, as it is a common way to avoid - * ambiguity when formatting non-decimal values. - */ - public boolean shouldShowAltForm() { - return (flags & FLAG_SHOW_ALT_FORM) != 0; - } - - /** - * Corresponds to printf flag '0'. - *

      - * Logging backends should honor this flag, as it is very commonly used to format hexadecimal or - * octal values to allow specific bit values to be calculated. - */ - public boolean shouldShowLeadingZeros() { - return (flags & FLAG_SHOW_LEADING_ZEROS) != 0; - } - - /** - * Corresponds to printf flag '+'. - *

      - * Logging backends are free to ignore this flag, though it does provide some visual clarity when - * tabulating certain types of values. - */ - public boolean shouldPrefixPlusForPositiveValues() { - return (flags & FLAG_PREFIX_PLUS_FOR_POSITIVE_VALUES) != 0; - } - - /** - * Corresponds to printf flag ' '. - *

      - * Logging backends are free to ignore this flag, though if they choose to support - * {@link #shouldPrefixPlusForPositiveValues()} then it is advisable to support this as well. - */ - public boolean shouldPrefixSpaceForPositiveValues() { - return (flags & FLAG_PREFIX_SPACE_FOR_POSITIVE_VALUES) != 0; - } - - /** - * Corresponds to printf flag ','. - *

      - * Logging backends are free to select the locale in which the formatting will occur or ignore - * this flag altogether. - */ - public boolean shouldShowGrouping() { - return (flags & FLAG_SHOW_GROUPING) != 0; - } - - /** - * Corresponds to formatting with an upper-case format character. - *

      - * Logging backends are free to ignore this flag. - */ - public boolean shouldUpperCase() { - return (flags & FLAG_UPPER_CASE) != 0; - } - - /** - * Appends the data for this options instance in a printf compatible form to the given buffer. - * This method neither appends the leading {@code %} symbol nor a format type character. Output is - * written in the form {@code [width][.precision][flags]} and for the default instance, nothing is - * appended. - * - * @param out The output buffer to which the options are appended. - */ - @CanIgnoreReturnValue - public StringBuilder appendPrintfOptions(StringBuilder out) { - if (!isDefault()) { - // Knock out the upper-case flag because that does not correspond to an options character. - int optionFlags = flags & ~FLAG_UPPER_CASE; - for (int bit = 0; (1 << bit) <= optionFlags; bit++) { - if ((optionFlags & (1 << bit)) != 0) { - out.append(FLAG_CHARS_ORDERED.charAt(bit)); + + /** + * Appends the data for this options instance in a printf compatible form to the given buffer. + * This method neither appends the leading {@code %} symbol nor a format type character. Output + * is + * written in the form {@code [width][.precision][flags]} and for the default instance, nothing + * is + * appended. + * + * @param out + * The output buffer to which the options are appended. + */ + @CanIgnoreReturnValue + public StringBuilder appendPrintfOptions(StringBuilder out) { + if (!isDefault()) { + // Knock out the upper-case flag because that does not correspond to an options character. + int optionFlags = flags & ~FLAG_UPPER_CASE; + for (int bit = 0; (1 << bit) <= optionFlags; bit++) { + if ((optionFlags & (1 << bit)) != 0) { + out.append(FLAG_CHARS_ORDERED.charAt(bit)); + } + } + if (width != UNSET) { + out.append(width); + } + if (precision != UNSET) { + out.append('.') + .append(precision); + } } - } - if (width != UNSET) { - out.append(width); - } - if (precision != UNSET) { - out.append('.').append(precision); - } + return out; } - return out; - } - - @Override - public boolean equals(@Nullable Object o) { - // Various functions ensure that the same instance gets re-used, so it seems likely that it's - // worth optimizing for it here. - if (o == this) { - return true; + + @Override + public boolean equals(@Nullable Object o) { + // Various functions ensure that the same instance gets re-used, so it seems likely + // that it is worth optimizing for it here. + if (o == this) { + return true; + } + if (o instanceof FormatOptions other) { + return (other.flags == flags) && (other.width == width) && + (other.precision == precision); + } + return false; } - if (o instanceof FormatOptions) { - FormatOptions other = (FormatOptions) o; - return (other.flags == flags) && (other.width == width) && (other.precision == precision); + + @Override + public int hashCode() { + int result = flags; + result = (31 * result) + width; + result = (31 * result) + precision; + return result; } - return false; - } - - @Override - public int hashCode() { - int result = flags; - result = (31 * result) + width; - result = (31 * result) + precision; - return result; - } } diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatType.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatType.java index 3dfd89caa..40301b44e 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatType.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatType.java @@ -32,100 +32,108 @@ /** * The general formatting type of any one of the predefined {@code FormatChar} instances. * - * @see - * Original Java code of Google Flogger + * @see + * Original Java code of Google Flogger */ public enum FormatType { - /** General formatting that can be applied to any type. */ - GENERAL(false, true) { - @Override - public boolean canFormat(Object arg) { - return true; - } - }, + /** General formatting that can be applied to any type. */ + GENERAL(false, true) { + @Override + public boolean canFormat(Object arg) { + return true; + } + }, - /** Formatting that can be applied to any boolean type. */ - BOOLEAN(false, false) { - @Override - public boolean canFormat(Object arg) { - return arg instanceof Boolean; - } - }, + /** Formatting that can be applied to any boolean type. */ + BOOLEAN(false, false) { + @Override + public boolean canFormat(Object arg) { + return arg instanceof Boolean; + } + }, - /** - * Formatting that can be applied to Character or any integral type that can be losslessly - * converted to an int and for which {@link Character#isValidCodePoint(int)} returns true. - */ - CHARACTER(false, false) { - @Override - public boolean canFormat(Object arg) { - // Ordering in relative likelihood. - if (arg instanceof Character) { - return true; - } else if ((arg instanceof Integer) || (arg instanceof Byte) || (arg instanceof Short)) { - return Character.isValidCodePoint(((Number) arg).intValue()); - } else { - return false; - } - } - }, + /** + * Formatting that can be applied to Character or any integral type that can be losslessly + * converted to an int and for which {@link Character#isValidCodePoint(int)} returns true. + */ + CHARACTER(false, false) { + @Override + public boolean canFormat(Object arg) { + // Ordering in relative likelihood. + if (arg instanceof Character) { + return true; + } else if ((arg instanceof Integer) || (arg instanceof Byte) || + (arg instanceof Short)) { + return Character.isValidCodePoint(((Number) arg).intValue()); + } else { + return false; + } + } + }, - /** - * Formatting that can be applied to any integral Number type. Logging backends must support Byte, - * Short, Integer, Long and BigInteger but may also support additional numeric types directly. A - * logging backend that encounters an unknown numeric type should fall back to using - * {@code toString()}. - */ - INTEGRAL(true, false) { - @Override - public boolean canFormat(Object arg) { - // Ordering in relative likelihood. - return (arg instanceof Integer) - || (arg instanceof Long) - || (arg instanceof Byte) - || (arg instanceof Short) - || (arg instanceof BigInteger); - } - }, + /** + * Formatting that can be applied to any integral Number type. Logging backends must support + * Byte, + * Short, Integer, Long and BigInteger but may also support additional numeric types directly. + * A + * logging backend that encounters an unknown numeric type should fall back to using + * {@code toString()}. + */ + INTEGRAL(true, false) { + @Override + public boolean canFormat(Object arg) { + // Ordering in relative likelihood. + return (arg instanceof Integer) + || (arg instanceof Long) + || (arg instanceof Byte) + || (arg instanceof Short) + || (arg instanceof BigInteger); + } + }, - /** - * Formatting that can be applied to any Number type. Logging backends must support all the - * integral types as well as Float, Double and BigDecimal, but may also support additional numeric - * types directly. A logging backend that encounters an unknown numeric type should fall back to - * using {@code toString()}. - */ - FLOAT(true, true) { - @Override - public boolean canFormat(Object arg) { - // Ordering in relative likelihood. - return (arg instanceof Double) || (arg instanceof Float) || (arg instanceof BigDecimal); - } - }; + /** + * Formatting that can be applied to any Number type. Logging backends must support all the + * integral types as well as Float, Double and BigDecimal, but may also support additional + * numeric + * types directly. A logging backend that encounters an unknown numeric type should fall back + * to + * using {@code toString()}. + */ + FLOAT(true, true) { + @Override + public boolean canFormat(Object arg) { + // Ordering in relative likelihood. + return (arg instanceof Double) || (arg instanceof Float) || (arg instanceof BigDecimal); + } + }; - private final boolean isNumeric; - private final boolean supportsPrecision; + private final boolean isNumeric; + private final boolean supportsPrecision; - private FormatType(boolean isNumeric, boolean supportsPrecision) { - this.isNumeric = isNumeric; - this.supportsPrecision = supportsPrecision; - } + private FormatType(boolean isNumeric, boolean supportsPrecision) { + this.isNumeric = isNumeric; + this.supportsPrecision = supportsPrecision; + } - /** - * True if the notion of a specified precision value makes sense to this format type. Precision is - * specified in addition to width and can control the resolution of a formatting operation (e.g. - * how many digits to output after the decimal point for floating point values). - */ - boolean supportsPrecision() { - return supportsPrecision; - } + /** + * True if the notion of a specified precision value makes sense to this format type. Precision + * is + * specified in addition to width and can control the resolution of a formatting operation + * (e.g. + * how many digits to output after the decimal point for floating point values). + */ + boolean supportsPrecision() { + return supportsPrecision; + } - /** - * True if this format type requires a {@link Number} instance (or one of the corresponding - * fundamental types) as an argument. - */ - public boolean isNumeric() { - return isNumeric; - } + /** + * True if this format type requires a {@link Number} instance (or one of the corresponding + * fundamental types) as an argument. + */ + public boolean isNumeric() { + return isNumeric; + } - public abstract boolean canFormat(Object arg); + public abstract boolean canFormat(Object arg); } diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LogData.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LogData.java index 7fbd8d9ad..511740c45 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LogData.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LogData.java @@ -27,6 +27,7 @@ package io.spine.logging.jvm.backend; import io.spine.logging.jvm.JvmLogSite; + import java.util.logging.Level; /** @@ -39,94 +40,90 @@ * using the hierarchical key. See {@link Metadata}. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger */ public interface LogData { - /** Returns the log level for the current log statement. */ - Level getLevel(); - - /** - * @deprecated Use getTimestampNanos() - */ - @Deprecated - long getTimestampMicros(); + /** Returns the log level for the current log statement. */ + Level getLevel(); - /** Returns a nanosecond timestamp for the current log statement. */ - long getTimestampNanos(); + /** Returns a nanosecond timestamp for the current log statement. */ + long getTimestampNanos(); - /** - * Returns the logger name (which is usually a canonicalized class name) or {@code null} if not - * given. - */ - String getLoggerName(); + /** + * Returns the logger name (which is usually a canonicalized class name) or {@code null} + * if not given. + */ + String getLoggerName(); - /** - * Returns the log site data for the current log statement. - * - * @throws IllegalStateException if called prior to the postProcess() method being called. - */ - JvmLogSite getLogSite(); + /** + * Returns the log site data for the current log statement. + * + * @throws IllegalStateException + * if called prior to the postProcess() method being called. + */ + JvmLogSite getLogSite(); - /** - * Returns any additional metadata for this log statement. If no additional metadata is present, - * the immutable empty metadata instance is returned. - * - *

      IMPORTANT: The returned instance is restricted to metadata added at the log site, and will - * not include any scoped metadata to be applied to the log statement. To process combined log - * site and scoped metadata, obtain or create a {@link MetadataProcessor}. - */ - Metadata getMetadata(); + /** + * Returns any additional metadata for this log statement. If no additional metadata is present, + * the immutable empty metadata instance is returned. + * + *

      IMPORTANT: The returned instance is restricted to metadata added at the log site, and will + * not include any scoped metadata to be applied to the log statement. To process combined log + * site and scoped metadata, obtain or create a {@link MetadataProcessor}. + */ + Metadata getMetadata(); - /** - * Returns whether this log statement should be emitted regardless of its log level or any other - * properties. - *

      - * This allows extensions of {@code LogContext} or {@code LoggingBackend} which implement - * additional filtering or rate-limiting fluent methods to easily check whether a log statement - * was forced. Forced log statements should behave exactly as if none of the filtering or - * rate-limiting occurred, including argument validity checks. - *

      - * Thus the idiomatic use of {@code wasForced()} is: - *

      {@code
      -   * public API someFilteringMethod(int value) {
      -   *   if (wasForced()) {
      -   *     return api();
      -   *   }
      -   *   if (value < 0) {
      -   *     throw new IllegalArgumentException("Bad things ...");
      -   *   }
      -   *   // rest of method...
      -   * }
      -   * }
      - *

      - * Checking for forced log statements before checking the validity of arguments provides a - * last-resort means to mitigate cases in which syntactically incorrect log statements are only - * discovered when they are enabled. - */ - boolean wasForced(); + /** + * Returns whether this log statement should be emitted regardless of its log + * level or any other properties. + * + *

      This allows extensions of {@code LogContext} or {@code LoggingBackend} which implement + * additional filtering or rate-limiting fluent methods to easily check whether a log statement + * was forced. Forced log statements should behave exactly as if none of the filtering or + * rate-limiting occurred, including argument validity checks. + * + *

      Thus the idiomatic use of {@code wasForced()} is: + *

      {@code
      +     * public API someFilteringMethod(int value) {
      +     *   if (wasForced()) {
      +     *     return api();
      +     *   }
      +     *   if (value < 0) {
      +     *     throw new IllegalArgumentException("Bad things ...");
      +     *   }
      +     *   // rest of method...
      +     * }
      +     * }
      + * + *

      Checking for forced log statements before checking the validity of arguments provides a + * last-resort means to mitigate cases in which syntactically incorrect log statements are only + * discovered when they are enabled. + */ + boolean wasForced(); - /** - * Returns a template key for this log statement, or {@code null} if the statement does not - * require formatting (in which case the message to be logged can be determined by calling - * {@link #getLiteralArgument()}). - */ - TemplateContext getTemplateContext(); + /** + * Returns a template key for this log statement, or {@code null} if the statement does not + * require formatting (in which case the message to be logged can be determined by calling + * {@link #getLiteralArgument()}). + */ + TemplateContext getTemplateContext(); - /** - * Returns the arguments to be formatted with the message. Arguments exist when a {@code log()} - * method with a format message and separate arguments was invoked. - * - * @throws IllegalStateException if no arguments are available (ie, when there is no template - * context). - */ - Object[] getArguments(); + /** + * Returns the arguments to be formatted with the message. Arguments exist when a {@code log()} + * method with a format message and separate arguments was invoked. + * + * @throws IllegalStateException + * if no arguments are available (i.e., when there is no template context). + */ + Object[] getArguments(); - /** - * Returns the single argument to be logged directly when no arguments were provided. - * - * @throws IllegalStateException if no single literal argument is available (ie, when a template - * context exists). - */ - Object getLiteralArgument(); + /** + * Returns the single argument to be logged directly when no arguments were provided. + * + * @throws IllegalStateException + * if no single literal argument is available (ie, when a template + * context exists). + */ + Object getLiteralArgument(); } diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LoggerBackend.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LoggerBackend.java index c72daa731..ea606a437 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LoggerBackend.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LoggerBackend.java @@ -34,8 +34,6 @@ /** * Interface for all logger backends. * - *

      - * *

      Implementation Notes:

      * * Often each {@link AbstractLogger AbstractLogger} @@ -49,9 +47,10 @@ * were passed have exited. * *

      This means that ALL formatting or serialization of log statement arguments or - * metadata values MUST be completed inside the log method itself. If the backend needs to - * perform asynchronous I/O operations it can do so by constructing a serialized form of the {@link - * LogData} instance and enqueing that for processing. + * metadata values MUST be completed inside the log method itself. + * If the backend needs to perform asynchronous I/O operations it can do so + * by constructing a serialized form of the {@link LogData} instance and + * enqueing that for processing. * *

      Note also that this restriction is NOT purely about mutable arguments (which could * change before formatting occurs and produce incorrect output), but also stops log statements from @@ -63,22 +62,23 @@ */ public abstract class LoggerBackend { /** - * Returns the logger name (which is usually a canonicalized class name) or {@code null} if not - * given. + * Returns the logger name (which is usually a canonicalized class name) or + * {@code null} if not given. */ public abstract String getLoggerName(); /** - * Returns whether logging is enabled for the given level for this backend. Different backends may - * return different values depending on the class with which they are associated. + * Returns whether logging is enabled for the given level for this backend. + * Different backends may return different values depending on the class + * with which they are associated. */ public abstract boolean isLoggable(Level lvl); /** * Outputs the log statement represented by the given {@link LogData} instance. * - * @param data user and logger supplied data to be rendered in a backend specific way. References - * to {@code data} must not be held after the {@link log} invocation returns. + * @param data user and logger supplied data to be rendered in a backend-specific way. + * References to {@code data} must not be held after the {@code log} invocation returns. */ public abstract void log(LogData data); @@ -87,11 +87,11 @@ public abstract class LoggerBackend { * three distinct causes: * *

        - *
      1. Bad format strings in log messages (e.g. {@code "foo=%Q"}. These will always be instances - * of {@link ParseException ParseException} and contain - * human readable error messages describing the problem. - *
      2. A backend optionally choosing not to handle errors from user code during formatting. This - * is not recommended (see below) but may be useful in testing or debugging. + *
      3. Bad format strings in log messages (e.g., {@code "foo=%Q"}. + * These are always instances of {@link ParseException ParseException} and contain + * human-readable error messages describing the problem. + *
      4. A backend optionally choosing not to handle errors from user code during formatting. + * This is not recommended (see below) but may be useful in testing or debugging. *
      5. Runtime errors in the backend itself. *
      * @@ -103,14 +103,14 @@ public abstract class LoggerBackend { * *

      Typically a backend would handle an error by logging an alternative representation of the * "bad" log data, being careful not to allow any more exceptions to occur. If a backend chooses - * to propagate an error (e.g. when testing or debugging) it must wrap it in {@link - * LoggingException} to avoid it being re-caught. + * to propagate an error (e.g., when testing or debugging) it must wrap it in + * {@link LoggingException} to avoid it being re-caught. * * @param error the exception throw when {@code badData} was initially logged. * @param badData the original {@code LogData} instance which caused an error. It is not expected * that simply trying to log this again will succeed and error handlers must be careful in how * they handle this instance, its arguments and metadata. References to {@code badData} must - * not be held after the {@link handleError} invocation returns. + * not be held after the {@code handleError} invocation returns. * @throws LoggingException to indicate an error which should be propagated into user code. */ public abstract void handleError(RuntimeException error, LogData badData); diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LoggingException.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LoggingException.java index acd55e57f..e438350eb 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LoggingException.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LoggingException.java @@ -28,6 +28,8 @@ import org.jspecify.annotations.Nullable; +import java.io.Serial; + /** * Exception thrown when a log statement cannot be emitted correctly. This exception should only be * thrown by logger backend implementations which have opted not to handle specific issues. @@ -35,19 +37,18 @@ * Typically a logger backend would only throw {@code LoggingException} in response to issues in * test code or other debugging environments. In production code, the backend should be configured * to emit a modified log statement which includes the error information. - *

      - * See also {@link LoggerBackend#handleError(RuntimeException, LogData)}. + * + *

      See also {@link LoggerBackend#handleError(RuntimeException, LogData)}. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger */ public class LoggingException extends RuntimeException { - public LoggingException(@Nullable String message) { - super(message); - } + @Serial + private static final long serialVersionUID = 0L; - public LoggingException(@Nullable String message, @Nullable Throwable cause) { - super(message, cause); - } + public LoggingException(@Nullable String message) { + super(message); + } } diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataHandler.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataHandler.java index c532ce0fe..6b355e617 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataHandler.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataHandler.java @@ -26,15 +26,16 @@ package io.spine.logging.jvm.backend; -import static io.spine.logging.jvm.util.Checks.checkArgument; -import static io.spine.logging.jvm.util.Checks.checkNotNull; - -import io.spine.logging.jvm.JvmMetadataKey; import com.google.errorprone.annotations.CanIgnoreReturnValue; +import io.spine.logging.jvm.JvmMetadataKey; + import java.util.HashMap; import java.util.Iterator; import java.util.Map; +import static io.spine.logging.jvm.util.Checks.checkArgument; +import static io.spine.logging.jvm.util.Checks.checkNotNull; + /** * Callback API for logger backend implementations to handle metadata keys/values. The API methods * will be called once for each distinct key, in encounter order. Different methods are called @@ -44,301 +45,346 @@ * MetadataHandler.Builder Builder} class, which lets keys be individually mapped to callbacks, * however the class can also just be extended to implement alternate/custom behavior. * - * @param the arbitrary context type. - * - * @see - * Original Java code of Google Flogger + * @param + * the arbitrary context type. + * @see + * Original Java code of Google Flogger */ public abstract class MetadataHandler { - /** - * Handles a single metadata key/value mapping. This method is called directly for singleton non - * repeatable) keys, but may also be called for repeated keys by the default implementation of - * {@link #handleRepeated}. It is up to the implementation to override that method if this - * behaviour is unwanted. - * - * @param key the metadata key (not necessarily a "singleton" key). - * @param value associated metadata value. - * @param context an arbitrary context object supplied to the process method. - * @param the key/value type. - */ - protected abstract void handle(JvmMetadataKey key, T value, C context); - - /** - * Handles values for a repeatable metadata key. The method is called for all repeatable keys - * (even those with only one value). The default implementation makes repeated callbacks to the - * {@link #handle} method, in order, for each value. - * - * @param key the repeatable metadata key. - * @param values a lightweight iterator over all values associated with the key. Note that this - * instance is read-only and must not be held beyond the scope of this callback. - * @param context an arbitrary context object supplied to the process method. - * @param the key/value type. - */ - protected void handleRepeated(JvmMetadataKey key, Iterator values, C context) { - while (values.hasNext()) { - handle(key, values.next(), context); - } - } - - /** - * Returns a builder for a handler with the specified default callback. The default handler will - * receive all key/value pairs from the metadata individually, which can result in repeated keys - * being seen more than once. - * - *

      A default handler is required because no handler can know the complete set of keys which - * might be available and it is very undesirable to drop unknown keys. If default repeated values - * should be handled together, {@link Builder#setDefaultRepeatedHandler(RepeatedValueHandler)} - * should be called as well. - * - *

      Unknown keys/values can only be handled in a generic fashion unless a given key is matched - * to a known constant. However the entire point of this map-based handler is to avoid any need to - * do explicit matching, so the default handler should not need to know the value type. - * - * @param defaultHandler the default handler for unknown keys/values. - * @param the context type. - */ - public static Builder builder(ValueHandler defaultHandler) { - return new Builder(defaultHandler); - } - /** - * API for handling metadata key/value pairs individually. - * - * @param the key/value type. - * @param the type of the context passed to the callbacks. - */ - public interface ValueHandler { /** - * Handles metadata values individually. + * Handles a single metadata key/value mapping. This method is called directly for singleton non + * repeatable) keys, but may also be called for repeated keys by the default implementation of + * {@link #handleRepeated}. It is up to the implementation to override that method if this + * behaviour is unwanted. * - * @param key the metadata key (not necessarily a "singleton" key). - * @param value associated metadata value. - * @param context an arbitrary context object supplied to the process method. + * @param key + * the metadata key (not necessarily a "singleton" key). + * @param value + * associated metadata value. + * @param context + * an arbitrary context object supplied to the process method. + * @param + * the key/value type. */ - void handle(JvmMetadataKey key, T value, C context); - } + protected abstract void handle(JvmMetadataKey key, T value, C context); - /** - * API for handling repeated metadata key/values in a single callback. - * - * @param the key/value type. - * @param the type of the context passed to the callbacks. - */ - public interface RepeatedValueHandler { /** - * Handles all repeated metadata values for a given key. + * Handles values for a repeatable metadata key. The method is called for all repeatable keys + * (even those with only one value). The default implementation makes repeated callbacks to the + * {@link #handle} method, in order, for each value. * - * @param key the repeatable metadata key for which this handler was registered, or an unknown - * key if this is the default handler. - * @param values a lightweight iterator over all values associated with the key. Note that this - * instance is read-only and must not be held beyond the scope of this callback. - * @param context an arbitrary context object supplied to the process method. + * @param key + * the repeatable metadata key. + * @param values + * a lightweight iterator over all values associated with the key. Note that this + * instance is read-only and must not be held beyond the scope of this callback. + * @param context + * an arbitrary context object supplied to the process method. + * @param + * the key/value type. */ - void handle(JvmMetadataKey key, Iterator values, C context); - } - - /** - * Builder for a map-based {@link MetadataHandler} which allows handlers to be associated with - * individual callbacks. - * - * @param the context type. - */ - public static final class Builder { - // Since the context is ignored, this can safely be cast to ValueHandler - private static final ValueHandler IGNORE_VALUE = - new ValueHandler() { - @Override - public void handle(JvmMetadataKey key, Object value, Object context) {} - }; - - // Since the context is ignored, this can safely be cast to RepeatedValueHandler. - private static final RepeatedValueHandler IGNORE_REPEATED_VALUE = - (key, value, context) -> { /* No op. */ }; - - private final Map, ValueHandler> singleValueHandlers = - new HashMap<>(); - private final Map, RepeatedValueHandler> repeatedValueHandlers = - new HashMap<>(); - private final ValueHandler defaultHandler; - private RepeatedValueHandler defaultRepeatedHandler = null; - - private Builder(ValueHandler defaultHandler) { - this.defaultHandler = checkNotNull(defaultHandler, "default handler"); + protected void handleRepeated(JvmMetadataKey key, Iterator values, C context) { + while (values.hasNext()) { + handle(key, values.next(), context); + } } /** - * Sets a handler for any unknown repeated keys which allows values to be processed via a - * generic {@link Iterator}. To handle repeated values against a known key with their expected - * type, register a handler via {@link #addRepeatedHandler(JvmMetadataKey,RepeatedValueHandler)}. + * Returns a builder for a handler with the specified default callback. The default handler + * will + * receive all key/value pairs from the metadata individually, which can result in repeated + * keys + * being seen more than once. * - *

      Note that if a repeated key is associated with an individual value handler (i.e. via - * {@link #addHandler(JvmMetadataKey,ValueHandler)}), then that will be used in preference - * to the default handler set here. + *

      A default handler is required because no handler can know the complete set of keys which + * might be available and it is very undesirable to drop unknown keys. If default repeated + * values + * should be handled together, {@link Builder#setDefaultRepeatedHandler(RepeatedValueHandler)} + * should be called as well. * - * @param defaultHandler the default handler for unknown repeated keys/values. - * @return the builder instance for chaining. - */ - @CanIgnoreReturnValue - public Builder setDefaultRepeatedHandler( - RepeatedValueHandler defaultHandler) { - this.defaultRepeatedHandler = checkNotNull(defaultHandler, "handler"); - return this; - } - - /** - * Registers a value handler for the specified key, replacing any previously registered value. + *

      Unknown keys/values can only be handled in a generic fashion unless a given key is + * matched + * to a known constant. However the entire point of this map-based handler is to avoid any need + * to + * do explicit matching, so the default handler should not need to know the value type. * - * @param key the key for which the handler should be invoked (can be a repeated key). - * @param handler the value handler to be invoked for every value associated with the key. - * @param the key/value type. - * @return the builder instance for chaining. + * @param defaultHandler + * the default handler for unknown keys/values. + * @param + * the context type. */ - @CanIgnoreReturnValue - public Builder addHandler( - JvmMetadataKey key, ValueHandler handler) { - checkNotNull(key, "key"); - checkNotNull(handler, "handler"); - repeatedValueHandlers.remove(key); - singleValueHandlers.put(key, handler); - return this; + public static Builder builder(ValueHandler defaultHandler) { + return new Builder<>(defaultHandler); } /** - * Registers a repeated value handler for the specified key, replacing any previously - * registered value. + * API for handling metadata key/value pairs individually. * - * @param key the repeated key for which the handler should be invoked. - * @param handler the repeated value handler to be invoked once for all associated values. - * @param the key/value type. - * @return the builder instance for chaining. + * @param + * the key/value type. + * @param + * the type of the context passed to the callbacks. */ - @CanIgnoreReturnValue - public Builder addRepeatedHandler( - JvmMetadataKey key, RepeatedValueHandler handler) { - checkNotNull(key, "key"); - checkNotNull(handler, "handler"); - checkArgument(key.canRepeat(), "key must be repeating"); - singleValueHandlers.remove(key); - repeatedValueHandlers.put(key, handler); - return this; - } + public interface ValueHandler { - /** - * Registers "no op" handlers for the given keys, resulting in their values being ignored. - * - * @param key a key to ignore in the builder. - * @param rest additional keys to ignore in the builder. - * @return the builder instance for chaining. - */ - @CanIgnoreReturnValue - public Builder ignoring(JvmMetadataKey key, JvmMetadataKey... rest) { - checkAndIgnore(key); - for (JvmMetadataKey k : rest) { - checkAndIgnore(k); - } - return this; + /** + * Handles metadata values individually. + * + * @param key + * the metadata key (not necessarily a "singleton" key). + * @param value + * associated metadata value. + * @param context + * an arbitrary context object supplied to the process method. + */ + void handle(JvmMetadataKey key, T value, C context); } /** - * Registers "no op" handlers for the given keys, resulting in their values being ignored. + * API for handling repeated metadata key/values in a single callback. * - * @param keys the keys to ignore in the builder. - * @return the builder instance for chaining. + * @param + * the key/value type. + * @param + * the type of the context passed to the callbacks. */ - @CanIgnoreReturnValue - public Builder ignoring(Iterable> keys) { - for (JvmMetadataKey k : keys) { - checkAndIgnore(k); - } - return this; - } + public interface RepeatedValueHandler { - void checkAndIgnore(JvmMetadataKey key) { - checkNotNull(key, "key"); - // It is more efficient to ignore a repeated key explicitly. - if (key.canRepeat()) { - addRepeatedHandler(key, IGNORE_REPEATED_VALUE); - } else { - addHandler(key, IGNORE_VALUE); - } + /** + * Handles all repeated metadata values for a given key. + * + * @param key + * the repeatable metadata key for which this handler was registered, or an unknown + * key if this is the default handler. + * @param values + * a lightweight iterator over all values associated with the key. Note that this + * instance is read-only and must not be held beyond the scope of this callback. + * @param context + * an arbitrary context object supplied to the process method. + */ + void handle(JvmMetadataKey key, Iterator values, C context); } /** - * Removes any existing handlers for the given keys, returning them to the default handler(s). - * This method is useful when making several handlers with different mappings from a single - * builder. + * Builder for a map-based {@link MetadataHandler} which allows handlers to be associated with + * individual callbacks. * - * @param key a key to remove from the builder. - * @param rest additional keys to remove from the builder. - * @return the builder instance for chaining. + * @param + * the context type. */ - @CanIgnoreReturnValue - public Builder removeHandlers(JvmMetadataKey key, JvmMetadataKey... rest) { - checkAndRemove(key); - for (JvmMetadataKey k : rest) { - checkAndRemove(k); - } - return this; - } + public static final class Builder { - void checkAndRemove(JvmMetadataKey key) { - checkNotNull(key, "key"); - singleValueHandlers.remove(key); - repeatedValueHandlers.remove(key); - } + // Since the context is ignored, this can safely be cast to ValueHandler + private static final ValueHandler IGNORE_VALUE = + (key, value, context) -> { }; - /** Returns the immutable, map-based metadata handler. */ - public MetadataHandler build() { - return new MapBasedhandler(this); - } - } + // Since the context is ignored, this can safely be cast to RepeatedValueHandler. + private static final RepeatedValueHandler IGNORE_REPEATED_VALUE = + (key, value, context) -> { /* No op. */ }; - private static final class MapBasedhandler extends MetadataHandler { - private final Map, ValueHandler> singleValueHandlers = - new HashMap<>(); - private final Map, RepeatedValueHandler> repeatedValueHandlers = - new HashMap<>(); - private final ValueHandler defaultHandler; - private final RepeatedValueHandler defaultRepeatedHandler; + private final Map, ValueHandler> singleValueHandlers = + new HashMap<>(); + private final Map, RepeatedValueHandler> repeatedValueHandlers = + new HashMap<>(); + private final ValueHandler defaultHandler; + private RepeatedValueHandler defaultRepeatedHandler = null; - private MapBasedhandler(Builder builder) { - this.singleValueHandlers.putAll(builder.singleValueHandlers); - this.repeatedValueHandlers.putAll(builder.repeatedValueHandlers); - this.defaultHandler = builder.defaultHandler; - this.defaultRepeatedHandler = builder.defaultRepeatedHandler; - } + private Builder(ValueHandler defaultHandler) { + this.defaultHandler = checkNotNull(defaultHandler, "default handler"); + } + + /** + * Sets a handler for any unknown repeated keys which allows values to be processed via a + * generic {@link Iterator}. To handle repeated values against a known key with their + * expected + * type, register a handler via + * {@link #addRepeatedHandler(JvmMetadataKey, RepeatedValueHandler)}. + * + *

      Note that if a repeated key is associated with an individual value handler (i.e. via + * {@link #addHandler(JvmMetadataKey, ValueHandler)}), then that will be used in preference + * to the default handler set here. + * + * @param defaultHandler + * the default handler for unknown repeated keys/values. + * @return the builder instance for chaining. + */ + @CanIgnoreReturnValue + public Builder setDefaultRepeatedHandler( + RepeatedValueHandler defaultHandler) { + this.defaultRepeatedHandler = checkNotNull(defaultHandler, "handler"); + return this; + } + + /** + * Registers a value handler for the specified key, replacing any previously registered + * value. + * + * @param key + * the key for which the handler should be invoked (can be a repeated key). + * @param handler + * the value handler to be invoked for every value associated with the key. + * @param + * the key/value type. + * @return the builder instance for chaining. + */ + @CanIgnoreReturnValue + public Builder addHandler( + JvmMetadataKey key, ValueHandler handler) { + checkNotNull(key, "key"); + checkNotNull(handler, "handler"); + repeatedValueHandlers.remove(key); + singleValueHandlers.put(key, handler); + return this; + } - @SuppressWarnings("unchecked") // See comments for why casting is safe. - @Override - protected void handle(JvmMetadataKey key, T value, C context) { - // Safe cast because of how our private map is managed. - ValueHandler handler = - (ValueHandler) singleValueHandlers.get(key); - if (handler != null) { - handler.handle(key, value, context); - } else { - // Casting MetadataKey to "" is safe since it only produces elements of 'T'. - defaultHandler.handle((JvmMetadataKey) key, value, context); - } + /** + * Registers a repeated value handler for the specified key, replacing any previously + * registered value. + * + * @param key + * the repeated key for which the handler should be invoked. + * @param handler + * the repeated value handler to be invoked once for all associated values. + * @param + * the key/value type. + * @return the builder instance for chaining. + */ + @CanIgnoreReturnValue + public Builder addRepeatedHandler( + JvmMetadataKey key, RepeatedValueHandler handler) { + checkNotNull(key, "key"); + checkNotNull(handler, "handler"); + checkArgument(key.canRepeat(), "key must be repeating"); + singleValueHandlers.remove(key); + repeatedValueHandlers.put(key, handler); + return this; + } + + /** + * Registers "no op" handlers for the given keys, resulting in their values being ignored. + * + * @param key + * a key to ignore in the builder. + * @param rest + * additional keys to ignore in the builder. + * @return the builder instance for chaining. + */ + @CanIgnoreReturnValue + public Builder ignoring(JvmMetadataKey key, JvmMetadataKey... rest) { + checkAndIgnore(key); + for (JvmMetadataKey k : rest) { + checkAndIgnore(k); + } + return this; + } + + /** + * Registers "no op" handlers for the given keys, resulting in their values being ignored. + * + * @param keys + * the keys to ignore in the builder. + * @return the builder instance for chaining. + */ + @CanIgnoreReturnValue + public Builder ignoring(Iterable> keys) { + for (JvmMetadataKey k : keys) { + checkAndIgnore(k); + } + return this; + } + + void checkAndIgnore(JvmMetadataKey key) { + checkNotNull(key, "key"); + // It is more efficient to ignore a repeated key explicitly. + if (key.canRepeat()) { + addRepeatedHandler(key, IGNORE_REPEATED_VALUE); + } else { + addHandler(key, IGNORE_VALUE); + } + } + + /** + * Removes any existing handlers for the given keys, returning them to the default + * handler(s). + * This method is useful when making several handlers with different mappings from a single + * builder. + * + * @param key + * a key to remove from the builder. + * @param rest + * additional keys to remove from the builder. + * @return the builder instance for chaining. + */ + @CanIgnoreReturnValue + public Builder removeHandlers(JvmMetadataKey key, JvmMetadataKey... rest) { + checkAndRemove(key); + for (JvmMetadataKey k : rest) { + checkAndRemove(k); + } + return this; + } + + void checkAndRemove(JvmMetadataKey key) { + checkNotNull(key, "key"); + singleValueHandlers.remove(key); + repeatedValueHandlers.remove(key); + } + + /** Returns the immutable, map-based metadata handler. */ + public MetadataHandler build() { + return new MapBasedhandler(this); + } } - @SuppressWarnings("unchecked") // See comments for why casting is safe. - @Override - protected void handleRepeated(JvmMetadataKey key, Iterator values, C context) { - // Safe cast because of how our private map is managed. - RepeatedValueHandler handler = - (RepeatedValueHandler) repeatedValueHandlers.get(key); - if (handler != null) { - handler.handle(key, values, context); - } else if (defaultRepeatedHandler != null && !singleValueHandlers.containsKey(key)) { - // Casting MetadataKey to "" is safe since it only produces elements of 'T'. - // Casting the iterator is safe since it also only produces elements of 'T'. - defaultRepeatedHandler.handle( - (JvmMetadataKey) key, (Iterator) values, context); - } else { - // Dispatches keys individually. - super.handleRepeated(key, values, context); - } + private static final class MapBasedhandler extends MetadataHandler { + + private final Map, ValueHandler> singleValueHandlers = + new HashMap<>(); + private final Map, RepeatedValueHandler> repeatedValueHandlers = + new HashMap<>(); + private final ValueHandler defaultHandler; + private final RepeatedValueHandler defaultRepeatedHandler; + + private MapBasedhandler(Builder builder) { + this.singleValueHandlers.putAll(builder.singleValueHandlers); + this.repeatedValueHandlers.putAll(builder.repeatedValueHandlers); + this.defaultHandler = builder.defaultHandler; + this.defaultRepeatedHandler = builder.defaultRepeatedHandler; + } + + @SuppressWarnings("unchecked") // See comments for why casting is safe. + @Override + protected void handle(JvmMetadataKey key, T value, C context) { + // Safe cast because of how our private map is managed. + ValueHandler handler = + (ValueHandler) singleValueHandlers.get(key); + if (handler != null) { + handler.handle(key, value, context); + } else { + // Casting MetadataKey to "" is safe since it only produces elements of 'T'. + defaultHandler.handle((JvmMetadataKey) key, value, context); + } + } + + @SuppressWarnings("unchecked") // See comments for why casting is safe. + @Override + protected void handleRepeated(JvmMetadataKey key, Iterator values, C context) { + // Safe cast because of how our private map is managed. + RepeatedValueHandler handler = + (RepeatedValueHandler) repeatedValueHandlers.get(key); + if (handler != null) { + handler.handle(key, values, context); + } else if (defaultRepeatedHandler != null && !singleValueHandlers.containsKey(key)) { + // Casting MetadataKey to "" is safe since it only produces elements of 'T'. + // Casting the iterator is safe since it also only produces elements of 'T'. + defaultRepeatedHandler.handle( + (JvmMetadataKey) key, (Iterator) values, context); + } else { + // Dispatches keys individually. + super.handleRepeated(key, values, context); + } + } } - } } diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataKeyValueHandlers.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataKeyValueHandlers.java index 5da8761bc..3c377137d 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataKeyValueHandlers.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataKeyValueHandlers.java @@ -30,7 +30,7 @@ import io.spine.logging.jvm.JvmMetadataKey.KeyValueHandler; import io.spine.logging.jvm.backend.MetadataHandler.RepeatedValueHandler; import io.spine.logging.jvm.backend.MetadataHandler.ValueHandler; -import java.util.Iterator; + import java.util.Set; /** @@ -39,62 +39,60 @@ * handlers from this class. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger */ public final class MetadataKeyValueHandlers { - private static final ValueHandler EMIT_METADATA = - new ValueHandler() { - @Override - public void handle(JvmMetadataKey key, Object value, KeyValueHandler kvf) { - key.safeEmit(value, kvf); - } - }; - private static final RepeatedValueHandler EMIT_REPEATED_METADATA = - new RepeatedValueHandler() { - @Override - public void handle(JvmMetadataKey key, Iterator value, KeyValueHandler kvf) { - key.safeEmitRepeated(value, kvf); - } - }; + private static final ValueHandler EMIT_METADATA = + JvmMetadataKey::safeEmit; + + private static final RepeatedValueHandler EMIT_REPEATED_METADATA = + JvmMetadataKey::safeEmitRepeated; - /** Returns a singleton value handler which dispatches metadata to a {@link KeyValueHandler}. */ - public static ValueHandler getDefaultValueHandler() { - return EMIT_METADATA; - } + /** + * Returns a singleton value handler which dispatches metadata to a {@link KeyValueHandler}. + */ + public static ValueHandler getDefaultValueHandler() { + return EMIT_METADATA; + } - /** Returns a singleton value handler which dispatches metadata to a {@link KeyValueHandler}. */ - public static RepeatedValueHandler getDefaultRepeatedValueHandler() { - return EMIT_REPEATED_METADATA; - } + /** Returns a singleton value handler which dispatches metadata to a {@link KeyValueHandler}. */ + public static RepeatedValueHandler getDefaultRepeatedValueHandler() { + return EMIT_REPEATED_METADATA; + } - /** - * Returns a new {@link MetadataHandler.Builder} which handles all non-ignored metadata keys by - * dispatching their values to the key itself. This is convenient for generic metadata processing - * when used in conjunction with something like {@link KeyValueFormatter}. - * - *

      The returned builder can be built immediately or customized further to handler some keys - * specially (e.g. allowing keys/values to modify logging behaviour). - * - * @return a builder configured with the default key/value handlers and ignored keys. - */ - public static MetadataHandler.Builder getDefaultBuilder( - Set> ignored) { - return MetadataHandler.builder(getDefaultValueHandler()) - .setDefaultRepeatedHandler(getDefaultRepeatedValueHandler()) - .ignoring(ignored); - } + /** + * Returns a new {@link MetadataHandler.Builder} which handles all non-ignored metadata keys by + * dispatching their values to the key itself. This is convenient for generic metadata + * processing when used in conjunction with something like {@link KeyValueFormatter}. + * + *

      The returned builder can be built immediately or customized further to handler some keys + * specially (e.g., allowing keys/values to modify logging behaviour). + * + * @return a builder configured with the default key/value handlers and ignored keys. + */ + public static MetadataHandler.Builder getDefaultBuilder( + Set> ignored) { + return MetadataHandler.builder(getDefaultValueHandler()) + .setDefaultRepeatedHandler(getDefaultRepeatedValueHandler()) + .ignoring(ignored); + } - /** - * Returns a new {@link MetadataHandler} which handles all non-ignored metadata keys by - * dispatching their values to the key itself. This is convenient for generic metadata processing - * when used in conjunction with something like {@link KeyValueFormatter}. - * - * @return a handler configured with the default key/value handlers and ignored keys. - */ - public static MetadataHandler getDefaultHandler(Set> ignored) { - return getDefaultBuilder(ignored).build(); - } + /** + * Returns a new {@link MetadataHandler} which handles all non-ignored metadata keys by + * dispatching their values to the key itself. This is convenient for generic metadata + * processing when used in conjunction with something like {@link KeyValueFormatter}. + * + * @return a handler configured with the default key/value handlers and ignored keys. + */ + public static MetadataHandler getDefaultHandler( + Set> ignored) { + return getDefaultBuilder(ignored).build(); + } - private MetadataKeyValueHandlers() {} + /** + * Prevents instantiation of this utility class. + */ + private MetadataKeyValueHandlers() { + } } diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataProcessor.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataProcessor.java index 6b7b38320..c27ab6f01 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataProcessor.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataProcessor.java @@ -26,11 +26,10 @@ package io.spine.logging.jvm.backend; -import static io.spine.logging.jvm.util.Checks.checkArgument; -import static io.spine.logging.jvm.util.Checks.checkNotNull; - -import io.spine.logging.jvm.LogContext; import io.spine.logging.jvm.JvmMetadataKey; +import io.spine.logging.jvm.LogContext; +import org.jspecify.annotations.Nullable; + import java.util.AbstractSet; import java.util.ArrayList; import java.util.Collections; @@ -40,6 +39,9 @@ import java.util.Map; import java.util.Set; +import static io.spine.logging.jvm.util.Checks.checkArgument; +import static io.spine.logging.jvm.util.Checks.checkNotNull; + /** * Processor combining scope and log-site metadata into a single view. This is necessary when * backends wish to combine metadata without incurring the cost of building maps etc. While it is @@ -62,430 +64,452 @@ *

      Instances of MetadataProcessor are reusable, but not thread safe. All metadata processing must * be done in the logging thread. * - * @see - * Original Java code of Google Flogger + * @see + * Original Java code of Google Flogger */ public abstract class MetadataProcessor { - // Immutable empty processor which never handles any metadata. - private static final MetadataProcessor EMPTY_PROCESSOR = new MetadataProcessor() { - @Override - public void process(MetadataHandler handler, C context) {} - @Override - public void handle(JvmMetadataKey key, MetadataHandler handler, C context) {} + // Immutable empty processor which never handles any metadata. + private static final MetadataProcessor EMPTY_PROCESSOR = new MetadataProcessor() { + @Override + public void process(MetadataHandler handler, C context) { + } - @Override - public T getSingleValue(JvmMetadataKey key) { - return null; - } + @Override + public void handle(JvmMetadataKey key, MetadataHandler handler, C context) { + } - @Override - public int keyCount() { - return 0; - } + @Override + public T getSingleValue(JvmMetadataKey key) { + return null; + } - @Override - public Set> keySet() { - return Collections.emptySet(); - } - }; - - /** - * Returns a new processor for the combined scope and log-site metadata. Note that this returned - * instance may read directly from the supplied metadata during processing, so the supplied - * metadata must not be modified while the processor instance is being used. - * - * @param scopeMetadata Metadata for the current scope (i.e., from {@code ScopedLoggingContext}) - * @param logMetadata Metadata extracted from the current log statement (i.e., from {@code LogData}) - * @return a processor to handle a unified view of the data - */ - public static MetadataProcessor forScopeAndLogSite(Metadata scopeMetadata, Metadata logMetadata) { - int totalSize = scopeMetadata.size() + logMetadata.size(); - if (totalSize == 0) { - return EMPTY_PROCESSOR; - } else if (totalSize <= LightweightProcessor.MAX_LIGHTWEIGHT_ELEMENTS) { - return getLightweightProcessor(scopeMetadata, logMetadata); - } else { - return getSimpleProcessor(scopeMetadata, logMetadata); - } - } - - // Visible for testing - static MetadataProcessor getLightweightProcessor(Metadata scope, Metadata logged) { - return new LightweightProcessor(scope, logged); - } - - // Visible for testing - static MetadataProcessor getSimpleProcessor(Metadata scope, Metadata logged) { - return new SimpleProcessor(scope, logged); - } - - private MetadataProcessor() {} - - /** - * Processes a combined view of the scope and log-site metadata in this processor by invoking the - * given handler for each distinct metadata key. The handler method invoked depends on whether the - * key is single valued or repeated. - * - *

      Rules for merging scope and log-site metadata are as follows: - * - *

        - *
      • Distinct keys are iterated in the order they were first declared, with scope keys - * preceding log-site keys. - *
      • For singleton keys, a log-site value replaces any value supplied in the scope. - *
      • For repeated keys, all values are collected in declaration order, with scope values - * preceding log-site values. - *
      - * - *

      Note that equal or identical repeated values are permitted, and no "deduplication" is - * performed. This is very much in contrast to the {@link io.spine.logging.jvm.context.Tags - * Tags} mechanism, which de-duplicates mappings and reorders keys and values to generate a - * minimal, canonical representation. - * - *

      Furthermore, scope-supplied tags will be a single value in the scope metadata, keyed with - * the {@link LogContext.Key#TAGS TAGS} key. - * - * @param handler the metadata handler to be called back - * @param context arbitrary context instance to be passed into each callback. - */ - public abstract void process(MetadataHandler handler, C context); - - /** - * Invokes the given handler for the combined scope and log-site metadata for a specified key. - * The handler method invoked depends on whether the key is single valued or repeated. - * If no metadata is present for the given key, the handler is not invoked. - */ - public abstract void handle(JvmMetadataKey key, MetadataHandler handler, C context); - - /** - * Returns the unique value for a single valued key, or {@code null} if not present. - * - * @throws IllegalArgumentException if passed a repeatable key (even if that key has one value). - */ - public abstract T getSingleValue(JvmMetadataKey key); - - /** - * Returns the number of unique keys represented by this processor. This is the same as the size - * of {@link #keySet()}, but a separate method to avoid needing to allocate anything just to know - * the number of keys. - */ - public abstract int keyCount(); - - /** - * Returns the set of {@link JvmMetadataKey}s known to this processor, in the order in which - * they will be processed. Note that this implementation is lightweight, but not necessarily - * performant for things like containment testing. - */ - public abstract Set> keySet(); - - /* - * The values in the keyMap array are structured as: - * [ bits 31-5 : bitmap of additional repeated indices | bits 4-0 first value index ] - * - * There are 27 additional bits for the mask, but since index 0 could never be an "additional" - * value, the bit-mask indices only need to start from 1, giving a maximum of: - * 1 (first value index) + 27 (additional repeated indices in mask) - * indices in total. - * - * Obviously this could be extended to a "long", but the bloom filter is only efficient up to - * about 10-15 elements (and that's a super rare case anyway). At some point it's just not worth - * trying to squeeze anymore value from this class and the "SimpleProcessor" should be used - * instead (we might even want to switch before hitting 28 elements depending on performance). - */ - private static final class LightweightProcessor extends MetadataProcessor { - private static final int MAX_LIGHTWEIGHT_ELEMENTS = 28; - - private final Metadata scope; - private final Metadata logged; - // Mapping of key/value indices for distinct keys (kept in key "encounter" order). - private final int[] keyMap; - // Count of unique keys in the keyMap. - private final int keyCount; - - private LightweightProcessor(Metadata scope, Metadata logged) { - this.scope = checkNotNull(scope, "scope metadata"); - this.logged = checkNotNull(logged, "logged metadata"); - // We can never have more distinct keys, so this never needs resizing. This should be the - // only variable sized allocation required by this algorithm. When duplicate keys exist some - // elements at the end of the array will be unused, but the array is typically small and it is - // common for all keys to be distinct, so "right sizing" the array wouldn't be worth it. - int maxKeyCount = scope.size() + logged.size(); - // This should be impossible (outside of tests). - checkArgument(maxKeyCount <= MAX_LIGHTWEIGHT_ELEMENTS, "metadata size too large"); - this.keyMap = new int[maxKeyCount]; - this.keyCount = prepareKeyMap(keyMap); - } + @Override + public int keyCount() { + return 0; + } - @Override - public void process(MetadataHandler handler, C context) { - for (int i = 0; i < keyCount; i++) { - int n = keyMap[i]; - dispatch(getKey(n & 0x1F), n, handler, context); - } + @Override + public Set> keySet() { + return Collections.emptySet(); + } + }; + + /** + * Returns a new processor for the combined scope and log-site metadata. Note that this returned + * instance may read directly from the supplied metadata during processing, so the supplied + * metadata must not be modified while the processor instance is being used. + * + * @param scopeMetadata + * Metadata for the current scope (i.e., from {@code ScopedLoggingContext}) + * @param logMetadata + * Metadata extracted from the current log statement (i.e., from {@code LogData}) + * @return a processor to handle a unified view of the data + */ + public static MetadataProcessor forScopeAndLogSite(Metadata scopeMetadata, + Metadata logMetadata) { + var totalSize = scopeMetadata.size() + logMetadata.size(); + if (totalSize == 0) { + return EMPTY_PROCESSOR; + } else if (totalSize <= LightweightProcessor.MAX_LIGHTWEIGHT_ELEMENTS) { + return getLightweightProcessor(scopeMetadata, logMetadata); + } else { + return getSimpleProcessor(scopeMetadata, logMetadata); + } } - @Override - public void handle(JvmMetadataKey key, MetadataHandler handler, C context) { - int index = indexOf(key, keyMap, keyCount); - if (index >= 0) { - dispatch(key, keyMap[index], handler, context); - } + // Visible for testing + static MetadataProcessor getLightweightProcessor(Metadata scope, Metadata logged) { + return new LightweightProcessor(scope, logged); } - @Override - public T getSingleValue(JvmMetadataKey key) { - checkArgument(!key.canRepeat(), "key must be single valued"); - int index = indexOf(key, keyMap, keyCount); - // For single keys, the keyMap values are just the value index. - return (index >= 0) ? key.cast(getValue(keyMap[index])) : null; + // Visible for testing + static MetadataProcessor getSimpleProcessor(Metadata scope, Metadata logged) { + return new SimpleProcessor(scope, logged); } - @Override - public int keyCount() { - return keyCount; + private MetadataProcessor() { } - @Override - public Set> keySet() { - // We may want to cache this, since it's effectively immutable, but it's also a small and - // likely short lived instance, so quite possibly not worth it for the cost of another field. - return new AbstractSet>() { + /** + * Processes a combined view of the scope and log-site metadata in this processor by invoking + * the + * given handler for each distinct metadata key. The handler method invoked depends on whether + * the + * key is single valued or repeated. + * + *

      Rules for merging scope and log-site metadata are as follows: + * + *

        + *
      • Distinct keys are iterated in the order they were first declared, with scope keys + * preceding log-site keys. + *
      • For singleton keys, a log-site value replaces any value supplied in the scope. + *
      • For repeated keys, all values are collected in declaration order, with scope values + * preceding log-site values. + *
      + * + *

      Note that equal or identical repeated values are permitted, and no "deduplication" is + * performed. This is very much in contrast to the {@link io.spine.logging.jvm.context.Tags + * Tags} mechanism, which de-duplicates mappings and reorders keys and values to generate a + * minimal, canonical representation. + * + *

      Furthermore, scope-supplied tags will be a single value in the scope metadata, keyed with + * the {@link LogContext.Key#TAGS TAGS} key. + * + * @param handler + * the metadata handler to be called back + * @param context + * arbitrary context instance to be passed into each callback. + */ + public abstract void process(MetadataHandler handler, C context); + + /** + * Invokes the given handler for the combined scope and log-site metadata for a specified key. + * The handler method invoked depends on whether the key is single valued or repeated. + * If no metadata is present for the given key, the handler is not invoked. + */ + public abstract void handle(JvmMetadataKey key, MetadataHandler handler, C context); + + /** + * Returns the unique value for a single valued key, or {@code null} if not present. + * + * @throws IllegalArgumentException + * if passed a repeatable key (even if that key has one value). + */ + public abstract T getSingleValue(JvmMetadataKey key); + + /** + * Returns the number of unique keys represented by this processor. This is the same as the + * size + * of {@link #keySet()}, but a separate method to avoid needing to allocate anything just to + * know + * the number of keys. + */ + public abstract int keyCount(); + + /** + * Returns the set of {@link JvmMetadataKey}s known to this processor, in the order in which + * they will be processed. Note that this implementation is lightweight, but not necessarily + * performant for things like containment testing. + */ + public abstract Set> keySet(); + + /* + * The values in the keyMap array are structured as: + * [ bits 31-5 : bitmap of additional repeated indices | bits 4-0 first value index ] + * + * There are 27 additional bits for the mask, but since index 0 could never be an "additional" + * value, the bit-mask indices only need to start from 1, giving a maximum of: + * 1 (first value index) + 27 (additional repeated indices in mask) + * indices in total. + * + * Obviously this could be extended to a "long", but the bloom filter is only efficient up to + * about 10-15 elements (and that's a super rare case anyway). At some point it's just not worth + * trying to squeeze anymore value from this class and the "SimpleProcessor" should be used + * instead (we might even want to switch before hitting 28 elements depending on performance). + */ + private static final class LightweightProcessor extends MetadataProcessor { + + private static final int MAX_LIGHTWEIGHT_ELEMENTS = 28; + + private final Metadata scope; + private final Metadata logged; + // Mapping of key/value indices for distinct keys (kept in key "encounter" order). + private final int[] keyMap; + // Count of unique keys in the keyMap. + private final int keyCount; + + private LightweightProcessor(Metadata scope, Metadata logged) { + this.scope = checkNotNull(scope, "scope metadata"); + this.logged = checkNotNull(logged, "logged metadata"); + // We can never have more distinct keys, so this never needs resizing. This should be the + // only variable sized allocation required by this algorithm. When duplicate keys exist some + // elements at the end of the array will be unused, but the array is typically small and it is + // common for all keys to be distinct, so "right sizing" the array wouldn't be worth it. + var maxKeyCount = scope.size() + logged.size(); + // This should be impossible (outside of tests). + checkArgument(maxKeyCount <= MAX_LIGHTWEIGHT_ELEMENTS, "metadata size too large"); + this.keyMap = new int[maxKeyCount]; + this.keyCount = prepareKeyMap(keyMap); + } + + @Override + public void process(MetadataHandler handler, C context) { + for (var i = 0; i < keyCount; i++) { + var n = keyMap[i]; + dispatch(getKey(n & 0x1F), n, handler, context); + } + } + + @Override + public void handle(JvmMetadataKey key, MetadataHandler handler, C context) { + var index = indexOf(key, keyMap, keyCount); + if (index >= 0) { + dispatch(key, keyMap[index], handler, context); + } + } + @Override - public int size() { - return keyCount; + public T getSingleValue(JvmMetadataKey key) { + checkArgument(!key.canRepeat(), "key must be single valued"); + var index = indexOf(key, keyMap, keyCount); + // For single keys, the keyMap values are just the value index. + return (index >= 0) ? key.cast(getValue(keyMap[index])) : null; } @Override - public Iterator> iterator() { - return new Iterator>() { - private int i = 0; + public int keyCount() { + return keyCount; + } + + @Override + public Set> keySet() { + // We may want to cache this, since it's effectively immutable, but it's also a small and + // likely short lived instance, so quite possibly not worth it for the cost of another field. + return new AbstractSet>() { + @Override + public int size() { + return keyCount; + } + + @Override + public Iterator> iterator() { + return new Iterator<>() { + private int i = 0; + + @Override + public boolean hasNext() { + return i < keyCount; + } + + @Override + public JvmMetadataKey next() { + return getKey(keyMap[i++] & 0x1F); + } + + @Override + // in case we are on an earlier Java version with no default method for this + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + }; + } + + // Separate method to re-capture the value type. + private void dispatch(JvmMetadataKey key, int n, + MetadataHandler handler, C context) { + if (!key.canRepeat()) { + // For single keys, the keyMap values are just the value index. + handler.handle(key, key.cast(getValue(n)), context); + } else { + handler.handleRepeated(key, new ValueIterator(key, n), context); + } + } + + // Note that this could be made a reusable instance (reset between callbacks) if we wanted to + // same a little on allocations. However this is a fixed size instance and repeated keys are + // a fairly unusual use case. + private final class ValueIterator implements Iterator { + + private final JvmMetadataKey key; + private int nextIndex; + // For repeated keys, the bits 5-32 contain a mask of additional indices (where bit 5 + // implies index 1, since index 0 cannot apply to an additional repeated value). + private int mask; + + private ValueIterator(JvmMetadataKey key, int valueIndices) { + this.key = key; + // Get the first element index (lowest 5 bits, 0-27). + this.nextIndex = valueIndices & 0x1F; + // Adjust keymap indices mask so bit-0 represents the index *after* the first element. + // This adjustment is 5 (rather than the 4 with which indices are encoded) because we are + // shifting past the first index. + this.mask = valueIndices >>> (5 + nextIndex); + } @Override public boolean hasNext() { - return i < keyCount; + return nextIndex >= 0; } @Override - public JvmMetadataKey next() { - return getKey(keyMap[i++] & 0x1F); + public T next() { + var next = key.cast(getValue(nextIndex)); + if (mask != 0) { + // Skip the previous value and any "gaps" in the mask to find the new next index. + var skip = 1 + Integer.numberOfTrailingZeros(mask); + mask >>>= skip; + nextIndex += skip; + } else { + // After returning the current value we're done. + nextIndex = -1; + } + return next; } @Override // in case we are on an earlier Java version with no default method for this public void remove() { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException(); } - }; } - }; - } - // Separate method to re-capture the value type. - private void dispatch(JvmMetadataKey key, int n, - MetadataHandler handler, C context) { - if (!key.canRepeat()) { - // For single keys, the keyMap values are just the value index. - handler.handle(key, key.cast(getValue(n)), context); - } else { - handler.handleRepeated(key, new ValueIterator(key, n), context); - } - } - - // Note that this could be made a reusable instance (reset between callbacks) if we wanted to - // same a little on allocations. However this is a fixed size instance and repeated keys are - // a fairly unusual use case. - private final class ValueIterator implements Iterator { - private final JvmMetadataKey key; - private int nextIndex; - // For repeated keys, the bits 5-32 contain a mask of additional indices (where bit 5 - // implies index 1, since index 0 cannot apply to an additional repeated value). - private int mask; - - private ValueIterator(JvmMetadataKey key, int valueIndices) { - this.key = key; - // Get the first element index (lowest 5 bits, 0-27). - this.nextIndex = valueIndices & 0x1F; - // Adjust keymap indices mask so bit-0 represents the index *after* the first element. - // This adjustment is 5 (rather than the 4 with which indices are encoded) because we are - // shifting past the first index. - this.mask = valueIndices >>> (5 + nextIndex); - } - - @Override - public boolean hasNext() { - return nextIndex >= 0; - } - - @Override - public T next() { - T next = key.cast(getValue(nextIndex)); - if (mask != 0) { - // Skip the previous value and any "gaps" in the mask to find the new next index. - int skip = 1 + Integer.numberOfTrailingZeros(mask); - mask >>>= skip; - nextIndex += skip; - } else { - // After returning the current value we're done. - nextIndex = -1; + // Fill the keyMap array and return the count of distinct keys found. + private int prepareKeyMap(int[] keyMap) { + var bloomFilterMask = 0L; + var count = 0; + for (var n = 0; n < keyMap.length; n++) { + var key = getKey(n); + // Use the bloom filter mask to get a quick true-negative test for whether we've seen this + // key before. Most keys are distinct and this test is very reliable up to 10-15 keys, so + // it saves building a HashSet or similar to track the set of unique keys. + var oldMask = bloomFilterMask; + bloomFilterMask |= key.getBloomFilterMask(); + if (bloomFilterMask == oldMask) { + // Very probably a duplicate key. This is rare compared to distinct keys, but will happen + // (e.g. for repeated keys with several values). Now we find the index of the key (since + // we need to update that element in the keyMap array). This is a linear search but in + // normal usage should happen once or twice over a small set (e.g. 5 distinct elements). + // It is still expected to be faster/cheaper than creating and populating a HashSet. + // + // NOTE: It is impossible to get here if (n == 0) because the key's bloom filter must have + // at least one bit set so can never equal the initial mask first time round the loop. + var i = indexOf(key, keyMap, count); + // If the index is -1, it wasn't actually in the set and this was a false-positive. + if (i != -1) { + // Definitely duplicate key. The key could still be non-repeating though since it might + // appear in both scope and logged metadata exactly once: + // * For non-repeating keys, just replace the existing map value with the new index. + // * For repeated keys, keep the index in the low 5-bits and set a new bit in the mask. + // + // Since we can never see (n == 0) here, we encode index 1 at bit 5 (hence "n + 4", not + // "n + 5" below). This trick just gives us the ability to store one more index. + keyMap[i] = key.canRepeat() ? keyMap[i] | (1 << (n + 4)) : n; + continue; + } + } + // This key is definitely not already in the keyMap, so add it and increment the count. + keyMap[count++] = n; + } + return count; } - return next; - } - - @Override // in case we are on an earlier Java version with no default method for this - public void remove() { - throw new UnsupportedOperationException(); - } - } - // Fill the keyMap array and return the count of distinct keys found. - private int prepareKeyMap(int[] keyMap) { - long bloomFilterMask = 0L; - int count = 0; - for (int n = 0; n < keyMap.length; n++) { - JvmMetadataKey key = getKey(n); - // Use the bloom filter mask to get a quick true-negative test for whether we've seen this - // key before. Most keys are distinct and this test is very reliable up to 10-15 keys, so - // it saves building a HashSet or similar to track the set of unique keys. - long oldMask = bloomFilterMask; - bloomFilterMask |= key.getBloomFilterMask(); - if (bloomFilterMask == oldMask) { - // Very probably a duplicate key. This is rare compared to distinct keys, but will happen - // (e.g. for repeated keys with several values). Now we find the index of the key (since - // we need to update that element in the keyMap array). This is a linear search but in - // normal usage should happen once or twice over a small set (e.g. 5 distinct elements). - // It is still expected to be faster/cheaper than creating and populating a HashSet. - // - // NOTE: It is impossible to get here if (n == 0) because the key's bloom filter must have - // at least one bit set so can never equal the initial mask first time round the loop. - int i = indexOf(key, keyMap, count); - // If the index is -1, it wasn't actually in the set and this was a false-positive. - if (i != -1) { - // Definitely duplicate key. The key could still be non-repeating though since it might - // appear in both scope and logged metadata exactly once: - // * For non-repeating keys, just replace the existing map value with the new index. - // * For repeated keys, keep the index in the low 5-bits and set a new bit in the mask. - // - // Since we can never see (n == 0) here, we encode index 1 at bit 5 (hence "n + 4", not - // "n + 5" below). This trick just gives us the ability to store one more index. - keyMap[i] = key.canRepeat() ? keyMap[i] | (1 << (n + 4)) : n; - continue; - } + // Returns the (unique) index into the keyMap array for the given key. + private int indexOf(JvmMetadataKey key, int[] keyMap, int count) { + for (var i = 0; i < count; i++) { + // Low 5 bits of keyMap values are *always* an index to a valid metadata key. + if (key.equals(getKey(keyMap[i] & 0x1F))) { + return i; + } + } + return -1; } - // This key is definitely not already in the keyMap, so add it and increment the count. - keyMap[count++] = n; - } - return count; - } - // Returns the (unique) index into the keyMap array for the given key. - private int indexOf(JvmMetadataKey key, int[] keyMap, int count) { - for (int i = 0; i < count; i++) { - // Low 5 bits of keyMap values are *always* an index to a valid metadata key. - if (key.equals(getKey(keyMap[i] & 0x1F))) { - return i; + private JvmMetadataKey getKey(int n) { + var scopeSize = scope.size(); + return n >= scopeSize ? logged.getKey(n - scopeSize) : scope.getKey(n); } - } - return -1; - } - private JvmMetadataKey getKey(int n) { - int scopeSize = scope.size(); - return n >= scopeSize ? logged.getKey(n - scopeSize) : scope.getKey(n); + private Object getValue(int n) { + var scopeSize = scope.size(); + return n >= scopeSize ? logged.getValue(n - scopeSize) : scope.getValue(n); + } } - private Object getValue(int n) { - int scopeSize = scope.size(); - return n >= scopeSize ? logged.getValue(n - scopeSize) : scope.getValue(n); - } - } - - /** - * Simple version of a metadata processor which allocates "large" data structures. This is needed - * when a large number of metadata elements need processing. It should behave exactly the same as - * the "lightweight" processor if the supplied Metadata is correctly behaved and not modified - * during processing. - */ - private static final class SimpleProcessor extends MetadataProcessor { - private final Map, Object> map; - - private SimpleProcessor(Metadata scope, Metadata logged) { - LinkedHashMap, Object> map = new LinkedHashMap, Object>(); - addTo(map, scope); - addTo(map, logged); - // Wrap any repeated value lists to make them unmodifiable (required for correctness). - for (Map.Entry, Object> e : map.entrySet()) { - if (e.getKey().canRepeat()) { - e.setValue(Collections.unmodifiableList((List) e.getValue())); + /** + * Simple version of a metadata processor which allocates "large" data structures. This is + * needed + * when a large number of metadata elements need processing. It should behave exactly the same + * as + * the "lightweight" processor if the supplied Metadata is correctly behaved and not modified + * during processing. + */ + private static final class SimpleProcessor extends MetadataProcessor { + + private final Map, Object> map; + + private SimpleProcessor(Metadata scope, Metadata logged) { + var map = new LinkedHashMap, Object>(); + addTo(map, scope); + addTo(map, logged); + // Wrap any repeated value lists to make them unmodifiable (required for correctness). + for (var e : map.entrySet()) { + if (e.getKey() + .canRepeat()) { + e.setValue(Collections.unmodifiableList((List) e.getValue())); + } + } + this.map = Collections.unmodifiableMap(map); } - } - this.map = Collections.unmodifiableMap(map); - } - // Unlike the LightweightProcessor, we copy references from the Metadata eagerly, so can "cast" - // values to their key-types early, ensuring safe casting when dispatching. - private static void addTo(Map, Object> map, Metadata metadata) { - for (int i = 0; i < metadata.size(); i++) { - JvmMetadataKey key = metadata.getKey(i); - Object value = map.get(key); - if (key.canRepeat()) { - @SuppressWarnings("unchecked") - List list = (List) value; - if (list == null) { - list = new ArrayList(); - map.put(key, list); - } - // Cast value to ensure that "repeated key is MetadataKey" implies "value is List" - list.add(key.cast(metadata.getValue(i))); - } else { - // Cast value to ensure that "singleton key is MetadataKey" implies "value is T". - map.put(key, key.cast(metadata.getValue(i))); + // Unlike the LightweightProcessor, we copy references from the Metadata eagerly, so can "cast" + // values to their key-types early, ensuring safe casting when dispatching. + private static void addTo(Map, Object> map, Metadata metadata) { + for (var i = 0; i < metadata.size(); i++) { + var key = metadata.getKey(i); + var value = map.get(key); + if (key.canRepeat()) { + @SuppressWarnings("unchecked") + var list = (List) value; + if (list == null) { + list = new ArrayList(); + map.put(key, list); + } + // Cast value to ensure that "repeated key is MetadataKey" implies "value is List" + list.add(key.cast(metadata.getValue(i))); + } else { + // Cast value to ensure that "singleton key is MetadataKey" implies "value is T". + map.put(key, key.cast(metadata.getValue(i))); + } + } } - } - } - @Override - public void process(MetadataHandler handler, C context) { - for (Map.Entry, Object> e : map.entrySet()) { - dispatch(e.getKey(), e.getValue(), handler, context); - } - } + @Override + public void process(MetadataHandler handler, C context) { + for (var e : map.entrySet()) { + dispatch(e.getKey(), e.getValue(), handler, context); + } + } - @Override - public void handle(JvmMetadataKey key, MetadataHandler handler, C context) { - Object value = map.get(key); - if (value != null) { - dispatch(key, value, handler, context); - } - } + @Override + public void handle(JvmMetadataKey key, MetadataHandler handler, C context) { + var value = map.get(key); + if (value != null) { + dispatch(key, value, handler, context); + } + } - // It's safe to ignore warnings since single keys are only ever 'T' when added to the map. - @Override - @SuppressWarnings("unchecked") - public T getSingleValue(JvmMetadataKey key) { - checkArgument(!key.canRepeat(), "key must be single valued"); - Object value = map.get(key); - return (value != null) ? (T) value : null; - } + // It's safe to ignore warnings since single keys are only ever 'T' when added to the map. + @Override + @SuppressWarnings("unchecked") + public <@Nullable T> T getSingleValue(JvmMetadataKey key) { + checkArgument(!key.canRepeat(), "key must be single valued"); + var value = map.get(key); + return (value != null) ? (T) value : null; + } - @Override - public int keyCount() { - return map.size(); - } + @Override + public int keyCount() { + return map.size(); + } - @Override - public Set> keySet() { - return map.keySet(); - } + @Override + public Set> keySet() { + return map.keySet(); + } - // It's safe to ignore warnings here since we know that repeated keys only ever get 'List' - // and single keys are only ever 'T' when added to the map. - @SuppressWarnings("unchecked") - private static void dispatch( - JvmMetadataKey key, Object value, MetadataHandler handler, C context) { - if (key.canRepeat()) { - handler.handleRepeated(key, ((List) value).iterator(), context); - } else { - handler.handle(key, (T) value, context); - } + // It's safe to ignore warnings here since we know that repeated keys only ever get 'List' + // and single keys are only ever 'T' when added to the map. + @SuppressWarnings("unchecked") + private static void dispatch( + JvmMetadataKey key, Object value, MetadataHandler handler, C context) { + if (key.canRepeat()) { + handler.handleRepeated(key, ((List) value).iterator(), context); + } else { + handler.handle(key, (T) value, context); + } + } } - } } diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/Platform.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/Platform.java index 0bd50c49a..1c817d06f 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/Platform.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/Platform.java @@ -50,281 +50,310 @@ * constructor. Platform instances are created on first-use of a fluent logger, and platform * implementors must take care to avoid cycles during initialization and re-entrant behaviour. * - * @see - * Original Java code of Google Flogger + * @see + * Original Java code of Google Flogger */ public abstract class Platform { - // non-final to prevent javac inlining. - @SuppressWarnings("ConstantField") - private static String DEFAULT_PLATFORM = - "io.spine.logging.backend.system.DefaultPlatform"; + // non-final to prevent javac inlining. + @SuppressWarnings("ConstantField") + private static String DEFAULT_PLATFORM = + "io.spine.logging.backend.system.DefaultPlatform"; - // The first available platform from this list is used. Each platform is defined separately - // outside of this array so that the IdentifierNameString annotation can be applied to each. - // This annotation tells Proguard that these strings refer to class names. - // If Proguard decides to obfuscate those classes, it will also obfuscate these strings so - // that reflection can still be used. - private static final String[] AVAILABLE_PLATFORMS = - new String[] { - // The fallback/default platform gives a workable, logging backend. - DEFAULT_PLATFORM - }; + // The first available platform from this list is used. Each platform is defined separately + // outside of this array so that the IdentifierNameString annotation can be applied to each. + // This annotation tells Proguard that these strings refer to class names. + // If Proguard decides to obfuscate those classes, it will also obfuscate these strings so + // that reflection can still be used. + private static final String[] AVAILABLE_PLATFORMS = { + // The fallback/default platform gives a workable, logging backend. + DEFAULT_PLATFORM + }; - // Use the lazy holder idiom here to avoid class loading issues. Loading the Platform subclass - // will trigger static initialization of the Platform class first, which would not be possible if - // the INSTANCE field were a static field in Platform. This means that any errors in platform - // loading are deferred until the first time one of the Platform's static methods is invoked. - private static final class LazyHolder { - private static final Platform INSTANCE = loadFirstAvailablePlatform(AVAILABLE_PLATFORMS); + // Use the lazy holder idiom here to avoid class loading issues. Loading the Platform subclass + // will trigger static initialization of the Platform class first, which would not be possible if + // the INSTANCE field were a static field in Platform. This means that any errors in platform + // loading are deferred until the first time one of the Platform's static methods is invoked. + private static final class LazyHolder { - private static Platform loadFirstAvailablePlatform(String[] platformClass) { - Platform platform = null; - // Try the platform provider first if it's available. - try { - platform = PlatformProvider.getPlatform(); - } catch (NoClassDefFoundError e) { - // May be an expected error: The PlatformProvider is an optional dependency that can - // be provided at runtime. Inside Google we use a generator to create the class file for - // it programmatically, but for third-party use cases the provider could be made available - // through custom classpath management. - } - if (platform != null) { - return platform; - } + private static final Platform INSTANCE = loadFirstAvailablePlatform(AVAILABLE_PLATFORMS); - StringBuilder errorMessage = new StringBuilder(); - // Try the reflection-based approach as a backup, if the provider isn't available. - for (String clazz : platformClass) { - try { - return (Platform) Class.forName(clazz).getConstructor().newInstance(); - } catch (Throwable e) { - // Catch errors so if we can't find _any_ implementations, we can report something useful. - // Unwrap any generic wrapper exceptions for readability here (extend this as needed). - if (e instanceof InvocationTargetException) { - e = e.getCause(); - } - errorMessage.append('\n').append(clazz).append(": ").append(e); + private static Platform loadFirstAvailablePlatform(String[] platformClass) { + var platform = viaHolder(); + if (platform != null) { + return platform; + } + + var errorMessage = new StringBuilder(); + // Try the reflection-based approach as a backup, if the provider isn't available. + for (var clazz : platformClass) { + try { + return (Platform) Class.forName(clazz) + .getConstructor() + .newInstance(); + } catch (Throwable e) { + // Catch errors so if we can't find _any_ implementations, we can report something useful. + // Unwrap any generic wrapper exceptions for readability here (extend this as needed). + if (e instanceof InvocationTargetException) { + e = e.getCause(); + } + errorMessage.append('\n') + .append(clazz) + .append(": ") + .append(e); + } + } + throw new IllegalStateException( + errorMessage.insert(0, "No logging platforms found:") + .toString()); } - } - throw new IllegalStateException( - errorMessage.insert(0, "No logging platforms found:").toString()); - } - } - /** - * Returns the current depth of recursion for logging in the current thread. - * - *

      This method is intended only for use by logging backends or the core Flogger library and - * only needs to be called by code which is invoking user code which itself might trigger - * reentrant logging. - * - *

        - *
      • A value of 1 means that this thread is currently in a normal log statement. This is the - * expected state and the caller should behave normally. - *
      • A value greater than 1 means that this thread is currently performing reentrant logging, - * and the caller may choose to change behaviour depending on the value if there is a risk that - * reentrant logging is being caused by the caller's code. - *
      • A value of zero means that this thread is not currently logging (though since this method - * should only be called as part of a logging library, this is expected to never happen). It - * should be ignored. - *
      - * - *

      When the core Flogger library detects the depth exceeding a preset threshold, it may start - * to modify its behaviour to attempt to mitigate the risk of unbounded reentrant logging. For - * example, some or all metadata may be removed from log sites, since processing user-provided - * metadata may itself trigger reentrant logging. - */ - public static int getCurrentRecursionDepth() { - return RecursionDepth.getCurrentDepth(); - } + private static @Nullable Platform viaHolder() { + Platform platform = null; + // Try the platform provider first if it is available. + try { + platform = PlatformProvider.getPlatform(); + } catch (NoClassDefFoundError e) { + // May be an expected error: The PlatformProvider is an optional dependency that can + // be provided at runtime. Inside Google we use a generator to create the class file for + // it programmatically, but for third-party use cases the provider could be made available + // through custom classpath management. + } + return platform; + } + } - /** - * API for determining the logging class and log statement sites, return from {@link - * #getCallerFinder}. These classes are immutable and thread-safe. - * - *

      This functionality is not provided directly by the {@code Platform} API because doing so - * would require several additional levels to be added to the stack before the implementation was - * reached. This is problematic for Android, which has only limited stack analysis. By allowing - * callers to resolve the implementation early and then call an instance directly (this is not an - * interface), we reduce the number of elements in the stack before the caller is found. - * - *

      Essential Implementation Restrictions

      - * - * Any implementation of this API MUST follow the rules listed below to avoid any risk of - * re-entrant code calling during logger initialization. Failure to do so risks creating complex, - * hard to debug, issues with Flogger configuration. - * - *
        - *
      1. Implementations MUST NOT attempt any logging in static methods or constructors. - *
      2. Implementations MUST NOT statically depend on any unknown code. - *
      3. Implementations MUST NOT depend on any unknown code in constructors. - *
      - * - *

      Note that logging and calling arbitrary unknown code (which might log) are permitted inside - * the instance methods of this API, since they are not called during platform initialization. The - * easiest way to achieve this is to simply avoid having any non-trivial static fields or any - * instance fields at all in the implementation. - * - *

      While this sounds onerous it's not difficult to achieve because this API is a singleton, and - * can delay any actual work until its methods are called. For example, if any additional state is - * required in the implementation, it can be held via a "lazy holder" to defer initialization. - */ - public abstract static class LogCallerFinder { /** - * Returns the name of the immediate caller of the given logger class. This is useful when - * determining the class name with which to create a logger backend. + * Returns the current depth of recursion for logging in the current thread. + * + *

      This method is intended only for use by logging backends or the core Flogger library and + * only needs to be called by code which is invoking user code which itself might trigger + * reentrant logging. + * + *

        + *
      • A value of 1 means that this thread is currently in a normal log statement. This is the + * expected state and the caller should behave normally. + *
      • A value greater than 1 means that this thread is currently performing reentrant logging, + * and the caller may choose to change behaviour depending on the value if there is a risk that + * reentrant logging is being caused by the caller's code. + *
      • A value of zero means that this thread is not currently logging (though since this method + * should only be called as part of a logging library, this is expected to never happen). It + * should be ignored. + *
      * - * @param loggerClass the class containing the log() methods whose caller we need to find. - * @return the name of the class that called the specified logger. - * @throws IllegalStateException if there was no caller of the specified logged passed on the - * stack (which may occur if the logger class was invoked directly by JNI). + *

      When the core Flogger library detects the depth exceeding a preset threshold, it may start + * to modify its behaviour to attempt to mitigate the risk of unbounded reentrant logging. For + * example, some or all metadata may be removed from log sites, since processing user-provided + * metadata may itself trigger reentrant logging. */ - public abstract String findLoggingClass(Class> loggerClass); + public static int getCurrentRecursionDepth() { + return RecursionDepth.getCurrentDepth(); + } /** - * Returns a LogSite found from the current stack trace for the caller of the log() method on - * the given logging class. + * API for determining the logging class and log statement sites, return from {@link + * #getCallerFinder}. These classes are immutable and thread-safe. + * + *

      This functionality is not provided directly by the {@code Platform} API because doing so + * would require several additional levels to be added to the stack before the implementation + * was + * reached. This is problematic for Android, which has only limited stack analysis. By allowing + * callers to resolve the implementation early and then call an instance directly (this is not + * an + * interface), we reduce the number of elements in the stack before the caller is found. + * + *

      Essential Implementation Restrictions

      + * + * Any implementation of this API MUST follow the rules listed below to avoid any risk + * of + * re-entrant code calling during logger initialization. Failure to do so risks creating + * complex, + * hard to debug, issues with Flogger configuration. + * + *
        + *
      1. Implementations MUST NOT attempt any logging in static methods or constructors. + *
      2. Implementations MUST NOT statically depend on any unknown code. + *
      3. Implementations MUST NOT depend on any unknown code in constructors. + *
      + * + *

      Note that logging and calling arbitrary unknown code (which might log) are permitted inside + * the instance methods of this API, since they are not called during platform initialization. The + * easiest way to achieve this is to simply avoid having any non-trivial static fields or any + * instance fields at all in the implementation. * - * @param loggerApi the class containing the log() methods whose caller we need to find. - * @param stackFramesToSkip the number of method calls which exist on the stack between the - * {@code log()} method and the point at which this method is invoked. - * @return A log site inferred from the stack, or {@link JvmLogSite#INVALID} if no log site - * can be determined. + *

      While this sounds onerous it's not difficult to achieve because this API is a singleton, and + * can delay any actual work until its methods are called. For example, if any additional state is + * required in the implementation, it can be held via a "lazy holder" to defer initialization. */ - public abstract JvmLogSite findLogSite(Class loggerApi, int stackFramesToSkip); - } + public abstract static class LogCallerFinder { - /** - * Returns the API for obtaining caller information about loggers and logging classes. - */ - public static LogCallerFinder getCallerFinder() { - return LazyHolder.INSTANCE.getCallerFinderImpl(); - } + /** + * Returns the name of the immediate caller of the given logger class. This is useful when + * determining the class name with which to create a logger backend. + * + * @param loggerClass + * the class containing the log() methods whose caller we need to find. + * @return the name of the class that called the specified logger. + * @throws IllegalStateException + * if there was no caller of the specified logged passed on the + * stack (which may occur if the logger class was invoked directly by JNI). + */ + public abstract String findLoggingClass(Class> loggerClass); - protected abstract LogCallerFinder getCallerFinderImpl(); + /** + * Returns a LogSite found from the current stack trace for the caller of the log() method + * on + * the given logging class. + * + * @param loggerApi + * the class containing the log() methods whose caller we need to find. + * @param stackFramesToSkip + * the number of method calls which exist on the stack between the + * {@code log()} method and the point at which this method is invoked. + * @return A log site inferred from the stack, or {@link JvmLogSite#INVALID} if no log site + * can be determined. + */ + public abstract JvmLogSite findLogSite(Class loggerApi, int stackFramesToSkip); + } + + /** + * Returns the API for obtaining caller information about loggers and logging classes. + */ + public static LogCallerFinder getCallerFinder() { + return LazyHolder.INSTANCE.getCallerFinderImpl(); + } + + protected abstract LogCallerFinder getCallerFinderImpl(); - /** - * Returns a logger backend of the given class name for use by a Fluent Logger. Note that the - * returned backend need not be unique; one backend could be used by multiple loggers. The given - * class name must be in the normal dot-separated form (e.g. "com.example.Foo$Bar") rather than - * the internal binary format (e.g. "com/example/Foo$Bar"). - * - * @param className the fully qualified name of the Java class to which the logger is associated. - * The logger name is derived from this string in a platform-specific way. - */ - public static LoggerBackend getBackend(String className) { - return LazyHolder.INSTANCE.getBackendImpl(className); - } + /** + * Returns a logger backend of the given class name for use by a Fluent Logger. Note that the + * returned backend need not be unique; one backend could be used by multiple loggers. The given + * class name must be in the normal dot-separated form (e.g. "com.example.Foo$Bar") rather than + * the internal binary format (e.g. "com/example/Foo$Bar"). + * + * @param className + * the fully qualified name of the Java class to which the logger is associated. + * The logger name is derived from this string in a platform-specific way. + */ + public static LoggerBackend getBackend(String className) { + return LazyHolder.INSTANCE.getBackendImpl(className); + } - protected abstract LoggerBackend getBackendImpl(String className); + protected abstract LoggerBackend getBackendImpl(String className); - /** - * Returns the singleton ContextDataProvider from which a ScopedLoggingContext can be obtained. - * Platform implementations are required to always provide the same instance here, since this can - * be cached by callers. - */ - public static ContextDataProvider getContextDataProvider() { - return LazyHolder.INSTANCE.getContextDataProviderImpl(); - } + /** + * Returns the singleton ContextDataProvider from which a ScopedLoggingContext can be obtained. + * Platform implementations are required to always provide the same instance here, since this + * can + * be cached by callers. + */ + public static ContextDataProvider getContextDataProvider() { + return LazyHolder.INSTANCE.getContextDataProviderImpl(); + } - // Provide default implementation here for new API, but Platform implementations are expected to - // override this (one day it should be possible to make this abstract). - protected ContextDataProvider getContextDataProviderImpl() { - return ContextDataProvider.getNoOpProvider(); - } + // Provide default implementation here for new API, but Platform implementations are expected to + // override this (one day it should be possible to make this abstract). + protected ContextDataProvider getContextDataProviderImpl() { + return ContextDataProvider.getNoOpProvider(); + } - /** - * Returns whether the given logger should have logging forced at the specified level. - * - *

      When logging is forced for a log statement, it will be emitted regardless. - * Or, the normal log level configuration of the logger and ignoring any rate limiting or - * other filtering. - * - *

      This method is intended to be invoked unconditionally from a fluent logger's - * {@code at(Level)} method to permit overriding of default logging behavior. - * - * @param loggerName the fully qualified logger name (e.g. "com.example.SomeClass") - * @param level the level of the log statement being invoked - * @param isEnabled whether the logger is enabled at the given level (i.e., the result of calling - * {@code isLoggable()} on the backend instance) - */ - public static boolean shouldForceLogging(String loggerName, Level level, boolean isEnabled) { - return getContextDataProvider().shouldForceLogging(loggerName, level, isEnabled); - } + /** + * Returns whether the given logger should have logging forced at the specified level. + * + *

      When logging is forced for a log statement, it will be emitted regardless. + * Or, the normal log level configuration of the logger and ignoring any rate limiting or + * other filtering. + * + *

      This method is intended to be invoked unconditionally from a fluent logger's + * {@code at(Level)} method to permit overriding of default logging behavior. + * + * @param loggerName + * the fully qualified logger name (e.g. "com.example.SomeClass") + * @param level + * the level of the log statement being invoked + * @param isEnabled + * whether the logger is enabled at the given level (i.e., the result of calling + * {@code isLoggable()} on the backend instance) + */ + public static boolean shouldForceLogging(String loggerName, Level level, boolean isEnabled) { + return getContextDataProvider().shouldForceLogging(loggerName, level, isEnabled); + } - /** - * Obtains a custom logging level set for the logger with the given name via - * a {@link io.spine.logging.jvm.context.LogLevelMap} set in the current logging context. - * - *

      The method returns {@code null} if: - *

        - *
      • There is no current logging context installed. - *
      • The context does not have a log level map. - *
      • The log level map does not have a custom level for the given logger. - *
      - * @param loggerName the name of the logger - * @return the custom level or {@code null} - */ - public static @Nullable Level getMappedLevel(String loggerName) { - checkNotNull(loggerName); - var provider = getContextDataProvider(); - var result = provider.getMappedLevel(loggerName); - if (result == null) { - return null; - } - return result; - } + /** + * Obtains a custom logging level set for the logger with the given name via + * a {@link io.spine.logging.jvm.context.LogLevelMap} set in the current logging context. + * + *

      The method returns {@code null} if: + *

        + *
      • There is no current logging context installed. + *
      • The context does not have a log level map. + *
      • The log level map does not have a custom level for the given logger. + *
      + * + * @param loggerName + * the name of the logger + * @return the custom level or {@code null} + */ + public static @Nullable Level getMappedLevel(String loggerName) { + checkNotNull(loggerName); + var provider = getContextDataProvider(); + var result = provider.getMappedLevel(loggerName); + if (result == null) { + return null; + } + return result; + } - /** Returns {@link Tags} from with the current context to be injected into log statements. */ - public static Tags getInjectedTags() { - return getContextDataProvider().getTags(); - } + /** Returns {@link Tags} from with the current context to be injected into log statements. */ + public static Tags getInjectedTags() { + return getContextDataProvider().getTags(); + } - /** Returns {@link Metadata} from with the current context to be injected into log statements. */ - // TODO(dbeaumont): Make this return either an extensible MetadataProcessor or ScopeMetadata. - public static Metadata getInjectedMetadata() { - return getContextDataProvider().getMetadata(); - } + /** Returns {@link Metadata} from with the current context to be injected into log statements. */ + // TODO(dbeaumont): Make this return either an extensible MetadataProcessor or ScopeMetadata. + public static Metadata getInjectedMetadata() { + return getContextDataProvider().getMetadata(); + } - /** - * Returns the current time from the epoch (00:00 1st Jan, 1970) with nanosecond granularity. - * This is a non-negative signed 64-bit value, which must be in the range {@code 0 <= timestamp - * < 2^63}, ensuring that the difference between any two timestamps will always yield a valid - * signed value. - * - *

      Warning: Not all Platform implementations will be able to deliver nanosecond precision and - * code should avoid relying on any implied precision. - */ - public static long getCurrentTimeNanos() { - return LazyHolder.INSTANCE.getCurrentTimeNanosImpl(); - } + /** + * Returns the current time from the epoch (00:00 1st Jan, 1970) with nanosecond granularity. + * This is a non-negative signed 64-bit value, which must be in the range {@code 0 <= timestamp + * < 2^63}, ensuring that the difference between any two timestamps will always yield a valid + * signed value. + * + *

      Warning: Not all Platform implementations will be able to deliver nanosecond precision and + * code should avoid relying on any implied precision. + */ + public static long getCurrentTimeNanos() { + return LazyHolder.INSTANCE.getCurrentTimeNanosImpl(); + } - protected long getCurrentTimeNanosImpl() { - // Sadly, this is the best you can currently do with vanilla Java. In Java9 you have access to - // nanosecond clocks, but Flogger needs to be backwards compatible, so it won't be as simple - // as just changing this line of code. - // Overflow will not occur until sometime around 2264, so it's safe not to care for now. - return MILLISECONDS.toNanos(System.currentTimeMillis()); - } + protected long getCurrentTimeNanosImpl() { + // Sadly, this is the best you can currently do with vanilla Java. In Java9 you have access to + // nanosecond clocks, but Flogger needs to be backwards compatible, so it won't be as simple + // as just changing this line of code. + // Overflow will not occur until sometime around 2264, so it's safe not to care for now. + return MILLISECONDS.toNanos(System.currentTimeMillis()); + } - /** - * Returns a human-readable string describing the platform and its configuration. This should - * contain everything a human would need to see to check that the Platform was configured as - * expected. It should contain the platform name along with any configurable elements - * (e.g., plugin services) and their settings. It is recommended (though not required) that this - * string is formatted with one piece of configuration per line in a tabular format, such as: - *

      {@code
      -   * platform: 
      -   * formatter: com.example.logging.FormatterPlugin
      -   * formatter.foo: <"foo" settings for the formatter plugin>
      -   * formatter.bar: <"bar" settings for the formatter plugin>
      -   * }
      - * It is not required that this string be machine parseable (though it should be stable). - */ - public static String getConfigInfo() { - return LazyHolder.INSTANCE.getConfigInfoImpl(); - } + /** + * Returns a human-readable string describing the platform and its configuration. This should + * contain everything a human would need to see to check that the Platform was configured as + * expected. It should contain the platform name along with any configurable elements + * (e.g., plugin services) and their settings. It is recommended (though not required) that this + * string is formatted with one piece of configuration per line in a tabular format, such as: + *
      {@code
      +     * platform: 
      +     * formatter: com.example.logging.FormatterPlugin
      +     * formatter.foo: <"foo" settings for the formatter plugin>
      +     * formatter.bar: <"bar" settings for the formatter plugin>
      +     * }
      + * It is not required that this string be machine parseable (though it should be stable). + */ + public static String getConfigInfo() { + return LazyHolder.INSTANCE.getConfigInfoImpl(); + } - protected abstract String getConfigInfoImpl(); + protected abstract String getConfigInfoImpl(); } diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/SimpleMessageFormatter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/SimpleMessageFormatter.java index 463783b06..27f41c1e3 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/SimpleMessageFormatter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/SimpleMessageFormatter.java @@ -26,15 +26,16 @@ package io.spine.logging.jvm.backend; -import io.spine.logging.jvm.LogContext; +import com.google.errorprone.annotations.CanIgnoreReturnValue; import io.spine.logging.jvm.JvmMetadataKey; import io.spine.logging.jvm.JvmMetadataKey.KeyValueHandler; -import com.google.errorprone.annotations.CanIgnoreReturnValue; +import io.spine.logging.jvm.LogContext; +import org.jspecify.annotations.Nullable; + import java.util.Collections; import java.util.HashSet; import java.util.Set; import java.util.logging.Level; -import org.jspecify.annotations.Nullable; /** * Helper class for formatting LogData as text. This class is useful for any logging backend which @@ -61,186 +62,218 @@ * #getSimpleFormatterIgnoring(JvmMetadataKey...)} can be used to obtain a static formatter, * instead of using the default. * - * @see - * Original Java code of Google Flogger + * @see + * Original Java code of Google Flogger */ public final class SimpleMessageFormatter { - @SuppressWarnings("ConstantCaseForConstants") - private static final Set> DEFAULT_KEYS_TO_IGNORE = - Collections.>singleton(LogContext.Key.LOG_CAUSE); - - private static final LogMessageFormatter DEFAULT_FORMATTER = newFormatter(DEFAULT_KEYS_TO_IGNORE); - - /** - * Returns the singleton default log message formatter. This formats log messages in the form: - * - *
      {@code
      -   * Log message [CONTEXT key="value" id=42 ]
      -   * }
      - * - *

      with context from the log data and scope, merged together in a sequence of key/value pairs - * after the formatted message. If the log message is long or multi-line, then the context suffix - * will be formatted on a single separate line. - * - *

      The {@code cause} is omitted from the context section, since it's handled separately by most - * logger backends and not considered part of the formatted message. Other internal metadata keys - * may also be suppressed. - */ - public static LogMessageFormatter getDefaultFormatter() { - return DEFAULT_FORMATTER; - } - - /** - * Returns a log message formatter which formats log messages in the form: - * - *

      {@code
      -   * Log message [CONTEXT key="value" id=42 ]
      -   * }
      - * - *

      with context from the log data and scope, merged together in a sequence of key/value pairs - * after the formatted message. If the log message is long or multi-line, then the context suffix - * will be formatted on a single separate line. - * - *

      This differs from the default formatter because it allows the caller to specify additional - * metadata keys to be omitted from the formatted context. By default the {@code cause} is always - * omitted from the context section, since it's handled separately by most logger backends and - * almost never expected to be part of the formatted message. Other internal metadata keys may - * also be suppressed. - */ - public static LogMessageFormatter getSimpleFormatterIgnoring(JvmMetadataKey... extraIgnoredKeys) { - if (extraIgnoredKeys.length == 0) { - return getDefaultFormatter(); + + @SuppressWarnings("ConstantCaseForConstants") + private static final Set> DEFAULT_KEYS_TO_IGNORE = + Collections.singleton(LogContext.Key.LOG_CAUSE); + + private static final LogMessageFormatter DEFAULT_FORMATTER = newFormatter( + DEFAULT_KEYS_TO_IGNORE); + + /** + * Returns the singleton default log message formatter. This formats log messages in the form: + * + *

      {@code
      +     * Log message [CONTEXT key="value" id=42 ]
      +     * }
      + * + *

      with context from the log data and scope, merged together in a sequence of key/value + * pairs + * after the formatted message. If the log message is long or multi-line, then the context + * suffix + * will be formatted on a single separate line. + * + *

      The {@code cause} is omitted from the context section, since it's handled separately by + * most + * logger backends and not considered part of the formatted message. Other internal metadata + * keys + * may also be suppressed. + */ + public static LogMessageFormatter getDefaultFormatter() { + return DEFAULT_FORMATTER; } - Set> ignored = new HashSet>(DEFAULT_KEYS_TO_IGNORE); - Collections.addAll(ignored, extraIgnoredKeys); - return newFormatter(ignored); - } - - /** - * Appends formatted context information to the given buffer using the supplied metadata handler. - * A custom metadata handler is useful if the logger backend wishes to: - * - *

        - *
      • Ignore more than just the default set of metadata keys (currently just the "cause"). - *
      • Intercept and capture metadata values for additional processing or logging control. - *
      - * - * @param metadataProcessor snapshot of the metadata to be processed ({@link MetadataProcessor} is - * reusable so passing one in can save repeated processing of the same metadata). - * @param metadataHandler a metadata handler for intercepting and dispatching metadata during - * formatting. - * @param buffer destination buffer into which the log message and metadata will be appended. - * @return the given destination buffer (for method chaining). - */ - @CanIgnoreReturnValue - public static StringBuilder appendContext( - MetadataProcessor metadataProcessor, - MetadataHandler metadataHandler, - StringBuilder buffer) { - KeyValueFormatter kvf = new KeyValueFormatter("[CONTEXT ", " ]", buffer); - metadataProcessor.process(metadataHandler, kvf); - kvf.done(); - return buffer; - } - - /** - * Returns the single literal value as a string. This method must never be called if the log data - * has arguments to be formatted. - * - *

      This method is designed to be paired with {@link - * #mustBeFormatted(LogData,MetadataProcessor,Set)} and can always be safely called if that method - * returned {@code false} for the same log data. - * - * @param logData the log statement data. - * @return the single logged value as a string. - * @throws IllegalStateException if the log data had arguments to be formatted (i.e. there was a - * template context). - */ - public static String getLiteralLogMessage(LogData logData) { - return MessageUtils.safeToString(logData.getLiteralArgument()); - } - - /** - * An internal helper method for logger backends which are aggressively optimized for performance. - * This method is a best-effort optimization and should not be necessary for most implementations. - * It is not a stable API and may be removed at some point in the future. - * - *

      This method attempts to determine, for the given log data and log metadata, if the default - * message formatting performed by the other methods in this class would just result in the - * literal log message being used, with no additional formatting. - * - *

      If this method returns {@code false} then the literal log message can be obtained via {@link - * #getLiteralLogMessage(LogData)}, otherwise it must be formatted manually. - * - *

      By calling this class it is possible to more easily detect cases where using buffers to - * format the log message is not required. Obviously a logger backend my have its own reasons for - * needing buffering (e.g. prepending log site data) and those must also be taken into account. - * - * @param logData the log statement data. - * @param metadata the metadata intended to be formatted with the log statement. - * @param keysToIgnore a set of metadata keys which are known not to appear in the final formatted - * message. - */ - public static boolean mustBeFormatted( - LogData logData, MetadataProcessor metadata, Set> keysToIgnore) { - // If there are logged arguments or more metadata keys than can be ignored, we fail immediately - // which avoids the cost of creating the metadata key set (so don't remove the size check). - return logData.getTemplateContext() != null - || metadata.keyCount() > keysToIgnore.size() - || !keysToIgnore.containsAll(metadata.keySet()); - } - - /** - * Returns a new "simple" formatter which ignores the given set of metadata keys. The caller must - * ensure that the given set is effectively immutable. - */ - private static LogMessageFormatter newFormatter(final Set> keysToIgnore) { - return new LogMessageFormatter() { - private final MetadataHandler handler = - MetadataKeyValueHandlers.getDefaultHandler(keysToIgnore); - - @Override - public StringBuilder append( - LogData logData, MetadataProcessor metadata, StringBuilder buffer) { - BaseMessageFormatter.appendFormattedMessage(logData, buffer); - return appendContext(metadata, handler, buffer); - } - - @Override - public String format(LogData logData, MetadataProcessor metadata) { - if (mustBeFormatted(logData, metadata, keysToIgnore)) { - return append(logData, metadata, new StringBuilder()).toString(); - } else { - return getLiteralLogMessage(logData); + + /** + * Returns a log message formatter which formats log messages in the form: + * + *

      {@code
      +     * Log message [CONTEXT key="value" id=42 ]
      +     * }
      + * + *

      with context from the log data and scope, merged together in a sequence of key/value + * pairs + * after the formatted message. If the log message is long or multi-line, then the context + * suffix + * will be formatted on a single separate line. + * + *

      This differs from the default formatter because it allows the caller to specify + * additional + * metadata keys to be omitted from the formatted context. By default the {@code cause} is + * always + * omitted from the context section, since it's handled separately by most logger backends and + * almost never expected to be part of the formatted message. Other internal metadata keys may + * also be suppressed. + */ + public static LogMessageFormatter getSimpleFormatterIgnoring( + JvmMetadataKey... extraIgnoredKeys) { + if (extraIgnoredKeys.length == 0) { + return getDefaultFormatter(); } - } - }; - } - - // ---- Everything below this point is deprecated and will be removed. ---- - - /** @deprecated Use a {@link LogMessageFormatter} and obtain the level and cause separately. */ - @Deprecated - public static void format(LogData logData, SimpleLogHandler receiver) { - // Deliberately don't support ScopedLoggingContext here (no injected metadata). This is as a - // forcing function to make users of this API migrate away from it if they need scoped metadata. - MetadataProcessor metadata = - MetadataProcessor.forScopeAndLogSite(Metadata.empty(), logData.getMetadata()); - receiver.handleFormattedLogMessage( - logData.getLevel(), - getDefaultFormatter().format(logData, metadata), - metadata.getSingleValue(LogContext.Key.LOG_CAUSE)); - } - - /** @deprecated Use a {@link LogMessageFormatter} and obtain the level and cause separately. */ - @Deprecated - public interface SimpleLogHandler { + Set> ignored = new HashSet<>(DEFAULT_KEYS_TO_IGNORE); + Collections.addAll(ignored, extraIgnoredKeys); + return newFormatter(ignored); + } + /** - * Handles a single formatted log statement with the given level, message and "cause". This is - * called back exactly once, from the same thread, for every call made to {@link #format}. + * Appends formatted context information to the given buffer using the supplied metadata + * handler. + * A custom metadata handler is useful if the logger backend wishes to: + * + *

        + *
      • Ignore more than just the default set of metadata keys (currently just the "cause"). + *
      • Intercept and capture metadata values for additional processing or logging control. + *
      + * + * @param metadataProcessor + * snapshot of the metadata to be processed ({@link MetadataProcessor} is + * reusable so passing one in can save repeated processing of the same metadata). + * @param metadataHandler + * a metadata handler for intercepting and dispatching metadata during + * formatting. + * @param buffer + * destination buffer into which the log message and metadata will be appended. + * @return the given destination buffer (for method chaining). */ - void handleFormattedLogMessage(Level level, String message, @Nullable Throwable thrown); - } + @CanIgnoreReturnValue + public static StringBuilder appendContext( + MetadataProcessor metadataProcessor, + MetadataHandler metadataHandler, + StringBuilder buffer) { + var kvf = new KeyValueFormatter("[CONTEXT ", " ]", buffer); + metadataProcessor.process(metadataHandler, kvf); + kvf.done(); + return buffer; + } - private SimpleMessageFormatter() {} + /** + * Returns the single literal value as a string. This method must never be called if the log + * data + * has arguments to be formatted. + * + *

      This method is designed to be paired with {@link + * #mustBeFormatted(LogData, MetadataProcessor, Set)} and can always be safely called if that + * method + * returned {@code false} for the same log data. + * + * @param logData + * the log statement data. + * @return the single logged value as a string. + * @throws IllegalStateException + * if the log data had arguments to be formatted (i.e. there was a + * template context). + */ + public static String getLiteralLogMessage(LogData logData) { + return MessageUtils.safeToString(logData.getLiteralArgument()); + } + + /** + * An internal helper method for logger backends which are aggressively optimized for + * performance. + * This method is a best-effort optimization and should not be necessary for most + * implementations. + * It is not a stable API and may be removed at some point in the future. + * + *

      This method attempts to determine, for the given log data and log metadata, if the + * default + * message formatting performed by the other methods in this class would just result in the + * literal log message being used, with no additional formatting. + * + *

      If this method returns {@code false} then the literal log message can be obtained via + * {@link + * #getLiteralLogMessage(LogData)}, otherwise it must be formatted manually. + * + *

      By calling this class it is possible to more easily detect cases where using buffers to + * format the log message is not required. Obviously a logger backend my have its own reasons + * for + * needing buffering (e.g. prepending log site data) and those must also be taken into account. + * + * @param logData + * the log statement data. + * @param metadata + * the metadata intended to be formatted with the log statement. + * @param keysToIgnore + * a set of metadata keys which are known not to appear in the final formatted + * message. + */ + public static boolean mustBeFormatted( + LogData logData, MetadataProcessor metadata, Set> keysToIgnore) { + // If there are logged arguments or more metadata keys than can be ignored, we fail immediately + // which avoids the cost of creating the metadata key set (so don't remove the size check). + return logData.getTemplateContext() != null + || metadata.keyCount() > keysToIgnore.size() + || !keysToIgnore.containsAll(metadata.keySet()); + } + + /** + * Returns a new "simple" formatter which ignores the given set of metadata keys. The caller + * must + * ensure that the given set is effectively immutable. + */ + private static LogMessageFormatter newFormatter(final Set> keysToIgnore) { + return new LogMessageFormatter() { + private final MetadataHandler handler = + MetadataKeyValueHandlers.getDefaultHandler(keysToIgnore); + + @Override + public StringBuilder append( + LogData logData, MetadataProcessor metadata, StringBuilder buffer) { + BaseMessageFormatter.appendFormattedMessage(logData, buffer); + return appendContext(metadata, handler, buffer); + } + + @Override + public String format(LogData logData, MetadataProcessor metadata) { + if (mustBeFormatted(logData, metadata, keysToIgnore)) { + return append(logData, metadata, new StringBuilder()).toString(); + } else { + return getLiteralLogMessage(logData); + } + } + }; + } + + // ---- Everything below this point is deprecated and will be removed. ---- + + /** @deprecated Use a {@link LogMessageFormatter} and obtain the level and cause separately. */ + @Deprecated + public static void format(LogData logData, SimpleLogHandler receiver) { + // Deliberately don't support ScopedLoggingContext here (no injected metadata). This is as a + // forcing function to make users of this API migrate away from it if they need scoped metadata. + var metadata = + MetadataProcessor.forScopeAndLogSite(Metadata.empty(), logData.getMetadata()); + receiver.handleFormattedLogMessage( + logData.getLevel(), + getDefaultFormatter().format(logData, metadata), + metadata.getSingleValue(LogContext.Key.LOG_CAUSE)); + } + + /** @deprecated Use a {@link LogMessageFormatter} and obtain the level and cause separately. */ + @Deprecated + public interface SimpleLogHandler { + + /** + * Handles a single formatted log statement with the given level, message and "cause". This + * is + * called back exactly once, from the same thread, for every call made to {@link #format}. + */ + void handleFormattedLogMessage(Level level, String message, @Nullable Throwable thrown); + } + + private SimpleMessageFormatter() { + } } diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ContextMetadata.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ContextMetadata.java index 6bb14f028..96beeae51 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ContextMetadata.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ContextMetadata.java @@ -26,16 +26,17 @@ package io.spine.logging.jvm.context; -import static io.spine.logging.jvm.util.Checks.checkArgument; -import static io.spine.logging.jvm.util.Checks.checkNotNull; - +import com.google.errorprone.annotations.CanIgnoreReturnValue; import io.spine.logging.jvm.JvmMetadataKey; import io.spine.logging.jvm.backend.Metadata; -import com.google.errorprone.annotations.CanIgnoreReturnValue; +import org.jspecify.annotations.Nullable; + import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import org.jspecify.annotations.Nullable; + +import static io.spine.logging.jvm.util.Checks.checkArgument; +import static io.spine.logging.jvm.util.Checks.checkNotNull; /** * Immutable {@link Metadata} implementation intended for use in nested contexts. Scope metadata can @@ -43,216 +44,238 @@ * needed by implementations of {@link ScopedLoggingContext} and should not be considered a stable * API. * - * @see - * Original Java code of Google Flogger + * @see + * Original Java code of Google Flogger */ public abstract class ContextMetadata extends Metadata { - private static final class Entry { - final JvmMetadataKey key; - final T value; - Entry(JvmMetadataKey key, T value) { - this.key = checkNotNull(key, "key"); - this.value = checkNotNull(value, "value"); - } - } - - /** - * A builder to collect metadata key/values pairs in order. This class is only expected to be - * needed by implementations of {@link ScopedLoggingContext} and should not be considered a stable - * API. - */ - public static final class Builder { - private static final Entry[] EMPTY_ARRAY = new Entry[0]; - - // Set an explicitly small initial capacity to avoid excessive allocations when we only ever - // expect one or two keys to be added per context. We don't optimize for the case of zero keys, - // since the scoped context builder shouldn't create a builder until the first key is added. - private final List> entries = new ArrayList>(2); - - private Builder() {} - - /** Add a single metadata key/value pair to the builder. */ - @CanIgnoreReturnValue - public Builder add(JvmMetadataKey key, T value) { - // Entries are immutable and get moved into the metadata when it's built, so these get shared - // and reduce the size of the metadata storage compared to storing adjacent key/value pairs. - entries.add(new Entry(key, value)); - return this; - } + private static final class Entry { - public ContextMetadata build() { - // Analysis shows it's quicker to pass an empty array here and let the JVM optimize to avoid - // creating an empty array just to overwrite all its elements. - return new ImmutableScopeMetadata(entries.toArray(EMPTY_ARRAY)); - } - } - - /** Returns a new {@code ScopeMetadata} builder. */ - public static Builder builder() { - return new Builder(); - } - - /** Returns a space efficient {@code ScopeMetadata} containing a single value. */ - public static ContextMetadata singleton(JvmMetadataKey key, T value) { - return new SingletonMetadata(key, value); - } - - /** Returns the empty {@code ScopeMetadata}. */ - // We can't use empty() here as that's already taken by Metadata. - public static ContextMetadata none() { - return EmptyMetadata.INSTANCE; - } - - private ContextMetadata() {} - - /** - * Concatenates the given context metadata after this instance. Key value pairs are - * simply concatenated (rather than being merged) which may result in multiple single valued keys - * existing in the resulting sequence. - * - *

      Whether this is achieved via copying or chaining of instances is an implementation detail. - * - *

      Use {@link io.spine.logging.jvm.backend.MetadataProcessor MetadataProcessor} to process - * metadata consistently with respect to single valued and repeated keys, and use {@link - * Metadata#findValue(JvmMetadataKey)} to look up the “most recent” value for a single - * valued key. - */ - public abstract ContextMetadata concatenate(ContextMetadata metadata); - - // Internal method to deal in entries directly during concatenation. - abstract Entry get(int n); - - @Override - public JvmMetadataKey getKey(int n) { - return get(n).key; - } - - @Override - public Object getValue(int n) { - return get(n).value; - } - - private static final class ImmutableScopeMetadata extends ContextMetadata { - private final Entry[] entries; - - ImmutableScopeMetadata(Entry[] entries) { - this.entries = entries; - } + final JvmMetadataKey key; + final T value; - @Override - public int size() { - return entries.length; + Entry(JvmMetadataKey key, T value) { + this.key = checkNotNull(key, "key"); + this.value = checkNotNull(value, "value"); + } } - @Override - Entry get(int n) { - return entries[n]; - } + /** + * A builder to collect metadata key/values pairs in order. This class is only expected to be + * needed by implementations of {@link ScopedLoggingContext} and should not be considered a + * stable + * API. + */ + public static final class Builder { - @Override - @Nullable - @SuppressWarnings("unchecked") - public T findValue(JvmMetadataKey key) { - checkArgument(!key.canRepeat(), "metadata key must be single valued"); - for (int n = entries.length - 1; n >= 0; n--) { - Entry e = entries[n]; - if (e.key.equals(key)) { - return (T) e.value; + private static final Entry[] EMPTY_ARRAY = new Entry[0]; + + // Set an explicitly small initial capacity to avoid excessive allocations when we only ever + // expect one or two keys to be added per context. + // We don't optimize for the case of zero keys, since the scoped context builder + // shouldn't create a builder until the first key is added. + private final List> entries = new ArrayList<>(2); + + private Builder() { } - } - return null; - } - @Override - public ContextMetadata concatenate(ContextMetadata metadata) { - int extraSize = metadata.size(); - if (extraSize == 0) { - return this; - } - if (entries.length == 0) { - return metadata; - } - Entry[] merged = Arrays.copyOf(entries, entries.length + extraSize); - for (int i = 0; i < extraSize; i++) { - merged[i + entries.length] = metadata.get(i); - } - return new ImmutableScopeMetadata(merged); + /** Add a single metadata key/value pair to the builder. */ + @CanIgnoreReturnValue + public Builder add(JvmMetadataKey key, T value) { + // Entries are immutable and get moved into the metadata when it is built, + // so these get shared and reduce the size of the metadata storage compared + // to storing adjacent key/value pairs. + entries.add(new Entry(key, value)); + return this; + } + + public ContextMetadata build() { + // Analysis shows it's quicker to pass an empty array here and let the JVM optimize to + // avoid creating an empty array just to overwrite all its elements. + return new ImmutableScopeMetadata(entries.toArray(EMPTY_ARRAY)); + } } - } - private static final class SingletonMetadata extends ContextMetadata { - private final Entry entry; + /** Returns a new {@code ScopeMetadata} builder. */ + public static Builder builder() { + return new Builder(); + } - SingletonMetadata(JvmMetadataKey key, T value) { - this.entry = new Entry(key, value); + /** Returns a space efficient {@code ScopeMetadata} containing a single value. */ + public static ContextMetadata singleton(JvmMetadataKey key, T value) { + return new SingletonMetadata(key, value); } - @Override - public int size() { - return 1; + /** Returns the empty {@code ScopeMetadata}. */ + // We can't use empty() here as that's already taken by Metadata. + public static ContextMetadata none() { + return EmptyMetadata.INSTANCE; } - @Override - Entry get(int n) { - if (n == 0) { - return entry; - } - throw new IndexOutOfBoundsException(); + private ContextMetadata() { } + /** + * Concatenates the given context metadata after this instance. Key value pairs are + * simply concatenated (rather than being merged) which may result in multiple single valued + * keys + * existing in the resulting sequence. + * + *

      Whether this is achieved via copying or chaining of instances is an implementation + * detail. + * + *

      Use {@link io.spine.logging.jvm.backend.MetadataProcessor MetadataProcessor} to process + * metadata consistently with respect to single valued and repeated keys, and use {@link + * Metadata#findValue(JvmMetadataKey)} to look up the “most recent” value for a single + * valued key. + */ + public abstract ContextMetadata concatenate(ContextMetadata metadata); + + // Internal method to deal in entries directly during concatenation. + abstract Entry get(int n); + @Override - @Nullable - @SuppressWarnings("unchecked") - public R findValue(JvmMetadataKey key) { - checkArgument(!key.canRepeat(), "metadata key must be single valued"); - return entry.key.equals(key) ? (R) entry.value : null; + public JvmMetadataKey getKey(int n) { + return get(n).key; } @Override - public ContextMetadata concatenate(ContextMetadata metadata) { - // No check for size() == 0 since this instance always has one value. - int extraSize = metadata.size(); - if (extraSize == 0) { - return this; - } - Entry[] merged = new Entry[extraSize + 1]; - merged[0] = entry; - for (int i = 0; i < extraSize; i++) { - merged[i + 1] = metadata.get(i); - } - return new ImmutableScopeMetadata(merged); + public Object getValue(int n) { + return get(n).value; } - } - // This is a static nested class as opposed to an anonymous class assigned to a constant field in - // order to decouple its classloading when Metadata is loaded. Android users are particularly - // careful about unnecessary class loading, and we've used similar mechanisms in Guava (see - // CharMatchers). - private static final class EmptyMetadata extends ContextMetadata { - static final ContextMetadata INSTANCE = new EmptyMetadata(); + private static final class ImmutableScopeMetadata extends ContextMetadata { - @Override - public int size() { - return 0; + private final Entry[] entries; + + ImmutableScopeMetadata(Entry[] entries) { + this.entries = entries; + } + + @Override + public int size() { + return entries.length; + } + + @Override + Entry get(int n) { + return entries[n]; + } + + @Override + @Nullable + @SuppressWarnings("unchecked") + public T findValue(JvmMetadataKey key) { + checkCannotRepeat(key); + for (var n = entries.length - 1; n >= 0; n--) { + var e = entries[n]; + if (e.key.equals(key)) { + return (T) e.value; + } + } + return null; + } + + + @Override + public ContextMetadata concatenate(ContextMetadata metadata) { + int extraSize = metadata.size(); + if (extraSize == 0) { + return this; + } + if (entries.length == 0) { + return metadata; + } + var merged = Arrays.copyOf(entries, entries.length + extraSize); + for (int i = 0; i < extraSize; i++) { + merged[i + entries.length] = metadata.get(i); + } + return new ImmutableScopeMetadata(merged); + } } - @Override - Entry get(int n) { - throw new IndexOutOfBoundsException(); + private static void checkCannotRepeat(JvmMetadataKey key) { + checkArgument(!key.canRepeat(), "metadata key must be single valued"); } - @Override - @Nullable - public T findValue(JvmMetadataKey key) { - // For consistency, do the same checks as for non-empty instances. - checkArgument(!key.canRepeat(), "metadata key must be single valued"); - return null; + private static final class SingletonMetadata extends ContextMetadata { + + private final Entry entry; + + private SingletonMetadata(JvmMetadataKey key, T value) { + this.entry = new Entry(key, value); + } + + @Override + public int size() { + return 1; + } + + @Override + Entry get(int n) { + if (n == 0) { + return entry; + } + throw new IndexOutOfBoundsException(n); + } + + @Override + @Nullable + @SuppressWarnings("unchecked") + public R findValue(JvmMetadataKey key) { + checkCannotRepeat(key); + return entry.key.equals(key) ? (R) entry.value : null; + } + + @Override + public ContextMetadata concatenate(ContextMetadata metadata) { + // No check for size() == 0 since this instance always has one value. + int extraSize = metadata.size(); + if (extraSize == 0) { + return this; + } + Entry[] merged = new Entry[extraSize + 1]; + merged[0] = entry; + for (int i = 0; i < extraSize; i++) { + merged[i + 1] = metadata.get(i); + } + return new ImmutableScopeMetadata(merged); + } } - @Override - public ContextMetadata concatenate(ContextMetadata metadata) { - return metadata; + /** + * This is a static nested class as opposed to an anonymous class assigned to a constant field + * to decouple its classloading when Metadata is loaded. + * + *

      Android users are particularly careful about unnecessary class loading, + * and we've used similar mechanisms in Guava (see CharMatchers). + */ + private static final class EmptyMetadata extends ContextMetadata { + + static final ContextMetadata INSTANCE = new EmptyMetadata(); + + @Override + public int size() { + return 0; + } + + @Override + Entry get(int n) { + throw new IndexOutOfBoundsException(n); + } + + @Override + @Nullable + public T findValue(JvmMetadataKey key) { + // For consistency, do the same checks as for non-empty instances. + checkCannotRepeat(key); + return null; + } + + @Override + public ContextMetadata concatenate(ContextMetadata metadata) { + return metadata; + } } - } } diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/LogLevelMap.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/LogLevelMap.java index 627a18182..1cb41991c 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/LogLevelMap.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/LogLevelMap.java @@ -26,9 +26,8 @@ package io.spine.logging.jvm.context; -import static io.spine.logging.jvm.util.Checks.checkNotNull; - import com.google.errorprone.annotations.CanIgnoreReturnValue; + import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -36,149 +35,156 @@ import java.util.Set; import java.util.logging.Level; +import static io.spine.logging.jvm.util.Checks.checkNotNull; + /** * A hierarchical mapping from logger name to {@link Level} used to override the configured log - * level during debugging. This class is designed to allow efficient (i.e. zero-allocation) + * level during debugging. This class is designed to allow efficient (i.e., zero-allocation) * resolution of the log level for a given logger. * *

      This class is immutable and thread safe. * - * @see - * Original Java code of Google Flogger + * @see + * Original Java code of Google Flogger */ public final class LogLevelMap { - /** - * Builder for log level map which uses type safe class/package keys (but requires that they be - * present in the JVM at the time the map is created). To set up a {@code LogLevelMap} with only - * class/package names, use {@link LogLevelMap#create(java.util.Map,Level)} or {@link - * LogLevelMap#create(java.util.Map)}. - */ - public static final class Builder { - private final Map map = new HashMap(); - private Level defaultLevel = Level.OFF; - - private Builder() {} - - private void put(String name, Level level) { - if (map.put(name, level) != null) { - throw new IllegalArgumentException("duplicate entry for class/package: " + name); - } + + /** + * Builder for log level map which uses type safe class/package keys (but requires that they be + * present in the JVM at the time the map is created). To set up a {@code LogLevelMap} with only + * class/package names, use {@link LogLevelMap#create(java.util.Map, Level)} or {@link + * LogLevelMap#create(java.util.Map)}. + */ + public static final class Builder { + + private final Map map = new HashMap<>(); + private Level defaultLevel = Level.OFF; + + private Builder() { + } + + private void put(String name, Level level) { + if (map.put(name, level) != null) { + throw new IllegalArgumentException("duplicate entry for class/package: " + name); + } + } + + /** Adds the given classes at the specified log level. */ + @CanIgnoreReturnValue + public Builder add(Level level, Class... classes) { + for (var cls : classes) { + put(cls.getName(), level); + } + return this; + } + + /** Adds the given packages at the specified log level. */ + @CanIgnoreReturnValue + public Builder add(Level level, Package... packages) { + for (var pkg : packages) { + put(pkg.getName(), level); + } + return this; + } + + /** Sets the default log level (use {@link Level#OFF} to disable. */ + @CanIgnoreReturnValue + public Builder setDefault(Level level) { + checkNotNull(defaultLevel, "default log level must not be null"); + this.defaultLevel = level; + return this; + } + + public LogLevelMap build() { + return LogLevelMap.create(map, defaultLevel); + } } - /** Adds the given classes at the specified log level. */ - @CanIgnoreReturnValue - public Builder add(Level level, Class... classes) { - for (Class cls : classes) { - put(cls.getName(), level); - } - return this; + /** Returns a new builder for constructing a {@code LogLevelMap}. */ + public static Builder builder() { + return new Builder(); } - /** Adds the given packages at the specified log level. */ - @CanIgnoreReturnValue - public Builder add(Level level, Package... packages) { - for (Package pkg : packages) { - put(pkg.getName(), level); - } - return this; + /** + * Returns an empty {@code LogLevelMap} with a single default level which will apply to all + * loggers. + */ + public static LogLevelMap create(Level level) { + return create(Collections.emptyMap(), level); } - /** Sets the default log level (use {@link Level#OFF} to disable. */ - @CanIgnoreReturnValue - public Builder setDefault(Level level) { - checkNotNull(defaultLevel, "default log level must not be null"); - this.defaultLevel = level; - return this; + /** + * Returns a {@code LogLevelMap} whose entries correspond to the given map, and with the default + * value of {@code Level.OFF}. The keys of the map must all be valid dot-separated logger names, + * and the values cannot be {@code null}. + */ + public static LogLevelMap create(Map map) { + return create(map, Level.OFF); } - public LogLevelMap build() { - return LogLevelMap.create(map, defaultLevel); + /** + * Returns a {@code LogLevelMap} whose entries correspond to the given map. The keys of the map + * must all be valid dot-separated logger names, and neither the values, nor the default value, + * can be {@code null}. + */ + public static LogLevelMap create(Map map, Level defaultLevel) { + checkNotNull(defaultLevel, "default log level must not be null"); + for (var e : map.entrySet()) { + var name = e.getKey(); + if (name.startsWith(".") || name.endsWith(".") || name.contains("..")) { + throw new IllegalArgumentException("invalid logger name: " + name); + } + if (e.getValue() == null) { + throw new IllegalArgumentException("log levels must not be null; logger=" + name); + } + } + return new LogLevelMap(map, defaultLevel); } - } - - /** Returns a new builder for constructing a {@code LogLevelMap}. */ - public static Builder builder() { - return new Builder(); - } - - /** - * Returns an empty {@code LogLevelMap} with a single default level which will apply to all - * loggers. - */ - public static LogLevelMap create(Level level) { - return create(Collections.emptyMap(), level); - } - - /** - * Returns a {@code LogLevelMap} whose entries correspond to the given map, and with the default - * value of {@code Level.OFF}. The keys of the map must all be valid dot-separated logger names, - * and the values cannot be {@code null}. - */ - public static LogLevelMap create(Map map) { - return create(map, Level.OFF); - } - - /** - * Returns a {@code LogLevelMap} whose entries correspond to the given map. The keys of the map - * must all be valid dot-separated logger names, and neither the values, nor the default value, - * can be {@code null}. - */ - public static LogLevelMap create(Map map, Level defaultLevel) { - checkNotNull(defaultLevel, "default log level must not be null"); - for (Map.Entry e : map.entrySet()) { - String name = e.getKey(); - if (name.startsWith(".") || name.endsWith(".") || name.contains("..")) { - throw new IllegalArgumentException("invalid logger name: " + name); - } - if (e.getValue() == null) { - throw new IllegalArgumentException("log levels must not be null; logger=" + name); - } + + private final SegmentTrie trie; + + private LogLevelMap(Map map, Level defaultLevel) { + this.trie = SegmentTrie.create(map, '.', defaultLevel); } - return new LogLevelMap(map, defaultLevel); - } - - private final SegmentTrie trie; - - private LogLevelMap(Map map, Level defaultLevel) { - this.trie = SegmentTrie.create(map, '.', defaultLevel); - } - - /** - * Returns the log level for the specified logger, matching the {@code loggerName} to an entry in - * the map, or the nearest parent in the naming hierarchy. If the given {@code loggerName} is - * invalid, the default value is returned. - */ - public Level getLevel(String loggerName) { - return trie.find(loggerName); - } - - /** - * Returns the union of this map with the given map. Logging is enabled in the merged map - * if-and-only-if it was enabled in one of the maps it was created from. - */ - public LogLevelMap merge(LogLevelMap other) { - Map thisMap = trie.getEntryMap(); - Map otherMap = other.trie.getEntryMap(); - - // HashMap/HashSet is fine because iteration order is unimportant for creating a SegmentTrie. - Map mergedMap = new HashMap(); - Set allKeys = new HashSet(thisMap.keySet()); - allKeys.addAll(otherMap.keySet()); - for (String key : allKeys) { - if (!otherMap.containsKey(key)) { - mergedMap.put(key, thisMap.get(key)); - } else if (!thisMap.containsKey(key)) { - mergedMap.put(key, otherMap.get(key)); - } else { - mergedMap.put(key, min(thisMap.get(key), otherMap.get(key))); - } + + /** + * Returns the log level for the specified logger, matching the {@code loggerName} to an entry + * in + * the map, or the nearest parent in the naming hierarchy. If the given {@code loggerName} is + * invalid, the default value is returned. + */ + public Level getLevel(String loggerName) { + return trie.find(loggerName); } - Level defaultLevel = min(trie.getDefaultValue(), other.trie.getDefaultValue()); - return create(mergedMap, defaultLevel); - } + /** + * Returns the union of this map with the given map. Logging is enabled in the merged map + * if-and-only-if it was enabled in one of the maps it was created from. + */ + public LogLevelMap merge(LogLevelMap other) { + var thisMap = trie.getEntryMap(); + var otherMap = other.trie.getEntryMap(); + + // HashMap/HashSet is fine because iteration order is unimportant for creating a SegmentTrie. + Map mergedMap = new HashMap<>(); + Set allKeys = new HashSet<>(thisMap.keySet()); + allKeys.addAll(otherMap.keySet()); + for (var key : allKeys) { + if (!otherMap.containsKey(key)) { + mergedMap.put(key, thisMap.get(key)); + } else if (!thisMap.containsKey(key)) { + mergedMap.put(key, otherMap.get(key)); + } else { + mergedMap.put(key, min(thisMap.get(key), otherMap.get(key))); + } + } + + var defaultLevel = min(trie.getDefaultValue(), other.trie.getDefaultValue()); + return create(mergedMap, defaultLevel); + } - private static Level min(Level a, Level b) { - return a.intValue() <= b.intValue() ? a : b; - } + private static Level min(Level a, Level b) { + return a.intValue() <= b.intValue() ? a : b; + } } diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/NoOpContextDataProvider.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/NoOpContextDataProvider.java index 6008bddfc..aa7aa8120 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/NoOpContextDataProvider.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/NoOpContextDataProvider.java @@ -38,101 +38,109 @@ /** * Fallback context data provider used when no other implementations are available for a platform. * - * @see - * Original Java code of Google Flogger + * @see + * Original Java code of Google Flogger */ final class NoOpContextDataProvider extends ContextDataProvider { - private static final ContextDataProvider NO_OP_INSTANCE = new NoOpContextDataProvider(); - - /** - * Returns a singleton "no op" instance of the context data provider API which logs a warning if - * used in code which attempts to set context information or modify scopes. This is intended for - * use by platform implementations in cases where no context is configured. - */ - static ContextDataProvider getNoOpInstance() { - return NO_OP_INSTANCE; - } - - private static final class NoOpScopedLoggingContext extends ScopedLoggingContext - implements LoggingContextCloseable { - // Since the ContextDataProvider class is loaded during Platform initialization we must be very - // careful to avoid any attempt to obtain a logger instance until we can be sure logging config - // is complete. - private static final class LazyLogger { - private static final FluentLogger2 logger = FluentLogger2.forEnclosingClass(); - } - private final AtomicBoolean haveWarned = new AtomicBoolean(); - - private void logWarningOnceOnly() { - if (haveWarned.compareAndSet(false, true)) { - var defaultPlatform = "io.spine.logging.backend.system.DefaultPlatform"; - LazyLogger.logger - .atWarning() - .withStackTrace(StackSize.SMALL) - .log(format( - "Scoped logging contexts are disabled; no context data provider was installed.%n" - + "To enable scoped logging contexts in your application, see the " - + "site-specific Platform class used to configure logging behaviour.%n" - + "Default Platform: `%s`.", - defaultPlatform) - ); - } + + private static final ContextDataProvider NO_OP_INSTANCE = new NoOpContextDataProvider(); + + /** + * Returns a singleton "no op" instance of the context data provider API which logs a warning if + * used in code which attempts to set context information or modify scopes. + * This is intended for use by platform implementations in cases where no context is configured. + */ + static ContextDataProvider getNoOpInstance() { + return NO_OP_INSTANCE; } - @Override - public ScopedLoggingContext.Builder newContext() { - return new ScopedLoggingContext.Builder() { + private static final class NoOpScopedLoggingContext extends ScopedLoggingContext + implements LoggingContextCloseable { + + // Since the ContextDataProvider class is loaded during Platform initialization we must be very + // careful to avoid any attempt to obtain a logger instance until we can be sure logging config + // is complete. + private static final class LazyLogger { + + private static final FluentLogger2 logger = FluentLogger2.forEnclosingClass(); + } + + private final AtomicBoolean haveWarned = new AtomicBoolean(); + + private void logWarningOnceOnly() { + if (haveWarned.compareAndSet(false, true)) { + var defaultPlatform = "io.spine.logging.backend.system.DefaultPlatform"; + LazyLogger.logger + .atWarning() + .withStackTrace(StackSize.SMALL) + .log(format( + "Scoped logging contexts are disabled; no context data provider was installed.%n" + + + "To enable scoped logging contexts in your application, see the " + + + "site-specific Platform class used to configure logging behaviour.%n" + + "Default Platform: `%s`.", + defaultPlatform) + ); + } + } + @Override - public LoggingContextCloseable install() { - logWarningOnceOnly(); - return NoOpScopedLoggingContext.this; + public ScopedLoggingContext.Builder newContext() { + return new ScopedLoggingContext.Builder() { + @Override + public LoggingContextCloseable install() { + logWarningOnceOnly(); + return NoOpScopedLoggingContext.this; + } + }; } - }; - } - @Override - public ScopedLoggingContext.Builder newContext(ScopeType scopeType) { - // Ignore scope bindings when there's no way to propagate them. - return newContext(); - } + @Override + public ScopedLoggingContext.Builder newContext(ScopeType scopeType) { + // Ignore scope bindings when there's no way to propagate them. + return newContext(); + } - @Override - public boolean addTags(Tags tags) { - logWarningOnceOnly(); - // Superclass methods still do argument checking, which is important for consistent behaviour. - return super.addTags(tags); - } + @Override + public boolean addTags(Tags tags) { + logWarningOnceOnly(); + // Superclass methods still do argument checking, which is important for consistent behaviour. + return super.addTags(tags); + } - @Override - public boolean addMetadata(JvmMetadataKey key, T value) { - logWarningOnceOnly(); - return super.addMetadata(key, value); - } + @Override + public boolean addMetadata(JvmMetadataKey key, T value) { + logWarningOnceOnly(); + return super.addMetadata(key, value); + } - @Override - public boolean applyLogLevelMap(LogLevelMap logLevelMap) { - logWarningOnceOnly(); - return super.applyLogLevelMap(logLevelMap); - } + @Override + public boolean applyLogLevelMap(LogLevelMap logLevelMap) { + logWarningOnceOnly(); + return super.applyLogLevelMap(logLevelMap); + } - @Override - public void close() {} + @Override + public void close() { + } - @Override - boolean isNoOp() { - return true; + @Override + boolean isNoOp() { + return true; + } } - } - private final ScopedLoggingContext noOpContext = new NoOpScopedLoggingContext(); + private final ScopedLoggingContext noOpContext = new NoOpScopedLoggingContext(); - @Override - public ScopedLoggingContext getContextApiSingleton() { - return noOpContext; - } + @Override + public ScopedLoggingContext getContextApiSingleton() { + return noOpContext; + } - @Override - public String toString() { - return "No-op Provider"; - } + @Override + public String toString() { + return "No-op Provider"; + } } diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContext.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContext.java index 49f29f384..9b254d007 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContext.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContext.java @@ -26,19 +26,20 @@ package io.spine.logging.jvm.context; -import static io.spine.logging.jvm.util.Checks.checkNotNull; -import static io.spine.logging.jvm.util.Checks.checkState; - -import io.spine.logging.jvm.JvmApi; -import io.spine.logging.jvm.LoggingScope; -import io.spine.logging.jvm.JvmMetadataKey; import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.MustBeClosed; +import io.spine.logging.jvm.JvmApi; +import io.spine.logging.jvm.JvmMetadataKey; +import io.spine.logging.jvm.LoggingScope; +import io.spine.logging.jvm.LoggingScopeProvider; +import org.jspecify.annotations.Nullable; + import java.io.Closeable; +import java.io.Serial; import java.util.concurrent.Callable; -import io.spine.logging.jvm.LoggingScopeProvider; -import org.jspecify.annotations.Nullable; +import static io.spine.logging.jvm.util.Checks.checkNotNull; +import static io.spine.logging.jvm.util.Checks.checkState; /** * A user-facing API for creating and modifying scoped logging contexts in applications. @@ -49,8 +50,8 @@ * *

        *
      • Adding a request ID to every log statement. - *
      • Forcing logging at a finer level for a specific request (e.g. based on a URL debug - * parameter). + *
      • Forcing logging at a finer level for a specific request + * (e.g., based on a URL debug parameter). *
      * *

      Contexts are nestable and new contexts can be added to provide additional metadata which will @@ -94,393 +95,440 @@ * of any modification methods called (e.g. {@link #addTags(Tags)}). * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger */ public abstract class ScopedLoggingContext { - /** A logging context which must be closed in the reverse order to which it was created. */ - // If Flogger is bumped to JDK 1.7, this should be switched to AutoCloseable. - public interface LoggingContextCloseable extends Closeable { - // Overridden to remove the throws clause allowing simple try-with-resources use. - @Override - public void close(); - } - - /** Lightweight internal helper class for context implementations to manage a list of scopes. */ - public static final class ScopeList { - /** - * Adds a new scope to the list for the given type. If the given type is null, or a scope for - * the type already exists in the list, the original (potentially {@code null}) list reference - * is returned. - */ - @Nullable public static ScopeList addScope( - @Nullable ScopeList list, @Nullable ScopeType type) { - return (type != null && lookup(list, type) == null) - ? new ScopeList(type, type.newScope(), list) - : list; + + /** A logging context which must be closed in the reverse order to which it was created. */ + // If Flogger is bumped to JDK 1.7, this should be switched to AutoCloseable. + public interface LoggingContextCloseable extends Closeable { + + // Overridden to remove the throws clause allowing simple try-with-resources use. + @Override + void close(); } - /** Finds a scope instance for the given type in a possibly null scope list. */ - @Nullable public static LoggingScope lookup(@Nullable ScopeList list, ScopeType type) { - while (list != null) { - if (type.equals(list.key)) { - return list.scope; + /** Lightweight internal helper class for context implementations to manage a list of scopes. */ + public static final class ScopeList { + + /** + * Adds a new scope to the list for the given type. If the given type is null, or a scope + * for + * the type already exists in the list, the original (potentially {@code null}) list + * reference + * is returned. + */ + @Nullable + public static ScopeList addScope( + @Nullable ScopeList list, @Nullable ScopeType type) { + return (type != null && lookup(list, type) == null) + ? new ScopeList(type, type.newScope(), list) + : list; + } + + /** Finds a scope instance for the given type in a possibly null scope list. */ + @Nullable + public static LoggingScope lookup(@Nullable ScopeList list, ScopeType type) { + while (list != null) { + if (type.equals(list.key)) { + return list.scope; + } + list = list.next; + } + return null; } - list = list.next; - } - return null; - } - private final ScopeType key; - private final LoggingScope scope; - @Nullable private final ScopeList next; + private final ScopeType key; + private final LoggingScope scope; + @Nullable + private final ScopeList next; - public ScopeList(ScopeType key, LoggingScope scope, @Nullable ScopeList next) { - this.key = checkNotNull(key, "scope type"); - this.scope = checkNotNull(scope, "scope"); - this.next = next; + public ScopeList(ScopeType key, LoggingScope scope, @Nullable ScopeList next) { + this.key = checkNotNull(key, "scope type"); + this.scope = checkNotNull(scope, "scope"); + this.next = next; + } } - } - - /** - * A fluent builder API for creating and installing new context scopes. This API should be used - * whenever the metadata to be added to a scope is known at the time the scope is created. - * - *

      This class is intended to be used only as part of a fluent statement, and retaining a - * reference to a builder instance for any length of time is not recommended. - */ - public abstract static class Builder { - private Tags tags = null; - private ContextMetadata.Builder metadata = null; - private LogLevelMap logLevelMap = null; - - protected Builder() {} /** - * Sets the tags to be used with the context. This method can be called at most once per - * builder. + * A fluent builder API for creating and installing new context scopes. This API should be used + * whenever the metadata to be added to a scope is known at the time the scope is created. + * + *

      This class is intended to be used only as part of a fluent statement, and retaining a + * reference to a builder instance for any length of time is not recommended. */ - @CanIgnoreReturnValue - public final Builder withTags(Tags tags) { - checkState(this.tags == null, "tags already set"); - checkNotNull(tags, "tags"); - this.tags = tags; - return this; + public abstract static class Builder { + + private Tags tags = null; + private ContextMetadata.Builder metadata = null; + private LogLevelMap logLevelMap = null; + + protected Builder() { + } + + /** + * Sets the tags to be used with the context. This method can be called at most once per + * builder. + */ + @CanIgnoreReturnValue + public final Builder withTags(Tags tags) { + checkState(this.tags == null, "tags already set"); + checkNotNull(tags, "tags"); + this.tags = tags; + return this; + } + + /** + * Adds a single metadata key/value pair to the context. This method can be called multiple + * times on a builder. + */ + @CanIgnoreReturnValue + public final Builder withMetadata(JvmMetadataKey key, T value) { + if (metadata == null) { + metadata = ContextMetadata.builder(); + } + metadata.add(key, value); + return this; + } + + /** + * Sets the log level map to be used with the context being built. This method can be called + * at + * most once per builder. + */ + @CanIgnoreReturnValue + public final Builder withLogLevelMap(LogLevelMap logLevelMap) { + checkState(this.logLevelMap == null, "log level map already set"); + checkNotNull(logLevelMap, "log level map"); + this.logLevelMap = logLevelMap; + return this; + } + + /** + * Wraps a runnable so it will execute within a new context based on the state of the + * builder. + * Note that each time this runnable is executed, a new context will be installed extending + * from + * the currently installed context at the time of execution. + * + * @throws InvalidLoggingContextStateException + * if the context created during this method cannot + * be closed correctly (e.g., if a nested context has also been opened, but not + * closed). + */ + public final Runnable wrap(final Runnable r) { + return new Runnable() { + @Override + @SuppressWarnings("MustBeClosedChecker") + public void run() { + // JDK 1.6 does not have "try-with-resources" + LoggingContextCloseable context = install(); + boolean hasError = true; + try { + r.run(); + hasError = false; + } finally { + closeAndMaybePropagateError(context, hasError); + } + } + }; + } + + /** + * Wraps a callable so it will execute within a new context based on the state of the + * builder. + * Note that each time this runnable is executed, a new context will be installed extending + * from + * the currently installed context at the time of execution. + * + * @throws InvalidLoggingContextStateException + * if the context created during this method cannot + * be closed correctly (e.g., if a nested context has also been opened, but not + * closed). + */ + public final Callable wrap(final Callable c) { + return new Callable() { + @Override + @SuppressWarnings("MustBeClosedChecker") + public R call() throws Exception { + LoggingContextCloseable context = install(); + boolean hasError = true; + try { + R result = c.call(); + hasError = false; + return result; + } finally { + closeAndMaybePropagateError(context, hasError); + } + } + }; + } + + /** Runs a runnable directly within a new context installed from this builder. */ + public final void run(Runnable r) { + wrap(r).run(); + } + + /** Calls a {@link Callable} directly within a new context installed from this builder. */ + @CanIgnoreReturnValue + public final R call(Callable c) throws Exception { + return wrap(c).call(); + } + + /** + * Calls a {@link Callable} directly within a new context installed from this builder, + * wrapping + * any checked exceptions with a {@link RuntimeException}. + */ + @CanIgnoreReturnValue + public final R callUnchecked(Callable c) { + try { + return call(c); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new RuntimeException("checked exception caught during context call", e); + } + } + + /** + * Installs a new context based on the state of the builder. The caller is required + * to + * invoke {@link LoggingContextCloseable#close() close()} on the returned instances in the + * reverse order to which they were obtained. For JDK 1.7 and above, this is best achieved + * by + * using a try-with-resources construction in the calling code. + * + *

      {@code
      +         * try (LoggingContextCloseable ctx = ScopedLoggingContext.getInstance()
      +         *     .newContext().withTags(Tags.of("my_tag", someValue).install()) {
      +         *   // Logging by code called from within this context will contain the additional metadata.
      +         *   logger.atInfo().log("Log message should contain tag value...");
      +         * }
      +         * }
      + * + *

      To avoid the need to manage contexts manually, it is strongly recommended that the + * helper + * methods, such as {@link #wrap(Runnable)} or {@link #run(Runnable)} are used to simplify + * the + * handling of contexts. This method is intended primarily to be overridden by context + * implementations rather than being invoked as a normal part of context use. + * + *

      An implementation of scoped contexts must preserve any existing metadata when a + * context is + * opened, and restore the previous state when it terminates. + * + *

      Note that the returned {@link LoggingContextCloseable} is not required to enforce the + * correct closure of nested contexts, and while it is permitted to throw a {@link + * InvalidLoggingContextStateException} in the face of mismatched or invalid usage, it is + * not + * required. + */ + @MustBeClosed + public abstract LoggingContextCloseable install(); + + /** + * Returns the configured tags, or null. This method may do work and results should be + * cached by + * context implementations. + */ + @Nullable + protected final Tags getTags() { + return tags; + } + + /** + * Returns the configured context metadata, or null. This method may do work and results + * should + * be cached by context implementations. + */ + @Nullable + protected final ContextMetadata getMetadata() { + return metadata != null ? metadata.build() : null; + } + + /** + * Returns the configured log level map, or null. This method may do work and results should + * be + * cached by context implementations. + */ + @Nullable + protected final LogLevelMap getLogLevelMap() { + return logLevelMap; + } } /** - * Adds a single metadata key/value pair to the context. This method can be called multiple - * times on a builder. + * Returns the platform/framework specific implementation of the logging context API. This is a + * singleton value and need not be cached by callers. If logging contexts are not supported, + * this + * method will return an empty context implementation which has no effect. */ - @CanIgnoreReturnValue - public final Builder withMetadata(JvmMetadataKey key, T value) { - if (metadata == null) { - metadata = ContextMetadata.builder(); - } - metadata.add(key, value); - return this; + public static ScopedLoggingContext getInstance() { + return ContextDataProvider.getInstance() + .getContextApiSingleton(); } - /** - * Sets the log level map to be used with the context being built. This method can be called at - * most once per builder. - */ - @CanIgnoreReturnValue - public final Builder withLogLevelMap(LogLevelMap logLevelMap) { - checkState(this.logLevelMap == null, "log level map already set"); - checkNotNull(logLevelMap, "log level map"); - this.logLevelMap = logLevelMap; - return this; + protected ScopedLoggingContext() { } /** - * Wraps a runnable so it will execute within a new context based on the state of the builder. - * Note that each time this runnable is executed, a new context will be installed extending from - * the currently installed context at the time of execution. + * Creates a new context builder to which additional logging metadata can be attached before + * being + * installed or used to wrap some existing code. + * + *

      {@code
      +     * ScopedLoggingContext ctx = ScopedLoggingContext.getInstance();
      +     * Foo result = ctx.newContext().withTags(Tags.of("my_tag", someValue)).call(MyClass::doFoo);
      +     * }
      * - * @throws InvalidLoggingContextStateException if the context created during this method cannot - * be closed correctly (e.g., if a nested context has also been opened, but not closed). + *

      Implementations of this API must return a subclass of {@link Builder} which can install + * all + * necessary metadata into a new context from the builder's current state. + * + *

      Note for users: if you don't need an instance of {@code ScopedLoggingContext} for some + * reason such as testability (injecting it, for example), consider using the static methods in + * {@link ScopedLoggingContexts} instead to avoid the need to call {@link #getInstance}: + * + *

      {@code
      +     * Foo result = ScopedLoggingContexts.newContext()
      +     *     .withTags(Tags.of("my_tag", someValue))
      +     *     .call(MyClass::doFoo);
      +     * }
      */ - public final Runnable wrap(final Runnable r) { - return new Runnable() { - @Override - @SuppressWarnings("MustBeClosedChecker") - public void run() { - // JDK 1.6 does not have "try-with-resources" - LoggingContextCloseable context = install(); - boolean hasError = true; - try { - r.run(); - hasError = false; - } finally { - closeAndMaybePropagateError(context, hasError); - } - } - }; - } + public abstract Builder newContext(); /** - * Wraps a callable so it will execute within a new context based on the state of the builder. - * Note that each time this runnable is executed, a new context will be installed extending from - * the currently installed context at the time of execution. + * Creates a new context builder to which additional logging metadata can be attached before + * being + * installed or used to wrap some existing code. + * + *

      This method is the same as {@link #newContext()} except it additionally binds a new + * {@link ScopeType} instance to the newly created context. + * This allows log statements to control stateful logging operations (e.g., rate limiting) + * using + * {@link JvmApi#per(LoggingScopeProvider) per(ScopeType)} method. * - * @throws InvalidLoggingContextStateException if the context created during this method cannot - * be closed correctly (e.g., if a nested context has also been opened, but not closed). + *

      Note for users: if you don't need an instance of {@code ScopedLoggingContext} for some + * reason such as testability (injecting it, for example), consider using the static methods in + * {@link ScopedLoggingContexts} instead to avoid the need to call {@link #getInstance}. */ - public final Callable wrap(final Callable c) { - return new Callable() { - @Override - @SuppressWarnings("MustBeClosedChecker") - public R call() throws Exception { - LoggingContextCloseable context = install(); - boolean hasError = true; - try { - R result = c.call(); - hasError = false; - return result; - } finally { - closeAndMaybePropagateError(context, hasError); - } - } - }; - } + public abstract Builder newContext(ScopeType scopeType); - /** Runs a runnable directly within a new context installed from this builder. */ - public final void run(Runnable r) { - wrap(r).run(); + /** + * Deprecated equivalent to {@link #newContext()}. + * + * @deprecated implementers and callers should use {@link #newContext()} instead. This method will + * be removed in the next Flogger release. + */ + @Deprecated + public Builder newScope() { + return newContext(); } - /** Calls a {@link Callable} directly within a new context installed from this builder. */ + /** + * Adds tags to the current set of log tags for the current context. Tags are merged together + * and + * existing tags cannot be modified. This is deliberate since two pieces of code may not know + * about each other and could accidentally use the same tag name; in that situation it's + * important + * that both tag values are preserved. + * + *

      Furthermore, the types of data allowed for tag values are strictly controlled. This is + * also + * very deliberate since these tags must be efficiently added to every log statement and so + * it's + * important that they resulting string representation is reliably cacheable and can be + * calculated + * without invoking arbitrary code (e.g. the {@code toString()} method of some unknown user + * type). + * + * @return false if there is no current context, or scoped contexts are not supported. + */ @CanIgnoreReturnValue - public final R call(Callable c) throws Exception { - return wrap(c).call(); + public boolean addTags(Tags tags) { + checkNotNull(tags, "tags"); + return false; } /** - * Calls a {@link Callable} directly within a new context installed from this builder, wrapping - * any checked exceptions with a {@link RuntimeException}. + * Adds a single metadata key/value pair to the current context. + * + *

      Unlike {@link Tags}, which have a well defined value ordering, independent of the order + * in + * which values were added, context metadata preserves the order of addition. As such, it is + * not + * advised to add values for the same metadata key from multiple threads, since that may create + * non-deterministic ordering. It is recommended (where possible) to add metadata when building + * a + * new context, rather than adding it to context visible to multiple threads. */ @CanIgnoreReturnValue - public final R callUnchecked(Callable c) { - try { - return call(c); - } catch (RuntimeException e) { - throw e; - } catch (Exception e) { - throw new RuntimeException("checked exception caught during context call", e); - } + public boolean addMetadata(JvmMetadataKey key, T value) { + checkNotNull(key, "key"); + checkNotNull(value, "value"); + return false; } /** - * Installs a new context based on the state of the builder. The caller is required to - * invoke {@link LoggingContextCloseable#close() close()} on the returned instances in the - * reverse order to which they were obtained. For JDK 1.7 and above, this is best achieved by - * using a try-with-resources construction in the calling code. - * - *

      {@code
      -     * try (LoggingContextCloseable ctx = ScopedLoggingContext.getInstance()
      -     *     .newContext().withTags(Tags.of("my_tag", someValue).install()) {
      -     *   // Logging by code called from within this context will contain the additional metadata.
      -     *   logger.atInfo().log("Log message should contain tag value...");
      -     * }
      -     * }
      + * Applies the given log level map to the current context. Log level settings are merged with + * any + * existing setting from the current (or parent) contexts such that logging will be enabled for + * a + * log statement if: * - *

      To avoid the need to manage contexts manually, it is strongly recommended that the helper - * methods, such as {@link #wrap(Runnable)} or {@link #run(Runnable)} are used to simplify the - * handling of contexts. This method is intended primarily to be overridden by context - * implementations rather than being invoked as a normal part of context use. + *

        + *
      • It was enabled by the given map. + *
      • It was already enabled by the current context. + *
      * - *

      An implementation of scoped contexts must preserve any existing metadata when a context is - * opened, and restore the previous state when it terminates. + *

      The effects of this call will be undone only when the current context terminates. * - *

      Note that the returned {@link LoggingContextCloseable} is not required to enforce the - * correct closure of nested contexts, and while it is permitted to throw a {@link - * InvalidLoggingContextStateException} in the face of mismatched or invalid usage, it is not - * required. + * @return false if there is no current context, or scoped contexts are not supported. */ - @MustBeClosed - public abstract LoggingContextCloseable install(); - - /** - * Returns the configured tags, or null. This method may do work and results should be cached by - * context implementations. - */ - @Nullable - protected final Tags getTags() { - return tags; + @CanIgnoreReturnValue + public boolean applyLogLevelMap(LogLevelMap logLevelMap) { + checkNotNull(logLevelMap, "log level map"); + return false; } - /** - * Returns the configured context metadata, or null. This method may do work and results should - * be cached by context implementations. - */ - @Nullable - protected final ContextMetadata getMetadata() { - return metadata != null ? metadata.build() : null; + private static void closeAndMaybePropagateError( + LoggingContextCloseable context, boolean callerHasError) { + // Because LoggingContextCloseable is not just a `Closeable`, there's no risk of it + // throwing any checked exceptions. + // In particular, when this is switched to use AutoCloseable, there's no risk of + // having to deal with InterruptedException. That's why having an extended interface is always + // better than using [Auto]Closeable directly. + try { + context.close(); + } catch (RuntimeException e) { + // This method is always called from a `finally` block which may be about to rethrow a user + // exception, so ignore any errors during close() if that's the case. + if (!callerHasError) { + throw (e instanceof InvalidLoggingContextStateException) + ? ((InvalidLoggingContextStateException) e) + : new InvalidLoggingContextStateException("invalid logging context state", e); + } + } } /** - * Returns the configured log level map, or null. This method may do work and results should be - * cached by context implementations. + * Thrown if it can be determined that contexts have been closed incorrectly. Note that the + * point at which this exception is thrown may not itself be the point where the mishandling + * occurred, but simply where it was first detected. */ - @Nullable - protected final LogLevelMap getLogLevelMap() { - return logLevelMap; - } - } - - /** - * Returns the platform/framework specific implementation of the logging context API. This is a - * singleton value and need not be cached by callers. If logging contexts are not supported, this - * method will return an empty context implementation which has no effect. - */ - public static ScopedLoggingContext getInstance() { - return ContextDataProvider.getInstance().getContextApiSingleton(); - } - - protected ScopedLoggingContext() {} - - /** - * Creates a new context builder to which additional logging metadata can be attached before being - * installed or used to wrap some existing code. - * - *

      {@code
      -   * ScopedLoggingContext ctx = ScopedLoggingContext.getInstance();
      -   * Foo result = ctx.newContext().withTags(Tags.of("my_tag", someValue)).call(MyClass::doFoo);
      -   * }
      - * - *

      Implementations of this API must return a subclass of {@link Builder} which can install all - * necessary metadata into a new context from the builder's current state. - * - *

      Note for users: if you don't need an instance of {@code ScopedLoggingContext} for some - * reason such as testability (injecting it, for example), consider using the static methods in - * {@link ScopedLoggingContexts} instead to avoid the need to call {@link #getInstance}: - * - *

      {@code
      -   * Foo result = ScopedLoggingContexts.newContext()
      -   *     .withTags(Tags.of("my_tag", someValue))
      -   *     .call(MyClass::doFoo);
      -   * }
      - */ - public abstract Builder newContext(); - - /** - * Creates a new context builder to which additional logging metadata can be attached before being - * installed or used to wrap some existing code. - * - *

      This method is the same as {@link #newContext()} except it additionally binds a new - * {@link ScopeType} instance to the newly created context. - * This allows log statements to control stateful logging operations (e.g., rate limiting) using - * {@link JvmApi#per(LoggingScopeProvider) per(ScopeType)} method. - * - *

      Note for users: if you don't need an instance of {@code ScopedLoggingContext} for some - * reason such as testability (injecting it, for example), consider using the static methods in - * {@link ScopedLoggingContexts} instead to avoid the need to call {@link #getInstance}. - */ - public abstract Builder newContext(ScopeType scopeType); - - /** - * Deprecated equivalent to {@link #newContext()}. - * - * @deprecated implementers and callers should use {@link #newContext()} instead. This method will - * be removed in the next Flogger release. - */ - @Deprecated - public - Builder newScope() { - return newContext(); - } - - /** - * Adds tags to the current set of log tags for the current context. Tags are merged together and - * existing tags cannot be modified. This is deliberate since two pieces of code may not know - * about each other and could accidentally use the same tag name; in that situation it's important - * that both tag values are preserved. - * - *

      Furthermore, the types of data allowed for tag values are strictly controlled. This is also - * very deliberate since these tags must be efficiently added to every log statement and so it's - * important that they resulting string representation is reliably cacheable and can be calculated - * without invoking arbitrary code (e.g. the {@code toString()} method of some unknown user type). - * - * @return false if there is no current context, or scoped contexts are not supported. - */ - @CanIgnoreReturnValue - public boolean addTags(Tags tags) { - checkNotNull(tags, "tags"); - return false; - } - - /** - * Adds a single metadata key/value pair to the current context. - * - *

      Unlike {@link Tags}, which have a well defined value ordering, independent of the order in - * which values were added, context metadata preserves the order of addition. As such, it is not - * advised to add values for the same metadata key from multiple threads, since that may create - * non-deterministic ordering. It is recommended (where possible) to add metadata when building a - * new context, rather than adding it to context visible to multiple threads. - */ - @CanIgnoreReturnValue - public boolean addMetadata(JvmMetadataKey key, T value) { - checkNotNull(key, "key"); - checkNotNull(value, "value"); - return false; - } - - /** - * Applies the given log level map to the current context. Log level settings are merged with any - * existing setting from the current (or parent) contexts such that logging will be enabled for a - * log statement if: - * - *

        - *
      • It was enabled by the given map. - *
      • It was already enabled by the current context. - *
      - * - *

      The effects of this call will be undone only when the current context terminates. - * - * @return false if there is no current context, or scoped contexts are not supported. - */ - @CanIgnoreReturnValue - public boolean applyLogLevelMap(LogLevelMap logLevelMap) { - checkNotNull(logLevelMap, "log level map"); - return false; - } - - private static void closeAndMaybePropagateError( - LoggingContextCloseable context, boolean callerHasError) { - // Because LoggingContextCloseable is not just a `Closeable`, there's no risk of it - // throwing any checked exceptions. - // In particular, when this is switched to use AutoCloseable, there's no risk of - // having to deal with InterruptedException. That's why having an extended interface is always - // better than using [Auto]Closeable directly. - try { - context.close(); - } catch (RuntimeException e) { - // This method is always called from a `finally` block which may be about to rethrow a user - // exception, so ignore any errors during close() if that's the case. - if (!callerHasError) { - throw (e instanceof InvalidLoggingContextStateException) - ? ((InvalidLoggingContextStateException) e) - : new InvalidLoggingContextStateException("invalid logging context state", e); - } - } - } - - /** - * Thrown if it can be determined that contexts have been closed incorrectly. Note that the point - * at which this exception is thrown may not itself be the point where the mishandling occurred, - * but simply where it was first detected. - */ - public static final class InvalidLoggingContextStateException extends IllegalStateException { + public static final class InvalidLoggingContextStateException extends IllegalStateException { - private static final long serialVersionUID = 0L; + @Serial + private static final long serialVersionUID = 0L; - private InvalidLoggingContextStateException(String message, Throwable cause) { - super(message, cause); + private InvalidLoggingContextStateException(String message, Throwable cause) { + super(message, cause); + } } - } - /** Package private checker to help avoid unhelpful debug logs. */ - boolean isNoOp() { - return false; - } + /** Package-private checker to help avoid unhelpful debug logs. */ + boolean isNoOp() { + return false; + } } diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/SegmentTrie.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/SegmentTrie.java index 01fde70ad..71253919a 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/SegmentTrie.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/SegmentTrie.java @@ -26,9 +26,6 @@ package io.spine.logging.jvm.context; -import static io.spine.logging.jvm.util.Checks.checkNotNull; -import static java.lang.Math.min; - import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -38,6 +35,9 @@ import java.util.Map; import java.util.TreeMap; +import static io.spine.logging.jvm.util.Checks.checkNotNull; +import static java.lang.Math.min; + /** * A fast prefix-Trie implementation for segmented keys. For example given the mapping: * @@ -70,283 +70,304 @@ *

      Limitations: Separators are chars only (not Unicode code-points or strings) and cannot * represent anything outside the basic-multilingual plane (e.g. no string or Emoji separators). * - * @see - * Original Java code of Google Flogger + * @see + * Original Java code of Google Flogger */ // This class could easily be made a shareable utility class if need by anyone else. abstract class SegmentTrie { - /** - * Returns a prefix Trie for the given mapping, where keys are segmented via the given separator. - */ - public static SegmentTrie create( - Map map, char separator, T defaultValue) { - switch (map.size()) { - case 0: - return new EmptyTrie(defaultValue); - case 1: - Map.Entry e = map.entrySet().iterator().next(); - return new SingletonTrie(e.getKey(), e.getValue(), separator, defaultValue); - default: - return new SortedTrie(map, separator, defaultValue); + + /** + * Returns a prefix Trie for the given mapping, where keys are segmented via the given + * separator. + */ + public static SegmentTrie create( + Map map, char separator, T defaultValue) { + switch (map.size()) { + case 0: + return new EmptyTrie(defaultValue); + case 1: + var e = map.entrySet() + .iterator() + .next(); + return new SingletonTrie(e.getKey(), e.getValue(), separator, defaultValue); + default: + return new SortedTrie(map, separator, defaultValue); + } + } + + private final T defaultValue; + + SegmentTrie(T defaultValue) { + this.defaultValue = defaultValue; } - } - private final T defaultValue; + public final T getDefaultValue() { + return defaultValue; + } - SegmentTrie(T defaultValue) { - this.defaultValue = defaultValue; - } + /** Returns the value of the entry which most closely matches the given key. */ + public abstract T find(String key); - public final T getDefaultValue() { - return defaultValue; - } + /** Returns an immutable view of the entries in this Trie. */ + public abstract Map getEntryMap(); - /** Returns the value of the entry which most closely matches the given key. */ - public abstract T find(String key); + // Trivial implementation for the empty map (always return the default value). + private static final class EmptyTrie extends SegmentTrie { - /** Returns an immutable view of the entries in this Trie. */ - public abstract Map getEntryMap(); + EmptyTrie(T defaultValue) { + super(defaultValue); + } - // Trivial implementation for the empty map (always return the default value). - private static final class EmptyTrie extends SegmentTrie { - EmptyTrie(T defaultValue) { - super(defaultValue); - } + @Override + public T find(String k) { + return getDefaultValue(); + } - @Override - public T find(String k) { - return getDefaultValue(); + @Override + public Map getEntryMap() { + return Collections.emptyMap(); + } } - @Override - public Map getEntryMap() { - return Collections.emptyMap(); - } - } + // Trivial implementation for a map with one entry. + private static final class SingletonTrie extends SegmentTrie { - // Trivial implementation for a map with one entry. - private static final class SingletonTrie extends SegmentTrie { - private final String key; - private final T value; - private final char separator; + private final String key; + private final T value; + private final char separator; - SingletonTrie(String key, T value, char separator, T defaultValue) { - super(defaultValue); - this.key = checkNotNull(key, "key"); - this.value = value; - this.separator = separator; - } + SingletonTrie(String key, T value, char separator, T defaultValue) { + super(defaultValue); + this.key = checkNotNull(key, "key"); + this.value = value; + this.separator = separator; + } - @Override - public T find(String k) { - // Remember that just being a prefix isn't enough, it must match up to the end of a segment. - return k.regionMatches(0, key, 0, key.length()) - && (k.length() == key.length() || k.charAt(key.length()) == separator) - ? value - : getDefaultValue(); - } + @Override + public T find(String k) { + // Remember that just being a prefix isn't enough, it must match up to the end of a segment. + return k.regionMatches(0, key, 0, key.length()) + && (k.length() == key.length() || k.charAt(key.length()) == separator) + ? value + : getDefaultValue(); + } - @Override - public Map getEntryMap() { - Map map = new HashMap(); - map.put(key, value); - return Collections.unmodifiableMap(map); + @Override + public Map getEntryMap() { + Map map = new HashMap(); + map.put(key, value); + return Collections.unmodifiableMap(map); + } } - } - // General purpose implementation using a custom binary search to reduce repeated re-comparing of - // keys. Nothing in or called by the "find" method is allowed to allocate any memory. - private static final class SortedTrie extends SegmentTrie { - private final String[] keys; - private final List values; - private final int[] parent; - private final char separator; + // General purpose implementation using a custom binary search to reduce repeated re-comparing of + // keys. Nothing in or called by the "find" method is allowed to allocate any memory. + private static final class SortedTrie extends SegmentTrie { - SortedTrie(Map entries, char separator, T defaultValue) { - super(defaultValue); - TreeMap sorted = new TreeMap(entries); - this.keys = sorted.keySet().toArray(new String[0]); - this.values = new ArrayList(sorted.values()); - this.parent = buildParentMap(keys, separator); - this.separator = separator; - } + private final String[] keys; + private final List values; + private final int[] parent; + private final char separator; - @Override - public T find(String key) { - int keyLen = key.length(); + SortedTrie(Map entries, char separator, T defaultValue) { + super(defaultValue); + var sorted = new TreeMap(entries); + this.keys = sorted.keySet() + .toArray(new String[0]); + this.values = new ArrayList(sorted.values()); + this.parent = buildParentMap(keys, separator); + this.separator = separator; + } - // Find the left-hand-side bound and get the size of the common prefix. - int lhsIdx = 0; - int lhsPrefix = prefixCompare(key, keys[lhsIdx], 0); - if (lhsPrefix == keyLen) { - // If equal, just return the element. - return values.get(lhsIdx); - } - if (lhsPrefix < 0) { - // If the key is before the first element it has no parent. - return getDefaultValue(); - } + @Override + public T find(String key) { + var keyLen = key.length(); - // Find the right-hand-side bound and get the size of the common prefix. - int rhsIdx = keys.length - 1; - int rhsPrefix = prefixCompare(key, keys[rhsIdx], 0); - if (rhsPrefix == keyLen) { - // If equal, just return the element. - return values.get(rhsIdx); - } - if (rhsPrefix >= 0) { - // If the key is after the last element it may have a parent. - return findParent(key, rhsIdx, rhsPrefix); - } - // If rhsPrefix is negative, it's the bitwise-NOT of what we want. - rhsPrefix = ~rhsPrefix; + // Find the left-hand-side bound and get the size of the common prefix. + var lhsIdx = 0; + var lhsPrefix = prefixCompare(key, keys[lhsIdx], 0); + if (lhsPrefix == keyLen) { + // If equal, just return the element. + return values.get(lhsIdx); + } + if (lhsPrefix < 0) { + // If the key is before the first element it has no parent. + return getDefaultValue(); + } - // Binary search: At the top of the loop, lhsPrefix & rhsPrefix are positive. - while (true) { - // Determine the pivot index. - // NOTE: In theory we might be able to improve performance by biasing the pivot index - // towards the side with the larger common prefix length. - int midIdx = (lhsIdx + rhsIdx) >>> 1; - if (midIdx == lhsIdx) { - // No match found: The left-hand-side is the nearest lexicographical entry (but not - // equal), but we know that if the search key has a parent in the trie, then it must be - // a parent of this entry (even if this entry is not a direct sibling). - return findParent(key, lhsIdx, lhsPrefix); - } - // Find the prefix length of the pivot value (using the minimum prefix length of the - // current bounds to limit the work done). - int midPrefix = prefixCompare(key, keys[midIdx], min(lhsPrefix, rhsPrefix)); - if (keyLen == midPrefix) { - // If equal, just return the element. - return values.get(midIdx); - } - if (midPrefix >= 0) { - // key > pivot, so reset left-hand bound - lhsIdx = midIdx; - lhsPrefix = midPrefix; - } else { - // key < pivot, so reset right-hand bound - rhsIdx = midIdx; - rhsPrefix = ~midPrefix; + // Find the right-hand-side bound and get the size of the common prefix. + var rhsIdx = keys.length - 1; + var rhsPrefix = prefixCompare(key, keys[rhsIdx], 0); + if (rhsPrefix == keyLen) { + // If equal, just return the element. + return values.get(rhsIdx); + } + if (rhsPrefix >= 0) { + // If the key is after the last element it may have a parent. + return findParent(key, rhsIdx, rhsPrefix); + } + // If rhsPrefix is negative, it's the bitwise-NOT of what we want. + rhsPrefix = ~rhsPrefix; + + // Binary search: At the top of the loop, lhsPrefix & rhsPrefix are positive. + while (true) { + // Determine the pivot index. + // NOTE: In theory we might be able to improve performance by biasing the pivot index + // towards the side with the larger common prefix length. + var midIdx = (lhsIdx + rhsIdx) >>> 1; + if (midIdx == lhsIdx) { + // No match found: The left-hand-side is the nearest lexicographical entry (but not + // equal), but we know that if the search key has a parent in the trie, then it must be + // a parent of this entry (even if this entry is not a direct sibling). + return findParent(key, lhsIdx, lhsPrefix); + } + // Find the prefix length of the pivot value (using the minimum prefix length of the + // current bounds to limit the work done). + var midPrefix = prefixCompare(key, keys[midIdx], min(lhsPrefix, rhsPrefix)); + if (keyLen == midPrefix) { + // If equal, just return the element. + return values.get(midIdx); + } + if (midPrefix >= 0) { + // key > pivot, so reset left-hand bound + lhsIdx = midIdx; + lhsPrefix = midPrefix; + } else { + // key < pivot, so reset right-hand bound + rhsIdx = midIdx; + rhsPrefix = ~midPrefix; + } + } } - } - } - /** - * Finds the value of the nearest parent of the given key, starting at the element - * lexicographically preceding the key (but which is not equal to the key). - * - * @param k the key whose parent value we wish to find. - * @param idx the index of the closest matching key in the trie ({@code k < keys[idx]}). - * @param len the common prefix length between {@code k} and {@code keys[idx]}. - * @return the value of the nearest parent of {@code k}. - */ - private T findParent(String k, int idx, int len) { - while (!isParent(keys[idx], k, len)) { - idx = parent[idx]; - if (idx == -1) { - return getDefaultValue(); + /** + * Finds the value of the nearest parent of the given key, starting at the element + * lexicographically preceding the key (but which is not equal to the key). + * + * @param k + * the key whose parent value we wish to find. + * @param idx + * the index of the closest matching key in the trie ({@code k < keys[idx]}). + * @param len + * the common prefix length between {@code k} and {@code keys[idx]}. + * @return the value of the nearest parent of {@code k}. + */ + private T findParent(String k, int idx, int len) { + while (!isParent(keys[idx], k, len)) { + idx = parent[idx]; + if (idx == -1) { + return getDefaultValue(); + } + } + return values.get(idx); } - } - return values.get(idx); - } - /** - * Determines if a given candidate value {@code p} is the parent of a key {@code k}. - * - *

      We know that {@code p < k} (lexicographically) and (importantly) {@code p != k}. We also - * know that {@code len} is common prefix length. - * - *

      Thus either: - * - *

        - *
      • The common prefix is a strict prefix of k (i.e. {@code k.length() > len}). - *
      • The common prefix is equal to {@code k}, but {@code p} must be longer (or else {@code p - * == k}). - *
      - * - * Thus if {@code (p.length <= len)} then {@code (k.length() > p.length())}. - * - * @param p the candidate parent key to check. - * @param k the key whose parent we are looking for. - * @param len the maximum length of any possible parent of {@code k}. - */ - private boolean isParent(String p, String k, int len) { - return p.length() <= len && k.charAt(p.length()) == separator; - } + /** + * Determines if a given candidate value {@code p} is the parent of a key {@code k}. + * + *

      We know that {@code p < k} (lexicographically) and (importantly) {@code p != k}. We + * also + * know that {@code len} is common prefix length. + * + *

      Thus either: + * + *

        + *
      • The common prefix is a strict prefix of k (i.e. {@code k.length() > len}). + *
      • The common prefix is equal to {@code k}, but {@code p} must be longer (or else {@code p + * == k}). + *
      + * + * Thus if {@code (p.length <= len)} then {@code (k.length() > p.length())}. + * + * @param p + * the candidate parent key to check. + * @param k + * the key whose parent we are looking for. + * @param len + * the maximum length of any possible parent of {@code k}. + */ + private boolean isParent(String p, String k, int len) { + return p.length() <= len && k.charAt(p.length()) == separator; + } - /** - * Returns the common prefix between two strings, encoding the returned value to indicate - * lexicographical order. That is: - * - *
        - *
      • If {@code lhs >= rhs}, the returned value is the common prefix length. - *
      • If {@code lhs < rhs}, the returned value is the bitwise-NOT of the common prefix - * length. - *
      - * - *

      This permits the function to be used for both comparison, and for determining the common - * prefix length (if the returned prefix length is non-negative and equal to {@code - * lhs.length()} then {@code lhs == rhs}). - * - *

      By allowing a known existing lower bound for the prefix length to be provided, this method - * can skip re-comparing the beginning of values repeatedly when used in a binary search. The - * given lower bound value is expected to be the result of previous calls the this function (or - * {@code 0}). - * - * @param lhs first value to compare. - * @param rhs second value to compare. - * @param start a lower bound for the common prefix length of the given keys, which must be - * {@code <= min(lhs.length(), rhs.length())}. - * @return the common prefix length, encoded to indicate lexicographical ordering. - */ - private static int prefixCompare(String lhs, String rhs, int start) { - if (start < 0) { - throw new IllegalStateException("lhs=" + lhs + ", rhs=" + rhs + ", start=" + start); - } - int len = min(lhs.length(), rhs.length()); - for (int n = start; n < len; n++) { - int diff = lhs.charAt(n) - rhs.charAt(n); - if (diff != 0) { - return diff < 0 ? ~n : n; + /** + * Returns the common prefix between two strings, encoding the returned value to indicate + * lexicographical order. That is: + * + *

        + *
      • If {@code lhs >= rhs}, the returned value is the common prefix length. + *
      • If {@code lhs < rhs}, the returned value is the bitwise-NOT of the common prefix + * length. + *
      + * + *

      This permits the function to be used for both comparison, and for determining the common + * prefix length (if the returned prefix length is non-negative and equal to {@code + * lhs.length()} then {@code lhs == rhs}). + * + *

      By allowing a known existing lower bound for the prefix length to be provided, this method + * can skip re-comparing the beginning of values repeatedly when used in a binary search. The + * given lower bound value is expected to be the result of previous calls the this function (or + * {@code 0}). + * + * @param lhs + * first value to compare. + * @param rhs + * second value to compare. + * @param start + * a lower bound for the common prefix length of the given keys, which must be + * {@code <= min(lhs.length(), rhs.length())}. + * @return the common prefix length, encoded to indicate lexicographical ordering. + */ + private static int prefixCompare(String lhs, String rhs, int start) { + if (start < 0) { + throw new IllegalStateException("lhs=" + lhs + ", rhs=" + rhs + ", start=" + start); + } + var len = min(lhs.length(), rhs.length()); + for (var n = start; n < len; n++) { + var diff = lhs.charAt(n) - rhs.charAt(n); + if (diff != 0) { + return diff < 0 ? ~n : n; + } + } + return (len < rhs.length()) ? ~len : len; } - } - return (len < rhs.length()) ? ~len : len; - } - /** - * Builds an index mapping array {@code pmap} such that {@code pmap[idx]} is the index of the - * parent element of {@code keys[idx]}, or {@code -1} if no parent exists. - */ - private static int[] buildParentMap(String[] keys, char separator) { - int[] pmap = new int[keys.length]; - // The first key cannot have a parent. - pmap[0] = -1; - for (int n = 1; n < keys.length; n++) { - // Assume no parent will be found (just makes things a bit easier later). - pmap[n] = -1; - // Generate each parent key in turn until a match is found. - String key = keys[n]; - for (int sidx = key.lastIndexOf(separator); sidx >= 0; sidx = key.lastIndexOf(separator)) { - key = key.substring(0, sidx); - int i = Arrays.binarySearch(keys, 0, n, key); - if (i >= 0) { - // Match found, so set index and exit. - pmap[n] = i; - break; - } + /** + * Builds an index mapping array {@code pmap} such that {@code pmap[idx]} is the index of + * the + * parent element of {@code keys[idx]}, or {@code -1} if no parent exists. + */ + private static int[] buildParentMap(String[] keys, char separator) { + var pmap = new int[keys.length]; + // The first key cannot have a parent. + pmap[0] = -1; + for (var n = 1; n < keys.length; n++) { + // Assume no parent will be found (just makes things a bit easier later). + pmap[n] = -1; + // Generate each parent key in turn until a match is found. + var key = keys[n]; + for (var sidx = key.lastIndexOf(separator); + sidx >= 0; sidx = key.lastIndexOf(separator)) { + key = key.substring(0, sidx); + var i = Arrays.binarySearch(keys, 0, n, key); + if (i >= 0) { + // Match found, so set index and exit. + pmap[n] = i; + break; + } + } + } + return pmap; } - } - return pmap; - } - @Override - public Map getEntryMap() { - Map map = new LinkedHashMap(); - for (int n = 0; n < keys.length; n++) { - map.put(keys[n], values.get(n)); - } - return Collections.unmodifiableMap(map); + @Override + public Map getEntryMap() { + Map map = new LinkedHashMap(); + for (var n = 0; n < keys.length; n++) { + map.put(keys[n], values.get(n)); + } + return Collections.unmodifiableMap(map); + } } - } } diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/Tags.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/Tags.java index 751b3aaad..9292b7f67 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/Tags.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/Tags.java @@ -26,11 +26,9 @@ package io.spine.logging.jvm.context; -import static io.spine.logging.jvm.util.Checks.checkArgument; -import static io.spine.logging.jvm.util.Checks.checkMetadataIdentifier; -import static io.spine.logging.jvm.util.Checks.checkNotNull; - import com.google.errorprone.annotations.CanIgnoreReturnValue; +import org.jspecify.annotations.Nullable; + import java.util.AbstractMap; import java.util.AbstractSet; import java.util.ArrayList; @@ -43,7 +41,10 @@ import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; -import org.jspecify.annotations.Nullable; + +import static io.spine.logging.jvm.util.Checks.checkArgument; +import static io.spine.logging.jvm.util.Checks.checkMetadataIdentifier; +import static io.spine.logging.jvm.util.Checks.checkNotNull; /** * Immutable tags which can be attached to log statements via platform specific injection @@ -70,704 +71,733 @@ *

      The {@link #toString} implementation of this class provides a human readable, machine parsable * representation of the tags. * - * @see - * Original Java code of Google Flogger + * @see + * Original Java code of Google Flogger */ public final class Tags { - /** - * Allowed types of tag values. This ensures that tag values have well known semantics and can - * always be formatted in a clearly and unambiguously. - */ - // The ordering of elements in this enum should not change as it defines the sort order between - // values of different types. New elements need not be added at the end though. - private enum Type { - BOOLEAN() { - @Override - int compare(Object lhs, Object rhs) { - return ((Boolean) lhs).compareTo((Boolean) rhs); - } - }, - STRING() { - @Override - int compare(Object lhs, Object rhs) { - return ((String) lhs).compareTo((String) rhs); - } - }, - LONG() { - @Override - int compare(Object lhs, Object rhs) { - return ((Long) lhs).compareTo((Long) rhs); - } - }, - DOUBLE() { - @Override - int compare(Object lhs, Object rhs) { - return ((Double) lhs).compareTo((Double) rhs); - } - }; - abstract int compare(Object lhs, Object rhs); - - private static Type of(Object tag) { - // There should be exactly as many public methods to set tag values as there are cases here. - if (tag instanceof String) { - return STRING; - } else if (tag instanceof Boolean) { - return BOOLEAN; - } else if (tag instanceof Long) { - return LONG; - } else if (tag instanceof Double) { - return DOUBLE; - } else { - // Should never happen because only known types can be passed via public methods. - throw new AssertionError("invalid tag type: " + tag.getClass()); - } + /** + * Allowed types of tag values. This ensures that tag values have well known semantics and can + * always be formatted in a clearly and unambiguously. + */ + // The ordering of elements in this enum should not change as it defines the sort order between + // values of different types. New elements need not be added at the end though. + private enum Type { + BOOLEAN() { + @Override + int compare(Object lhs, Object rhs) { + return ((Boolean) lhs).compareTo((Boolean) rhs); + } + }, + STRING() { + @Override + int compare(Object lhs, Object rhs) { + return ((String) lhs).compareTo((String) rhs); + } + }, + LONG() { + @Override + int compare(Object lhs, Object rhs) { + return ((Long) lhs).compareTo((Long) rhs); + } + }, + DOUBLE() { + @Override + int compare(Object lhs, Object rhs) { + return ((Double) lhs).compareTo((Double) rhs); + } + }; + + abstract int compare(Object lhs, Object rhs); + + private static Type of(Object tag) { + // There should be exactly as many public methods to set tag values as there are cases here. + if (tag instanceof String) { + return STRING; + } else if (tag instanceof Boolean) { + return BOOLEAN; + } else if (tag instanceof Long) { + return LONG; + } else if (tag instanceof Double) { + return DOUBLE; + } else { + // Should never happen because only known types can be passed via public methods. + throw new AssertionError("invalid tag type: " + tag.getClass()); + } + } } - } - private static final Comparator VALUE_COMPARATOR = - new Comparator() { - @Override - public int compare(Object lhs, Object rhs) { - // By API we only get known types here, all of which are final and comparable. - Type ltype = Type.of(lhs); - Type rtype = Type.of(rhs); - return (ltype == rtype) ? ltype.compare(lhs, rhs) : ltype.compareTo(rtype); - } - }; - - // Note: This is just a "dumb" holder and doesn't have equals/hashcode defined. - private static final class KeyValuePair { - private final String key; - @Nullable private final Object value; - - private KeyValuePair(String key, @Nullable Object value) { - this.key = key; - this.value = value; + private static final Comparator VALUE_COMPARATOR = (lhs, rhs) -> { + // By API we only get known types here, all of which are final and comparable. + var ltype = Type.of(lhs); + var rtype = Type.of(rhs); + return (ltype == rtype) ? ltype.compare(lhs, rhs) : ltype.compareTo(rtype); + }; + + // Note: This is just a "dumb" holder and doesn't have equals/hashcode defined. + private static final class KeyValuePair { + + private final String key; + @Nullable + private final Object value; + + private KeyValuePair(String key, @Nullable Object value) { + this.key = key; + this.value = value; + } } - } - // A stylistic choice to make the comparator separate, rather than have KeyValuePair implement - // Comparable, because a class which implements Comparable is usually implicitly expected to - // also have sensible equals/hashCode methods, but we don't need those. - private static final Comparator KEY_VALUE_COMPARATOR = - new Comparator() { - @Override - public int compare(KeyValuePair lhs, KeyValuePair rhs) { - int signum = lhs.key.compareTo(rhs.key); - if (signum == 0) { + // A stylistic choice to make the comparator separate, rather than have KeyValuePair implement + // Comparable, because a class which implements Comparable is usually implicitly expected to + // also have sensible equals/hashCode methods, but we don't need those. + private static final Comparator KEY_VALUE_COMPARATOR = (lhs, rhs) -> { + var signum = lhs.key.compareTo(rhs.key); + if (signum == 0) { if (lhs.value != null) { - signum = rhs.value != null ? VALUE_COMPARATOR.compare(lhs.value, rhs.value) : 1; + signum = rhs.value != null ? VALUE_COMPARATOR.compare(lhs.value, rhs.value) : 1; } else { - signum = rhs.value != null ? -1 : 0; + signum = rhs.value != null ? -1 : 0; } - } - return signum; } - }; + return signum; + }; - private static final Tags EMPTY_TAGS = - new Tags(new LightweightTagMap(Collections.emptyList())); + private static final Tags EMPTY_TAGS = + new Tags(new LightweightTagMap(Collections.emptyList())); + + /** A mutable builder for tags. */ + public static final class Builder { + + private final List keyValuePairs = new ArrayList<>(); + + /** + * Adds an empty tag, ensuring that the given name exists in the tag map with at least an + * empty + * set of values. Adding the same name more than once has no effect. + * + *

      When viewed as a {@code Set}, the value for an empty tag is just the empty set. + * However if + * other values are added for the same name, the set of values will no longer be empty and + * the + * call to {@link #addTag(String)} will have had no lasting effect. + */ + @CanIgnoreReturnValue + public Builder addTag(String name) { + return addImpl(name, null); + } - /** A mutable builder for tags. */ - public static final class Builder { - private final List keyValuePairs = new ArrayList(); + /** + * Adds a string value for the given name, ensuring that the values for the given name + * contain + * at least this value. Adding the same name/value pair more than once has no effect. + */ + @CanIgnoreReturnValue + public Builder addTag(String name, String value) { + checkArgument(value != null, "tag value"); + return addImpl(name, value); + } - /** - * Adds an empty tag, ensuring that the given name exists in the tag map with at least an empty - * set of values. Adding the same name more than once has no effect. - * - *

      When viewed as a {@code Set}, the value for an empty tag is just the empty set. However if - * other values are added for the same name, the set of values will no longer be empty and the - * call to {@link #addTag(String)} will have had no lasting effect. - */ - @CanIgnoreReturnValue - public Builder addTag(String name) { - return addImpl(name, null); + /** + * Adds a boolean value for the given name, ensuring that the values for the given name + * contain + * at least this value. Adding the same name/value pair more than once has no effect. + */ + @CanIgnoreReturnValue + public Builder addTag(String name, boolean value) { + return addImpl(name, value); + } + + /** + * Adds a long value for the given name, ensuring that the values for the given name contain + * at + * least this value. Adding the same name/value pair more than once has no effect. + * + *

      Note however that for numeric values, differing types (long/double) are always + * considered + * distinct, so invoking both {@code addTag("foo", 1234L)} and + * {@code addTag("foo", 1234.0D)} + * will result in two values for the tag. + */ + @CanIgnoreReturnValue + public Builder addTag(String name, long value) { + return addImpl(name, value); + } + + /** + * Adds a double value for the given name, ensuring that the values for the given name + * contain + * at least this value. Adding the same name/value pair more than once has no effect. + * + *

      Note however that for numeric values, differing types (long/double) are always + * considered + * distinct, so invoking both {@code addTag("foo", 1234L)} and + * {@code addTag("foo", 1234.0D)} + * will result in two values for the tag. + */ + @CanIgnoreReturnValue + public Builder addTag(String name, double value) { + return addImpl(name, value); + } + + @CanIgnoreReturnValue + private Builder addImpl(String name, @Nullable Object value) { + keyValuePairs.add(new KeyValuePair(checkMetadataIdentifier(name), value)); + return this; + } + + /** Returns an immutable tags instance. */ + public Tags build() { + if (keyValuePairs.isEmpty()) { + return EMPTY_TAGS; + } + // Safe, even for a reused builder, because we never care about original value order. We + // could deduplicate here to guard against pathological use, but it should never matter. + Collections.sort(keyValuePairs, KEY_VALUE_COMPARATOR); + return new Tags(new LightweightTagMap(keyValuePairs)); + } + + @Override + public String toString() { + return build().toString(); + } + } + + /** Returns a new builder for adding tags. */ + public static Builder builder() { + return new Builder(); + } + + /** Returns the immutable empty tags instance. */ + public static Tags empty() { + return EMPTY_TAGS; } /** - * Adds a string value for the given name, ensuring that the values for the given name contain - * at least this value. Adding the same name/value pair more than once has no effect. + * Returns a single tag without needing to use the builder API. Where multiple tags are needed, + * it + * is always better to use the builder directly. */ - @CanIgnoreReturnValue - public Builder addTag(String name, String value) { - checkArgument(value != null, "tag value"); - return addImpl(name, value); + public static Tags of(String name, String value) { + return new Tags(name, value); } /** - * Adds a boolean value for the given name, ensuring that the values for the given name contain - * at least this value. Adding the same name/value pair more than once has no effect. + * Returns a single tag without needing to use the builder API. Where multiple tags are needed, + * it + * is always better to use the builder directly. */ - @CanIgnoreReturnValue - public Builder addTag(String name, boolean value) { - return addImpl(name, value); + public static Tags of(String name, boolean value) { + return new Tags(name, value); } /** - * Adds a long value for the given name, ensuring that the values for the given name contain at - * least this value. Adding the same name/value pair more than once has no effect. - * - *

      Note however that for numeric values, differing types (long/double) are always considered - * distinct, so invoking both {@code addTag("foo", 1234L)} and {@code addTag("foo", 1234.0D)} - * will result in two values for the tag. + * Returns a single tag without needing to use the builder API. Where multiple tags are needed, + * it + * is always better to use the builder directly. */ - @CanIgnoreReturnValue - public Builder addTag(String name, long value) { - return addImpl(name, value); + public static Tags of(String name, long value) { + return new Tags(name, value); } /** - * Adds a double value for the given name, ensuring that the values for the given name contain - * at least this value. Adding the same name/value pair more than once has no effect. - * - *

      Note however that for numeric values, differing types (long/double) are always considered - * distinct, so invoking both {@code addTag("foo", 1234L)} and {@code addTag("foo", 1234.0D)} - * will result in two values for the tag. + * Returns a single tag without needing to use the builder API. Where multiple tags are needed, + * it + * is always better to use the builder directly. */ - @CanIgnoreReturnValue - public Builder addTag(String name, double value) { - return addImpl(name, value); + public static Tags of(String name, double value) { + return new Tags(name, value); } - @CanIgnoreReturnValue - private Builder addImpl(String name, @Nullable Object value) { - keyValuePairs.add(new KeyValuePair(checkMetadataIdentifier(name), value)); - return this; - } + private final LightweightTagMap map; - /** Returns an immutable tags instance. */ - public Tags build() { - if (keyValuePairs.isEmpty()) { - return EMPTY_TAGS; - } - // Safe, even for a reused builder, because we never care about original value order. We - // could deduplicate here to guard against pathological use, but it should never matter. - Collections.sort(keyValuePairs, KEY_VALUE_COMPARATOR); - return new Tags(new LightweightTagMap(keyValuePairs)); + // Called for singleton Tags instances (but we need to check arguments here). + private Tags(String name, Object value) { + this(new LightweightTagMap(checkMetadataIdentifier(name), checkNotNull(value, "value"))); } - @Override - public String toString() { - return build().toString(); + // Canonical constructor, also called from merge(). + private Tags(LightweightTagMap map) { + this.map = map; } - } - - /** Returns a new builder for adding tags. */ - public static Builder builder() { - return new Builder(); - } - - /** Returns the immutable empty tags instance. */ - public static Tags empty() { - return EMPTY_TAGS; - } - - /** - * Returns a single tag without needing to use the builder API. Where multiple tags are needed, it - * is always better to use the builder directly. - */ - public static Tags of(String name, String value) { - return new Tags(name, value); - } - - /** - * Returns a single tag without needing to use the builder API. Where multiple tags are needed, it - * is always better to use the builder directly. - */ - public static Tags of(String name, boolean value) { - return new Tags(name, value); - } - - /** - * Returns a single tag without needing to use the builder API. Where multiple tags are needed, it - * is always better to use the builder directly. - */ - public static Tags of(String name, long value) { - return new Tags(name, value); - } - - /** - * Returns a single tag without needing to use the builder API. Where multiple tags are needed, it - * is always better to use the builder directly. - */ - public static Tags of(String name, double value) { - return new Tags(name, value); - } - - private final LightweightTagMap map; - - // Called for singleton Tags instances (but we need to check arguments here). - private Tags(String name, Object value) { - this(new LightweightTagMap(checkMetadataIdentifier(name), checkNotNull(value, "value"))); - } - - // Canonical constructor, also called from merge(). - private Tags(LightweightTagMap map) { - this.map = map; - } - - /** Returns an immutable map containing the tag values. */ - public Map> asMap() { - return map; - } - - /** Returns whether this instance is empty. */ - public boolean isEmpty() { - // In theory only the EMPTY_TAGS instance will ever be empty, but this check is not expensive. - return map.isEmpty(); - } - - /** Merges two tags instances, combining values for any name contained in both. */ - public Tags merge(Tags other) { - // Dereference "other" first as a null pointer check so we cannot risk returning null later. - if (other.isEmpty()) { - return this; - } - if (this.isEmpty()) { - return other; + + /** Returns an immutable map containing the tag values. */ + public Map> asMap() { + return map; } - // We could check if they are equal or one is a subset of the other, but we *really* don't - // expect that to be a common situation and merging should be fast enough. - return new Tags(new LightweightTagMap(map, other.map)); - } - - @Override - public boolean equals(@Nullable Object obj) { - return (obj instanceof Tags) && ((Tags) obj).map.equals(map); - } - - @Override - public int hashCode() { - // Invert the bits in the map hashcode just to be different. - return ~map.hashCode(); - } - - /** - * Returns human readable representation of the tags. This is not a stable representation and may - * change over time. If you need to format tags reliably for logging, you should not rely on this - * method. - */ - @Override - public String toString() { - return map.toString(); - } - - /* - * A super lightweight, immutable multi-map to hold tag values. The implementation packs all - * entries and values into a single array, and uses an offset array to jump to the start of each - * set. Type safety is ensured by careful partitioning during construction of the array. - * - * The total allocations for a Tags instance are: - * 1 x array for entries and values (no duplication, size of map + size of all value sets) - * 1 x array for offsets (size of the map) - * N x entries which hold 2 field each (N = size of map) - * 1 x entry set (holds 1 field) - * - * It's about 6 x 32-bits per entry (including object headers) and an extra 32 bits per value. For - * the largest normal use cases where you have up to 10 values in the tags, one per key, this is - * under 300 bytes. - * - * Previously, using a TreeMap>, it was in the region of 12 x 32 bits per - * entry and an additional 8 x 32 bits per value (based on examining the source for TreeSet and - * TreeMap), giving a rough estimate of at least 800 bytes. - */ - private static class LightweightTagMap extends AbstractMap> { - // Note if we weren't using binary search for lookup, none of this would be necessary. - @SuppressWarnings("unchecked") - private static final Comparator ENTRY_COMPARATOR = - new Comparator() { - @Override - public int compare(Object s1, Object s2) { - // Casting can fail if call passes in unexpected values via Set::contains(entry). - return ((Entry) s1).getKey().compareTo(((Entry) s2).getKey()); - } - }; - // A heuristic used when deciding to resize element or offset arrays. Arrays above this size - // will give savings when resized by more than 10%. In this code, the maximum saving is 50% of - // the array size, so arrays at or below this limit could only be wasting at most half this - // value of elements. - private static final int SMALL_ARRAY_LENGTH = 16; - - // A singleton map always has the same immutable offsets (start/end value indices). - private static final int[] singletonOffsets = new int[] {1, 2}; - - // This array holds ordered entries followed by values for each entry (grouped by key in order). - // - // The offsets array holds the starting offset to each contiguous group of values, plus a final - // offset to the end of the last group (but we allow sloppy array sizing, so there might be - // unused elements after the end of the last group and the array size is not to be trusted). - // - // [ E(0) ... E(n-1) , V(0,0), V(0,1) ... , V(1,0), V(1,1) ... V(n-1,0), V(n-1,1) ... xxx ... ] - // offsets --------[0]-^ ---------------[1]-^ --- ... ---[n-1]-^ -----------------[n]-^ - // - // E(n) = n-th entry, V(n,m) = m-th value for n-th entry. - // - // The set of entries has index -1, and entries start at 0 and end at offsets[0]. - // - // For an entry with index n >= 0, the values start at offsets[n] and end at offsets[n+1]. - // It is permitted to have zero values for an entry (i.e. offsets(n) == offsets(n+1)). - private final Object[] array; - private final int[] offsets; - - // Reusable, immutable entry set. Index -1 is a slightly special case, see getStart() etc. - private final Set>> entrySet = - new SortedArraySet>>(-1); - - // Cache these if anyone needs them (not likely in normal usage). - private Integer hashCode = null; - private String toString = null; - - // ---- Singleton constructor ---- - - LightweightTagMap(String name, Object value) { - this.offsets = singletonOffsets; - this.array = new Object[] {newEntry(name, 0), value}; + /** Returns whether this instance is empty. */ + public boolean isEmpty() { + // In theory only the EMPTY_TAGS instance will ever be empty, but this check is not expensive. + return map.isEmpty(); } - // ---- General constructor ---- + /** Merges two tags instances, combining values for any name contained in both. */ + public Tags merge(Tags other) { + // Dereference "other" first as a null pointer check so we cannot risk returning null later. + if (other.isEmpty()) { + return this; + } + if (this.isEmpty()) { + return other; + } + // We could check if they are equal or one is a subset of the other, but we *really* don't + // expect that to be a common situation and merging should be fast enough. + return new Tags(new LightweightTagMap(map, other.map)); + } - LightweightTagMap(List sortedPairs) { - // Allocate the maximum required space for entries and values. This is a bit wasteful if there - // are pairs with null values in (rare) or duplicates (very rare) but we might resize later. - int entryCount = countMapEntries(sortedPairs); - Object[] array = new Object[entryCount + sortedPairs.size()]; - int[] offsets = new int[entryCount + 1]; + @Override + public boolean equals(@Nullable Object obj) { + return (obj instanceof Tags) && ((Tags) obj).map.equals(map); + } - int totalElementCount = makeTagMap(sortedPairs, entryCount, array, offsets); - this.array = maybeResizeElementArray(array, totalElementCount); - this.offsets = offsets; + @Override + public int hashCode() { + // Invert the bits in the map hashcode just to be different. + return ~map.hashCode(); } - // ---- Merging constructor ---- - - LightweightTagMap(LightweightTagMap lhs, LightweightTagMap rhs) { - // We already checked that neither map is empty and it's probably not worth optimizing for the - // case where one is a subset of the other (by the time you've checked you might as well have - // just made a new instance anyway). - // - // We expect to efficiently use most or all of this array (resizing should be rare). - int maxEntryCount = lhs.size() + rhs.size(); - Object[] array = new Object[lhs.getTotalElementCount() + rhs.getTotalElementCount()]; - int[] offsets = new int[maxEntryCount + 1]; - - int totalElementCount = mergeTagMaps(lhs, rhs, maxEntryCount, array, offsets); - this.array = adjustOffsetsAndMaybeResize(array, offsets, totalElementCount); - this.offsets = maybeResizeOffsetsArray(offsets); + /** + * Returns human readable representation of the tags. This is not a stable representation and + * may + * change over time. If you need to format tags reliably for logging, you should not rely on + * this + * method. + */ + @Override + public String toString() { + return map.toString(); } - // ---- Helpers for making a tag map from the builder. ---- + /* + * A super lightweight, immutable multi-map to hold tag values. The implementation packs all + * entries and values into a single array, and uses an offset array to jump to the start of each + * set. Type safety is ensured by careful partitioning during construction of the array. + * + * The total allocations for a Tags instance are: + * 1 x array for entries and values (no duplication, size of map + size of all value sets) + * 1 x array for offsets (size of the map) + * N x entries which hold 2 field each (N = size of map) + * 1 x entry set (holds 1 field) + * + * It's about 6 x 32-bits per entry (including object headers) and an extra 32 bits per value. For + * the largest normal use cases where you have up to 10 values in the tags, one per key, this is + * under 300 bytes. + * + * Previously, using a TreeMap>, it was in the region of 12 x 32 bits per + * entry and an additional 8 x 32 bits per value (based on examining the source for TreeSet and + * TreeMap), giving a rough estimate of at least 800 bytes. + */ + private static class LightweightTagMap extends AbstractMap> { + + // Note if we weren't using binary search for lookup, none of this would be necessary. + @SuppressWarnings("unchecked") + private static final Comparator ENTRY_COMPARATOR = + new Comparator<>() { + @Override + public int compare(Object s1, Object s2) { + // Casting can fail if call passes in unexpected values via Set::contains(entry). + return ((Entry) s1).getKey() + .compareTo(((Entry) s2).getKey()); + } + }; + + // A heuristic used when deciding to resize element or offset arrays. Arrays above this size + // will give savings when resized by more than 10%. In this code, the maximum saving is 50% of + // the array size, so arrays at or below this limit could only be wasting at most half this + // value of elements. + private static final int SMALL_ARRAY_LENGTH = 16; + + // A singleton map always has the same immutable offsets (start/end value indices). + private static final int[] singletonOffsets = new int[]{1, 2}; + + // This array holds ordered entries followed by values for each entry (grouped by key in order). + // + // The offsets array holds the starting offset to each contiguous group of values, plus a final + // offset to the end of the last group (but we allow sloppy array sizing, so there might be + // unused elements after the end of the last group and the array size is not to be trusted). + // + // [ E(0) ... E(n-1) , V(0,0), V(0,1) ... , V(1,0), V(1,1) ... V(n-1,0), V(n-1,1) ... xxx ... ] + // offsets --------[0]-^ ---------------[1]-^ --- ... ---[n-1]-^ -----------------[n]-^ + // + // E(n) = n-th entry, V(n,m) = m-th value for n-th entry. + // + // The set of entries has index -1, and entries start at 0 and end at offsets[0]. + // + // For an entry with index n >= 0, the values start at offsets[n] and end at offsets[n+1]. + // It is permitted to have zero values for an entry (i.e. offsets(n) == offsets(n+1)). + private final Object[] array; + private final int[] offsets; + + // Reusable, immutable entry set. Index -1 is a slightly special case, see getStart() etc. + private final Set>> entrySet = + new SortedArraySet<>(-1); + + // Cache these if anyone needs them (not likely in normal usage). + private Integer hashCode = null; + private String toString = null; + + // ---- Singleton constructor ---- + + LightweightTagMap(String name, Object value) { + this.offsets = singletonOffsets; + this.array = new Object[]{newEntry(name, 0), value}; + } + + // ---- General constructor ---- + + LightweightTagMap(List sortedPairs) { + // Allocate the maximum required space for entries and values. This is a bit wasteful if there + // are pairs with null values in (rare) or duplicates (very rare) but we might resize later. + var entryCount = countMapEntries(sortedPairs); + var array = new Object[entryCount + sortedPairs.size()]; + var offsets = new int[entryCount + 1]; - // Count the unique keys for a sorted list of key-value pairs. - private static int countMapEntries(List sortedPairs) { - String key = null; - int count = 0; - for (KeyValuePair pair : sortedPairs) { - if (!pair.key.equals(key)) { - key = pair.key; - count++; + var totalElementCount = makeTagMap(sortedPairs, entryCount, array, offsets); + this.array = maybeResizeElementArray(array, totalElementCount); + this.offsets = offsets; } - } - return count; - } - // Processes a sorted sequence of key/value pairs to fill the given arrays/offsets. This is a - // single pass of the pairs - private int makeTagMap( - List sortedPairs, int entryCount, Object[] array, int[] offsets) { - String key = null; - Object value = null; - int newEntryIndex = 0; - int valueStart = entryCount; - for (KeyValuePair pair : sortedPairs) { - if (!pair.key.equals(key)) { - key = pair.key; - array[newEntryIndex] = newEntry(key, newEntryIndex); - offsets[newEntryIndex] = valueStart; - newEntryIndex++; - value = null; - } - if (pair.value != null && !pair.value.equals(value)) { - value = pair.value; - array[valueStart++] = value; - } - } - // If someone was using the builder concurrently, all bets are off. - if (newEntryIndex != entryCount) { - throw new ConcurrentModificationException("corrupted tag map"); - } - offsets[entryCount] = valueStart; - return valueStart; - } + // ---- Merging constructor ---- + + LightweightTagMap(LightweightTagMap lhs, LightweightTagMap rhs) { + // We already checked that neither map is empty and it's probably not worth optimizing for the + // case where one is a subset of the other (by the time you've checked you might as well have + // just made a new instance anyway). + // + // We expect to efficiently use most or all of this array (resizing should be rare). + var maxEntryCount = lhs.size() + rhs.size(); + var array = new Object[lhs.getTotalElementCount() + rhs.getTotalElementCount()]; + var offsets = new int[maxEntryCount + 1]; + + var totalElementCount = mergeTagMaps(lhs, rhs, maxEntryCount, array, offsets); + this.array = adjustOffsetsAndMaybeResize(array, offsets, totalElementCount); + this.offsets = maybeResizeOffsetsArray(offsets); + } - // ---- Helpers for merging tag maps. ---- - - private int mergeTagMaps( - LightweightTagMap lhs, - LightweightTagMap rhs, - int maxEntryCount, - Object[] array, - int[] offsets) { - // Merge values starting at the first safe offset after the largest possible number of - // entries. We may need to copy elements later to remove any gap due to duplicate keys. - // If the values are copied down we must remember to re-adjust the offsets as well. - int valueStart = maxEntryCount; - // The first offset is the start of the first values segment. - offsets[0] = valueStart; - - // We must have at least one entry per map, but they can be null once we run out. - int lhsEntryIndex = 0; - Entry> lhsEntry = lhs.getEntryOrNull(lhsEntryIndex); - int rhsEntryIndex = 0; - Entry> rhsEntry = rhs.getEntryOrNull(rhsEntryIndex); - - int newEntryIndex = 0; - while (lhsEntry != null || rhsEntry != null) { - // Nulls count as being *bigger* than anything (since they indicate the end of the array). - int signum = (lhsEntry == null) ? 1 : (rhsEntry == null) ? -1 : 0; - if (signum == 0) { - // Both entries exist and must be compared. - signum = lhsEntry.getKey().compareTo(rhsEntry.getKey()); - if (signum == 0) { - // Merge values, update both indices/entries. - array[newEntryIndex] = newEntry(lhsEntry.getKey(), newEntryIndex); - newEntryIndex++; - valueStart = mergeValues(lhsEntry.getValue(), rhsEntry.getValue(), array, valueStart); - offsets[newEntryIndex] = valueStart; - lhsEntry = lhs.getEntryOrNull(++lhsEntryIndex); - rhsEntry = rhs.getEntryOrNull(++rhsEntryIndex); - continue; - } - } - // Signum is non-zero and indicates which entry to process next (without merging). - if (signum < 0) { - valueStart = copyEntryAndValues(lhsEntry, newEntryIndex++, valueStart, array, offsets); - lhsEntry = lhs.getEntryOrNull(++lhsEntryIndex); - } else { - valueStart = copyEntryAndValues(rhsEntry, newEntryIndex++, valueStart, array, offsets); - rhsEntry = rhs.getEntryOrNull(++rhsEntryIndex); - } - } - return newEntryIndex; - } + // ---- Helpers for making a tag map from the builder. ---- + + // Count the unique keys for a sorted list of key-value pairs. + private static int countMapEntries(List sortedPairs) { + String key = null; + var count = 0; + for (var pair : sortedPairs) { + if (!pair.key.equals(key)) { + key = pair.key; + count++; + } + } + return count; + } - // Called when merging maps to merge the values for a pair of entries with duplicate keys. - private static int mergeValues( - SortedArraySet lhs, SortedArraySet rhs, Object[] array, int valueStart) { - // The indices here are the value indices within the lhs/rhs elements, not the indices of the - // elements in their respective maps, but the basic loop structure is very similar. - int lhsIndex = 0; - int rhsIndex = 0; - while (lhsIndex < lhs.size() || rhsIndex < rhs.size()) { - int signum = (lhsIndex == lhs.size()) ? 1 : (rhsIndex == rhs.size()) ? -1 : 0; - if (signum == 0) { - signum = VALUE_COMPARATOR.compare(lhs.getValue(lhsIndex), rhs.getValue(rhsIndex)); - } - // Signum can be zero here for duplicate values (unlike the entry processing loop above). - Object value; - if (signum < 0) { - value = lhs.getValue(lhsIndex++); - } else { - value = rhs.getValue(rhsIndex++); - if (signum == 0) { - // Equal values means we just drop the duplicate. - lhsIndex++; - } - } - array[valueStart++] = value; - } - return valueStart; - } + // Processes a sorted sequence of key/value pairs to fill the given arrays/offsets. This is a + // single pass of the pairs + private int makeTagMap( + List sortedPairs, int entryCount, Object[] array, int[] offsets) { + String key = null; + Object value = null; + var newEntryIndex = 0; + var valueStart = entryCount; + for (var pair : sortedPairs) { + if (!pair.key.equals(key)) { + key = pair.key; + array[newEntryIndex] = newEntry(key, newEntryIndex); + offsets[newEntryIndex] = valueStart; + newEntryIndex++; + value = null; + } + if (pair.value != null && !pair.value.equals(value)) { + value = pair.value; + array[valueStart++] = value; + } + } + // If someone was using the builder concurrently, all bets are off. + if (newEntryIndex != entryCount) { + throw new ConcurrentModificationException("corrupted tag map"); + } + offsets[entryCount] = valueStart; + return valueStart; + } - // Called when merging maps to copy an entry with a unique key, and all its values. - private int copyEntryAndValues( - Map.Entry> entry, - int entryIndex, - int valueStart, - Object[] array, - int[] offsets) { - SortedArraySet values = entry.getValue(); - int valueCount = values.getEnd() - values.getStart(); - System.arraycopy(values.getValuesArray(), values.getStart(), array, valueStart, valueCount); - array[entryIndex] = newEntry(entry.getKey(), entryIndex); - // Record the end offset for the segment, and return it as the start of the next segment. - int valueEnd = valueStart + valueCount; - offsets[entryIndex + 1] = valueEnd; - return valueEnd; - } + // ---- Helpers for merging tag maps. ---- + + private int mergeTagMaps( + LightweightTagMap lhs, + LightweightTagMap rhs, + int maxEntryCount, + Object[] array, + int[] offsets) { + // Merge values starting at the first safe offset after the largest possible number of + // entries. We may need to copy elements later to remove any gap due to duplicate keys. + // If the values are copied down we must remember to re-adjust the offsets as well. + var valueStart = maxEntryCount; + // The first offset is the start of the first values segment. + offsets[0] = valueStart; + + // We must have at least one entry per map, but they can be null once we run out. + var lhsEntryIndex = 0; + var lhsEntry = lhs.getEntryOrNull(lhsEntryIndex); + var rhsEntryIndex = 0; + var rhsEntry = rhs.getEntryOrNull(rhsEntryIndex); + + var newEntryIndex = 0; + while (lhsEntry != null || rhsEntry != null) { + // Nulls count as being *bigger* than anything (since they indicate the end of the array). + var signum = (lhsEntry == null) ? 1 : (rhsEntry == null) ? -1 : 0; + if (signum == 0) { + // Both entries exist and must be compared. + signum = lhsEntry.getKey() + .compareTo(rhsEntry.getKey()); + if (signum == 0) { + // Merge values, update both indices/entries. + array[newEntryIndex] = newEntry(lhsEntry.getKey(), newEntryIndex); + newEntryIndex++; + valueStart = mergeValues(lhsEntry.getValue(), rhsEntry.getValue(), array, + valueStart); + offsets[newEntryIndex] = valueStart; + lhsEntry = lhs.getEntryOrNull(++lhsEntryIndex); + rhsEntry = rhs.getEntryOrNull(++rhsEntryIndex); + continue; + } + } + // Signum is non-zero and indicates which entry to process next (without merging). + if (signum < 0) { + valueStart = copyEntryAndValues(lhsEntry, newEntryIndex++, valueStart, array, + offsets); + lhsEntry = lhs.getEntryOrNull(++lhsEntryIndex); + } else { + valueStart = copyEntryAndValues(rhsEntry, newEntryIndex++, valueStart, array, + offsets); + rhsEntry = rhs.getEntryOrNull(++rhsEntryIndex); + } + } + return newEntryIndex; + } - // Called after merging two maps to see if the offset array needs adjusting. - // This method may also "right size" the values array if it detected sufficient wastage. - private static Object[] adjustOffsetsAndMaybeResize( - Object[] array, int[] offsets, int entryCount) { - // See if there's a gap between entries and values (due to duplicate keys being merged). - // If not then we know that the array uses all its elements (since no values were merged). - int maxEntries = offsets[0]; - int offsetReduction = maxEntries - entryCount; - if (offsetReduction == 0) { - return array; - } - for (int i = 0; i <= entryCount; i++) { - offsets[i] -= offsetReduction; - } - Object[] dstArray = array; - int totalElementCount = offsets[entryCount]; - int valueCount = totalElementCount - entryCount; - if (mustResize(array.length, totalElementCount)) { - dstArray = new Object[totalElementCount]; - System.arraycopy(array, 0, dstArray, 0, entryCount); - } - // If we are reusing the working array, this copy leaves non-null values in the unused - // portion at the end of the array, but these references are also repeated earlier in the - // array, so there's no issue with leaking any values because of this. - System.arraycopy(array, maxEntries, dstArray, entryCount, valueCount); - return dstArray; - } + // Called when merging maps to merge the values for a pair of entries with duplicate keys. + private static int mergeValues( + SortedArraySet lhs, SortedArraySet rhs, Object[] array, int valueStart) { + // The indices here are the value indices within the lhs/rhs elements, not the indices of the + // elements in their respective maps, but the basic loop structure is very similar. + var lhsIndex = 0; + var rhsIndex = 0; + while (lhsIndex < lhs.size() || rhsIndex < rhs.size()) { + var signum = (lhsIndex == lhs.size()) ? 1 : (rhsIndex == rhs.size()) ? -1 : 0; + if (signum == 0) { + signum = VALUE_COMPARATOR.compare(lhs.getValue(lhsIndex), + rhs.getValue(rhsIndex)); + } + // Signum can be zero here for duplicate values (unlike the entry processing loop above). + Object value; + if (signum < 0) { + value = lhs.getValue(lhsIndex++); + } else { + value = rhs.getValue(rhsIndex++); + if (signum == 0) { + // Equal values means we just drop the duplicate. + lhsIndex++; + } + } + array[valueStart++] = value; + } + return valueStart; + } - // ---- General constructor helper methods ---- + // Called when merging maps to copy an entry with a unique key, and all its values. + private int copyEntryAndValues( + Map.Entry> entry, + int entryIndex, + int valueStart, + Object[] array, + int[] offsets) { + var values = entry.getValue(); + var valueCount = values.getEnd() - values.getStart(); + System.arraycopy(values.getValuesArray(), values.getStart(), array, valueStart, + valueCount); + array[entryIndex] = newEntry(entry.getKey(), entryIndex); + // Record the end offset for the segment, and return it as the start of the next segment. + var valueEnd = valueStart + valueCount; + offsets[entryIndex + 1] = valueEnd; + return valueEnd; + } - // Resize the value array if necessary. - private static Object[] maybeResizeElementArray(Object[] array, int bestLength) { - return mustResize(array.length, bestLength) ? Arrays.copyOf(array, bestLength) : array; - } + // Called after merging two maps to see if the offset array needs adjusting. + // This method may also "right size" the values array if it detected sufficient wastage. + private static Object[] adjustOffsetsAndMaybeResize( + Object[] array, int[] offsets, int entryCount) { + // See if there's a gap between entries and values (due to duplicate keys being merged). + // If not then we know that the array uses all its elements (since no values were merged). + var maxEntries = offsets[0]; + var offsetReduction = maxEntries - entryCount; + if (offsetReduction == 0) { + return array; + } + for (var i = 0; i <= entryCount; i++) { + offsets[i] -= offsetReduction; + } + var dstArray = array; + var totalElementCount = offsets[entryCount]; + var valueCount = totalElementCount - entryCount; + if (mustResize(array.length, totalElementCount)) { + dstArray = new Object[totalElementCount]; + System.arraycopy(array, 0, dstArray, 0, entryCount); + } + // If we are reusing the working array, this copy leaves non-null values in the unused + // portion at the end of the array, but these references are also repeated earlier in the + // array, so there's no issue with leaking any values because of this. + System.arraycopy(array, maxEntries, dstArray, entryCount, valueCount); + return dstArray; + } - // Resize the value array if necessary (separate since int[] and Object[] are not compatible). - private static int[] maybeResizeOffsetsArray(int[] offsets) { - // Remember we must account for the extra final offset (the end of the final segment). - int bestLength = offsets[0] + 1; - return mustResize(offsets.length, bestLength) ? Arrays.copyOf(offsets, bestLength) : offsets; - } + // ---- General constructor helper methods ---- - // Common logic to decide if we're wasting too much off an array and need to "right size" it. - // Returns true if more than 10% wasted in a non-trivial sized array. - private static boolean mustResize(int actualLength, int bestLength) { - return actualLength > SMALL_ARRAY_LENGTH && (9 * actualLength > 10 * bestLength); - } + // Resize the value array if necessary. + private static Object[] maybeResizeElementArray(Object[] array, int bestLength) { + return mustResize(array.length, bestLength) ? Arrays.copyOf(array, bestLength) : array; + } - // Returns a new entry for this map with the given key and values read according to the - // specified offset index (see SortedArraySet). - private Map.Entry> newEntry(String key, int index) { - return new SimpleImmutableEntry>( - key, new SortedArraySet(index)); - } + // Resize the value array if necessary (separate since int[] and Object[] are not compatible). + private static int[] maybeResizeOffsetsArray(int[] offsets) { + // Remember we must account for the extra final offset (the end of the final segment). + var bestLength = offsets[0] + 1; + return mustResize(offsets.length, bestLength) ? Arrays.copyOf(offsets, + bestLength) : offsets; + } - @SuppressWarnings("unchecked") // Safe when the index is in range. - private Map.Entry> getEntryOrNull(int index) { - return index < offsets[0] ? (Map.Entry>) array[index] : null; - } + // Common logic to decide if we're wasting too much off an array and need to "right size" it. + // Returns true if more than 10% wasted in a non-trivial sized array. + private static boolean mustResize(int actualLength, int bestLength) { + return actualLength > SMALL_ARRAY_LENGTH && (9 * actualLength > 10 * bestLength); + } - // Returns the total number of used elements in the entry/value array. Note that this may well - // be less than the total array size, since we allow for "sloppy" resizing. - private int getTotalElementCount() { - return offsets[size()]; - } + // Returns a new entry for this map with the given key and values read according to the + // specified offset index (see SortedArraySet). + private Map.Entry> newEntry(String key, int index) { + return new SimpleImmutableEntry<>( + key, new SortedArraySet<>(index)); + } - // ---- Public API methods. ---- + @SuppressWarnings("unchecked") // Safe when the index is in range. + private Map.Entry> getEntryOrNull(int index) { + return index < + offsets[0] ? (Map.Entry>) array[index] : null; + } - @Override - public Set>> entrySet() { - return entrySet; - } + // Returns the total number of used elements in the entry/value array. Note that this may well + // be less than the total array size, since we allow for "sloppy" resizing. + private int getTotalElementCount() { + return offsets[size()]; + } - /** - * A lightweight set based on an range in an array. This assumes (but does not enforce) that the - * elements in the array are ordered according to the comparator. It uses the array and offsets - * from the outer map class, needing only to specify its index from which start/end offsets can - * be derived. - */ - class SortedArraySet extends AbstractSet { - // -1 = key set, 0...N-1 = values set. - final int index; - - SortedArraySet(int index) { - this.index = index; - } - - Object[] getValuesArray() { - return array; - } - - // Caller must check 0 <= n < size(). - Object getValue(int n) { - return array[getStart() + n]; - } - - int getStart() { - return index == -1 ? 0 : offsets[index]; - } - - int getEnd() { - return offsets[index + 1]; - } - - private Comparator getComparator() { - return index == -1 ? ENTRY_COMPARATOR : VALUE_COMPARATOR; - } - - @Override - public int size() { - return getEnd() - getStart(); - } - - // Optional, but potentially faster to binary search for elements. - // TODO(dbeaumont): Benchmark for realistic tag usage and consider removing. - @Override - public boolean contains(Object o) { - return Arrays.binarySearch(array, getStart(), getEnd(), o, getComparator()) >= 0; - } - - @Override - public Iterator iterator() { - return new Iterator() { - private int n = 0; - - @Override - public boolean hasNext() { - return n < size(); - } - - @Override - public T next() { - // Copy to local variable to guard against concurrent calls to next() causing the index - // to become corrupted, and going off the end of the valid range for this iterator. - // This doesn't make concurrent iteration thread safe in general, but prevents weird - // situations where a value for a different element could be returned by mistake. - int index = n; - if (index < size()) { - @SuppressWarnings("unchecked") - T value = (T) array[getStart() + index]; - // Written value is never > size(), even with concurrent iteration. - n = index + 1; - return value; + // ---- Public API methods. ---- + + @Override + public Set>> entrySet() { + return entrySet; + } + + /** + * A lightweight set based on an range in an array. This assumes (but does not enforce) that + * the + * elements in the array are ordered according to the comparator. It uses the array and + * offsets + * from the outer map class, needing only to specify its index from which start/end offsets + * can + * be derived. + */ + class SortedArraySet extends AbstractSet { + + // -1 = key set, 0...N-1 = values set. + final int index; + + SortedArraySet(int index) { + this.index = index; } - throw new NoSuchElementException(); - } - @Override // in case we are on an earlier Java version with no default method for this - public void remove() { - throw new UnsupportedOperationException(); - } - }; - } - } + Object[] getValuesArray() { + return array; + } - @Override - public int hashCode() { - // Abstract maps cannot cache their hash codes, but we know we're immutable, so we can. - if (hashCode == null) { - hashCode = super.hashCode(); - } - return hashCode; - } + // Caller must check 0 <= n < size(). + Object getValue(int n) { + return array[getStart() + n]; + } - @Override - public String toString() { - if (toString == null) { - toString = super.toString(); - } - return toString; + int getStart() { + return index == -1 ? 0 : offsets[index]; + } + + int getEnd() { + return offsets[index + 1]; + } + + private Comparator getComparator() { + return index == -1 ? ENTRY_COMPARATOR : VALUE_COMPARATOR; + } + + @Override + public int size() { + return getEnd() - getStart(); + } + + // Optional, but potentially faster to binary search for elements. + // TODO(dbeaumont): Benchmark for realistic tag usage and consider removing. + @Override + public boolean contains(Object o) { + return Arrays.binarySearch(array, getStart(), getEnd(), o, getComparator()) >= 0; + } + + @Override + public Iterator iterator() { + return new Iterator<>() { + private int n = 0; + + @Override + public boolean hasNext() { + return n < size(); + } + + @Override + public T next() { + // Copy to local variable to guard against concurrent calls to next() causing the index + // to become corrupted, and going off the end of the valid range for this iterator. + // This doesn't make concurrent iteration thread safe in general, but prevents weird + // situations where a value for a different element could be returned by mistake. + var index = n; + if (index < size()) { + @SuppressWarnings("unchecked") + var value = (T) array[getStart() + index]; + // Written value is never > size(), even with concurrent iteration. + n = index + 1; + return value; + } + throw new NoSuchElementException(); + } + + @Override + // in case we are on an earlier Java version with no default method for this + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + } + + @Override + public int hashCode() { + // Abstract maps cannot cache their hash codes, but we know we're immutable, so we can. + if (hashCode == null) { + hashCode = super.hashCode(); + } + return hashCode; + } + + @Override + public String toString() { + if (toString == null) { + toString = super.toString(); + } + return toString; + } } - } } diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/BraceStyleParameter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/BraceStyleParameter.java index c583df8c2..36ae60437 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/BraceStyleParameter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/BraceStyleParameter.java @@ -29,6 +29,7 @@ import io.spine.logging.jvm.backend.FormatChar; import io.spine.logging.jvm.backend.FormatOptions; import io.spine.logging.jvm.backend.FormatType; + import java.text.MessageFormat; import java.util.Calendar; import java.util.Date; @@ -37,76 +38,79 @@ /** * A parameter implementation to mimic the formatting of brace style placeholders (ie, "{n}"). * - * @see - * Original Java code of Google Flogger + * @see + * Original Java code of Google Flogger */ public class BraceStyleParameter extends Parameter { - // Format options to mimic how '{0}' is formatted for numbers (i.e. like "%,d" or "%,f"). - private static final FormatOptions WITH_GROUPING = - FormatOptions.of(FormatOptions.FLAG_SHOW_GROUPING, FormatOptions.UNSET, FormatOptions.UNSET); + // Format options to mimic how '{0}' is formatted for numbers (i.e. like "%,d" or "%,f"). + private static final FormatOptions WITH_GROUPING = + FormatOptions.of(FormatOptions.FLAG_SHOW_GROUPING, FormatOptions.UNSET, + FormatOptions.UNSET); - // Message formatter for fallback cases where '{n}' formats sufficiently differently to any - // available printf specifier that we must preformat the result ourselves. - // TODO: Get the Locale from the Platform class for better i18n support. - private static final MessageFormat prototypeMessageFormatter = - new MessageFormat("{0}", Locale.ROOT); + // Message formatter for fallback cases where '{n}' formats sufficiently differently to any + // available printf specifier that we must preformat the result ourselves. + // TODO: Get the Locale from the Platform class for better i18n support. + private static final MessageFormat prototypeMessageFormatter = + new MessageFormat("{0}", Locale.ROOT); - /** Cache parameters with indices 0-9 to cover the vast majority of cases. */ - private static final int MAX_CACHED_PARAMETERS = 10; + /** Cache parameters with indices 0-9 to cover the vast majority of cases. */ + private static final int MAX_CACHED_PARAMETERS = 10; - /** Map of the most common default general parameters (corresponds to %s, %d, %f etc...). */ - private static final BraceStyleParameter[] DEFAULT_PARAMETERS; + /** Map of the most common default general parameters (corresponds to %s, %d, %f etc...). */ + private static final BraceStyleParameter[] DEFAULT_PARAMETERS; - static { - DEFAULT_PARAMETERS = new BraceStyleParameter[MAX_CACHED_PARAMETERS]; - for (int index = 0; index < MAX_CACHED_PARAMETERS; index++) { - DEFAULT_PARAMETERS[index] = new BraceStyleParameter(index); + static { + DEFAULT_PARAMETERS = new BraceStyleParameter[MAX_CACHED_PARAMETERS]; + for (var index = 0; index < MAX_CACHED_PARAMETERS; index++) { + DEFAULT_PARAMETERS[index] = new BraceStyleParameter(index); + } } - } - /** - * Returns a {@link Parameter} representing a plain "brace style" placeholder "{n}". Note that a - * cached value may be returned. - * - * @param index the index of the argument to be processed. - * @return the immutable, thread safe parameter instance. - */ - public static BraceStyleParameter of(int index) { - return index < MAX_CACHED_PARAMETERS - ? DEFAULT_PARAMETERS[index] - : new BraceStyleParameter(index); - } + /** + * Returns a {@link Parameter} representing a plain "brace style" placeholder "{n}". + * Note that a cached value may be returned. + * + * @param index + * the index of the argument to be processed. + * @return the immutable, thread safe parameter instance. + */ + public static BraceStyleParameter of(int index) { + return index < MAX_CACHED_PARAMETERS + ? DEFAULT_PARAMETERS[index] + : new BraceStyleParameter(index); + } - private BraceStyleParameter(int index) { - super(FormatOptions.getDefault(), index); - } + private BraceStyleParameter(int index) { + super(FormatOptions.getDefault(), index); + } - @Override - protected void accept(ParameterVisitor visitor, Object value) { - // Special cases which MessageFormat treats specially (oddly Calendar is not a special case). - if (FormatType.INTEGRAL.canFormat(value)) { - visitor.visit(value, FormatChar.DECIMAL, WITH_GROUPING); - } else if (FormatType.FLOAT.canFormat(value)) { - // Technically floating point formatting via {0} differs from "%,f", but as "%,f" results in - // more precision it seems better to mimic "%,f" rather than discard both precision and type - // information by calling visitPreformatted(). - visitor.visit(value, FormatChar.FLOAT, WITH_GROUPING); - } else if (value instanceof Date) { - // MessageFormat is not thread safe, so we always clone(). - String formatted = ((MessageFormat) prototypeMessageFormatter.clone()) - .format(new Object[] {value}, new StringBuffer(), null /* field position */) - .toString(); - visitor.visitPreformatted(value, formatted); - } else if (value instanceof Calendar) { - visitor.visitDateTime(value, DateTimeFormat.DATETIME_FULL, getFormatOptions()); - } else { - visitor.visit(value, FormatChar.STRING, getFormatOptions()); + @Override + protected void accept(ParameterVisitor visitor, Object value) { + // Special cases which MessageFormat treats specially (oddly Calendar is not a special case). + if (FormatType.INTEGRAL.canFormat(value)) { + visitor.visit(value, FormatChar.DECIMAL, WITH_GROUPING); + } else if (FormatType.FLOAT.canFormat(value)) { + // Technically floating point formatting via {0} differs from "%,f", but as "%,f" results in + // more precision it seems better to mimic "%,f" rather than discard both precision and type + // information by calling visitPreformatted(). + visitor.visit(value, FormatChar.FLOAT, WITH_GROUPING); + } else if (value instanceof Date) { + // MessageFormat is not thread safe, so we always clone(). + var formatted = ((MessageFormat) prototypeMessageFormatter.clone()) + .format(new Object[]{value}, new StringBuffer(), null /* field position */) + .toString(); + visitor.visitPreformatted(value, formatted); + } else if (value instanceof Calendar) { + visitor.visitDateTime(value, DateTimeFormat.DATETIME_FULL, getFormatOptions()); + } else { + visitor.visit(value, FormatChar.STRING, getFormatOptions()); + } } - } - @Override - public String getFormat() { - return "%s"; - } + @Override + public String getFormat() { + return "%s"; + } } diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeFormat.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeFormat.java index dd8b344c0..9fb45669e 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeFormat.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeFormat.java @@ -32,137 +32,176 @@ /** * Supported date/time sub-format characters for the %t/%T formatting pattern. - *

      - * WARNING: Many date/time format specifiers use the system default time-zone for formatting + * + *

      WARNING: Many date/time format specifiers use the system default time-zone for formatting * {@code Date} or {@code long} arguments. This makes it non system-portable, and its use is heavily * discouraged with non-{@code Calendar} arguments. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger */ public enum DateTimeFormat { - // The following conversion characters are used for formatting times: - - /** - * Hour of the day for the 24-hour clock, formatted as two digits with a leading zero as - * necessary, i.e. 00 - 23. - */ - TIME_HOUR_OF_DAY_PADDED('H'), - /** Hour of the day for the 24-hour clock, i.e. 0 - 23. */ - TIME_HOUR_OF_DAY('k'), - /** - * Hour for the 12-hour clock, formatted as two digits with a leading zero as necessary, - * i.e. 01 - 12. - */ - TIME_HOUR_12H_PADDED('I'), - /** Hour for the 12-hour clock, i.e. 1 - 12. */ - TIME_HOUR_12H('l'), - /** - * Minute within the hour formatted as two digits with a leading zero as necessary, i.e. 00 - 59. - */ - TIME_MINUTE_OF_HOUR_PADDED('M'), - /** - * Seconds within the minute, formatted as two digits with a leading zero as necessary, - * i.e. 00 - 60 ("60" is a special value required to support leap seconds). - */ - TIME_SECONDS_OF_MINUTE_PADDED('S'), - /** - * Millisecond within the second formatted as three digits with leading zeros as necessary, - * i.e. 000 - 999. - */ - TIME_MILLIS_OF_SECOND_PADDED('L'), - /** - * Nanosecond within the second, formatted as nine digits with leading zeros as necessary, - * i.e. 000000000 - 999999999. - */ - TIME_NANOS_OF_SECOND_PADDED('N'), - /** Locale-specific morning or afternoon marker in lower case, e.g. "am" or "pm". */ - TIME_AM_PM('p'), - /** - * RFC 822 style numeric time zone offset from GMT, e.g. "-0800". This value will be adjusted as - * necessary for Daylight Saving Time. For long, Long, and Date the time zone used is the default - * time zone for this instance of the Java virtual machine. - */ - TIME_TZ_NUMERIC('z'), - /** - * A string representing the abbreviation for the time zone. This value will be adjusted as - * necessary for Daylight Saving Time. For long, Long, and Date the time zone used is the default - * time zone for this instance of the Java virtual machine. - */ - TIME_TZ_SHORT('Z'), - /** Seconds since the beginning of the epoch starting at 1 January 1970 00:00:00 UTC. */ - TIME_EPOCH_SECONDS('s'), - /** Milliseconds since the beginning of the epoch starting at 1 January 1970 00:00:00 UTC. */ - TIME_EPOCH_MILLIS('Q'), - - // The following conversion characters are used for formatting dates: - - /** Locale-specific full month name, e.g. "January", "February". */ - DATE_MONTH_FULL('B'), - /** Locale-specific abbreviated month name, e.g. "Jan", "Feb". */ - DATE_MONTH_SHORT('b'), - /** Same as 'b'. */ - DATE_MONTH_SHORT_ALT('h'), - /** Locale-specific full name of the day of the week, e.g. "Sunday", "Monday". */ - DATE_DAY_FULL('A'), - /** Locale-specific short name of the day of the week, e.g. "Sun", "Mon". */ - DATE_DAY_SHORT('a'), - /** - * Four-digit year divided by 100, formatted as two digits with leading zero as necessary, i.e. 00 - * - 99. Note that this is not strictly the "century", because "19xx" is "19", not "20". - */ - DATE_CENTURY_PADDED('C'), - /** Year, formatted as at least four digits with leading zeros as necessary, e.g. 0092. */ - DATE_YEAR_PADDED('Y'), - /** Last two digits of the year, formatted with leading zeros as necessary, i.e. 00 - 99. */ - DATE_YEAR_OF_CENTURY_PADDED('y'), - /** Day of year, formatted as three digits with leading zeros as necessary, e.g. 001 - 366. */ - DATE_DAY_OF_YEAR_PADDED('j'), - /** Month, formatted as two digits with leading zeros as necessary, i.e. 01 - 13. */ - DATE_MONTH_PADDED('m'), - /** Day of month, formatted as two digits with leading zeros as necessary, i.e. 01 - 31. */ - DATE_DAY_OF_MONTH_PADDED('d'), - /** Day of month, formatted as two digits, i.e. 1 - 31. */ - DATE_DAY_OF_MONTH('e'), - - // The following conversion characters are used for formatting common date/time compositions. - - /** Time formatted for the 24-hour clock as "%tH:%tM". */ - DATETIME_HOURS_MINUTES('R'), - /** Time formatted for the 24-hour clock as "%tH:%tM:%tS". */ - DATETIME_HOURS_MINUTES_SECONDS('T'), - /** Time formatted for the 12-hour clock as "%tI:%tM:%tS %Tp". */ - DATETIME_HOURS_MINUTES_SECONDS_12H('r'), - /** Date formatted as "%tm/%td/%ty". */ - DATETIME_MONTH_DAY_YEAR('D'), - /** ISO 8601 complete date formatted as "%tY-%tm-%td". */ - DATETIME_YEAR_MONTH_DAY('F'), - /** Date and time formatted as "%ta %tb %td %tT %tZ %tY", e.g. "Sun Jul 20 16:17:00 EDT 1969". */ - DATETIME_FULL('c'); - - private static final Map MAP; - - static { - Map map = new HashMap(); - for (DateTimeFormat dtf : values()) { - if (map.put(dtf.formatChar, dtf) != null) { - throw new IllegalStateException("duplicate format character: " + dtf); - } + // The following conversion characters are used for formatting times: + + /** + * Hour of the day for the 24-hour clock, formatted as two digits with a leading zero as + * necessary, i.e., 00 - 23. + */ + TIME_HOUR_OF_DAY_PADDED('H'), + + /** Hour of the day for the 24-hour clock, i.e. 0 - 23. */ + TIME_HOUR_OF_DAY('k'), + + /** + * Hour for the 12-hour clock, formatted as two digits with a leading zero as necessary, + * i.e., 01 - 12. + */ + TIME_HOUR_12H_PADDED('I'), + + /** Hour for the 12-hour clock, i.e., 1 - 12. */ + TIME_HOUR_12H('l'), + + /** + * Minute within the hour formatted as two digits with a leading zero as necessary, + * i.e., 00 - 59. + */ + TIME_MINUTE_OF_HOUR_PADDED('M'), + + /** + * Seconds within the minute, formatted as two digits with a leading zero as necessary, + * i.e., 00 - 60 ("60" is a special value required to support leap seconds). + */ + TIME_SECONDS_OF_MINUTE_PADDED('S'), + + /** + * Millisecond within the second formatted as three digits with leading zeros as necessary, + * i.e., 000 - 999. + */ + TIME_MILLIS_OF_SECOND_PADDED('L'), + + /** + * Nanosecond within the second, formatted as nine digits with leading zeros as necessary, + * i.e., 000000000 - 999999999. + */ + TIME_NANOS_OF_SECOND_PADDED('N'), + + /** Locale-specific morning or afternoon marker in lower case, e.g. "am" or "pm". */ + TIME_AM_PM('p'), + + /** + * RFC 822 style numeric time zone offset from GMT, e.g. "-0800". This value will be adjusted + * as + * necessary for Daylight Saving Time. For long, Long, and Date the time zone used is the + * default + * time zone for this instance of the Java virtual machine. + */ + TIME_TZ_NUMERIC('z'), + + /** + * A string representing the abbreviation for the time zone. This value will be adjusted as + * necessary for Daylight Saving Time. For long, Long, and Date the time zone used is the + * default + * time zone for this instance of the Java virtual machine. + */ + TIME_TZ_SHORT('Z'), + + /** Seconds since the beginning of the epoch starting at 1 January 1970 00:00:00 UTC. */ + TIME_EPOCH_SECONDS('s'), + + /** Milliseconds since the beginning of the epoch starting at 1 January 1970 00:00:00 UTC. */ + TIME_EPOCH_MILLIS('Q'), + + // The following conversion characters are used for formatting dates: + + /** Locale-specific full month name, e.g. "January", "February". */ + DATE_MONTH_FULL('B'), + + /** Locale-specific abbreviated month name, e.g. "Jan", "Feb". */ + DATE_MONTH_SHORT('b'), + + /** Same as 'b'. */ + DATE_MONTH_SHORT_ALT('h'), + + /** Locale-specific full name of the day of the week, e.g., "Sunday", "Monday". */ + DATE_DAY_FULL('A'), + + /** Locale-specific short name of the day of the week, e.g., "Sun", "Mon". */ + DATE_DAY_SHORT('a'), + + /** + * Four-digit year divided by 100, formatted as two digits with leading zero as necessary, + * i.e., 00 - 99. Note that this is not strictly the "century", + * because "19xx" is "19", not "20". + */ + DATE_CENTURY_PADDED('C'), + + /** Year, formatted as at least four digits with leading zeros as necessary, e.g., 0092. */ + DATE_YEAR_PADDED('Y'), + + /** Last two digits of the year, formatted with leading zeros as necessary, i.e., 00 - 99. */ + DATE_YEAR_OF_CENTURY_PADDED('y'), + + /** + * Day of year, formatted as three digits with leading zeros as necessary, + * e.g. 001 - 366. + */ + DATE_DAY_OF_YEAR_PADDED('j'), + + /** Month, formatted as two digits with leading zeros as necessary, i.e., 01 - 13. */ + DATE_MONTH_PADDED('m'), + + /** Day of month, formatted as two digits with leading zeros as necessary, i.e., 01 - 31. */ + DATE_DAY_OF_MONTH_PADDED('d'), + + /** Day of month, formatted as two digits, i.e., 1 - 31. */ + DATE_DAY_OF_MONTH('e'), + + // The following conversion characters are used for formatting common date/time compositions. + + /** Time formatted for the 24-hour clock as "%tH:%tM". */ + DATETIME_HOURS_MINUTES('R'), + + /** Time formatted for the 24-hour clock as "%tH:%tM:%tS". */ + DATETIME_HOURS_MINUTES_SECONDS('T'), + + /** Time formatted for the 12-hour clock as "%tI:%tM:%tS %Tp". */ + DATETIME_HOURS_MINUTES_SECONDS_12H('r'), + + /** Date formatted as "%tm/%td/%ty". */ + DATETIME_MONTH_DAY_YEAR('D'), + + /** ISO 8601 complete date formatted as "%tY-%tm-%td". */ + DATETIME_YEAR_MONTH_DAY('F'), + + /** + * Date and time formatted as "%ta %tb %td %tT %tZ %tY", + * e.g., "Sun Jul 20 16:17:00 EDT 1969". + */ + DATETIME_FULL('c'); + + private static final Map MAP; + + static { + Map map = new HashMap<>(); + for (var dtf : values()) { + if (map.put(dtf.formatChar, dtf) != null) { + throw new IllegalStateException("duplicate format character: " + dtf); + } + } + MAP = Collections.unmodifiableMap(map); } - MAP = Collections.unmodifiableMap(map); - } - public static final DateTimeFormat of(char c) { - return MAP.get(c); - } + public static DateTimeFormat of(char c) { + return MAP.get(c); + } - private final char formatChar; + private final char formatChar; - DateTimeFormat(char formatChar) { - this.formatChar = formatChar; - } + DateTimeFormat(char formatChar) { + this.formatChar = formatChar; + } - public char getChar() { - return formatChar; - } + public char getChar() { + return formatChar; + } } diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/Parameter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/Parameter.java index 53bfb21e7..11e58c284 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/Parameter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/Parameter.java @@ -37,57 +37,61 @@ *

      * Note that all subclasses of Parameter must be immutable and thread safe. * - * @see - * Original Java code of Google Flogger + * @see + * Original Java code of Google Flogger */ public abstract class Parameter { - private final int index; - private final FormatOptions options; - /** - * Constructs a parameter to format an argument using specified formatting options. - * - * @param options the format options for this parameter. - * @param index the index of the argument processed by this parameter. - */ - protected Parameter(FormatOptions options, int index) { - if (options == null) { - throw new IllegalArgumentException("format options cannot be null"); - } - if (index < 0) { - throw new IllegalArgumentException("invalid index: " + index); + private final int index; + private final FormatOptions options; + + /** + * Constructs a parameter to format an argument using specified formatting options. + * + * @param options + * the format options for this parameter. + * @param index + * the index of the argument processed by this parameter. + */ + protected Parameter(FormatOptions options, int index) { + if (options == null) { + throw new IllegalArgumentException("format options cannot be null"); + } + if (index < 0) { + throw new IllegalArgumentException("invalid index: " + index); + } + this.index = index; + this.options = options; } - this.index = index; - this.options = options; - } - /** Returns the index of the argument to be processed by this parameter. */ - public final int getIndex() { - return index; - } + /** Returns the index of the argument to be processed by this parameter. */ + public final int getIndex() { + return index; + } - /** Returns the formatting options. */ - protected final FormatOptions getFormatOptions() { - return options; - } + /** Returns the formatting options. */ + protected final FormatOptions getFormatOptions() { + return options; + } - public final void accept(ParameterVisitor visitor, Object[] args) { - if (getIndex() < args.length) { - Object value = args[getIndex()]; - if (value != null) { - accept(visitor, value); - } else { - visitor.visitNull(); - } - } else { - visitor.visitMissing(); + public final void accept(ParameterVisitor visitor, Object[] args) { + if (getIndex() < args.length) { + var value = args[getIndex()]; + if (value != null) { + accept(visitor, value); + } else { + visitor.visitNull(); + } + } else { + visitor.visitMissing(); + } } - } - protected abstract void accept(ParameterVisitor visitor, Object value); + protected abstract void accept(ParameterVisitor visitor, Object value); - /** - * Returns the printf format string specified for this parameter (eg, "%d" or "%tc"). - */ - public abstract String getFormat(); + /** + * Returns the printf format string specified for this parameter (eg, "%d" or "%tc"). + */ + public abstract String getFormat(); } diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/SimpleParameter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/SimpleParameter.java index 01236c3da..200308615 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/SimpleParameter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/SimpleParameter.java @@ -26,14 +26,15 @@ package io.spine.logging.jvm.parameter; -import static io.spine.logging.jvm.util.Checks.checkNotNull; - import io.spine.logging.jvm.backend.FormatChar; import io.spine.logging.jvm.backend.FormatOptions; + import java.util.Collections; import java.util.EnumMap; import java.util.Map; +import static io.spine.logging.jvm.util.Checks.checkNotNull; + /** * A simple, single argument, parameter which can format arguments according to the rules specified * by {@link FormatChar}. @@ -41,79 +42,84 @@ * This class is immutable and thread safe, as per the Parameter contract. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger */ public final class SimpleParameter extends Parameter { - /** Cache parameters with indices 0-9 to cover the vast majority of cases. */ - private static final int MAX_CACHED_PARAMETERS = 10; - /** Map of the most common default general parameters (corresponds to %s, %d, %f etc...). */ - private static final Map DEFAULT_PARAMETERS; + /** Cache parameters with indices 0-9 to cover the vast majority of cases. */ + private static final int MAX_CACHED_PARAMETERS = 10; - static { - Map map = - new EnumMap(FormatChar.class); - for (FormatChar fc : FormatChar.values()) { - map.put(fc, createParameterArray(fc)); + /** Map of the most common default general parameters (corresponds to %s, %d, %f etc...). */ + private static final Map DEFAULT_PARAMETERS; + + static { + Map map = new EnumMap<>(FormatChar.class); + for (var fc : FormatChar.values()) { + map.put(fc, createParameterArray(fc)); + } + DEFAULT_PARAMETERS = Collections.unmodifiableMap(map); } - DEFAULT_PARAMETERS = Collections.unmodifiableMap(map); - } - /** Helper to make reusable default parameter instances for the commonest indices. */ - private static SimpleParameter[] createParameterArray(FormatChar formatChar) { - SimpleParameter[] parameters = new SimpleParameter[MAX_CACHED_PARAMETERS]; - for (int index = 0; index < MAX_CACHED_PARAMETERS; index++) { - parameters[index] = new SimpleParameter(index, formatChar, FormatOptions.getDefault()); + /** Helper to make reusable default parameter instances for the commonest indices. */ + private static SimpleParameter[] createParameterArray(FormatChar formatChar) { + var parameters = new SimpleParameter[MAX_CACHED_PARAMETERS]; + for (var index = 0; index < MAX_CACHED_PARAMETERS; index++) { + parameters[index] = new SimpleParameter(index, formatChar, FormatOptions.getDefault()); + } + return parameters; } - return parameters; - } - /** - * Returns a {@link Parameter} representing the given formatting options of the specified - * formatting character. Note that a cached value may be returned. - * - * @param index the index of the argument to be processed. - * @param formatChar the basic formatting type. - * @param options additional formatting options. - * @return the immutable, thread safe parameter instance. - */ - public static SimpleParameter of(int index, FormatChar formatChar, FormatOptions options) { - // We can safely test FormatSpec with '==' because the factory methods always return the default - // instance if applicable (and the class has no visible constructors). - if (index < MAX_CACHED_PARAMETERS && options.isDefault()) { - return DEFAULT_PARAMETERS.get(formatChar)[index]; + /** + * Returns a {@link Parameter} representing the given formatting options of the specified + * formatting character. Note that a cached value may be returned. + * + * @param index + * the index of the argument to be processed. + * @param formatChar + * the basic formatting type. + * @param options + * additional formatting options. + * @return the immutable, thread safe parameter instance. + */ + public static SimpleParameter of(int index, FormatChar formatChar, FormatOptions options) { + // We can safely test FormatSpec with '==' because the factory methods always return the default + // instance if applicable (and the class has no visible constructors). + if (index < MAX_CACHED_PARAMETERS && options.isDefault()) { + return DEFAULT_PARAMETERS.get(formatChar)[index]; + } + return new SimpleParameter(index, formatChar, options); } - return new SimpleParameter(index, formatChar, options); - } - private final FormatChar formatChar; - private final String formatString; + private final FormatChar formatChar; + private final String formatString; - private SimpleParameter(int index, FormatChar formatChar, FormatOptions options) { - super(options, index); - this.formatChar = checkNotNull(formatChar, "format char"); - // TODO: Consider special case for hex strings where options are common (HexParameter?). - this.formatString = options.isDefault() - ? formatChar.getDefaultFormatString() - : buildFormatString(options, formatChar); - } + private SimpleParameter(int index, FormatChar formatChar, FormatOptions options) { + super(options, index); + this.formatChar = checkNotNull(formatChar, "format char"); + // TODO: Consider special case for hex strings where options are common (HexParameter?). + this.formatString = options.isDefault() + ? formatChar.getDefaultFormatString() + : buildFormatString(options, formatChar); + } - // Visible for testing. - static String buildFormatString(FormatOptions options, FormatChar formatChar) { - // The format char is guaranteed to be a lower-case ASCII character, so can be made upper case - // by simply subtracting 0x20 (or clearing the 6th bit). - char c = formatChar.getChar(); - c = options.shouldUpperCase() ? (char) (c & ~0x20) : c; - return options.appendPrintfOptions(new StringBuilder("%")).append(c).toString(); - } + // Visible for testing. + static String buildFormatString(FormatOptions options, FormatChar formatChar) { + // The format char is guaranteed to be a lower-case ASCII character, so can be made upper case + // by simply subtracting 0x20 (or clearing the 6th bit). + char c = formatChar.getChar(); + c = options.shouldUpperCase() ? (char) (c & ~0x20) : c; + return options.appendPrintfOptions(new StringBuilder("%")) + .append(c) + .toString(); + } - @Override - protected void accept(ParameterVisitor visitor, Object value) { - visitor.visit(value, formatChar, getFormatOptions()); - } + @Override + protected void accept(ParameterVisitor visitor, Object value) { + visitor.visit(value, formatChar, getFormatOptions()); + } - @Override - public String getFormat() { - return formatString; - } + @Override + public String getFormat() { + return formatString; + } } diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultPrintfMessageParser.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultPrintfMessageParser.java index e3f1a3852..e6cfa7085 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultPrintfMessageParser.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultPrintfMessageParser.java @@ -26,9 +26,6 @@ package io.spine.logging.jvm.parser; -import static io.spine.logging.jvm.backend.FormatOptions.FLAG_LEFT_ALIGN; -import static io.spine.logging.jvm.backend.FormatOptions.FLAG_UPPER_CASE; - import io.spine.logging.jvm.backend.FormatChar; import io.spine.logging.jvm.backend.FormatOptions; import io.spine.logging.jvm.parameter.DateTimeFormat; @@ -37,6 +34,9 @@ import io.spine.logging.jvm.parameter.ParameterVisitor; import io.spine.logging.jvm.parameter.SimpleParameter; +import static io.spine.logging.jvm.backend.FormatOptions.FLAG_LEFT_ALIGN; +import static io.spine.logging.jvm.backend.FormatOptions.FLAG_UPPER_CASE; + /** * Default implementation of the printf message parser. This parser supports all the place-holders * available in {@code String#format} but can be extended, if desired, for additional behavior @@ -46,85 +46,89 @@ * This class is immutable and thread safe (and any subclasses must also be so). * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger */ public class DefaultPrintfMessageParser extends PrintfMessageParser { - private static final PrintfMessageParser INSTANCE = new DefaultPrintfMessageParser(); - public static PrintfMessageParser getInstance() { - return INSTANCE; - } + private static final PrintfMessageParser INSTANCE = new DefaultPrintfMessageParser(); - private DefaultPrintfMessageParser() {} + public static PrintfMessageParser getInstance() { + return INSTANCE; + } - @Override - public int parsePrintfTerm( - MessageBuilder builder, - int index, - String message, - int termStart, - int specStart, - int formatStart) - throws ParseException { + private DefaultPrintfMessageParser() { + } - // Assume terms are single characters. - int termEnd = formatStart + 1; - // This _must_ be an ASCII letter representing printf-like specifier (but need not be valid). - char typeChar = message.charAt(formatStart); - boolean isUpperCase = (typeChar & 0x20) == 0; - FormatOptions options = FormatOptions.parse(message, specStart, formatStart, isUpperCase); + @Override + public int parsePrintfTerm( + MessageBuilder builder, + int index, + String message, + int termStart, + int specStart, + int formatStart) + throws ParseException { - Parameter parameter; - FormatChar formatChar = FormatChar.of(typeChar); - if (formatChar != null) { - if (!options.areValidFor(formatChar)) { - throw ParseException.withBounds("invalid format specifier", message, termStart, termEnd); - } - parameter = SimpleParameter.of(index, formatChar, options); - } else if (typeChar == 't' || typeChar == 'T') { - if (!options.validate(FLAG_LEFT_ALIGN | FLAG_UPPER_CASE, false)) { - throw ParseException.withBounds( - "invalid format specification", message, termStart, termEnd); - } - // Time/date format terms have an extra character in them. - termEnd += 1; - if (termEnd > message.length()) { - throw ParseException.atPosition("truncated format specifier", message, termStart); - } - DateTimeFormat dateTimeFormat = DateTimeFormat.of(message.charAt(formatStart + 1)); - if (dateTimeFormat == null) { - throw ParseException.atPosition("illegal date/time conversion", message, formatStart + 1); - } - parameter = DateTimeParameter.of(dateTimeFormat, options, index); - } else if (typeChar == 'h' || typeChar == 'H') { - // %h/%H is a legacy format we want to support for syntax compliance with String.format() - // but which we don't need to support in the backend. - if (!options.validate(FLAG_LEFT_ALIGN | FLAG_UPPER_CASE, false)) { - throw ParseException.withBounds( - "invalid format specification", message, termStart, termEnd); - } - parameter = wrapHexParameter(options, index); - } else { - throw ParseException.withBounds( - "invalid format specification", message, termStart, formatStart + 1); + // Assume terms are single characters. + var termEnd = formatStart + 1; + // This _must_ be an ASCII letter representing printf-like specifier (but need not be valid). + var typeChar = message.charAt(formatStart); + var isUpperCase = (typeChar & 0x20) == 0; + var options = FormatOptions.parse(message, specStart, formatStart, isUpperCase); + + Parameter parameter; + var formatChar = FormatChar.of(typeChar); + if (formatChar != null) { + if (!options.areValidFor(formatChar)) { + throw ParseException.withBounds("invalid format specifier", message, termStart, + termEnd); + } + parameter = SimpleParameter.of(index, formatChar, options); + } else if (typeChar == 't' || typeChar == 'T') { + if (!options.validate(FLAG_LEFT_ALIGN | FLAG_UPPER_CASE, false)) { + throw ParseException.withBounds( + "invalid format specification", message, termStart, termEnd); + } + // Time/date format terms have an extra character in them. + termEnd += 1; + if (termEnd > message.length()) { + throw ParseException.atPosition("truncated format specifier", message, termStart); + } + var dateTimeFormat = DateTimeFormat.of(message.charAt(formatStart + 1)); + if (dateTimeFormat == null) { + throw ParseException.atPosition("illegal date/time conversion", message, + formatStart + 1); + } + parameter = DateTimeParameter.of(dateTimeFormat, options, index); + } else if (typeChar == 'h' || typeChar == 'H') { + // %h/%H is a legacy format we want to support for syntax compliance with String.format() + // but which we don't need to support in the backend. + if (!options.validate(FLAG_LEFT_ALIGN | FLAG_UPPER_CASE, false)) { + throw ParseException.withBounds( + "invalid format specification", message, termStart, termEnd); + } + parameter = wrapHexParameter(options, index); + } else { + throw ParseException.withBounds( + "invalid format specification", message, termStart, formatStart + 1); + } + builder.addParameter(termStart, termEnd, parameter); + return termEnd; } - builder.addParameter(termStart, termEnd, parameter); - return termEnd; - } - // Static method so the anonymous synthetic parameter is static, rather than an inner class. - private static Parameter wrapHexParameter(final FormatOptions options, int index) { - // %h / %H is really just %x / %X on the hashcode. - return new Parameter(options, index) { - @Override - protected void accept(ParameterVisitor visitor, Object value) { - visitor.visit(value.hashCode(), FormatChar.HEX, getFormatOptions()); - } + // Static method so the anonymous synthetic parameter is static, rather than an inner class. + private static Parameter wrapHexParameter(final FormatOptions options, int index) { + // %h / %H is really just %x / %X on the hashcode. + return new Parameter(options, index) { + @Override + protected void accept(ParameterVisitor visitor, Object value) { + visitor.visit(value.hashCode(), FormatChar.HEX, getFormatOptions()); + } - @Override - public String getFormat() { - return options.shouldUpperCase() ? "%H" : "%h"; - } - }; - } + @Override + public String getFormat() { + return options.shouldUpperCase() ? "%H" : "%h"; + } + }; + } } diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/MessageBuilder.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/MessageBuilder.java index a2a77e9ec..d57f754a0 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/MessageBuilder.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/MessageBuilder.java @@ -35,103 +35,113 @@ * all the formatting requirements of a log message. One message builder is created for each log * message that's parsed. * - * @param The message type being built. - * - * @see - * Original Java code of Google Flogger + * @param + * The message type being built. + * @see + * Original Java code of Google Flogger */ public abstract class MessageBuilder { - private final TemplateContext context; - // Mask of parameter indices seen during parsing, used to determine if there are gaps in the - // specified parameters (which is a parsing error). - // This could be a long if we cared about tracking up to 64 parameters, but I suspect we don't. - private int pmask = 0; + private final TemplateContext context; + + // Mask of parameter indices seen during parsing, used to determine if there are gaps in the + // specified parameters (which is a parsing error). + // This could be a long if we cared about tracking up to 64 parameters, but I suspect we don't. + private int pmask = 0; - // The maximum argument index referenced by the formatted message (only valid after parsing). - private int maxIndex = -1; + // The maximum argument index referenced by the formatted message (only valid after parsing). + private int maxIndex = -1; - public MessageBuilder(TemplateContext context) { - this.context = Checks.checkNotNull(context, "context"); - } + public MessageBuilder(TemplateContext context) { + this.context = Checks.checkNotNull(context, "context"); + } - /** Returns the parser used to process the log format message in this builder. */ - public final MessageParser getParser() { - return context.getParser(); - } + /** Returns the parser used to process the log format message in this builder. */ + public final MessageParser getParser() { + return context.getParser(); + } - /** Returns the log format message to be parsed by this builder. */ - public final String getMessage() { - return context.getMessage(); - } + /** Returns the log format message to be parsed by this builder. */ + public final String getMessage() { + return context.getMessage(); + } - /** - * Returns the expected number of arguments to be formatted by this message. This is only valid - * once parsing has completed successfully. - */ - public final int getExpectedArgumentCount() { - return maxIndex + 1; - } + /** + * Returns the expected number of arguments to be formatted by this message. This is only valid + * once parsing has completed successfully. + */ + public final int getExpectedArgumentCount() { + return maxIndex + 1; + } - /** - * Called by parser implementations to signify that the parsing of the next parameter is complete. - * This method will call {@link #addParameterImpl(int, int, Parameter)} with exactly the same - * arguments, but may also do additional work before or after that call. - * - * @param termStart the index of the first character in the log message string that was parsed to - * form the given parameter. - * @param termEnd the index after the last character in the log message string that was parsed to - * form the given parameter. - * @param param a parameter representing the format specified by the substring of the log message - * in the range {@code [termStart, termEnd)}. - */ - public final void addParameter(int termStart, int termEnd, Parameter param) { - // Set a bit in the parameter mask according to which parameter was referenced. - // Shifting wraps, so we must do a check here. - if (param.getIndex() < 32) { - pmask |= (1 << param.getIndex()); + /** + * Called by parser implementations to signify that the parsing of the next parameter is + * complete. + * This method will call {@link #addParameterImpl(int, int, Parameter)} with exactly the same + * arguments, but may also do additional work before or after that call. + * + * @param termStart + * the index of the first character in the log message string that was parsed to + * form the given parameter. + * @param termEnd + * the index after the last character in the log message string that was parsed to + * form the given parameter. + * @param param + * a parameter representing the format specified by the substring of the log message + * in the range {@code [termStart, termEnd)}. + */ + public final void addParameter(int termStart, int termEnd, Parameter param) { + // Set a bit in the parameter mask according to which parameter was referenced. + // Shifting wraps, so we must do a check here. + if (param.getIndex() < 32) { + pmask |= (1 << param.getIndex()); + } + maxIndex = Math.max(maxIndex, param.getIndex()); + addParameterImpl(termStart, termEnd, param); } - maxIndex = Math.max(maxIndex, param.getIndex()); - addParameterImpl(termStart, termEnd, param); - } - /** - * Adds the specified parameter to the format instance currently being built. This method is to - * signify that the parsing of the next parameter is complete. - *

      - * Note that each successive call to this method during parsing will specify a disjoint ranges of - * characters from the log message and that each range will be higher that the previously - * specified one. - * - * @param termStart the index of the first character in the log message string that was parsed to - * form the given parameter. - * @param termEnd the index after the last character in the log message string that was parsed to - * form the given parameter. - * @param param a parameter representing the format specified by the substring of the log message - * in the range {@code [termStart, termEnd)}. - */ - protected abstract void addParameterImpl(int termStart, int termEnd, Parameter param); + /** + * Adds the specified parameter to the format instance currently being built. This method is to + * signify that the parsing of the next parameter is complete. + *

      + * Note that each successive call to this method during parsing will specify a disjoint ranges + * of + * characters from the log message and that each range will be higher that the previously + * specified one. + * + * @param termStart + * the index of the first character in the log message string that was parsed to + * form the given parameter. + * @param termEnd + * the index after the last character in the log message string that was parsed to + * form the given parameter. + * @param param + * a parameter representing the format specified by the substring of the log message + * in the range {@code [termStart, termEnd)}. + */ + protected abstract void addParameterImpl(int termStart, int termEnd, Parameter param); - /** Returns the implementation specific result of parsing the current log message. */ - protected abstract T buildImpl(); + /** Returns the implementation specific result of parsing the current log message. */ + protected abstract T buildImpl(); - /** - * Builds a log message using the current message context. - * - * @return the implementation specific result of parsing the current log message. - */ - public final T build() { - getParser().parseImpl(this); - // There was a gap in the parameters if either: - // 1) the mask had a gap, e.g. ..00110111 - // 2) there were more than 32 parameters and the mask wasn't full. - // Gaps above the 32nd parameter are not detected. - if ((pmask & (pmask + 1)) != 0 || (maxIndex > 31 && pmask != -1)) { - int firstMissing = Integer.numberOfTrailingZeros(~pmask); - throw ParseException.generic( - String.format("unreferenced arguments [first missing index=%d]", firstMissing), - getMessage()); + /** + * Builds a log message using the current message context. + * + * @return the implementation specific result of parsing the current log message. + */ + public final T build() { + getParser().parseImpl(this); + // There was a gap in the parameters if either: + // 1) the mask had a gap, e.g., ..00110111 + // 2) there were more than 32 parameters and the mask wasn't full. + // Gaps above the 32nd parameter are not detected. + if ((pmask & (pmask + 1)) != 0 || (maxIndex > 31 && pmask != -1)) { + int firstMissing = Integer.numberOfTrailingZeros(~pmask); + throw ParseException.generic( + String.format("unreferenced arguments [first missing index=%d]", firstMissing) + ); + } + return buildImpl(); } - return buildImpl(); - } } diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/ParseException.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/ParseException.java index 24b28888c..8ff2cb0c9 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/ParseException.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/ParseException.java @@ -26,103 +26,135 @@ package io.spine.logging.jvm.parser; +import java.io.Serial; + /** * The exception that should be thrown whenever parsing of a log message fails. This exception must * not be thrown outside of template parsing. * - * @see - * Original Java code of Google Flogger + * @see + * Original Java code of Google Flogger */ public final class ParseException extends RuntimeException { - // The prefix/suffix to show when an error snippet is truncated (eg, "...ello [%Q] Worl..."). - // If the snippet starts or ends the message then no ellipsis is shown (eg, "...ndex=[%Q]"). - private static final String ELLIPSIS = "..."; - // The length of the snippet to show before and after the error. Fewer characters will be shown - // if the error is near the start/end of the log message and more characters will be shown if - // adding the ellipsis would have made things longer. The maximum prefix/suffix of the snippet - // is (SNIPPET_LENGTH + ELLIPSIS.length()). - private static final int SNIPPET_LENGTH = 5; - /** - * Creates a new parse exception for situations in which both the start and end positions of the - * error are known. - * - * @param errorMessage the user error message. - * @param logMessage the original log message. - * @param start the index of the first character in the invalid section of the log message. - * @param end the index after the last character in the invalid section of the log message. - * @return the parser exception. - */ - public static ParseException withBounds( - String errorMessage, String logMessage, int start, int end) { - return new ParseException(msg(errorMessage, logMessage, start, end), logMessage); - } + /** + * The prefix/suffix to show when an error snippet is truncated (eg, "...ello [%Q] Worl..."). + * If the snippet starts or ends the message then no ellipsis is shown (e.g., "...ndex=[%Q]"). + */ + private static final String ELLIPSIS = "..."; + + /** + * The length of the snippet to show before and after the error. Fewer characters will be shown + * if the error is near the start/end of the log message and more characters will be shown if + * adding the ellipsis would have made things longer. The maximum prefix/suffix of the snippet + * is (SNIPPET_LENGTH + ELLIPSIS.length()). + */ + private static final int SNIPPET_LENGTH = 5; - /** - * Creates a new parse exception for situations in which the position of the error is known. - * - * @param errorMessage the user error message. - * @param logMessage the original log message. - * @param position the index of the invalid character in the log message. - * @return the parser exception. - */ - public static ParseException atPosition(String errorMessage, String logMessage, int position) { - return new ParseException(msg(errorMessage, logMessage, position, position + 1), logMessage); - } + @Serial + private static final long serialVersionUID = 0L; - /** - * Creates a new parse exception for situations in which only the start position of the error is - * known. - * - * @param errorMessage the user error message. - * @param logMessage the original log message. - * @param start the index of the first character in the invalid section of the log message. - * @return the parser exception. - */ - public static ParseException withStartPosition( - String errorMessage, String logMessage, int start) { - return new ParseException(msg(errorMessage, logMessage, start, -1), logMessage); - } + /** + * Creates a new parse exception for situations in which both the start and end positions of the + * error are known. + * + * @param errorMessage + * the user error message. + * @param logMessage + * the original log message. + * @param start + * the index of the first character in the invalid section of the log message. + * @param end + * the index after the last character in the invalid section of the log message. + * @return the parser exception. + */ + public static ParseException withBounds( + String errorMessage, String logMessage, int start, int end) { + return new ParseException(msg(errorMessage, logMessage, start, end)); + } - /** - * Creates a new parse exception for cases where position is not relevant. - * - * @param errorMessage the user error message. - * @param logMessage the original log message. - */ - public static ParseException generic(String errorMessage, String logMessage) { - return new ParseException(errorMessage, logMessage); - } + /** + * Creates a new parse exception for situations in which the position of the error is known. + * + * @param errorMessage + * the user error message. + * @param logMessage + * the original log message. + * @param position + * the index of the invalid character in the log message. + * @return the parser exception. + */ + public static ParseException atPosition(String errorMessage, String logMessage, int position) { + return new ParseException(msg(errorMessage, logMessage, position, position + 1)); + } - private ParseException(String errorMessage, String logMessage) { - super(errorMessage); - } + /** + * Creates a new parse exception for situations in which only the start position of the error + * is known. + * + * @param errorMessage + * the user error message. + * @param logMessage + * the original log message. + * @param start + * the index of the first character in the invalid section of the log message. + * @return the parser exception. + */ + public static ParseException withStartPosition( + String errorMessage, String logMessage, int start) { + return new ParseException(msg(errorMessage, logMessage, start, -1)); + } - /** Helper to format a human readable error message for this exception. */ - private static String msg(String errorMessage, String logMessage, int errorStart, int errorEnd) { - if (errorEnd < 0) { - errorEnd = logMessage.length(); + /** + * Creates a new parse exception for cases where position is not relevant. + * + * @param errorMessage + * the user error message. + */ + static ParseException generic(String errorMessage) { + return new ParseException(errorMessage); } - StringBuilder out = new StringBuilder(errorMessage).append(": "); - if (errorStart > SNIPPET_LENGTH + ELLIPSIS.length()) { - out.append(ELLIPSIS).append(logMessage, errorStart - SNIPPET_LENGTH, errorStart); - } else { - out.append(logMessage, 0, errorStart); + + private ParseException(String errorMessage) { + super(errorMessage); } - out.append('[').append(logMessage.substring(errorStart, errorEnd)).append(']'); - if (logMessage.length() - errorEnd > SNIPPET_LENGTH + ELLIPSIS.length()) { - out.append(logMessage, errorEnd, errorEnd + SNIPPET_LENGTH).append(ELLIPSIS); - } else { - out.append(logMessage, errorEnd, logMessage.length()); + + /** + * Helper to format a human-readable error message for this exception. + */ + private static String msg(String errorMessage, String logMessage, int errorStart, + int errorEnd) { + if (errorEnd < 0) { + errorEnd = logMessage.length(); + } + StringBuilder out = new StringBuilder(errorMessage).append(": "); + if (errorStart > SNIPPET_LENGTH + ELLIPSIS.length()) { + out.append(ELLIPSIS) + .append(logMessage, errorStart - SNIPPET_LENGTH, errorStart); + } else { + out.append(logMessage, 0, errorStart); + } + out.append('[') + .append(logMessage.substring(errorStart, errorEnd)) + .append(']'); + if (logMessage.length() - errorEnd > SNIPPET_LENGTH + ELLIPSIS.length()) { + out.append(logMessage, errorEnd, errorEnd + SNIPPET_LENGTH) + .append(ELLIPSIS); + } else { + out.append(logMessage, errorEnd, logMessage.length()); + } + return out.toString(); } - return out.toString(); - } - // Disable expensive stack analysis because the parse exception will contain everything it needs - // to point the user at the proximal cause in the log message itself, and backends must always - // wrap this in a LoggingException if they do throw it up into user code (not recommended). - @Override - public synchronized Throwable fillInStackTrace() { - return this; - } + /** + * Disable expensive stack analysis because the parse exception contains everything it needs to + * point the user at the proximal cause in the log message itself, and backends must always + * wrap this in a {@link io.spine.logging.jvm.backend.LoggingException} if they do throw it up + * into user code (not recommended). + */ + @Override + public synchronized Throwable fillInStackTrace() { + return this; + } } diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/util/Checks.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/util/Checks.java index f71b2bd51..ce5dc99a6 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/util/Checks.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/util/Checks.java @@ -32,61 +32,63 @@ * Flogger's own version of the Guava {@code Preconditions} class for simple, often used checks. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger */ public class Checks { - private Checks() {} - // Warning: The methods in this class may not use String.format() to construct "fancy" error - // messages (because that's not GWT compatible). - - @CanIgnoreReturnValue - public static T checkNotNull(T value, String name) { - if (value == null) { - throw new NullPointerException(name + " must not be null"); + private Checks() { } - return value; - } - public static void checkArgument(boolean condition, String message) { - if (!condition) { - throw new IllegalArgumentException(message); - } - } + // Warning: The methods in this class may not use String.format() to construct "fancy" error + // messages (because that's not GWT compatible). - public static void checkState(boolean condition, String message) { - if (!condition) { - throw new IllegalStateException(message); + @CanIgnoreReturnValue + public static T checkNotNull(T value, String name) { + if (value == null) { + throw new NullPointerException(name + " must not be null"); + } + return value; } - } - /** Checks if the given string is a valid metadata identifier. */ - @CanIgnoreReturnValue - public static String checkMetadataIdentifier(String s) { - // Note that we avoid using regular expressions here, since we've not used it anywhere else - // thus far in Flogger (avoid it make it more likely that Flogger can be transpiled). - if (s.isEmpty()) { - throw new IllegalArgumentException("identifier must not be empty"); + public static void checkArgument(boolean condition, String message) { + if (!condition) { + throw new IllegalArgumentException(message); + } } - if (!isLetter(s.charAt(0))) { - throw new IllegalArgumentException("identifier must start with an ASCII letter: " + s); + + public static void checkState(boolean condition, String message) { + if (!condition) { + throw new IllegalStateException(message); + } } - for (int n = 1; n < s.length(); n++) { - char c = s.charAt(n); - if (!isLetter(c) && (c < '0' || c > '9') && c != '_') { - throw new IllegalArgumentException( - "identifier must contain only ASCII letters, digits or underscore: " + s); - } + + /** Checks if the given string is a valid metadata identifier. */ + @CanIgnoreReturnValue + public static String checkMetadataIdentifier(String s) { + // Note that we avoid using regular expressions here, since we've not used it anywhere else + // thus far in Flogger (avoid it make it more likely that Flogger can be transpiled). + if (s.isEmpty()) { + throw new IllegalArgumentException("identifier must not be empty"); + } + if (!isLetter(s.charAt(0))) { + throw new IllegalArgumentException("identifier must start with an ASCII letter: " + s); + } + for (var n = 1; n < s.length(); n++) { + var c = s.charAt(n); + if (!isLetter(c) && (c < '0' || c > '9') && c != '_') { + throw new IllegalArgumentException( + "identifier must contain only ASCII letters, digits or underscore: " + s); + } + } + return s; } - return s; - } - // WARNING: The reason the we are NOT using method from Character like "isLetter()", - // "isJavaLetter()", "isJavaIdentifierStart()" etc. is that these rely on the Unicode definitions - // of "LETTER", which are not stable between releases. In theory something marked as a letter in - // Unicode could be changed to not be a letter in a later release. There is a notion of stable - // identifiers in Unicode, which is what should be used here, but that needs more investigation. - private static boolean isLetter(char c) { - return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); - } + // WARNING: The reason the we are NOT using method from Character like "isLetter()", + // "isJavaLetter()", "isJavaIdentifierStart()" etc. is that these rely on the Unicode definitions + // of "LETTER", which are not stable between releases. In theory something marked as a letter in + // Unicode could be changed to not be a letter in a later release. There is a notion of stable + // identifiers in Unicode, which is what should be used here, but that needs more investigation. + private static boolean isLetter(char c) { + return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); + } } diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/util/StaticMethodCaller.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/util/StaticMethodCaller.java index 5873f63d7..f48044756 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/util/StaticMethodCaller.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/util/StaticMethodCaller.java @@ -26,7 +26,6 @@ package io.spine.logging.jvm.util; -import java.lang.reflect.Method; import org.jspecify.annotations.Nullable; /** @@ -35,110 +34,114 @@ * be invoked once during logger initialization and then the results cached in the platform class * (thus there is no requirement for the class being invoked to handle caching of the result). * - * @see - * Original Java code of Google Flogger + * @see + * Original Java code of Google Flogger */ public final class StaticMethodCaller { - // TODO(cgdecker): Rename this class; eventually perhaps just roll it into DefaultPlatform + // TODO(cgdecker): Rename this class; eventually perhaps just roll it into DefaultPlatform - /** - * Attempts to get an instance of the given {@code type} that is specified by the given {@code - * propertyName}, returning {@code null} if that is not possible for any reason. - * - *

      The property's value, if present, is expected to be one of: - * - *

        - *
      1. A fully-qualified class name, in which case the instance is obtained by invoking the - * class's no-arg static {@code getInstance} method, if present, or public no-arg - * constructor. - *
      2. A fully-qualified class name followed by {@code #} and a method name, in which case the - * instance is obtained by invoking a no-arg static method of that name, if present, or a - * public no-arg constructor if not present. - *
      - */ - public static T getInstanceFromSystemProperty(String propertyName, Class type) { - return getInstanceFromSystemProperty(propertyName, null, type); - } - - /** - * Attempts to get an instance of the given {@code type} that is specified by the given {@code - * propertyName}, returning {@code null} if that is not possible for any reason. - * - *

      The property's value, if present, or the given {@code defaultValue}, is expected to be one - * of: - * - *

        - *
      1. A fully-qualified class name, in which case the instance is obtained by invoking the - * class's no-arg static {@code getInstance} method, if present, or public no-arg - * constructor. - *
      2. A fully-qualified class name followed by {@code #} and a method name, in which case the - * instance is obtained by invoking a no-arg static method of that name, if present, or a - * public no-arg constructor if not present. - *
      - */ - @Nullable - public static T getInstanceFromSystemProperty( - String propertyName, @Nullable String defaultValue, Class type) { - String property = readProperty(propertyName, defaultValue); - if (property == null) { - return null; + /** + * Attempts to get an instance of the given {@code type} that is specified by the given {@code + * propertyName}, returning {@code null} if that is not possible for any reason. + * + *

      The property's value, if present, is expected to be one of: + * + *

        + *
      1. A fully-qualified class name, in which case the instance is obtained by invoking the + * class's no-arg static {@code getInstance} method, if present, or public no-arg + * constructor. + *
      2. A fully-qualified class name followed by {@code #} and a method name, in which case the + * instance is obtained by invoking a no-arg static method of that name, if present, or a + * public no-arg constructor if not present. + *
      + */ + public static T getInstanceFromSystemProperty(String propertyName, Class type) { + return getInstanceFromSystemProperty(propertyName, null, type); } - int hashIndex = property.indexOf('#'); - String className = hashIndex == -1 ? property : property.substring(0, hashIndex); - // TODO(cgdecker): Eventually we should eleminate method checks and only use constructors - String methodName = hashIndex == -1 ? "getInstance" : property.substring(hashIndex + 1); - - String attemptedMethod = className + '#' + methodName + "()"; - try { - Class clazz = Class.forName(className); - try { - Method method = clazz.getMethod(methodName); - // If the method exists, try to invoke it and don't fall back to the constructor if it - // fails. The fallback is only for the case where the method in question has been removed. - return type.cast(method.invoke(null)); - } catch (NoSuchMethodException e) { - // If the user explicitly specified a getInstance method via "ClassName#getInstance" and - // that getInstance method doesn't exist, fall back to constructor invocation. This allows - // system properties that were set for service types Flogger provides to continue to work - // even though we intentionally removed their getInstance() methods. - if (hashIndex == -1 || !methodName.equals("getInstance")) { - // Otherwise, error and return - error("method '%s' does not exist: %s\n", property, e); - return null; + /** + * Attempts to get an instance of the given {@code type} that is specified by the given {@code + * propertyName}, returning {@code null} if that is not possible for any reason. + * + *

      The property's value, if present, or the given {@code defaultValue}, is expected to be one + * of: + * + *

        + *
      1. A fully-qualified class name, in which case the instance is obtained by invoking the + * class's no-arg static {@code getInstance} method, if present, or public no-arg + * constructor. + *
      2. A fully-qualified class name followed by {@code #} and a method name, in which case the + * instance is obtained by invoking a no-arg static method of that name, if present, or a + * public no-arg constructor if not present. + *
      + */ + @Nullable + public static T getInstanceFromSystemProperty( + String propertyName, @Nullable String defaultValue, Class type) { + var property = readProperty(propertyName, defaultValue); + if (property == null) { + return null; } - } - // The method didn't exist, try the constructor - attemptedMethod = "new " + className + "()"; - return type.cast(clazz.getConstructor().newInstance()); - } catch (ClassNotFoundException e) { - // Expected if an optional aspect is not being used (no error). - } catch (ClassCastException e) { - error("cannot cast result of calling '%s' to '%s': %s\n", attemptedMethod, type.getName(), e); - } catch (Exception e) { - // Catches SecurityException *and* ReflexiveOperationException (which doesn't exist in 1.6). - error( - "cannot call expected no-argument constructor or static method '%s': %s\n", - attemptedMethod, e); + var hashIndex = property.indexOf('#'); + var className = hashIndex == -1 ? property : property.substring(0, hashIndex); + // TODO(cgdecker): Eventually we should eleminate method checks and only use constructors + var methodName = hashIndex == -1 ? "getInstance" : property.substring(hashIndex + 1); + + var attemptedMethod = className + '#' + methodName + "()"; + try { + var clazz = Class.forName(className); + try { + var method = clazz.getMethod(methodName); + // If the method exists, try to invoke it and don't fall back to the constructor if it + // fails. The fallback is only for the case where the method in question has been removed. + return type.cast(method.invoke(null)); + } catch (NoSuchMethodException e) { + // If the user explicitly specified a getInstance method via "ClassName#getInstance" and + // that getInstance method doesn't exist, fall back to constructor invocation. This allows + // system properties that were set for service types Flogger provides to continue to work + // even though we intentionally removed their getInstance() methods. + if (hashIndex == -1 || !methodName.equals("getInstance")) { + // Otherwise, error and return + error("method '%s' does not exist: %s\n", property, e); + return null; + } + } + + // The method didn't exist, try the constructor + attemptedMethod = "new " + className + "()"; + return type.cast(clazz.getConstructor() + .newInstance()); + } catch (ClassNotFoundException e) { + // Expected if an optional aspect is not being used (no error). + } catch (ClassCastException e) { + error("cannot cast result of calling '%s' to '%s': %s\n", attemptedMethod, + type.getName(), e); + } catch (Exception e) { + // Catches SecurityException *and* ReflexiveOperationException (which doesn't exist in 1.6). + error( + "cannot call expected no-argument constructor or static method '%s': %s\n", + attemptedMethod, e); + } + return null; } - return null; - } - private static String readProperty(String propertyName, @Nullable String defaultValue) { - Checks.checkNotNull(propertyName, "property name"); - try { - return System.getProperty(propertyName, defaultValue); - } catch (SecurityException e) { - error("cannot read property name %s: %s", propertyName, e); + private static String readProperty(String propertyName, @Nullable String defaultValue) { + Checks.checkNotNull(propertyName, "property name"); + try { + return System.getProperty(propertyName, defaultValue); + } catch (SecurityException e) { + error("cannot read property name %s: %s", propertyName, e); + } + return null; } - return null; - } - // This cannot use a fluent logger here and it's even risky to use a JDK logger. - private static void error(String msg, Object... args) { - System.err.println(StaticMethodCaller.class + ": " + String.format(msg, args)); - } + // This cannot use a fluent logger here and it's even risky to use a JDK logger. + private static void error(String msg, Object... args) { + System.err.println(StaticMethodCaller.class + ": " + String.format(msg, args)); + } - private StaticMethodCaller() {} + private StaticMethodCaller() { + } } diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/AbstractLoggerSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/AbstractLoggerSpec.kt index 9ae9329eb..158944b4f 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/AbstractLoggerSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/AbstractLoggerSpec.kt @@ -102,6 +102,7 @@ internal class AbstractLoggerSpec { fun `report nested exceptions`() { val innerException = IllegalStateException("<>") val outerException = object : IllegalStateException("Ooopsie") { + @Suppress("unused") private val serialVersionUID: Long = 42L override fun toString(): String = throw innerException // It is a nested throwing. } diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/FluentLogger2Spec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LoggerSpec.kt similarity index 99% rename from jvm/middleware/src/test/kotlin/io/spine/logging/jvm/FluentLogger2Spec.kt rename to jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LoggerSpec.kt index 88d6e06d7..77b27733f 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/FluentLogger2Spec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LoggerSpec.kt @@ -49,7 +49,7 @@ import org.junit.jupiter.api.Test * Original Java code of Google Flogger */ @DisplayName("`FluentLogger2` should") -internal class FluentLogger2Spec { +internal class LoggerSpec { @Test fun `create a logger for enclosing class`() { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataProcessorSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataProcessorSpec.kt index 27de8f442..6088a57df 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataProcessorSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataProcessorSpec.kt @@ -46,6 +46,7 @@ import org.junit.jupiter.api.Test * @see * Original Java code of Google Flogger */ +@Suppress("unused") internal abstract class MetadataProcessorSpec(private val factory: ProcessorFactory) { companion object { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/FakeLogData.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/FakeLogData.kt index 6b0c8ea20..d9b076bbf 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/FakeLogData.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/FakeLogData.kt @@ -37,7 +37,6 @@ import io.spine.logging.jvm.given.FakeLogSite import io.spine.logging.jvm.parser.DefaultBraceStyleMessageParser import io.spine.logging.jvm.parser.DefaultPrintfMessageParser import io.spine.logging.jvm.parser.MessageParser -import java.util.concurrent.TimeUnit import java.util.logging.Level /** @@ -121,11 +120,6 @@ class FakeLogData : LogData { return level } - @Deprecated("Deprecated in Java") - override fun getTimestampMicros(): Long { - return TimeUnit.NANOSECONDS.toMicros(timestampNanos) - } - override fun getTimestampNanos(): Long { return timestampNanos } diff --git a/logging/src/jvmMain/kotlin/io/spine/logging/JvmLogger.kt b/logging/src/jvmMain/kotlin/io/spine/logging/JvmLogger.kt index 561a7182d..b32520903 100644 --- a/logging/src/jvmMain/kotlin/io/spine/logging/JvmLogger.kt +++ b/logging/src/jvmMain/kotlin/io/spine/logging/JvmLogger.kt @@ -36,7 +36,7 @@ import kotlin.time.toTimeUnit import java.util.logging.Level as JLevel /** - * Implements [Logger] using [FluentLogger2] as the underlying implementation. + * Implements [FluentLogger2] using [FluentLogger2] as the underlying implementation. */ @CheckReturnValue public class JvmLogger( diff --git a/pom.xml b/pom.xml index a1306fabe..01af158a1 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ all modules and does not describe the project structure per-subproject. --> io.spine spine-logging -2.0.0-SNAPSHOT.250 +2.0.0-SNAPSHOT.251 2015 From d7f9c22b7e10976cf3d1753da84a73e472a8f218 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Wed, 25 Jun 2025 20:04:31 +0100 Subject: [PATCH 05/28] Improve doc formatting --- .../io/spine/logging/jvm/RateLimitStatus.java | 20 ++- .../spine/logging/jvm/backend/FormatChar.java | 8 +- .../jvm/context/ScopedLoggingContexts.java | 119 +++++++++++------- .../logging/jvm/parameter/DateTimeFormat.java | 16 +-- 4 files changed, 92 insertions(+), 71 deletions(-) diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/RateLimitStatus.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/RateLimitStatus.java index 46fc674bc..2e1eaad55 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/RateLimitStatus.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/RateLimitStatus.java @@ -126,7 +126,7 @@ public abstract class RateLimitStatus { /** * The status to return whenever a rate limiter determines that logging should not occur. * - *

      All other statuses implicity "allow" logging. + *

      All other statuses implicitly "allow" logging. */ public static final RateLimitStatus DISALLOW = sentinel(); @@ -135,8 +135,7 @@ public abstract class RateLimitStatus { * *

      Note: Truly stateless rate limiters should be very rare, since they cannot hold * onto a pending "allow" state. Even a simple "sampling rate limiter" should be stateful if - * once - * the "allow" state is reached it continues to be returned until logging actually occurs. + * once the "allow" state is reached it continues to be returned until logging actually occurs. */ public static final RateLimitStatus ALLOW = sentinel(); @@ -150,16 +149,13 @@ public void reset() { /** * A log guard ensures that only one thread can claim "logging rights" for a log statement once - * an - * "allow" rate limit status is set. It also tracks the number of skipped invocations of the - * log - * site key. + * an "allow" rate limit status is set. It also tracks the number of skipped invocations of the + * log site key. * *

      Note that the skipped count is tracked via the "log site key" and there may be several - * keys - * for a single log site (e.g. due to use of the {@code per(...)} methods). This is consistent - * with everywhere else which handles log site specific state, but does make it a little less - * obvious what the skipped count refers to at first glance. + * keys for a single log site (e.g. due to use of the {@code per(...)} methods). This is + * consistent with everywhere else which handles log site specific state, but does make it a + * little less obvious what the skipped count refers to at first glance. */ private static final class LogGuard { @@ -231,7 +227,7 @@ static RateLimitStatus combine( return a; } // This is already a rare situation where 2 rate limiters are active for the same log statement. - // However, in most of these cases, at least one will likley "disallow" logging. + // However, in most of these cases, at least one will likely "disallow" logging. if (a == DISALLOW || b == ALLOW) { return a; } diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatChar.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatChar.java index 756e81e28..46edd7692 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatChar.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatChar.java @@ -60,11 +60,9 @@ public enum FormatChar { /** * Formats a Unicode code-point. This formatting rule can be applied to any character or - * integral - * numeric value, providing that {@link Character#isValidCodePoint(int)} returns true. Note - * that - * if the argument cannot be represented losslessly as an integer, it must be considered - * invalid. + * integral numeric value, providing that {@link Character#isValidCodePoint(int)} returns + * true. Note that if the argument cannot be represented losslessly as an integer, it must be + * considered invalid. *

      * This is a non-numeric format with an upper-case variant. */ diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContexts.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContexts.java index f3d4598a1..35d2b6dcb 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContexts.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContexts.java @@ -34,9 +34,10 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue; /** - * Static methods equivalent to the instance methods on {@link ScopedLoggingContext} but which - * always operate on the current {@link ScopedLoggingContext} that would be returned by {@link - * ScopedLoggingContext#getInstance}. + * Static methods equivalent to the instance methods on + * {@link ScopedLoggingContext} but which always operate on the current + * {@link ScopedLoggingContext} that would be returned by + * {@link ScopedLoggingContext#getInstance}. * * @see * Original Java code of Google Flogger @@ -63,8 +64,9 @@ private static boolean warnOnFailure(boolean wasSuccessful) { private ScopedLoggingContexts() {} /** - * Creates a new {@link ScopedLoggingContext.Builder} to which additional logging metadata can be - * attached before being installed or used to wrap some existing code. + * Creates a new {@link ScopedLoggingContext.Builder} to which additional + * logging metadata can be attached before being installed or used to wrap + * some existing code. * *

      {@code
          * Foo result = ScopedLoggingContexts.newContext()
      @@ -79,29 +81,38 @@ public static ScopedLoggingContext.Builder newContext() {
         /**
          * Adds tags by modifying the current context (if one exists).
          *
      -   * 

      Warning: It is always better to create a new context via {@link #newContext()} rather than - * attempting to modify an existing context. In order of preference you should: + *

      Warning: It is always better to create a new context via + * {@link #newContext()} rather than attempting to modify an existing + * context. In order of preference you should: * *

        *
      1. Call or wrap a new context with metadata added to it. - *
      2. {@link ScopedLoggingContext.Builder#install install()} a new context and close it when - * you it exits (e.g. if you are using callbacks to listen to state changes in a task). - * However it is vital that the returned {@link ScopedLoggingContext.LoggingContextCloseable} - * is always closed. - *
      3. Call this method and check that it succeeded (e.g. logging a warning if it fails). + *
      4. {@link ScopedLoggingContext.Builder#install install()} a new + * context and close it when you it exits (e.g. if you are using + * callbacks to listen to state changes in a task). However it is + * vital that the returned + * {@link ScopedLoggingContext.LoggingContextCloseable} is always + * closed. + *
      5. Call this method and check that it succeeded (e.g. logging a + * warning if it fails). *
      * - *

      The given tags are merged with those of the modifed context but existing tags will not be - * overwritten or removed. This is deliberate since two pieces of code may not know about each - * other and could accidentally use the same tag name; in that situation it's important that both - * tag values are preserved. + *

      The given tags are merged with those of the modified context but + * existing tags will not be overwritten or removed. This is deliberate + * since two pieces of code may not know about each other and could + * accidentally use the same tag name; in that situation it's important + * that both tag values are preserved. * - *

      Furthermore, the types of data allowed for tag values are strictly controlled. This is also - * very deliberate since these tags must be efficiently added to every log statement and so it's - * important that they resulting string representation is reliably cacheable and can be calculated - * without invoking arbitrary code (e.g. the {@code toString()} method of some unknown user type). + *

      Furthermore, the types of data allowed for tag values are strictly + * controlled. This is also very deliberate since these tags must be + * efficiently added to every log statement and so it's important that + * their resulting string representation is reliably cacheable and can be + * calculated without invoking arbitrary code (e.g. the {@code toString()} + * method of some unknown user type). * - * @return false if there is no current context, or scoped contexts are not supported. + * @param tags the tags to add to the current context. + * @return {@code false} if there is no current context, or scoped + * contexts are not supported. */ @CanIgnoreReturnValue public static boolean addTags(Tags tags) { @@ -111,23 +122,35 @@ public static boolean addTags(Tags tags) { /** * Adds a single metadata key/value pair to the current context. * - *

      Warning: It is always better to create a new context via {@link #newContext()} rather than - * attempting to modify an existing context. In order of preference you should: + *

      Warning: It is always better to create a new context via + * {@link #newContext()} rather than attempting to modify an existing + * context. In order of preference you should: * *

        *
      1. Call or wrap a new context with metadata added to it. - *
      2. {@link ScopedLoggingContext.Builder#install install()} a new context and close it when - * you it exits (e.g. if you are using callbacks to listen to state changes in a task). - * However it is vital that the returned {@link ScopedLoggingContext.LoggingContextCloseable} - * is always closed. - *
      3. Call this method and check that it succeeded (e.g. logging a warning if it fails). + *
      4. {@link ScopedLoggingContext.Builder#install install()} a new + * context and close it when you it exits (e.g. if you are using + * callbacks to listen to state changes in a task). However, it is + * vital that the returned + * {@link ScopedLoggingContext.LoggingContextCloseable} is always + * closed. + *
      5. Call this method and check that it succeeded (e.g. logging a + * warning if it fails). *
      * - *

      Unlike {@link Tags}, which have a well defined value ordering, independent of the order in - * which values were added, context metadata preserves the order of addition. As such, it is not - * advised to add values for the same metadata key from multiple threads, since that may create - * non-deterministic ordering. It is recommended (where possible) to add metadata when building a - * new context, rather than adding it to context visible to multiple threads. + *

      Unlike {@link Tags}, which have a well defined value ordering, + * independent of the order in which values were added, context metadata + * preserves the order of addition. As such, it is not advised to add + * values for the same metadata key from multiple threads, since that may + * create non-deterministic ordering. It is recommended (where possible) + * to add metadata when building a new context, rather than adding it to + * context visible to multiple threads. + * + * @param the type of the metadata value. + * @param key the metadata key. + * @param value the metadata value. + * @return {@code false} if there is no current context, or scoped + * contexts are not supported. */ @CanIgnoreReturnValue public static boolean addMetadata(JvmMetadataKey key, T value) { @@ -137,29 +160,37 @@ public static boolean addMetadata(JvmMetadataKey key, T value) { /** * Applies the given log level map to the current context. * - *

      Warning: It is always better to create a new context via {@link #newContext()} rather than - * attempting to modify an existing context. In order of preference you should: + *

      Warning: It is always better to create a new context via + * {@link #newContext()} rather than attempting to modify an existing + * context. In order of preference you should: * *

        *
      1. Call or wrap a new context with metadata added to it. - *
      2. {@link ScopedLoggingContext.Builder#install install()} a new context and close it when - * you it exits (e.g. if you are using callbacks to listen to state changes in a task). - * However it is vital that the returned {@link ScopedLoggingContext.LoggingContextCloseable} - * is always closed. - *
      3. Call this method and check that it succeeded (e.g. logging a warning if it fails). + *
      4. {@link ScopedLoggingContext.Builder#install install()} a new + * context and close it when you it exits (e.g. if you are using + * callbacks to listen to state changes in a task). However it is + * vital that the returned + * {@link ScopedLoggingContext.LoggingContextCloseable} is always + * closed. + *
      5. Call this method and check that it succeeded (e.g. logging a + * warning if it fails). *
      * - * Log level settings are merged with any existing setting from the current (or parent) contexts - * such that logging will be enabled for a log statement if: + *

      Log level settings are merged with any existing setting from the + * current (or parent) contexts such that logging will be enabled for a + * log statement if: * *

        *
      • It was enabled by the given map. *
      • It was already enabled by the current context. *
      * - *

      The effects of this call will be undone only when the current context terminates. + *

      The effects of this call will be undone only when the current + * context terminates. * - * @return false if there is no current context, or scoped contexts are not supported. + * @param logLevelMap the log level map to apply to the current context. + * @return {@code false} if there is no current context, or scoped + * contexts are not supported. */ @CanIgnoreReturnValue public static boolean applyLogLevelMap(LogLevelMap logLevelMap) { diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeFormat.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeFormat.java index 9fb45669e..88180bb9c 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeFormat.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeFormat.java @@ -90,18 +90,15 @@ public enum DateTimeFormat { /** * RFC 822 style numeric time zone offset from GMT, e.g. "-0800". This value will be adjusted - * as - * necessary for Daylight Saving Time. For long, Long, and Date the time zone used is the - * default - * time zone for this instance of the Java virtual machine. + * as necessary for Daylight Saving Time. For long, Long, and Date the time zone used is the + * default time zone for this instance of the Java virtual machine. */ TIME_TZ_NUMERIC('z'), /** * A string representing the abbreviation for the time zone. This value will be adjusted as * necessary for Daylight Saving Time. For long, Long, and Date the time zone used is the - * default - * time zone for this instance of the Java virtual machine. + * default time zone for this instance of the Java virtual machine. */ TIME_TZ_SHORT('Z'), @@ -130,8 +127,8 @@ public enum DateTimeFormat { /** * Four-digit year divided by 100, formatted as two digits with leading zero as necessary, - * i.e., 00 - 99. Note that this is not strictly the "century", - * because "19xx" is "19", not "20". + * i.e., 00 - 99. Note that this is not strictly the "century", because "19xx" is "19", not + * "20". */ DATE_CENTURY_PADDED('C'), @@ -142,8 +139,7 @@ public enum DateTimeFormat { DATE_YEAR_OF_CENTURY_PADDED('y'), /** - * Day of year, formatted as three digits with leading zeros as necessary, - * e.g. 001 - 366. + * Day of year, formatted as three digits with leading zeros as necessary, e.g. 001 - 366. */ DATE_DAY_OF_YEAR_PADDED('j'), From 222df911d4def388907c948a83313fcb8e9e9553 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Wed, 25 Jun 2025 20:11:17 +0100 Subject: [PATCH 06/28] Rename `FluentLogger2` to `Middleman` --- .../jvm/{FluentLogger2.java => Middleman.java} | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) rename jvm/middleware/src/main/java/io/spine/logging/jvm/{FluentLogger2.java => Middleman.java} (92%) diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/FluentLogger2.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/Middleman.java similarity index 92% rename from jvm/middleware/src/main/java/io/spine/logging/jvm/FluentLogger2.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/Middleman.java index 086681da1..892cc5308 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/FluentLogger2.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/Middleman.java @@ -48,7 +48,7 @@ * @see * Original Java code of Google Flogger */ -public final class FluentLogger2 extends AbstractLogger { +public final class Middleman extends AbstractLogger { /** * The non-wildcard, fully specified, logging API for this logger. Fluent logger implementations * should specify a non-wildcard API like this with which to generify the abstract logger. @@ -76,11 +76,11 @@ private static final class NoOp extends JvmApi.NoOp implements Api {} * Returns a new logger instance which parses log messages using printf format for the enclosing * class using the system default logging backend. */ - public static FluentLogger2 forEnclosingClass() { + public static Middleman forEnclosingClass() { // NOTE: It is _vital_ that the call to "caller finder" is made directly inside the static // factory method. See getCallerFinder() for more information. - var loggingClass = Platform.getCallerFinder().findLoggingClass(FluentLogger2.class); - return new FluentLogger2(Platform.getBackend(loggingClass)); + var loggingClass = Platform.getCallerFinder().findLoggingClass(Middleman.class); + return new Middleman(Platform.getBackend(loggingClass)); } /** @@ -91,7 +91,7 @@ public static FluentLogger2 forEnclosingClass() { * {@code io.spine.logging.JvmLoggerFactoryKt}. Now, as we aggregate the Flogger code, * we open the constructor for simplicity. */ - public FluentLogger2(LoggerBackend backend) { + public Middleman(LoggerBackend backend) { super(backend); } @@ -109,14 +109,14 @@ public Api at(Level level) { /** Logging context implementing the fully specified API for this logger. */ // VisibleForTesting - final class Context extends LogContext implements Api { + final class Context extends LogContext implements Api { private Context(Level level, boolean isForced) { super(level, isForced); } @Override - protected FluentLogger2 getLogger() { - return FluentLogger2.this; + protected Middleman getLogger() { + return Middleman.this; } @Override From a307c72d3bb0efc3aa4163180613fc5017c59f18 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Wed, 25 Jun 2025 20:11:30 +0100 Subject: [PATCH 07/28] Rename `FluentLogger2` to `Middleman` --- .../main/java/io/spine/logging/jvm/JvmLogSite.java | 2 +- .../logging/jvm/context/NoOpContextDataProvider.java | 4 ++-- .../logging/jvm/context/ScopedLoggingContexts.java | 4 ++-- .../kotlin/io/spine/logging/jvm/LogContextSpec.kt | 4 ++-- .../test/kotlin/io/spine/logging/jvm/LoggerSpec.kt | 12 ++++++------ .../src/jvmMain/kotlin/io/spine/logging/JvmLogger.kt | 10 +++++----- .../kotlin/io/spine/logging/LoggingFactory.kt | 4 ++-- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmLogSite.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmLogSite.java index ff2ee9dc3..0fc88c274 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmLogSite.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmLogSite.java @@ -62,7 +62,7 @@ public abstract class JvmLogSite implements LogSiteKey { * fails for any reason. *

      * If a log statement does end up with invalid log site information, then any fluent logging - * methods which rely on being able to look up site specific metadata will be disabled and + * methods which rely on being able to look up site-specific metadata will be disabled and * essentially become "no ops". */ public static final JvmLogSite INVALID = new JvmLogSite() { diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/NoOpContextDataProvider.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/NoOpContextDataProvider.java index aa7aa8120..2d086166e 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/NoOpContextDataProvider.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/NoOpContextDataProvider.java @@ -26,7 +26,7 @@ package io.spine.logging.jvm.context; -import io.spine.logging.jvm.FluentLogger2; +import io.spine.logging.jvm.Middleman; import io.spine.logging.jvm.JvmMetadataKey; import io.spine.logging.jvm.StackSize; import io.spine.logging.jvm.context.ScopedLoggingContext.LoggingContextCloseable; @@ -63,7 +63,7 @@ private static final class NoOpScopedLoggingContext extends ScopedLoggingContext // is complete. private static final class LazyLogger { - private static final FluentLogger2 logger = FluentLogger2.forEnclosingClass(); + private static final Middleman logger = Middleman.forEnclosingClass(); } private final AtomicBoolean haveWarned = new AtomicBoolean(); diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContexts.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContexts.java index 35d2b6dcb..d7358ccd4 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContexts.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContexts.java @@ -28,7 +28,7 @@ import static java.util.concurrent.TimeUnit.MINUTES; -import io.spine.logging.jvm.FluentLogger2; +import io.spine.logging.jvm.Middleman; import io.spine.logging.jvm.JvmMetadataKey; import io.spine.logging.jvm.StackSize; import com.google.errorprone.annotations.CanIgnoreReturnValue; @@ -43,7 +43,7 @@ * Original Java code of Google Flogger */ public final class ScopedLoggingContexts { - private static final FluentLogger2 logger = FluentLogger2.forEnclosingClass(); + private static final Middleman logger = Middleman.forEnclosingClass(); private static boolean warnOnFailure(boolean wasSuccessful) { if (!wasSuccessful && !ScopedLoggingContext.getInstance().isNoOp()) { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LogContextSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LogContextSpec.kt index eaaadd01e..0f3cff069 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LogContextSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LogContextSpec.kt @@ -72,7 +72,7 @@ import org.junit.jupiter.api.Test internal class LogContextSpec { private val backend = MemoizingLoggerBackend() - private val logger = FluentLogger2(backend) + private val logger = Middleman(backend) companion object { // Arbitrary constants of overloaded types for testing argument mappings. @@ -93,7 +93,7 @@ internal class LogContextSpec { // In normal use, the logger would never need to be passed in, // and you'd use `logVarargs()`. private fun logHelper( - logger: FluentLogger2, + logger: Middleman, logSite: JvmLogSite, n: Int, message: String diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LoggerSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LoggerSpec.kt index 77b27733f..614249d5d 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LoggerSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LoggerSpec.kt @@ -29,14 +29,14 @@ package io.spine.logging.jvm import io.kotest.matchers.shouldBe import io.kotest.matchers.types.shouldBeInstanceOf import io.kotest.matchers.types.shouldNotBeInstanceOf -import io.spine.logging.jvm.FluentLogger2.forEnclosingClass +import io.spine.logging.jvm.Middleman.forEnclosingClass import io.spine.logging.jvm.backend.given.MemoizingLoggerBackend import java.util.logging.Level import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test /** - * Tests for [FluentLogger2]. + * Tests for [Middleman]. * * Fluent loggers are typically very simple classes whose only real * responsibility is to be a factory for specific API implementations. @@ -69,7 +69,7 @@ internal class LoggerSpec { @Test fun `provide a no-op API for disabled levels`() { val backend = MemoizingLoggerBackend() - val logger = FluentLogger2(backend) + val logger = Middleman(backend) backend.setLevel(Level.INFO) // Down to and including the configured log level are not no-op instances. @@ -77,9 +77,9 @@ internal class LoggerSpec { logger.atWarning().shouldNotBeInstanceOf>() logger.atInfo().shouldNotBeInstanceOf>() - logger.atSevere().shouldBeInstanceOf() - logger.atWarning().shouldBeInstanceOf() - logger.atInfo().shouldBeInstanceOf() + logger.atSevere().shouldBeInstanceOf() + logger.atWarning().shouldBeInstanceOf() + logger.atInfo().shouldBeInstanceOf() // Below the configured log level, you only get no-op instances. logger.atFine().shouldBeInstanceOf>() diff --git a/logging/src/jvmMain/kotlin/io/spine/logging/JvmLogger.kt b/logging/src/jvmMain/kotlin/io/spine/logging/JvmLogger.kt index b32520903..1eaf6b2ae 100644 --- a/logging/src/jvmMain/kotlin/io/spine/logging/JvmLogger.kt +++ b/logging/src/jvmMain/kotlin/io/spine/logging/JvmLogger.kt @@ -26,7 +26,7 @@ package io.spine.logging -import io.spine.logging.jvm.FluentLogger2 +import io.spine.logging.jvm.Middleman import io.spine.logging.jvm.JvmLogSites.callerOf import com.google.errorprone.annotations.CheckReturnValue import io.spine.logging.jvm.JvmLogSite @@ -36,12 +36,12 @@ import kotlin.time.toTimeUnit import java.util.logging.Level as JLevel /** - * Implements [FluentLogger2] using [FluentLogger2] as the underlying implementation. + * Implements [Middleman] using [Middleman] as the underlying implementation. */ @CheckReturnValue public class JvmLogger( cls: KClass<*>, - internal val delegate: FluentLogger2 + internal val delegate: Middleman ) : Logger(cls) { /** @@ -65,9 +65,9 @@ public class JvmLogger( } /** - * Implements [LoggingApi] wrapping [FluentLogger2.Api]. + * Implements [LoggingApi] wrapping [Middleman.Api]. */ -private class ApiImpl(private val delegate: FluentLogger2.Api): JvmLogger.Api { +private class ApiImpl(private val delegate: Middleman.Api): JvmLogger.Api { private var loggingDomain: LoggingDomain? = null diff --git a/logging/src/jvmMain/kotlin/io/spine/logging/LoggingFactory.kt b/logging/src/jvmMain/kotlin/io/spine/logging/LoggingFactory.kt index 883f74434..0d6d9b4c0 100644 --- a/logging/src/jvmMain/kotlin/io/spine/logging/LoggingFactory.kt +++ b/logging/src/jvmMain/kotlin/io/spine/logging/LoggingFactory.kt @@ -26,7 +26,7 @@ package io.spine.logging -import io.spine.logging.jvm.FluentLogger2 +import io.spine.logging.jvm.Middleman import io.spine.logging.jvm.backend.Platform import io.spine.reflect.CallerFinder import kotlin.reflect.KClass @@ -79,7 +79,7 @@ public actual object LoggingFactory: ClassValue() { private fun createForClass(cls: Class<*>): JvmLogger { val floggerBackend = Platform.getBackend(cls.name) - val flogger = FluentLogger2(floggerBackend) + val flogger = Middleman(floggerBackend) // As for now, `JvmLogger` just delegates actual work to Flogger. return JvmLogger(cls.kotlin, flogger) } From 9ebff0ea410bd8aa18c6b3c15028a8159ceb3039 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Wed, 25 Jun 2025 20:11:40 +0100 Subject: [PATCH 08/28] Update `config` ref. --- config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config b/config index e60974948..36a2aa28d 160000 --- a/config +++ b/config @@ -1 +1 @@ -Subproject commit e60974948530988efae6f63237b47e19dba80773 +Subproject commit 36a2aa28dd5a25efd029668e4357df05e6024ac9 From b64c8a0cdc39e3de6d49c068ff3beae907bf623b Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Wed, 25 Jun 2025 20:11:47 +0100 Subject: [PATCH 09/28] Update build time --- dependencies.md | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/dependencies.md b/dependencies.md index a10a522b8..942bb7a0b 100644 --- a/dependencies.md +++ b/dependencies.md @@ -724,7 +724,7 @@ The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 19:34:15 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 20:06:58 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -1553,7 +1553,7 @@ This report was generated on **Wed Jun 25 19:34:15 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 19:34:16 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 20:06:59 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -2366,7 +2366,7 @@ This report was generated on **Wed Jun 25 19:34:16 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 19:34:16 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 20:06:59 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -3187,7 +3187,7 @@ This report was generated on **Wed Jun 25 19:34:16 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 19:34:16 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 20:07:00 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -4035,7 +4035,7 @@ This report was generated on **Wed Jun 25 19:34:16 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 19:34:16 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 20:07:00 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -4875,7 +4875,7 @@ This report was generated on **Wed Jun 25 19:34:16 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 19:34:17 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 20:07:01 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -5715,7 +5715,7 @@ This report was generated on **Wed Jun 25 19:34:17 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 19:34:17 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 20:07:01 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -6563,7 +6563,7 @@ This report was generated on **Wed Jun 25 19:34:17 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 19:34:17 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 20:07:02 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -7415,7 +7415,7 @@ This report was generated on **Wed Jun 25 19:34:17 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 19:34:17 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 20:07:02 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -8244,7 +8244,7 @@ This report was generated on **Wed Jun 25 19:34:17 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 19:34:18 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 20:07:03 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -8981,7 +8981,7 @@ This report was generated on **Wed Jun 25 19:34:18 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 19:34:18 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 20:07:03 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -9706,7 +9706,7 @@ This report was generated on **Wed Jun 25 19:34:18 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 19:34:18 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 20:07:03 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -10519,7 +10519,7 @@ This report was generated on **Wed Jun 25 19:34:18 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 19:34:18 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 20:07:04 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -11308,7 +11308,7 @@ This report was generated on **Wed Jun 25 19:34:18 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 19:34:19 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 20:07:04 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -12296,7 +12296,7 @@ This report was generated on **Wed Jun 25 19:34:19 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 19:34:19 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 20:07:05 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -13169,7 +13169,7 @@ This report was generated on **Wed Jun 25 19:34:19 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 19:34:19 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Wed Jun 25 20:07:05 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -13986,4 +13986,4 @@ This report was generated on **Wed Jun 25 19:34:19 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 19:34:19 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). \ No newline at end of file +This report was generated on **Wed Jun 25 20:07:06 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). \ No newline at end of file From d359006280796061ee93e6fa7b1af75f7457a869 Mon Sep 17 00:00:00 2001 From: Alexander Yevsyukov Date: Wed, 25 Jun 2025 21:37:57 +0100 Subject: [PATCH 10/28] Improve Javadoc comments --- buildSrc/src/main/kotlin/io/spine/gradle/Runtime.kt | 12 ++++++------ .../io/spine/gradle/report/pom/PomXmlWriter.kt | 12 ++++++------ .../kotlin/io/spine/logging/LoggingFactory.kt | 10 +++++----- .../spine/logging/backend/system/package-info.java | 5 ++--- 4 files changed, 19 insertions(+), 20 deletions(-) diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/Runtime.kt b/buildSrc/src/main/kotlin/io/spine/gradle/Runtime.kt index c5b5f5464..0e67c108a 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/Runtime.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/Runtime.kt @@ -46,15 +46,15 @@ private const val ABOUT = "" class Cli(private val workingFolder: File) { /** - * Executes the given terminal command and retrieves the command output. + * Executes the given terminal command and returns its output. * - *

      {@link Runtime#exec(String[], String[], File) Executes} the given {@code String} array as - * a CLI command. If the execution is successful, returns the command output. Throws - * an {@link IllegalStateException} otherwise. + *

      Internally calls {@link Runtime#exec(String[], String[], File)} to run the given + * {@code String} array as a CLI command. If the execution is successful, the command output + * is returned; otherwise an {@link IllegalStateException} is thrown. * * @param command the command to execute * @return the command line output - * @throws IllegalStateException upon an execution error + * @throws IllegalStateException if the execution fails */ fun execute(vararg command: String): String { val outWriter = StringWriter() @@ -87,7 +87,7 @@ class Cli(private val workingFolder: File) { /** * Asynchronously reads all lines from this [InputStream] and appends them - * to the passed [StringWriter]. + * to the given [StringWriter]. */ fun InputStream.pourTo(dest: StringWriter) { Thread { diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/PomXmlWriter.kt b/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/PomXmlWriter.kt index 53122196a..21394a7f5 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/PomXmlWriter.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/PomXmlWriter.kt @@ -35,9 +35,9 @@ import java.io.StringWriter /** * Writes the dependencies of a Gradle project and its subprojects as a `pom.xml` file. * - * The resulting file is not usable for `maven` build tasks, but serves rather as a description - * of the first-level dependencies for each project/subproject. Their transitive dependencies - * are not included into the result. + * The resulting file is not usable for `maven` build tasks but serves as a description + * of the first-level dependencies for each project or subproject. Their transitive dependencies + * are not included in the result. */ internal class PomXmlWriter internal constructor( @@ -48,10 +48,10 @@ internal constructor( * Writes the `pom.xml` file containing dependencies of this project * and its subprojects to the specified location. * - *

      If a file with the specified location exists, its contents will be substituted + *

      If a file with the specified location exists, its contents are replaced * with a new `pom.xml`. * - * @param file a file to write `pom.xml` contents to + * @param file a file to write the `pom.xml` contents to */ fun writeTo(file: File) { val fileWriter = FileWriter(file) @@ -74,7 +74,7 @@ internal constructor( /** * Obtains a string that contains project dependencies as XML. * - *

      Obtained string also contains a closing project tag. + *

      The returned string also contains the closing project tag. */ private fun projectDependencies(): String { val destination = StringWriter() diff --git a/logging/src/commonMain/kotlin/io/spine/logging/LoggingFactory.kt b/logging/src/commonMain/kotlin/io/spine/logging/LoggingFactory.kt index 6fa1ca3f1..5bf9ebc0b 100644 --- a/logging/src/commonMain/kotlin/io/spine/logging/LoggingFactory.kt +++ b/logging/src/commonMain/kotlin/io/spine/logging/LoggingFactory.kt @@ -36,14 +36,14 @@ public expect object LoggingFactory { /** * Obtains the logger for the enclosing class. * - * Implementation should provide the same logger instance for the same class. + * The implementation should return the same logger instance for the same class. */ public fun > forEnclosingClass(): Logger /** * Obtains the logger for the given class. * - * Implementation should provide the same logger instance for the same class. + * The implementation should return the same logger instance for the same class. */ public fun > loggerFor(cls: KClass<*>): Logger @@ -56,8 +56,8 @@ public expect object LoggingFactory { /** * Creates a key for a single piece of metadata. If metadata is set more than once - * using this key for the same log statement, the last set value will be the one used, and - * other values will be ignored (although callers should never rely on this behavior). + * with this key for the same log statement, only the last value is used and + * other values are ignored (although callers should never rely on this behavior). * * Key instances behave like singletons, and two key instances with the same label will still * be considered distinct. The recommended approach is to always assign [MetadataKey] @@ -69,7 +69,7 @@ public expect object LoggingFactory { /** * Creates a key for a repeated piece of metadata. If metadata is added more than once - * using this key for a log statement, all values will be retained as key/value pairs in + * with this key for a log statement, all values are retained as key/value pairs in * the order they were added. * * Key instances behave like singletons, and two key instances with the same label will still diff --git a/platforms/jvm-default-platform/src/main/java/io/spine/logging/backend/system/package-info.java b/platforms/jvm-default-platform/src/main/java/io/spine/logging/backend/system/package-info.java index e88808768..aa5d027eb 100644 --- a/platforms/jvm-default-platform/src/main/java/io/spine/logging/backend/system/package-info.java +++ b/platforms/jvm-default-platform/src/main/java/io/spine/logging/backend/system/package-info.java @@ -28,9 +28,8 @@ * Contains the default logger platform implementation for a server-side * Java environment. * - *

      Although, {@code system} is not the best name for this package. - * The better option is {@code default}, but it is reserved by Java - * and cannot be used here. + *

      Although {@code system} is not the best name for this package, + * the better option, {@code default}, is reserved by Java and cannot be used here. * * @see Original Java code of Google Flogger */ From ccb0f12fc013f10311daa570c69403d065932724 Mon Sep 17 00:00:00 2001 From: Alexander Yevsyukov Date: Wed, 25 Jun 2025 21:56:48 +0100 Subject: [PATCH 11/28] docs: adjust Javadoc formatting --- .../io/spine/logging/jvm/AbstractLogger.java | 3 +++ .../java/io/spine/logging/jvm/JvmApi.java | 20 ++++++++++++++ .../java/io/spine/logging/jvm/JvmLogSite.java | 6 +++++ .../io/spine/logging/jvm/JvmLogSites.java | 12 +++++++++ .../java/io/spine/logging/jvm/LogContext.java | 6 +++++ .../logging/jvm/LogPerBucketingStrategy.java | 1 + .../java/io/spine/logging/jvm/LogSiteMap.java | 1 + .../spine/logging/jvm/LogSiteStackTrace.java | 1 + .../java/io/spine/logging/jvm/Middleman.java | 3 +++ .../io/spine/logging/jvm/RateLimitStatus.java | 1 + .../java/io/spine/logging/jvm/StackSize.java | 8 ++++++ .../jvm/backend/BaseMessageFormatter.java | 2 ++ .../spine/logging/jvm/backend/FormatChar.java | 14 ++++++++++ .../logging/jvm/backend/FormatOptions.java | 17 ++++++++++++ .../io/spine/logging/jvm/backend/LogData.java | 1 + .../logging/jvm/backend/LoggerBackend.java | 1 + .../logging/jvm/backend/LoggingException.java | 1 + .../logging/jvm/backend/MetadataHandler.java | 26 +++++++++++++++++++ .../jvm/backend/MetadataProcessor.java | 3 +++ .../spine/logging/jvm/backend/Platform.java | 6 +++++ .../jvm/backend/SimpleMessageFormatter.java | 6 +++++ .../logging/jvm/backend/TemplateContext.java | 1 + .../logging/jvm/context/SegmentTrie.java | 8 ++++++ .../jvm/parameter/BraceStyleParameter.java | 1 + .../jvm/parameter/DateTimeParameter.java | 1 + .../logging/jvm/parameter/Parameter.java | 3 +++ .../jvm/parameter/ParameterVisitor.java | 3 +++ .../jvm/parameter/SimpleParameter.java | 4 +++ .../jvm/parser/BraceStyleMessageParser.java | 4 +++ .../DefaultBraceStyleMessageParser.java | 1 + .../parser/DefaultPrintfMessageParser.java | 1 + .../logging/jvm/parser/MessageBuilder.java | 6 +++++ .../logging/jvm/parser/MessageParser.java | 2 ++ .../logging/jvm/parser/ParseException.java | 10 +++++++ .../jvm/parser/PrintfMessageParser.java | 4 +++ 35 files changed, 188 insertions(+) diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/AbstractLogger.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/AbstractLogger.java index 6c391fce7..5929dc541 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/AbstractLogger.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/AbstractLogger.java @@ -46,6 +46,7 @@ * * @param * the logging API provided by this logger. + * * @see * Original Java code of Google Flogger */ @@ -81,10 +82,12 @@ protected AbstractLogger(LoggerBackend backend) { /** * Returns a fluent logging API appropriate for the specified log level. + * *

      * If a logger implementation determines that logging is definitely disabled at this point then * this method is expected to return a "no-op" implementation of that logging API, which will * result in all further calls made for the log statement to being silently ignored. + * *

      * A simple implementation of this method in a concrete subclass might look like: *

      {@code
      diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmApi.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmApi.java
      index 474150e2c..fcae9d50e 100644
      --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmApi.java
      +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmApi.java
      @@ -35,6 +35,7 @@
       /**
        * The basic logging API. An implementation of this API (or an extension of it) will be
        * returned by any fluent logger and forms the basis of the fluent call chain.
      + *
        * 

      * In typical usage each method in the API, with the exception of the terminal {@code log()} * statements, will carry out some simple task (which may involve modifying the context of the log @@ -82,9 +83,11 @@ public interface JvmApi> { * is emitted all the rate limiters are reset. In particular for {@code every(N)} this means that * logs need not always be emitted at multiples of {@code N} if other rate limiters are active, * though it will always be at least {@code N}. + * *

      * When rate limiting is active, a {@code "skipped"} count is added to log statements to indicate * how many logs were disallowed since the last log statement was emitted. + * *

      * If this method is called multiple times for a single log statement, the last invocation will * take precedence. @@ -107,9 +110,11 @@ public interface JvmApi> { * only be emitted once all rate limiters have reached their threshold, and when a log statement * is emitted all the rate limiters are reset. In particular for {@code onAverageEvery(N)} this * means that logs may occurs less frequently than one-in-N if other rate limiters are active. + * *

      * When rate limiting is active, a {@code "skipped"} count is added to log statements to indicate * how many logs were disallowed since the last log statement was emitted. + * *

      * If this method is called multiple times for a single log statement, the last invocation will * take precedence. @@ -124,6 +129,7 @@ public interface JvmApi> { * specified duration must not be negative, and it is expected, but not required, that it is * constant. In the absence of any other rate limiting, this method always allows the first * invocation of any log statement to be emitted. + * *

      * Note that for performance reasons {@code atMostEvery()} is explicitly not intended to * perform "proper" rate limiting to produce a limited average rate over many samples. @@ -136,6 +142,7 @@ public interface JvmApi> { * }

      * where {@code currentTimestampNanos} is the timestamp of the current log statement and * {@code lastTimestampNanos} is a time stamp of the last log statement that was emitted. + * *

      * The effect of this is that when logging invocation is relatively infrequent, the period * between emitted log statements can be higher than the specified duration. For example @@ -145,6 +152,7 @@ public interface JvmApi> { * }

      * logging would occur after {@code 0s}, {@code 2.4s} and {@code 4.8s} (not {@code 4.2s}), * giving an effective duration of {@code 2.4s} between log statements over time. + * *

      * Providing a zero-length duration (i.e., {@code n == 0}) disables rate limiting and makes this * method an effective no-op. @@ -165,9 +173,11 @@ public interface JvmApi> { * only be emitted once all rate limiters have reached their threshold, and when a log statement * is emitted all the rate limiters are reset. So even if the rate limit duration has expired, it * does not mean that logging will occur. + * *

      * When rate limiting is active, a {@code "skipped"} count is added to log statements to indicate * how many logs were disallowed since the last log statement was emitted. + * *

      * If this method is called multiple times for a single log statement, the last invocation will * take precedence. @@ -341,6 +351,7 @@ public interface JvmApi> { * @param key the metadata key (expected to be a static constant) * @param value a value to be associated with the key in this log statement. Null values are * allowed, but the effect is always a no-op + * * @throws NullPointerException if the given key is null * @see JvmMetadataKey */ @@ -431,6 +442,7 @@ public interface JvmApi> { * 16 bits is a log statement index to distinguish multiple statements on the same line * (this becomes important if line numbers are stripped from the class file and everything * appears to be on the same line). + * * @param sourceFileName Optional base name of the source file (this value is strictly for * debugging and does not contribute to either equals() or hashCode() behavior). */ @@ -449,11 +461,13 @@ API withInjectedLogSite( * logger.atFine().log("Message: %s", value); * } * } + * *

      * Note that if logging is enabled for a log level, it does not always follow that the log * statement will definitely be written to the backend (due to the effects of other methods in * the fluent chain), but if this method returns {@code false} then it can safely be assumed that * no logging will occur. + * *

      * This method is unaffected by additional methods in the fluent chain and should only ever be * invoked immediately after the level selector method. In other words, the expression: @@ -466,6 +480,7 @@ API withInjectedLogSite( *

      By avoiding passing a separate {@code Level} at runtime to determine "loggability", this API * makes it easier to coerce bytecode optimizers into doing "dead code" removal on sections * guarded by this method. + * *

      * If a proxy logger class is supplied for which: *

      {@code logger.atFine()}
      @@ -486,6 +501,7 @@ API withInjectedLogSite( * * @param message the message template string containing an argument placeholder for each element * of {@code varargs}. + * * @param varargs the non-null array of arguments to be formatted. */ void logVarargs(String message, @Nullable Object[] varargs); @@ -497,6 +513,7 @@ API withInjectedLogSite( *
      {@code
          * logger.at(INFO).withCause(error).log();
          * }
      + * *

      * However, as it is good practice to give all log statements a meaningful log message, use of this * method should be rare. @@ -505,6 +522,7 @@ API withInjectedLogSite( /** * Logs the given literal string without interpreting any argument placeholders. + * *

      * Important: This is intended only for use with hard-coded, literal strings which cannot * contain user data. If you wish to log user-generated data, you should do something like: @@ -524,6 +542,7 @@ API withInjectedLogSite( * Logs a formatted representation of the given parameter, using the specified message template. * The message string is expected to contain argument placeholder terms appropriate to the * logger's choice of parser. + * *

      * Note that printf-style loggers are always expected to accept the standard Java printf * formatting characters (e.g. "%s", "%d", etc...) and all flags unless otherwise stated. @@ -816,6 +835,7 @@ void log( /** * An implementation of {@link JvmApi} which does nothing and discards all parameters. + * *

      * This class (or a subclass in the case of an extended API) should be returned whenever logging * is definitely disabled (e.g. when the log level is too low). diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmLogSite.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmLogSite.java index 0fc88c274..83e7d7227 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmLogSite.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmLogSite.java @@ -33,14 +33,17 @@ /** * A value type which representing the location of a single log statement. This class is similar to * the {@code StackTraceElement} class but differs in one important respect. + * *

      * A LogSite can be associated with a globally unique ID, which can identify a log statement more * uniquely than a line number (it is possible to have multiple log statements appear to be on a * single line, especially for obfuscated classes). + * *

      * Log sites are intended to be injected into code automatically, typically via some form of * bytecode rewriting. Each injection mechanism can have its own implementation of {@code LogSite} * adapted to its needs. + * *

      * As a fallback, for cases where no injection mechanism is configured, a log site based upon stack * trace analysis is used. However, due to limitations in the information available from @@ -60,6 +63,7 @@ public abstract class JvmLogSite implements LogSiteKey { * injecting it via {@link JvmApi#withInjectedLogSite} which will suppress any further * log site analysis for that log statement. This is also returned if stack trace analysis * fails for any reason. + * *

      * If a log statement does end up with invalid log site information, then any fluent logging * methods which rely on being able to look up site-specific metadata will be disabled and @@ -135,6 +139,7 @@ public final String toString() { /** * Creates a log site injected from constants held a class' constant pool. + * *

      * Used for compile-time log site injection, and by the agent. * @@ -145,6 +150,7 @@ public final String toString() { * 16 bits is a log statement index to distinguish multiple statements on the same line * (this becomes important if line numbers are stripped from the class file and everything * appears to be on the same line). + * * @param sourceFileName Optional base name of the source file (this value is strictly for * debugging and does not contribute to either equals() or hashCode() behavior). * diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmLogSites.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmLogSites.java index 7e9b24480..a6468f002 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmLogSites.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmLogSites.java @@ -44,6 +44,7 @@ public final class JvmLogSites { * conjunction with the {@link JvmApi#withInjectedLogSite(JvmLogSite)} method to implement * logging helper methods. In some platforms, log site determination may be unsupported, and in * those cases this method will always return the {@link JvmLogSite#INVALID} instance. + * *

      * For example (in {@code MyLoggingHelper}): *

      {@code
      @@ -53,34 +54,40 @@ public final class JvmLogSites {
          *       .logVarargs(message, args);
          * }
          * }
      + * *

      * This method should be used for the simple cases where the class in which the logging occurs is * a public logging API. If the log statement is in a different class (not the public logging API) * and the {@code LogSite} instance needs to be passed through several layers, consider using * {@link #logSite()} instead to avoid too much "magic" in your code. + * *

      * You should also seek to ensure that any API used with this method "looks like a logging API". * It's no good if a log entry contains a class and method name which doesn't correspond to * anything the user can relate to. In particular, the API should probably always accept the log * message or at least some of its parameters, and should always have methods with "log" in their * names to make the connection clear. + * *

      * It is very important to note that this method can be very slow, since determining the log site * can involve stack trace analysis. It is only recommended that it is used for cases where * logging is expected to occur (e.g. {@code INFO} level or above). Implementing a helper method * for {@code FINE} logging is usually unnecessary (it doesn't normally need to follow any * specific "best practice" behavior). + * *

      * Note that even when log site determination is supported, it is not defined as to whether two * invocations of this method on the same line of code will produce the same instance, equivalent * instances or distinct instance. Thus you should never invoke this method twice in a single * statement (and you should never need to). + * *

      * Note that this method call may be replaced in compiled applications via bytecode manipulation * or other mechanisms to improve performance. * * @param loggingApi the logging API to be identified as the source of log statements (this must * appear somewhere on the stack above the point at which this method is called). + * * @return the log site of the caller of the specified logging API, * or {@link JvmLogSite#INVALID} if the logging API was not found. */ @@ -94,6 +101,7 @@ public static JvmLogSite callerOf(Class loggingApi) { * the {@link JvmApi#withInjectedLogSite(JvmLogSite)} method to implement logging helper * methods. In some platforms, log site determination may be unsupported, and in those cases this * method will always return the {@link JvmLogSite#INVALID} instance. + * *

      * For example (in {@code MyLoggingHelper}): *

      {@code
      @@ -107,21 +115,25 @@ public static JvmLogSite callerOf(Class loggingApi) {
          * 
      {@code
          * MyLoggingHelper.logAndSomethingElse(logSite(), "message...");
          * }
      + * *

      * Because this method adds an additional parameter and exposes a Flogger specific type to the * calling code, you should consider using {@link #callerOf(Class)} for simple logging * utilities. + * *

      * It is very important to note that this method can be very slow, since determining the log site * can involve stack trace analysis. It is only recommended that it is used for cases where * logging is expected to occur (e.g. {@code INFO} level or above). Implementing a helper method * for {@code FINE} logging is usually unnecessary (it doesn't normally need to follow any * specific "best practice" behavior). + * *

      * Note that even when log site determination is supported, it is not defined as to whether two * invocations of this method on the same line of code will produce the same instance, equivalent * instances or distinct instance. Thus you should never invoke this method twice in a single * statement (and you should never need to). + * *

      * Note that this method call may be replaced in compiled applications via bytecode manipulation * or other mechanisms to improve performance. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/LogContext.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/LogContext.java index e408b0f1a..82dd14a98 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/LogContext.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/LogContext.java @@ -387,6 +387,7 @@ public String toString() { * * @param level * the log level for this log statement. + * * @param isForced * whether to force this log statement (see {@link #wasForced()} for details). */ @@ -406,8 +407,10 @@ protected LogContext(Level level, boolean isForced) { * * @param level * the log level for this log statement. + * * @param isForced * whether to force this log statement (see {@link #wasForced()} for details). + * * @param timestampNanos * the nanosecond timestamp for this log statement. */ @@ -524,6 +527,7 @@ public final Metadata getMetadata() { * * @param key * the metadata key (see {@link LogData}). + * * @param value * the metadata value. */ @@ -628,6 +632,7 @@ protected final void removeMetadata(JvmMetadataKey key) { * * @param logSiteKey * used to lookup persistent, per log statement, state. + * * @return true if logging should be attempted (usually based on rate limiter state). */ protected boolean postProcess(@Nullable LogSiteKey logSiteKey) { @@ -703,6 +708,7 @@ protected boolean postProcess(@Nullable LogSiteKey logSiteKey) { * * @param status * a rate limiting status, or {@code null} if the rate limiter was not active. + * * @return whether logging will occur based on the current combined state of * active rate limiters. */ diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/LogPerBucketingStrategy.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/LogPerBucketingStrategy.java index 6b4dcd0a9..6779b03e2 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/LogPerBucketingStrategy.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/LogPerBucketingStrategy.java @@ -254,6 +254,7 @@ protected LogPerBucketingStrategy(String name) { * * @param key * a non-null key from a potentially unbounded set of log aggregation keys. + * * @return an immutable value from some known bounded set, which will be held persistently by * internal Flogger data structures as part of the log aggregation feature. If * {@code null} is diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/LogSiteMap.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/LogSiteMap.java index 0f824d8e8..0abd12f43 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/LogSiteMap.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/LogSiteMap.java @@ -50,6 +50,7 @@ * * @param * The value type in the map. + * * @see * Original Java code of Google Flogger */ diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/LogSiteStackTrace.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/LogSiteStackTrace.java index c1d558a12..b5fbdf1d8 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/LogSiteStackTrace.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/LogSiteStackTrace.java @@ -48,6 +48,7 @@ public final class LogSiteStackTrace extends Exception { /** * Creates a synthetic exception to hold a call-stack generated for the log statement itself. + * *

      * This exception is never expected to actually get thrown or caught at any point. * diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/Middleman.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/Middleman.java index 892cc5308..18a8bc3e2 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/Middleman.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/Middleman.java @@ -36,11 +36,13 @@ /** * The default implementation of {@link AbstractLogger} which returns the basic {@link JvmApi} * and uses the default parser and system configured backend. + * *

      * Note that when extending the logging API or specifying a new parser, you will need to create a * new logger class (rather than extending this one). Unlike the {@link LogContext} class, * which must be extended in order to modify the logging API, this class is not generified and thus * cannot be modified to produce a different logging API. + * *

      * The choice to prevent direct extension of loggers was made deliberately to ensure that users of * a specific logger implementation always get the same behavior. @@ -52,6 +54,7 @@ public final class Middleman extends AbstractLogger { /** * The non-wildcard, fully specified, logging API for this logger. Fluent logger implementations * should specify a non-wildcard API like this with which to generify the abstract logger. + * *

      * It is possible to add methods to this logger-specific API directly, but it is recommended that * a separate top-level API and LogContext is created, allowing it to be shared by other diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/RateLimitStatus.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/RateLimitStatus.java index 2e1eaad55..cf3779830 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/RateLimitStatus.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/RateLimitStatus.java @@ -78,6 +78,7 @@ * final class CustomRateLimiter extends RateLimitStatus { * private static final LogSiteMap map = * new LogSiteMap() { + * * @Override protected CustomRateLimiter initialValue() { * return new CustomRateLimiter(); * } diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/StackSize.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/StackSize.java index cdbb147c7..c4d77c547 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/StackSize.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/StackSize.java @@ -43,12 +43,14 @@ public enum StackSize { * also be useful for {@code WARNING} level log statements in cases where context is not as * important. For {@code SEVERE} log statements, it is advised to use a stack size of * {@link #MEDIUM} or above. + * *

      * Requesting a small stack trace for log statements which occur under normal circumstances is * acceptable, but may affect performance. Consider using * {@link JvmApi#withStackTrace(StackSize)} in conjunction with rate limiting methods, * such as {@link JvmApi#atMostEvery(int, java.util.concurrent.TimeUnit)}, to mitigate * performance issues. + * *

      * The current maximum size of a {@code SMALL} stack trace is 10 elements, but this may change. */ @@ -58,9 +60,11 @@ public enum StackSize { * Produces a medium sized stack suitable for providing contextual information for most log * statements at {@code WARNING} or above. There should be enough stack trace elements in a * {@code MEDIUM} stack to provide sufficient debugging context in most cases. + * *

      * Requesting a medium stack trace for any log statements which can occur regularly under normal * circumstances is not recommended. + * *

      * The current maximum size of a {@code MEDIUM} stack trace is 20 elements, but this may change. */ @@ -70,9 +74,11 @@ public enum StackSize { * Produces a large stack suitable for providing highly detailed contextual information. * This is most useful for {@code SEVERE} log statements which might be processed by external * tools and subject to automated analysis. + * *

      * Requesting a large stack trace for any log statement which can occur under normal circumstances * is not recommended. + * *

      * The current maximum size of a {@code LARGE} stack trace is 50 elements, but this may change. */ @@ -81,6 +87,7 @@ public enum StackSize { /** * Provides the complete stack trace. This is included for situations in which it is known that * the upper-most elements of the stack are definitely required for analysis. + * *

      * Requesting a full stack trace for any log statement which can occur under normal circumstances * is not recommended. @@ -107,6 +114,7 @@ public enum StackSize { /** * Returns the maximum stack depth to create when adding contextual stack information to a log * statement. + * *

      * Note that the precise number of stack elements emitted for the enum values might change over * time, but it can be assumed that {@code NONE < SMALL <= MEDIUM <= LARGE <= FULL}. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/BaseMessageFormatter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/BaseMessageFormatter.java index 2aa1086eb..2ed52e125 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/BaseMessageFormatter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/BaseMessageFormatter.java @@ -66,8 +66,10 @@ public class BaseMessageFormatter extends MessageBuilder * * @param data * the log data with the message to be appended. + * * @param out * a buffer to append to. + * * @return the given buffer (for method chaining). */ @CanIgnoreReturnValue diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatChar.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatChar.java index 46edd7692..95823aa19 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatChar.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatChar.java @@ -32,6 +32,7 @@ * An enum representing the printf-like formatting characters that must be supported by all logging * backends. It is important to note that while backends must accept any of these format specifiers, * they are not obliged to implement all specified formatting behavior. + * *

      * The default term formatter takes care of supporting all these options when expressed in their * normal '%X' form (including flags, width and precision). Custom messages parsers must convert @@ -46,6 +47,7 @@ public enum FormatChar { * Formats the argument in a manner specific to the chosen logging backend. In many cases this * will be equivalent to using {@code STRING}, but it allows backend implementations to log more * structured representations of known types. + * *

      * This is a non-numeric format with an upper-case variant. */ @@ -53,6 +55,7 @@ public enum FormatChar { /** * Formats the argument as a boolean. + * *

      * This is a non-numeric format with an upper-case variant. */ @@ -63,6 +66,7 @@ public enum FormatChar { * integral numeric value, providing that {@link Character#isValidCodePoint(int)} returns * true. Note that if the argument cannot be represented losslessly as an integer, it must be * considered invalid. + * *

      * This is a non-numeric format with an upper-case variant. */ @@ -70,6 +74,7 @@ public enum FormatChar { /** * Formats the argument as a decimal integer. + * *

      * This is a numeric format. */ @@ -77,8 +82,10 @@ public enum FormatChar { /** * Formats the argument as an unsigned octal integer. + * *

      * This is a numeric format. + * *

      * '(' is only supported for {@link java.math.BigInteger} or {@link java.math.BigDecimal} */ @@ -86,8 +93,10 @@ public enum FormatChar { /** * Formats the argument as an unsigned hexadecimal integer. + * *

      * This is a numeric format with an upper-case variant. + * *

      * '(' is only supported for {@link java.math.BigInteger} or {@link java.math.BigDecimal} */ @@ -95,6 +104,7 @@ public enum FormatChar { /** * Formats the argument as a signed decimal floating value. + * *

      * This is a numeric format. */ @@ -102,6 +112,7 @@ public enum FormatChar { /** * Formats the argument using computerized scientific notation. + * *

      * This is a numeric format with an upper-case variant. */ @@ -109,6 +120,7 @@ public enum FormatChar { /** * Formats the argument using general scientific notation. + * *

      * This is a numeric format with an upper-case variant. */ @@ -118,6 +130,7 @@ public enum FormatChar { * Formats the argument using hexadecimal exponential form. This formatting option is primarily * useful when debugging issues with the precise bit-wise representation of doubles because no * rounding of the value takes place. + * *

      * This is a numeric format with an upper-case variant. */ @@ -178,6 +191,7 @@ private static boolean isLowerCase(char letter) { /** * Returns the lower-case printf style formatting character. + * *

      * Note that as this enumeration is not a subset of any other common formatting syntax, it is * not diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatOptions.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatOptions.java index 10002b6ea..5438654ac 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatOptions.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/FormatOptions.java @@ -170,10 +170,13 @@ public static FormatOptions of(int flags, int width, int precision) { * * @param message * the original log message in which the formatting options have been identified. + * * @param pos * the index of the first character to parse. + * * @param end * the index after the last character to be parsed. + * * @return the parsed options instance. * @throws ParseException * if the specified sub-sequence of the string could not be parsed. @@ -293,8 +296,10 @@ private FormatOptions(int flags, int width, int precision) { * @param allowedFlags * A mask of flag values to be retained in the returned instance. Use * {@link #ALL_FLAGS} to retain all flag values, or {@code 0} to suppress all flags. + * * @param allowWidth * specifies whether to include width in the returned instance. + * * @param allowPrecision * specifies whether to include precision in the returned instance. */ @@ -348,6 +353,7 @@ public int getPrecision() { /** * Validates these options according to the allowed criteria and checks for inconsistencies in * flag values. + * *

      * Note that there is not requirement for options used internally in custom message parsers to * be @@ -357,8 +363,10 @@ public int getPrecision() { * @param allowedFlags * a bit mask specifying a subset of the printf flags that are allowed for * these options. + * * @param allowPrecision * true if these options are allowed to have a precision value specified. + * * @return true if these options are valid given the specified constraints. */ public boolean validate(int allowedFlags, boolean allowPrecision) { @@ -399,6 +407,7 @@ static boolean checkFlagConsistency(int flags, boolean hasWidth) { /** * Validates these options as if they were being applied to the given {@link FormatChar} and * checks for inconsistencies in flag values. + * *

      * Note that there is not requirement for options used internally in custom message parsers to * be @@ -408,6 +417,7 @@ static boolean checkFlagConsistency(int flags, boolean hasWidth) { * * @param formatChar * the formatting rule to check these options against. + * * @return true if these options are valid for the given format. */ public boolean areValidFor(FormatChar formatChar) { @@ -426,6 +436,7 @@ public int getFlags() { /** * Corresponds to printf flag '-' (incompatible with '0'). + * *

      * Logging backends may ignore this flag, though it does provide some visual clarity when * aligning @@ -437,6 +448,7 @@ public boolean shouldLeftAlign() { /** * Corresponds to printf flag '#'. + * *

      * Logging backends should honor this flag for hex or octal, as it is a common way to avoid * ambiguity when formatting non-decimal values. @@ -447,6 +459,7 @@ public boolean shouldShowAltForm() { /** * Corresponds to printf flag '0'. + * *

      * Logging backends should honor this flag, as it is very commonly used to format hexadecimal or * octal values to allow specific bit values to be calculated. @@ -457,6 +470,7 @@ public boolean shouldShowLeadingZeros() { /** * Corresponds to printf flag '+'. + * *

      * Logging backends are free to ignore this flag, though it does provide some visual clarity * when @@ -468,6 +482,7 @@ public boolean shouldPrefixPlusForPositiveValues() { /** * Corresponds to printf flag ' '. + * *

      * Logging backends are free to ignore this flag, though if they choose to support * {@link #shouldPrefixPlusForPositiveValues()} then it is advisable to support this as well. @@ -478,6 +493,7 @@ public boolean shouldPrefixSpaceForPositiveValues() { /** * Corresponds to printf flag ','. + * *

      * Logging backends are free to select the locale in which the formatting will occur or ignore * this flag altogether. @@ -488,6 +504,7 @@ public boolean shouldShowGrouping() { /** * Corresponds to formatting with an upper-case format character. + * *

      * Logging backends are free to ignore this flag. */ diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LogData.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LogData.java index 511740c45..f1c1c0cda 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LogData.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LogData.java @@ -32,6 +32,7 @@ /** * A backend API for determining metadata associated with a log statement. + * *

      * Some metadata is expected to be available for all log statements (such as the log level or a * timestamp) whereas other data is optional (class/method name for example). As well providing the diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LoggerBackend.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LoggerBackend.java index ea606a437..a565bf1f5 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LoggerBackend.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LoggerBackend.java @@ -111,6 +111,7 @@ public abstract class LoggerBackend { * that simply trying to log this again will succeed and error handlers must be careful in how * they handle this instance, its arguments and metadata. References to {@code badData} must * not be held after the {@code handleError} invocation returns. + * * @throws LoggingException to indicate an error which should be propagated into user code. */ public abstract void handleError(RuntimeException error, LogData badData); diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LoggingException.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LoggingException.java index e438350eb..0f4c160ff 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LoggingException.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/LoggingException.java @@ -33,6 +33,7 @@ /** * Exception thrown when a log statement cannot be emitted correctly. This exception should only be * thrown by logger backend implementations which have opted not to handle specific issues. + * *

      * Typically a logger backend would only throw {@code LoggingException} in response to issues in * test code or other debugging environments. In production code, the backend should be configured diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataHandler.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataHandler.java index 6b355e617..ddb9eefd8 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataHandler.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataHandler.java @@ -47,6 +47,7 @@ * * @param * the arbitrary context type. + * * @see * Original Java code of Google Flogger @@ -61,10 +62,13 @@ public abstract class MetadataHandler { * * @param key * the metadata key (not necessarily a "singleton" key). + * * @param value * associated metadata value. + * * @param context * an arbitrary context object supplied to the process method. + * * @param * the key/value type. */ @@ -77,11 +81,14 @@ public abstract class MetadataHandler { * * @param key * the repeatable metadata key. + * * @param values * a lightweight iterator over all values associated with the key. Note that this * instance is read-only and must not be held beyond the scope of this callback. + * * @param context * an arbitrary context object supplied to the process method. + * * @param * the key/value type. */ @@ -112,6 +119,7 @@ protected void handleRepeated(JvmMetadataKey key, Iterator values, C c * * @param defaultHandler * the default handler for unknown keys/values. + * * @param * the context type. */ @@ -124,6 +132,7 @@ public static Builder builder(ValueHandler defaultHandler) { * * @param * the key/value type. + * * @param * the type of the context passed to the callbacks. */ @@ -134,8 +143,10 @@ public interface ValueHandler { * * @param key * the metadata key (not necessarily a "singleton" key). + * * @param value * associated metadata value. + * * @param context * an arbitrary context object supplied to the process method. */ @@ -147,6 +158,7 @@ public interface ValueHandler { * * @param * the key/value type. + * * @param * the type of the context passed to the callbacks. */ @@ -158,9 +170,11 @@ public interface RepeatedValueHandler { * @param key * the repeatable metadata key for which this handler was registered, or an unknown * key if this is the default handler. + * * @param values * a lightweight iterator over all values associated with the key. Note that this * instance is read-only and must not be held beyond the scope of this callback. + * * @param context * an arbitrary context object supplied to the process method. */ @@ -208,6 +222,7 @@ private Builder(ValueHandler defaultHandler) { * * @param defaultHandler * the default handler for unknown repeated keys/values. + * * @return the builder instance for chaining. */ @CanIgnoreReturnValue @@ -223,10 +238,13 @@ public Builder setDefaultRepeatedHandler( * * @param key * the key for which the handler should be invoked (can be a repeated key). + * * @param handler * the value handler to be invoked for every value associated with the key. + * * @param * the key/value type. + * * @return the builder instance for chaining. */ @CanIgnoreReturnValue @@ -245,10 +263,13 @@ public Builder addHandler( * * @param key * the repeated key for which the handler should be invoked. + * * @param handler * the repeated value handler to be invoked once for all associated values. + * * @param * the key/value type. + * * @return the builder instance for chaining. */ @CanIgnoreReturnValue @@ -267,8 +288,10 @@ public Builder addRepeatedHandler( * * @param key * a key to ignore in the builder. + * * @param rest * additional keys to ignore in the builder. + * * @return the builder instance for chaining. */ @CanIgnoreReturnValue @@ -285,6 +308,7 @@ public Builder ignoring(JvmMetadataKey key, JvmMetadataKey... rest) { * * @param keys * the keys to ignore in the builder. + * * @return the builder instance for chaining. */ @CanIgnoreReturnValue @@ -313,8 +337,10 @@ void checkAndIgnore(JvmMetadataKey key) { * * @param key * a key to remove from the builder. + * * @param rest * additional keys to remove from the builder. + * * @return the builder instance for chaining. */ @CanIgnoreReturnValue diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataProcessor.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataProcessor.java index c27ab6f01..f743e08d1 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataProcessor.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataProcessor.java @@ -103,8 +103,10 @@ public Set> keySet() { * * @param scopeMetadata * Metadata for the current scope (i.e., from {@code ScopedLoggingContext}) + * * @param logMetadata * Metadata extracted from the current log statement (i.e., from {@code LogData}) + * * @return a processor to handle a unified view of the data */ public static MetadataProcessor forScopeAndLogSite(Metadata scopeMetadata, @@ -159,6 +161,7 @@ private MetadataProcessor() { * * @param handler * the metadata handler to be called back + * * @param context * arbitrary context instance to be passed into each callback. */ diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/Platform.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/Platform.java index 1c817d06f..b2770968a 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/Platform.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/Platform.java @@ -194,6 +194,7 @@ public abstract static class LogCallerFinder { * * @param loggerClass * the class containing the log() methods whose caller we need to find. + * * @return the name of the class that called the specified logger. * @throws IllegalStateException * if there was no caller of the specified logged passed on the @@ -208,9 +209,11 @@ public abstract static class LogCallerFinder { * * @param loggerApi * the class containing the log() methods whose caller we need to find. + * * @param stackFramesToSkip * the number of method calls which exist on the stack between the * {@code log()} method and the point at which this method is invoked. + * * @return A log site inferred from the stack, or {@link JvmLogSite#INVALID} if no log site * can be determined. */ @@ -270,8 +273,10 @@ protected ContextDataProvider getContextDataProviderImpl() { * * @param loggerName * the fully qualified logger name (e.g. "com.example.SomeClass") + * * @param level * the level of the log statement being invoked + * * @param isEnabled * whether the logger is enabled at the given level (i.e., the result of calling * {@code isLoggable()} on the backend instance) @@ -293,6 +298,7 @@ public static boolean shouldForceLogging(String loggerName, Level level, boolean * * @param loggerName * the name of the logger + * * @return the custom level or {@code null} */ public static @Nullable Level getMappedLevel(String loggerName) { diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/SimpleMessageFormatter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/SimpleMessageFormatter.java index 27f41c1e3..a1da41f1b 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/SimpleMessageFormatter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/SimpleMessageFormatter.java @@ -142,11 +142,14 @@ public static LogMessageFormatter getSimpleFormatterIgnoring( * @param metadataProcessor * snapshot of the metadata to be processed ({@link MetadataProcessor} is * reusable so passing one in can save repeated processing of the same metadata). + * * @param metadataHandler * a metadata handler for intercepting and dispatching metadata during * formatting. + * * @param buffer * destination buffer into which the log message and metadata will be appended. + * * @return the given destination buffer (for method chaining). */ @CanIgnoreReturnValue @@ -172,6 +175,7 @@ public static StringBuilder appendContext( * * @param logData * the log statement data. + * * @return the single logged value as a string. * @throws IllegalStateException * if the log data had arguments to be formatted (i.e. there was a @@ -204,8 +208,10 @@ public static String getLiteralLogMessage(LogData logData) { * * @param logData * the log statement data. + * * @param metadata * the metadata intended to be formatted with the log statement. + * * @param keysToIgnore * a set of metadata keys which are known not to appear in the final formatted * message. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/TemplateContext.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/TemplateContext.java index f6dadf98e..6f1ce3d19 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/TemplateContext.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/TemplateContext.java @@ -34,6 +34,7 @@ * A context object for templates that allows caches to validate existing templates or create new * ones. If two template contexts are equal (via {@link #equals}) then the templates they produce * are interchangeable. + * *

      * Template contexts are created by the frontend and passed through to backend implementations via * the {@link LogData} interface. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/SegmentTrie.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/SegmentTrie.java index 71253919a..dddb77ac1 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/SegmentTrie.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/SegmentTrie.java @@ -247,10 +247,13 @@ public T find(String key) { * * @param k * the key whose parent value we wish to find. + * * @param idx * the index of the closest matching key in the trie ({@code k < keys[idx]}). + * * @param len * the common prefix length between {@code k} and {@code keys[idx]}. + * * @return the value of the nearest parent of {@code k}. */ private T findParent(String k, int idx, int len) { @@ -282,8 +285,10 @@ private T findParent(String k, int idx, int len) { * * @param p * the candidate parent key to check. + * * @param k * the key whose parent we are looking for. + * * @param len * the maximum length of any possible parent of {@code k}. */ @@ -312,11 +317,14 @@ private boolean isParent(String p, String k, int len) { * * @param lhs * first value to compare. + * * @param rhs * second value to compare. + * * @param start * a lower bound for the common prefix length of the given keys, which must be * {@code <= min(lhs.length(), rhs.length())}. + * * @return the common prefix length, encoded to indicate lexicographical ordering. */ private static int prefixCompare(String lhs, String rhs, int start) { diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/BraceStyleParameter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/BraceStyleParameter.java index 36ae60437..d27efebb9 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/BraceStyleParameter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/BraceStyleParameter.java @@ -74,6 +74,7 @@ public class BraceStyleParameter extends Parameter { * * @param index * the index of the argument to be processed. + * * @return the immutable, thread safe parameter instance. */ public static BraceStyleParameter of(int index) { diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeParameter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeParameter.java index f1143cffa..1b22bb6a2 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeParameter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeParameter.java @@ -30,6 +30,7 @@ /** * A parameter for formatting date/time arguments. + * *

      * This class is immutable and thread safe, as per the Parameter contract. * diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/Parameter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/Parameter.java index 11e58c284..7603e1445 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/Parameter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/Parameter.java @@ -30,10 +30,12 @@ /** * An abstract representation of a parameter for a message template. + * *

      * Note that this is implemented as a class (rather than via an interface) because it is very * helpful to have explicit checks for the index values and count to ensure we can calculate * reliable low bounds for the number of arguments a template can accept. + * *

      * Note that all subclasses of Parameter must be immutable and thread safe. * @@ -51,6 +53,7 @@ public abstract class Parameter { * * @param options * the format options for this parameter. + * * @param index * the index of the argument processed by this parameter. */ diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/ParameterVisitor.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/ParameterVisitor.java index dce687fd0..c814212f5 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/ParameterVisitor.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/ParameterVisitor.java @@ -39,6 +39,7 @@ public interface ParameterVisitor { /** * Visits a log message argument with formatting specified by {@code %s}, {@code %d} etc... + * *

      * Note that this method may still visit arguments which represent date/time values if the format * is not explicit (e.g. {@code log("time=%s", dateTime)}). @@ -51,6 +52,7 @@ public interface ParameterVisitor { /** * Visits a date/time log message argument with formatting specified by {@code %t} or similar. + * *

      * Note that because this method is called based on the specified format (and not the argument * type) it may visit arguments whose type is not a known date/time value. This is necessary to @@ -65,6 +67,7 @@ public interface ParameterVisitor { /** * Visits a log message argument for which formatting has already occurred. This method is only * invoked when non-printf message formatting is used (e.g. brace style formatting). + * *

      * This method is intended for use by {@code Parameter} implementations which describe formatting * rules which cannot by represented by either {@link FormatChar} or {@link DateTimeFormat}. This diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/SimpleParameter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/SimpleParameter.java index 200308615..f06153a68 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/SimpleParameter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/SimpleParameter.java @@ -38,6 +38,7 @@ /** * A simple, single argument, parameter which can format arguments according to the rules specified * by {@link FormatChar}. + * *

      * This class is immutable and thread safe, as per the Parameter contract. * @@ -75,10 +76,13 @@ private static SimpleParameter[] createParameterArray(FormatChar formatChar) { * * @param index * the index of the argument to be processed. + * * @param formatChar * the basic formatting type. + * * @param options * additional formatting options. + * * @return the immutable, thread safe parameter instance. */ public static SimpleParameter of(int index, FormatChar formatChar, FormatOptions options) { diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/BraceStyleMessageParser.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/BraceStyleMessageParser.java index 09a82d32c..74316cd26 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/BraceStyleMessageParser.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/BraceStyleMessageParser.java @@ -31,6 +31,7 @@ * {@link java.text.MessageFormat MessageFormat}. This is an abstract parser which knows how to * process and extract place-holder terms at a high level, but does not impose its own semantics * on formatting extensions (eg, "{0,number,#.##}"). + * *

      * Typically you should not subclass this class, but instead subclass * {@link DefaultBraceStyleMessageParser}, which provides default behavior for simple place-holders. @@ -49,6 +50,7 @@ public abstract class BraceStyleMessageParser extends MessageParser { * Parses a single brace format term from a log message into a message template builder. Note that * the default brace style parser currently does not handle anything other than the simplest "{n}" * forms of parameter specification, and it will treat anything more complex as a parsing error. + * *

      * A simple example of a positional parameter: *

      @@ -57,6 +59,7 @@ public abstract class BraceStyleMessageParser extends MessageParser {
          * formatStart: -1    │
          * termEnd: 9 ────────╯
          * 
      + * *

      * A more complex example with a trailing format specification: *

      @@ -72,6 +75,7 @@ public abstract class BraceStyleMessageParser extends MessageParser {
          * @param termStart the index of the initial '{' character that starts the term.
          * @param formatStart the index of the optional formatting substring after the first comma
          *        (which extends to {@code termEnd - 1}) or -1 if there is no formatting substring.
      + *
          * @param termEnd the index after the final '}' character that completes this term.
          */
         abstract void parseBraceFormatTerm(
      diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultBraceStyleMessageParser.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultBraceStyleMessageParser.java
      index bf9773f79..347ab7b2d 100644
      --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultBraceStyleMessageParser.java
      +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultBraceStyleMessageParser.java
      @@ -33,6 +33,7 @@
        * mechanism supports the more general "{n,xxx}" form for brace format style logging, the default
        * message parser is currently limited to simple indexed place holders (e.g. "{0}"). This class
        * could easily be extended to support these trailing format specifiers.
      + *
        * 

      * Note also that the implicit place holder syntax used by Log4J (i.e. "{}") is not currently * supported, however this may change. Currently an unescaped "{}" term in a log message will cause diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultPrintfMessageParser.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultPrintfMessageParser.java index e6cfa7085..e23b64756 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultPrintfMessageParser.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultPrintfMessageParser.java @@ -42,6 +42,7 @@ * available in {@code String#format} but can be extended, if desired, for additional behavior * For consistency it is recommended, but not required, that custom printf parsers always extend * from this class. + * *

      * This class is immutable and thread safe (and any subclasses must also be so). * diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/MessageBuilder.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/MessageBuilder.java index d57f754a0..866209bb7 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/MessageBuilder.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/MessageBuilder.java @@ -37,6 +37,7 @@ * * @param * The message type being built. + * * @see * Original Java code of Google Flogger @@ -84,9 +85,11 @@ public final int getExpectedArgumentCount() { * @param termStart * the index of the first character in the log message string that was parsed to * form the given parameter. + * * @param termEnd * the index after the last character in the log message string that was parsed to * form the given parameter. + * * @param param * a parameter representing the format specified by the substring of the log message * in the range {@code [termStart, termEnd)}. @@ -104,6 +107,7 @@ public final void addParameter(int termStart, int termEnd, Parameter param) { /** * Adds the specified parameter to the format instance currently being built. This method is to * signify that the parsing of the next parameter is complete. + * *

      * Note that each successive call to this method during parsing will specify a disjoint ranges * of @@ -113,9 +117,11 @@ public final void addParameter(int termStart, int termEnd, Parameter param) { * @param termStart * the index of the first character in the log message string that was parsed to * form the given parameter. + * * @param termEnd * the index after the last character in the log message string that was parsed to * form the given parameter. + * * @param param * a parameter representing the format specified by the substring of the log message * in the range {@code [termStart, termEnd)}. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/MessageParser.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/MessageParser.java index d25bb312d..41738e401 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/MessageParser.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/MessageParser.java @@ -43,11 +43,13 @@ public abstract class MessageParser { /** * Abstract parse method implemented by specific subclasses to modify parsing behavior. + * *

      * Note that when extending parsing behavior, it is expected that specific parsers such as * {@link DefaultPrintfMessageParser} or {@link DefaultBraceStyleMessageParser} will be * sub-classed. Extending this class directly is only necessary when an entirely new type of * format needs to be supported (which should be extremely rare). + * *

      * Implementations of this method are required to invoke the * {@link MessageBuilder#addParameterImpl} method of the supplied builder once for each diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/ParseException.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/ParseException.java index 8ff2cb0c9..c892509b5 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/ParseException.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/ParseException.java @@ -61,12 +61,16 @@ public final class ParseException extends RuntimeException { * * @param errorMessage * the user error message. + * * @param logMessage * the original log message. + * * @param start * the index of the first character in the invalid section of the log message. + * * @param end * the index after the last character in the invalid section of the log message. + * * @return the parser exception. */ public static ParseException withBounds( @@ -79,10 +83,13 @@ public static ParseException withBounds( * * @param errorMessage * the user error message. + * * @param logMessage * the original log message. + * * @param position * the index of the invalid character in the log message. + * * @return the parser exception. */ public static ParseException atPosition(String errorMessage, String logMessage, int position) { @@ -95,10 +102,13 @@ public static ParseException atPosition(String errorMessage, String logMessage, * * @param errorMessage * the user error message. + * * @param logMessage * the original log message. + * * @param start * the index of the first character in the invalid section of the log message. + * * @return the parser exception. */ public static ParseException withStartPosition( diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/PrintfMessageParser.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/PrintfMessageParser.java index 36668c3c0..9b4f5abb8 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/PrintfMessageParser.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/PrintfMessageParser.java @@ -31,6 +31,7 @@ * {@link String#format}. This is an abstract parser which knows how to * process and extract placeholder terms at a high level, but does not impose its own semantics * for place-holder types. + * *

      * Typically you should not subclass this class, but instead subclass * {@link DefaultPrintfMessageParser}, which provides compatibility with {@link String#format}. @@ -61,6 +62,7 @@ static String getSafeSystemNewline() { /** * Parses a single printf-like term from a log message into a message template builder. + * *

      * A simple example of an implicit parameter (the argument index is not specified): *

      @@ -71,6 +73,7 @@ static String getSafeSystemNewline() {
          * return: 8 ────────╯
          * 
      * If this case there is no format specification, so {@code specStart == formatStart}. + * *

      * A complex example with an explicit index: *

      @@ -89,6 +92,7 @@ static String getSafeSystemNewline() {
          * @param termStart the index of the initial '%' character that starts the term.
          * @param specStart the index of the first format specification character (after any optional
          *        index specification).
      + *
          * @param formatStart the index of the (first) format character in the term.
          * @return the index after the last character of the term.
          */
      
      From 38ca9dd645cc40e62e024fc217ba5cbddd2e9b60 Mon Sep 17 00:00:00 2001
      From: Alexander Yevsyukov 
      Date: Thu, 26 Jun 2025 11:31:08 +0100
      Subject: [PATCH 12/28] Remove the `Jvm` prefix in `JvmMetadataKey`
      
      ---
       .../logging/backend/jul/JulRecordSpec.kt      |  4 +-
       .../backend/log4j2/Log4j2LogEventUtil.java    |  8 +--
       .../logging/backend/log4j2/ValueQueue.java    |  2 +-
       .../grpc/GrpcScopedLoggingContext.java        |  4 +-
       .../java/io/spine/logging/jvm/JvmApi.java     | 14 ++---
       .../java/io/spine/logging/jvm/LogContext.java | 60 +++++++++----------
       .../{JvmMetadataKey.java => MetadataKey.java} | 22 +++----
       .../jvm/backend/KeyValueFormatter.java        |  2 +-
       .../spine/logging/jvm/backend/Metadata.java   | 14 ++---
       .../logging/jvm/backend/MetadataHandler.java  | 50 ++++++++--------
       .../jvm/backend/MetadataKeyValueHandlers.java | 12 ++--
       .../jvm/backend/MetadataProcessor.java        | 52 ++++++++--------
       .../jvm/backend/SimpleMessageFormatter.java   | 16 ++---
       .../logging/jvm/context/ContextMetadata.java  | 24 ++++----
       .../jvm/context/NoOpContextDataProvider.java  |  4 +-
       .../jvm/context/ScopedLoggingContext.java     |  6 +-
       .../jvm/context/ScopedLoggingContexts.java    |  4 +-
       .../io/spine/logging/jvm/JvmMetadataKeys.kt   | 12 ++--
       .../spine/logging/jvm/JvmMetadataKeySpec.kt   | 14 ++---
       .../jvm/backend/MetadataHandlerSpec.kt        | 12 ++--
       .../jvm/backend/MetadataProcessorSpec.kt      | 12 ++--
       .../logging/jvm/backend/given/FakeLogData.kt  |  4 +-
       .../logging/jvm/backend/given/FakeMetadata.kt | 10 ++--
       .../jvm/backend/given/MetadataAssertions.kt   | 14 ++---
       .../logging/jvm/given/MemoizingKvHandler.kt   |  4 +-
       .../kotlin/io/spine/logging/JvmMetadataKey.kt |  6 +-
       26 files changed, 193 insertions(+), 193 deletions(-)
       rename jvm/middleware/src/main/java/io/spine/logging/jvm/{JvmMetadataKey.java => MetadataKey.java} (95%)
      
      diff --git a/backends/jul-backend/src/test/kotlin/io/spine/logging/backend/jul/JulRecordSpec.kt b/backends/jul-backend/src/test/kotlin/io/spine/logging/backend/jul/JulRecordSpec.kt
      index fb84982a3..908f69ab1 100644
      --- a/backends/jul-backend/src/test/kotlin/io/spine/logging/backend/jul/JulRecordSpec.kt
      +++ b/backends/jul-backend/src/test/kotlin/io/spine/logging/backend/jul/JulRecordSpec.kt
      @@ -35,7 +35,7 @@ import io.kotest.matchers.string.shouldContain
       import io.kotest.matchers.string.shouldEndWith
       import io.kotest.matchers.string.shouldNotContain
       import io.kotest.matchers.types.shouldBeSameInstanceAs
      -import io.spine.logging.jvm.JvmMetadataKey
      +import io.spine.logging.jvm.MetadataKey
       import io.spine.logging.jvm.LogContext.Key
       import io.spine.logging.jvm.backend.Metadata
       import io.spine.logging.jvm.backend.given.FakeLogData
      @@ -62,7 +62,7 @@ internal class JulRecordSpec {
               private val INT_KEY = singleKey("int")
               private val STR_KEY = singleKey("str")
               private val PATH_KEY =
      -            object : JvmMetadataKey("path", String::class.java, true) {
      +            object : MetadataKey("path", String::class.java, true) {
                       override fun emitRepeated(values: Iterator, out: KeyValueHandler) {
                           val joined = values.asSequence().joinToString("/")
                           out.handle(label, joined)
      diff --git a/backends/log4j2-backend/src/main/java/io/spine/logging/backend/log4j2/Log4j2LogEventUtil.java b/backends/log4j2-backend/src/main/java/io/spine/logging/backend/log4j2/Log4j2LogEventUtil.java
      index 0994a02ee..e7e2c0b33 100644
      --- a/backends/log4j2-backend/src/main/java/io/spine/logging/backend/log4j2/Log4j2LogEventUtil.java
      +++ b/backends/log4j2-backend/src/main/java/io/spine/logging/backend/log4j2/Log4j2LogEventUtil.java
      @@ -33,7 +33,7 @@
       
       import io.spine.logging.jvm.LogContext;
       import io.spine.logging.jvm.JvmLogSite;
      -import io.spine.logging.jvm.JvmMetadataKey;
      +import io.spine.logging.jvm.MetadataKey;
       import io.spine.logging.jvm.backend.BaseMessageFormatter;
       import io.spine.logging.jvm.backend.LogData;
       import io.spine.logging.jvm.backend.MessageUtils;
      @@ -205,11 +205,11 @@ private static void appendLogData(LogData data, StringBuilder out) {
           out.append("\n  line number: ").append(data.getLogSite().getLineNumber());
         }
       
      -  private static final MetadataHandler HANDLER =
      +  private static final MetadataHandler HANDLER =
             MetadataHandler.builder(Log4j2LogEventUtil::handleMetadata).build();
       
         private static void handleMetadata(
      -          JvmMetadataKey key, Object value, JvmMetadataKey.KeyValueHandler kvh) {
      +          MetadataKey key, Object value, MetadataKey.KeyValueHandler kvh) {
           if (key.getClass().equals(LogContext.Key.TAGS.getClass())) {
             processTags(key, value, kvh);
           } else {
      @@ -225,7 +225,7 @@ private static void handleMetadata(
         }
       
         private static void processTags(
      -          JvmMetadataKey key, Object value, JvmMetadataKey.KeyValueHandler kvh) {
      +          MetadataKey key, Object value, MetadataKey.KeyValueHandler kvh) {
           ValueQueue valueQueue = ValueQueue.appendValueToNewQueue(value);
           // Unlike single metadata (which is usually formatted as a single value), tags are always
           // formatted as a list.
      diff --git a/backends/log4j2-backend/src/main/java/io/spine/logging/backend/log4j2/ValueQueue.java b/backends/log4j2-backend/src/main/java/io/spine/logging/backend/log4j2/ValueQueue.java
      index 067c197a8..9922e09ee 100644
      --- a/backends/log4j2-backend/src/main/java/io/spine/logging/backend/log4j2/ValueQueue.java
      +++ b/backends/log4j2-backend/src/main/java/io/spine/logging/backend/log4j2/ValueQueue.java
      @@ -28,7 +28,7 @@
       
       import static io.spine.logging.jvm.util.Checks.checkNotNull;
       
      -import io.spine.logging.jvm.JvmMetadataKey.KeyValueHandler;
      +import io.spine.logging.jvm.MetadataKey.KeyValueHandler;
       import io.spine.logging.jvm.context.Tags;
       import java.util.Iterator;
       import java.util.LinkedList;
      diff --git a/contexts/grpc-context/src/main/java/io/spine/logging/context/grpc/GrpcScopedLoggingContext.java b/contexts/grpc-context/src/main/java/io/spine/logging/context/grpc/GrpcScopedLoggingContext.java
      index 1a27ac022..67e3c3e2e 100644
      --- a/contexts/grpc-context/src/main/java/io/spine/logging/context/grpc/GrpcScopedLoggingContext.java
      +++ b/contexts/grpc-context/src/main/java/io/spine/logging/context/grpc/GrpcScopedLoggingContext.java
      @@ -28,7 +28,7 @@
       
       import static io.spine.logging.jvm.util.Checks.checkNotNull;
       
      -import io.spine.logging.jvm.JvmMetadataKey;
      +import io.spine.logging.jvm.MetadataKey;
       import io.spine.logging.jvm.context.ContextMetadata;
       import io.spine.logging.jvm.context.LogLevelMap;
       import io.spine.logging.jvm.context.ScopeType;
      @@ -99,7 +99,7 @@ public boolean addTags(Tags tags) {
         }
       
         @Override
      -  public  boolean addMetadata(JvmMetadataKey key, T value) {
      +  public  boolean addMetadata(MetadataKey key, T value) {
           // Serves as the null pointer check, and we don't care much about the extra allocation in the
           // case where there's no context, because that should be very rare (and the singleton is small).
           ContextMetadata metadata = ContextMetadata.singleton(key, value);
      diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmApi.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmApi.java
      index fcae9d50e..2a1b94845 100644
      --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmApi.java
      +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmApi.java
      @@ -339,7 +339,7 @@ public interface JvmApi> {
          *   
    • Key value pairs which are explicitly extracted from logs by tools. * * - *

      Metadata keys can support repeated values (see {@link JvmMetadataKey#canRepeat()}), and if a + *

      Metadata keys can support repeated values (see {@link MetadataKey#canRepeat()}), and if a * repeatable key is used multiple times in the same log statement, the effect is to collect all * the given values in order. If a non-repeatable key is passed multiple times, only the last * value is retained (though callers should not rely on this behavior and should simply avoid @@ -353,9 +353,9 @@ public interface JvmApi> { * allowed, but the effect is always a no-op * * @throws NullPointerException if the given key is null - * @see JvmMetadataKey + * @see MetadataKey */ - API with(JvmMetadataKey key, @Nullable T value); + API with(MetadataKey key, @Nullable T value); /** * Sets a boolean metadata key constant to {@code true} for this log statement in a structured way @@ -374,9 +374,9 @@ public interface JvmApi> { * * @param key the boolean metadata key (expected to be a static constant) * @throws NullPointerException if the given key is null - * @see JvmMetadataKey + * @see MetadataKey */ - API with(JvmMetadataKey key); + API with(MetadataKey key); /** * Sets the log site for the current log statement. Explicit log site injection is very rarely @@ -866,14 +866,14 @@ public final boolean isEnabled() { } @Override - public final API with(JvmMetadataKey key, @Nullable T value) { + public final API with(MetadataKey key, @Nullable T value) { // Identical to the check in LogContext for consistency. checkNotNull(key, "metadata key"); return noOp(); } @Override - public final API with(JvmMetadataKey key) { + public final API with(MetadataKey key) { // Do this inline rather than calling with(key, true) to keep no-op minimal. checkNotNull(key, "metadata key"); return noOp(); diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/LogContext.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/LogContext.java index 82dd14a98..71860ba8f 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/LogContext.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/LogContext.java @@ -84,36 +84,36 @@ private Key() { * This * value is set by {@link JvmApi#withCause(Throwable)}. */ - public static final JvmMetadataKey LOG_CAUSE = - JvmMetadataKey.single("cause", Throwable.class); + public static final MetadataKey LOG_CAUSE = + MetadataKey.single("cause", Throwable.class); /** * The key associated with a rate limiting counter for "1-in-N" rate limiting. The value is * set by {@link JvmApi#every(int)}. */ - public static final JvmMetadataKey LOG_EVERY_N = - JvmMetadataKey.single("ratelimit_count", Integer.class); + public static final MetadataKey LOG_EVERY_N = + MetadataKey.single("ratelimit_count", Integer.class); /** * The key associated with a rate limiting counter for "1-in-N" randomly sampled rate * limiting. The value is set by {@link JvmApi#onAverageEvery(int)}. */ - public static final JvmMetadataKey LOG_SAMPLE_EVERY_N = - JvmMetadataKey.single("sampling_count", Integer.class); + public static final MetadataKey LOG_SAMPLE_EVERY_N = + MetadataKey.single("sampling_count", Integer.class); /** * The key associated with a rate limiting period for "at most once every N" rate limiting. * The value is set by {@link JvmApi#atMostEvery(int, TimeUnit)}. */ - public static final JvmMetadataKey LOG_AT_MOST_EVERY = - JvmMetadataKey.single("ratelimit_period", RateLimitPeriod.class); + public static final MetadataKey LOG_AT_MOST_EVERY = + MetadataKey.single("ratelimit_period", RateLimitPeriod.class); /** * The key associated with a count of rate limited logs. This is only public so backends can * reference the key to control formatting. */ - public static final JvmMetadataKey SKIPPED_LOG_COUNT = - JvmMetadataKey.single("skipped", Integer.class); + public static final MetadataKey SKIPPED_LOG_COUNT = + MetadataKey.single("skipped", Integer.class); /** * The key associated with a sequence of log site "grouping keys". These serve to specialize @@ -121,8 +121,8 @@ private Key() { * used by the {@code per()} methods and is only public so backends can reference the key to * control formatting. */ - public static final JvmMetadataKey LOG_SITE_GROUPING_KEY = - new JvmMetadataKey<>("group_by", Object.class, true) { + public static final MetadataKey LOG_SITE_GROUPING_KEY = + new MetadataKey<>("group_by", Object.class, true) { @Override public void emitRepeated(Iterator keys, KeyValueHandler out) { if (keys.hasNext()) { @@ -179,8 +179,8 @@ public void emitRepeated(Iterator keys, KeyValueHandler out) { * statement itself. Thus it makes no sense to provide a public method to set this value * programmatically for a log statement. */ - public static final JvmMetadataKey WAS_FORCED = - JvmMetadataKey.single("forced", Boolean.class); + public static final MetadataKey WAS_FORCED = + MetadataKey.single("forced", Boolean.class); /** * The key associated with any injected {@link Tags}. @@ -195,8 +195,8 @@ public void emitRepeated(Iterator keys, KeyValueHandler out) { * data. Users should never build new {@link Tags} instances just to pass them into a log * statement. */ - public static final JvmMetadataKey TAGS = - new JvmMetadataKey<>("tags", Tags.class, false) { + public static final MetadataKey TAGS = + new MetadataKey<>("tags", Tags.class, false) { @Override public void emit(Tags tags, KeyValueHandler out) { for (Map.Entry> e : tags.asMap() @@ -217,8 +217,8 @@ public void emit(Tags tags, KeyValueHandler out) { * Key associated with the metadata for specifying additional stack information with a log * statement. */ - public static final JvmMetadataKey CONTEXT_STACK_SIZE = - JvmMetadataKey.single("stack_size", StackSize.class); + public static final MetadataKey CONTEXT_STACK_SIZE = + MetadataKey.single("stack_size", StackSize.class); } static final class MutableMetadata extends Metadata { @@ -252,11 +252,11 @@ public int size() { } @Override - public JvmMetadataKey getKey(int n) { + public MetadataKey getKey(int n) { if (n >= keyValueCount) { throw new IndexOutOfBoundsException(); } - return (JvmMetadataKey) keyValuePairs[2 * n]; + return (MetadataKey) keyValuePairs[2 * n]; } @Override @@ -267,7 +267,7 @@ public Object getValue(int n) { return keyValuePairs[(2 * n) + 1]; } - private int indexOf(JvmMetadataKey key) { + private int indexOf(MetadataKey key) { for (var index = 0; index < keyValueCount; index++) { if (keyValuePairs[2 * index].equals(key)) { return index; @@ -278,7 +278,7 @@ private int indexOf(JvmMetadataKey key) { @Override @Nullable - public T findValue(JvmMetadataKey key) { + public T findValue(MetadataKey key) { var index = indexOf(key); return index != -1 ? key.cast(keyValuePairs[(2 * index) + 1]) : null; } @@ -289,7 +289,7 @@ public T findValue(JvmMetadataKey key) { * cannot be repeated, and there is already a value for the key in the metadata, then the * existing value is replaced, otherwise the value is added at the end of the metadata. */ - void addValue(JvmMetadataKey key, T value) { + void addValue(MetadataKey key, T value) { if (!key.canRepeat()) { var index = indexOf(key); if (index != -1) { @@ -309,7 +309,7 @@ void addValue(JvmMetadataKey key, T value) { keyValueCount += 1; } - private static @NonNull JvmMetadataKey checkKey(JvmMetadataKey key) { + private static @NonNull MetadataKey checkKey(MetadataKey key) { return checkNotNull(key, "metadata key"); } @@ -318,7 +318,7 @@ void addValue(JvmMetadataKey key, T value) { } /** Removes all key/value pairs for a given key. */ - private void removeAllValues(JvmMetadataKey key) { + private void removeAllValues(MetadataKey key) { var index = indexOf(key); if (index >= 0) { var dest = 2 * index; @@ -531,7 +531,7 @@ public final Metadata getMetadata() { * @param value * the metadata value. */ - protected final void addMetadata(JvmMetadataKey key, T value) { + protected final void addMetadata(MetadataKey key, T value) { if (metadata == null) { metadata = new MutableMetadata(); } @@ -547,7 +547,7 @@ protected final void addMetadata(JvmMetadataKey key, T value) { * @param key * the metadata key (see {@link LogData}). */ - protected final void removeMetadata(JvmMetadataKey key) { + protected final void removeMetadata(MetadataKey key) { if (metadata != null) { metadata.removeAllValues(key); } @@ -863,7 +863,7 @@ public final boolean isEnabled() { } @Override - public final API with(JvmMetadataKey key, @Nullable T value) { + public final API with(MetadataKey key, @Nullable T value) { // Null keys are always bad (even if the value is also null). This is one of the few places // where the logger API will throw a runtime exception (and as such it's important to ensure // the NoOp implementation also does the check). The reasoning for this is that the metadata @@ -877,7 +877,7 @@ public final API with(JvmMetadataKey key, @Nullable T value) { } @Override - public final API with(JvmMetadataKey key) { + public final API with(MetadataKey key) { return with(key, Boolean.TRUE); } @@ -921,7 +921,7 @@ public final API onAverageEvery(int n) { return everyImpl(Key.LOG_SAMPLE_EVERY_N, n, "sampling"); } - private API everyImpl(JvmMetadataKey key, int n, String label) { + private API everyImpl(MetadataKey key, int n, String label) { // See wasForced() for discussion as to why this occurs before argument checking. if (wasForced()) { return api(); diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmMetadataKey.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/MetadataKey.java similarity index 95% rename from jvm/middleware/src/main/java/io/spine/logging/jvm/JvmMetadataKey.java rename to jvm/middleware/src/main/java/io/spine/logging/jvm/MetadataKey.java index 1804a5e0d..d4d0d4207 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/JvmMetadataKey.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/MetadataKey.java @@ -60,7 +60,7 @@ * {@code equals()} (rather than '==') since this will be safe in cases where non-singleton keys * exist, and is just as fast if the keys are singletons. * - *

      It is strongly recommended that any public {@link JvmMetadataKey} instances are defined + *

      It is strongly recommended that any public {@link MetadataKey} instances are defined * as {@code public static final} fields in a top-level or nested class, which does no logging. * Ideally a separate class would be defined to hold only the keys, since this allows keys * to be loaded very early in the logging {@link Platform} lifecycle without risking any static @@ -88,13 +88,13 @@ * rendered as part of the log statement in a default format. * *

      Note that some metadata entries are handled before being processed by the backend - * (e.g. rate limiting), but a metadata entry remains present to record the that rate limiting + * (e.g., rate limiting), but a metadata entry remains present to record the that rate limiting * was enabled. * * @see * Original Java code of Google Flogger */ -public class JvmMetadataKey { +public class MetadataKey { // High levels of reentrant logging could well be caused by custom metadata keys. This is set // lower than the total limit on reentrant logging because it's one of the more likely ways in // which unbounded reentrant logging could occur, but it's also easy to mitigate. @@ -104,7 +104,7 @@ public class JvmMetadataKey { * Callback interface to handle additional contextual {@code Metadata} in log statements. This * interface is only intended to be implemented by logger backend classes as part of handling * metadata, and should not be used in any general application code, other than to implement the - * {@link JvmMetadataKey#emit} method in this class. + * {@link MetadataKey#emit} method in this class. */ public interface KeyValueHandler { /** Handle a single key/value a pair of contextual metadata for a log statement. */ @@ -127,8 +127,8 @@ public interface KeyValueHandler { * primitive class may lead to a runtime exception because metadata keys * are used with generics. */ - public static JvmMetadataKey single(String label, Class clazz) { - return new JvmMetadataKey<>(label, clazz, false, false); + public static MetadataKey single(String label, Class clazz) { + return new MetadataKey<>(label, clazz, false, false); } /** @@ -147,8 +147,8 @@ public static JvmMetadataKey single(String label, Class claz * primitive class may lead to a runtime exception because metadata keys * are used with generics. */ - public static JvmMetadataKey repeated(String label, Class clazz) { - return new JvmMetadataKey<>(label, clazz, true, false); + public static MetadataKey repeated(String label, Class clazz) { + return new MetadataKey<>(label, clazz, true, false); } private final String label; @@ -162,14 +162,14 @@ public static JvmMetadataKey repeated(String label, Class clazz) { * but occasionally it can be useful to create a specific subtype to control the formatting of * values or to have a family of related keys with a common parent type. */ - protected JvmMetadataKey(String label, Class clazz, boolean canRepeat) { + protected MetadataKey(String label, Class clazz, boolean canRepeat) { this(label, clazz, canRepeat, true); } // Private constructor to allow instances generated by static factory methods to be marked as // non-custom. - private JvmMetadataKey(String label, Class clazz, - boolean canRepeat, boolean isCustom) { + private MetadataKey(String label, Class clazz, + boolean canRepeat, boolean isCustom) { this.label = checkMetadataIdentifier(label); this.clazz = checkNotNull(clazz, "class"); this.canRepeat = canRepeat; diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/KeyValueFormatter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/KeyValueFormatter.java index 894167e4a..fdaa90c02 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/KeyValueFormatter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/KeyValueFormatter.java @@ -26,7 +26,7 @@ package io.spine.logging.jvm.backend; -import io.spine.logging.jvm.JvmMetadataKey.KeyValueHandler; +import io.spine.logging.jvm.MetadataKey.KeyValueHandler; import java.util.Arrays; import java.util.HashSet; import java.util.Set; diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/Metadata.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/Metadata.java index d140db0ca..9b8f62ea6 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/Metadata.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/Metadata.java @@ -26,7 +26,7 @@ package io.spine.logging.jvm.backend; -import io.spine.logging.jvm.JvmMetadataKey; +import io.spine.logging.jvm.MetadataKey; import org.jspecify.annotations.Nullable; /** @@ -34,7 +34,7 @@ * directly via methods in the fluent API, of as part of a scoped logging context. * *

      Metadata keys can be “single valued” or “repeating” based on - * {@link JvmMetadataKey#canRepeat() MetadataKey.canRepeat()}, but it is permitted for + * {@link MetadataKey#canRepeat() MetadataKey.canRepeat()}, but it is permitted for * a {@code Metadata} implementation to retain multiple single valued keys, and in that situation * the key at the largest index is the one that should be used. * @@ -43,7 +43,7 @@ * of the sequence of key/value pairs, and this is what results in the potential for multiple single * valued keys to exist. * - *

      If the value of a single valued key is required, the {@link #findValue(JvmMetadataKey)} + *

      If the value of a single valued key is required, the {@link #findValue(MetadataKey)} * method should be used to look it up. For all other metadata processing, a {@link MetadataProcessor} * should be created to ensure that scope and log site metadata can be merged correctly. * @@ -70,7 +70,7 @@ public int size() { } @Override - public JvmMetadataKey getKey(int n) { + public MetadataKey getKey(int n) { throw cannotReadFromEmpty(); } @@ -85,7 +85,7 @@ private static IndexOutOfBoundsException cannotReadFromEmpty() { @Override @Nullable - public T findValue(JvmMetadataKey key) { + public T findValue(MetadataKey key) { return null; } } @@ -99,7 +99,7 @@ public T findValue(JvmMetadataKey key) { * @throws IndexOutOfBoundsException if either {@code n} is negative or {@code n} is greater * or equal to {@code getCount()}. */ - public abstract JvmMetadataKey getKey(int n); + public abstract MetadataKey getKey(int n); /** * Returns the non-null value for the Nth piece of metadata. @@ -116,5 +116,5 @@ public T findValue(JvmMetadataKey key) { */ // TODO(dbeaumont): Make this throw an exception for repeated keys. @Nullable - public abstract T findValue(JvmMetadataKey key); + public abstract T findValue(MetadataKey key); } diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataHandler.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataHandler.java index ddb9eefd8..a48ca46ab 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataHandler.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataHandler.java @@ -27,7 +27,7 @@ package io.spine.logging.jvm.backend; import com.google.errorprone.annotations.CanIgnoreReturnValue; -import io.spine.logging.jvm.JvmMetadataKey; +import io.spine.logging.jvm.MetadataKey; import java.util.HashMap; import java.util.Iterator; @@ -72,7 +72,7 @@ public abstract class MetadataHandler { * @param * the key/value type. */ - protected abstract void handle(JvmMetadataKey key, T value, C context); + protected abstract void handle(MetadataKey key, T value, C context); /** * Handles values for a repeatable metadata key. The method is called for all repeatable keys @@ -92,7 +92,7 @@ public abstract class MetadataHandler { * @param * the key/value type. */ - protected void handleRepeated(JvmMetadataKey key, Iterator values, C context) { + protected void handleRepeated(MetadataKey key, Iterator values, C context) { while (values.hasNext()) { handle(key, values.next(), context); } @@ -150,7 +150,7 @@ public interface ValueHandler { * @param context * an arbitrary context object supplied to the process method. */ - void handle(JvmMetadataKey key, T value, C context); + void handle(MetadataKey key, T value, C context); } /** @@ -178,7 +178,7 @@ public interface RepeatedValueHandler { * @param context * an arbitrary context object supplied to the process method. */ - void handle(JvmMetadataKey key, Iterator values, C context); + void handle(MetadataKey key, Iterator values, C context); } /** @@ -198,9 +198,9 @@ public static final class Builder { private static final RepeatedValueHandler IGNORE_REPEATED_VALUE = (key, value, context) -> { /* No op. */ }; - private final Map, ValueHandler> singleValueHandlers = + private final Map, ValueHandler> singleValueHandlers = new HashMap<>(); - private final Map, RepeatedValueHandler> repeatedValueHandlers = + private final Map, RepeatedValueHandler> repeatedValueHandlers = new HashMap<>(); private final ValueHandler defaultHandler; private RepeatedValueHandler defaultRepeatedHandler = null; @@ -214,10 +214,10 @@ private Builder(ValueHandler defaultHandler) { * generic {@link Iterator}. To handle repeated values against a known key with their * expected * type, register a handler via - * {@link #addRepeatedHandler(JvmMetadataKey, RepeatedValueHandler)}. + * {@link #addRepeatedHandler(MetadataKey, RepeatedValueHandler)}. * *

      Note that if a repeated key is associated with an individual value handler (i.e. via - * {@link #addHandler(JvmMetadataKey, ValueHandler)}), then that will be used in preference + * {@link #addHandler(MetadataKey, ValueHandler)}), then that will be used in preference * to the default handler set here. * * @param defaultHandler @@ -249,7 +249,7 @@ public Builder setDefaultRepeatedHandler( */ @CanIgnoreReturnValue public Builder addHandler( - JvmMetadataKey key, ValueHandler handler) { + MetadataKey key, ValueHandler handler) { checkNotNull(key, "key"); checkNotNull(handler, "handler"); repeatedValueHandlers.remove(key); @@ -274,7 +274,7 @@ public Builder addHandler( */ @CanIgnoreReturnValue public Builder addRepeatedHandler( - JvmMetadataKey key, RepeatedValueHandler handler) { + MetadataKey key, RepeatedValueHandler handler) { checkNotNull(key, "key"); checkNotNull(handler, "handler"); checkArgument(key.canRepeat(), "key must be repeating"); @@ -295,9 +295,9 @@ public Builder addRepeatedHandler( * @return the builder instance for chaining. */ @CanIgnoreReturnValue - public Builder ignoring(JvmMetadataKey key, JvmMetadataKey... rest) { + public Builder ignoring(MetadataKey key, MetadataKey... rest) { checkAndIgnore(key); - for (JvmMetadataKey k : rest) { + for (MetadataKey k : rest) { checkAndIgnore(k); } return this; @@ -312,14 +312,14 @@ public Builder ignoring(JvmMetadataKey key, JvmMetadataKey... rest) { * @return the builder instance for chaining. */ @CanIgnoreReturnValue - public Builder ignoring(Iterable> keys) { - for (JvmMetadataKey k : keys) { + public Builder ignoring(Iterable> keys) { + for (MetadataKey k : keys) { checkAndIgnore(k); } return this; } - void checkAndIgnore(JvmMetadataKey key) { + void checkAndIgnore(MetadataKey key) { checkNotNull(key, "key"); // It is more efficient to ignore a repeated key explicitly. if (key.canRepeat()) { @@ -344,15 +344,15 @@ void checkAndIgnore(JvmMetadataKey key) { * @return the builder instance for chaining. */ @CanIgnoreReturnValue - public Builder removeHandlers(JvmMetadataKey key, JvmMetadataKey... rest) { + public Builder removeHandlers(MetadataKey key, MetadataKey... rest) { checkAndRemove(key); - for (JvmMetadataKey k : rest) { + for (MetadataKey k : rest) { checkAndRemove(k); } return this; } - void checkAndRemove(JvmMetadataKey key) { + void checkAndRemove(MetadataKey key) { checkNotNull(key, "key"); singleValueHandlers.remove(key); repeatedValueHandlers.remove(key); @@ -366,9 +366,9 @@ public MetadataHandler build() { private static final class MapBasedhandler extends MetadataHandler { - private final Map, ValueHandler> singleValueHandlers = + private final Map, ValueHandler> singleValueHandlers = new HashMap<>(); - private final Map, RepeatedValueHandler> repeatedValueHandlers = + private final Map, RepeatedValueHandler> repeatedValueHandlers = new HashMap<>(); private final ValueHandler defaultHandler; private final RepeatedValueHandler defaultRepeatedHandler; @@ -382,7 +382,7 @@ private MapBasedhandler(Builder builder) { @SuppressWarnings("unchecked") // See comments for why casting is safe. @Override - protected void handle(JvmMetadataKey key, T value, C context) { + protected void handle(MetadataKey key, T value, C context) { // Safe cast because of how our private map is managed. ValueHandler handler = (ValueHandler) singleValueHandlers.get(key); @@ -390,13 +390,13 @@ protected void handle(JvmMetadataKey key, T value, C context) { handler.handle(key, value, context); } else { // Casting MetadataKey to "" is safe since it only produces elements of 'T'. - defaultHandler.handle((JvmMetadataKey) key, value, context); + defaultHandler.handle((MetadataKey) key, value, context); } } @SuppressWarnings("unchecked") // See comments for why casting is safe. @Override - protected void handleRepeated(JvmMetadataKey key, Iterator values, C context) { + protected void handleRepeated(MetadataKey key, Iterator values, C context) { // Safe cast because of how our private map is managed. RepeatedValueHandler handler = (RepeatedValueHandler) repeatedValueHandlers.get(key); @@ -406,7 +406,7 @@ protected void handleRepeated(JvmMetadataKey key, Iterator values, C c // Casting MetadataKey to "" is safe since it only produces elements of 'T'. // Casting the iterator is safe since it also only produces elements of 'T'. defaultRepeatedHandler.handle( - (JvmMetadataKey) key, (Iterator) values, context); + (MetadataKey) key, (Iterator) values, context); } else { // Dispatches keys individually. super.handleRepeated(key, values, context); diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataKeyValueHandlers.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataKeyValueHandlers.java index 3c377137d..47714f33e 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataKeyValueHandlers.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataKeyValueHandlers.java @@ -26,8 +26,8 @@ package io.spine.logging.jvm.backend; -import io.spine.logging.jvm.JvmMetadataKey; -import io.spine.logging.jvm.JvmMetadataKey.KeyValueHandler; +import io.spine.logging.jvm.MetadataKey; +import io.spine.logging.jvm.MetadataKey.KeyValueHandler; import io.spine.logging.jvm.backend.MetadataHandler.RepeatedValueHandler; import io.spine.logging.jvm.backend.MetadataHandler.ValueHandler; @@ -44,10 +44,10 @@ public final class MetadataKeyValueHandlers { private static final ValueHandler EMIT_METADATA = - JvmMetadataKey::safeEmit; + MetadataKey::safeEmit; private static final RepeatedValueHandler EMIT_REPEATED_METADATA = - JvmMetadataKey::safeEmitRepeated; + MetadataKey::safeEmitRepeated; /** * Returns a singleton value handler which dispatches metadata to a {@link KeyValueHandler}. @@ -72,7 +72,7 @@ public static RepeatedValueHandler getDefaultRepeatedVa * @return a builder configured with the default key/value handlers and ignored keys. */ public static MetadataHandler.Builder getDefaultBuilder( - Set> ignored) { + Set> ignored) { return MetadataHandler.builder(getDefaultValueHandler()) .setDefaultRepeatedHandler(getDefaultRepeatedValueHandler()) .ignoring(ignored); @@ -86,7 +86,7 @@ public static MetadataHandler.Builder getDefaultBuilder( * @return a handler configured with the default key/value handlers and ignored keys. */ public static MetadataHandler getDefaultHandler( - Set> ignored) { + Set> ignored) { return getDefaultBuilder(ignored).build(); } diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataProcessor.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataProcessor.java index f743e08d1..3f0452ab8 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataProcessor.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/MetadataProcessor.java @@ -26,7 +26,7 @@ package io.spine.logging.jvm.backend; -import io.spine.logging.jvm.JvmMetadataKey; +import io.spine.logging.jvm.MetadataKey; import io.spine.logging.jvm.LogContext; import org.jspecify.annotations.Nullable; @@ -77,11 +77,11 @@ public void process(MetadataHandler handler, C context) { } @Override - public void handle(JvmMetadataKey key, MetadataHandler handler, C context) { + public void handle(MetadataKey key, MetadataHandler handler, C context) { } @Override - public T getSingleValue(JvmMetadataKey key) { + public T getSingleValue(MetadataKey key) { return null; } @@ -91,7 +91,7 @@ public int keyCount() { } @Override - public Set> keySet() { + public Set> keySet() { return Collections.emptySet(); } }; @@ -172,7 +172,7 @@ private MetadataProcessor() { * The handler method invoked depends on whether the key is single valued or repeated. * If no metadata is present for the given key, the handler is not invoked. */ - public abstract void handle(JvmMetadataKey key, MetadataHandler handler, C context); + public abstract void handle(MetadataKey key, MetadataHandler handler, C context); /** * Returns the unique value for a single valued key, or {@code null} if not present. @@ -180,7 +180,7 @@ private MetadataProcessor() { * @throws IllegalArgumentException * if passed a repeatable key (even if that key has one value). */ - public abstract T getSingleValue(JvmMetadataKey key); + public abstract T getSingleValue(MetadataKey key); /** * Returns the number of unique keys represented by this processor. This is the same as the @@ -192,11 +192,11 @@ private MetadataProcessor() { public abstract int keyCount(); /** - * Returns the set of {@link JvmMetadataKey}s known to this processor, in the order in which + * Returns the set of {@link MetadataKey}s known to this processor, in the order in which * they will be processed. Note that this implementation is lightweight, but not necessarily * performant for things like containment testing. */ - public abstract Set> keySet(); + public abstract Set> keySet(); /* * The values in the keyMap array are structured as: @@ -246,7 +246,7 @@ public void process(MetadataHandler handler, C context) { } @Override - public void handle(JvmMetadataKey key, MetadataHandler handler, C context) { + public void handle(MetadataKey key, MetadataHandler handler, C context) { var index = indexOf(key, keyMap, keyCount); if (index >= 0) { dispatch(key, keyMap[index], handler, context); @@ -254,7 +254,7 @@ public void handle(JvmMetadataKey key, MetadataHandler handler, C cont } @Override - public T getSingleValue(JvmMetadataKey key) { + public T getSingleValue(MetadataKey key) { checkArgument(!key.canRepeat(), "key must be single valued"); var index = indexOf(key, keyMap, keyCount); // For single keys, the keyMap values are just the value index. @@ -267,17 +267,17 @@ public int keyCount() { } @Override - public Set> keySet() { + public Set> keySet() { // We may want to cache this, since it's effectively immutable, but it's also a small and // likely short lived instance, so quite possibly not worth it for the cost of another field. - return new AbstractSet>() { + return new AbstractSet>() { @Override public int size() { return keyCount; } @Override - public Iterator> iterator() { + public Iterator> iterator() { return new Iterator<>() { private int i = 0; @@ -287,7 +287,7 @@ public boolean hasNext() { } @Override - public JvmMetadataKey next() { + public MetadataKey next() { return getKey(keyMap[i++] & 0x1F); } @@ -302,7 +302,7 @@ public void remove() { } // Separate method to re-capture the value type. - private void dispatch(JvmMetadataKey key, int n, + private void dispatch(MetadataKey key, int n, MetadataHandler handler, C context) { if (!key.canRepeat()) { // For single keys, the keyMap values are just the value index. @@ -317,13 +317,13 @@ private void dispatch(JvmMetadataKey key, int n, // a fairly unusual use case. private final class ValueIterator implements Iterator { - private final JvmMetadataKey key; + private final MetadataKey key; private int nextIndex; // For repeated keys, the bits 5-32 contain a mask of additional indices (where bit 5 // implies index 1, since index 0 cannot apply to an additional repeated value). private int mask; - private ValueIterator(JvmMetadataKey key, int valueIndices) { + private ValueIterator(MetadataKey key, int valueIndices) { this.key = key; // Get the first element index (lowest 5 bits, 0-27). this.nextIndex = valueIndices & 0x1F; @@ -400,7 +400,7 @@ private int prepareKeyMap(int[] keyMap) { } // Returns the (unique) index into the keyMap array for the given key. - private int indexOf(JvmMetadataKey key, int[] keyMap, int count) { + private int indexOf(MetadataKey key, int[] keyMap, int count) { for (var i = 0; i < count; i++) { // Low 5 bits of keyMap values are *always* an index to a valid metadata key. if (key.equals(getKey(keyMap[i] & 0x1F))) { @@ -410,7 +410,7 @@ private int indexOf(JvmMetadataKey key, int[] keyMap, int count) { return -1; } - private JvmMetadataKey getKey(int n) { + private MetadataKey getKey(int n) { var scopeSize = scope.size(); return n >= scopeSize ? logged.getKey(n - scopeSize) : scope.getKey(n); } @@ -431,10 +431,10 @@ private Object getValue(int n) { */ private static final class SimpleProcessor extends MetadataProcessor { - private final Map, Object> map; + private final Map, Object> map; private SimpleProcessor(Metadata scope, Metadata logged) { - var map = new LinkedHashMap, Object>(); + var map = new LinkedHashMap, Object>(); addTo(map, scope); addTo(map, logged); // Wrap any repeated value lists to make them unmodifiable (required for correctness). @@ -449,7 +449,7 @@ private SimpleProcessor(Metadata scope, Metadata logged) { // Unlike the LightweightProcessor, we copy references from the Metadata eagerly, so can "cast" // values to their key-types early, ensuring safe casting when dispatching. - private static void addTo(Map, Object> map, Metadata metadata) { + private static void addTo(Map, Object> map, Metadata metadata) { for (var i = 0; i < metadata.size(); i++) { var key = metadata.getKey(i); var value = map.get(key); @@ -477,7 +477,7 @@ public void process(MetadataHandler handler, C context) { } @Override - public void handle(JvmMetadataKey key, MetadataHandler handler, C context) { + public void handle(MetadataKey key, MetadataHandler handler, C context) { var value = map.get(key); if (value != null) { dispatch(key, value, handler, context); @@ -487,7 +487,7 @@ public void handle(JvmMetadataKey key, MetadataHandler handler, C cont // It's safe to ignore warnings since single keys are only ever 'T' when added to the map. @Override @SuppressWarnings("unchecked") - public <@Nullable T> T getSingleValue(JvmMetadataKey key) { + public <@Nullable T> T getSingleValue(MetadataKey key) { checkArgument(!key.canRepeat(), "key must be single valued"); var value = map.get(key); return (value != null) ? (T) value : null; @@ -499,7 +499,7 @@ public int keyCount() { } @Override - public Set> keySet() { + public Set> keySet() { return map.keySet(); } @@ -507,7 +507,7 @@ public Set> keySet() { // and single keys are only ever 'T' when added to the map. @SuppressWarnings("unchecked") private static void dispatch( - JvmMetadataKey key, Object value, MetadataHandler handler, C context) { + MetadataKey key, Object value, MetadataHandler handler, C context) { if (key.canRepeat()) { handler.handleRepeated(key, ((List) value).iterator(), context); } else { diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/SimpleMessageFormatter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/SimpleMessageFormatter.java index a1da41f1b..1383dcc7c 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/SimpleMessageFormatter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/SimpleMessageFormatter.java @@ -27,8 +27,8 @@ package io.spine.logging.jvm.backend; import com.google.errorprone.annotations.CanIgnoreReturnValue; -import io.spine.logging.jvm.JvmMetadataKey; -import io.spine.logging.jvm.JvmMetadataKey.KeyValueHandler; +import io.spine.logging.jvm.MetadataKey; +import io.spine.logging.jvm.MetadataKey.KeyValueHandler; import io.spine.logging.jvm.LogContext; import org.jspecify.annotations.Nullable; @@ -59,7 +59,7 @@ * } * *

      If additional metadata keys, other than the {@code cause} are to be omitted, then {@link - * #getSimpleFormatterIgnoring(JvmMetadataKey...)} can be used to obtain a static formatter, + * #getSimpleFormatterIgnoring(MetadataKey...)} can be used to obtain a static formatter, * instead of using the default. * * @see > DEFAULT_KEYS_TO_IGNORE = + private static final Set> DEFAULT_KEYS_TO_IGNORE = Collections.singleton(LogContext.Key.LOG_CAUSE); private static final LogMessageFormatter DEFAULT_FORMATTER = newFormatter( @@ -120,11 +120,11 @@ public static LogMessageFormatter getDefaultFormatter() { * also be suppressed. */ public static LogMessageFormatter getSimpleFormatterIgnoring( - JvmMetadataKey... extraIgnoredKeys) { + MetadataKey... extraIgnoredKeys) { if (extraIgnoredKeys.length == 0) { return getDefaultFormatter(); } - Set> ignored = new HashSet<>(DEFAULT_KEYS_TO_IGNORE); + Set> ignored = new HashSet<>(DEFAULT_KEYS_TO_IGNORE); Collections.addAll(ignored, extraIgnoredKeys); return newFormatter(ignored); } @@ -217,7 +217,7 @@ public static String getLiteralLogMessage(LogData logData) { * message. */ public static boolean mustBeFormatted( - LogData logData, MetadataProcessor metadata, Set> keysToIgnore) { + LogData logData, MetadataProcessor metadata, Set> keysToIgnore) { // If there are logged arguments or more metadata keys than can be ignored, we fail immediately // which avoids the cost of creating the metadata key set (so don't remove the size check). return logData.getTemplateContext() != null @@ -230,7 +230,7 @@ public static boolean mustBeFormatted( * must * ensure that the given set is effectively immutable. */ - private static LogMessageFormatter newFormatter(final Set> keysToIgnore) { + private static LogMessageFormatter newFormatter(final Set> keysToIgnore) { return new LogMessageFormatter() { private final MetadataHandler handler = MetadataKeyValueHandlers.getDefaultHandler(keysToIgnore); diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ContextMetadata.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ContextMetadata.java index 96beeae51..180ad1933 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ContextMetadata.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ContextMetadata.java @@ -27,7 +27,7 @@ package io.spine.logging.jvm.context; import com.google.errorprone.annotations.CanIgnoreReturnValue; -import io.spine.logging.jvm.JvmMetadataKey; +import io.spine.logging.jvm.MetadataKey; import io.spine.logging.jvm.backend.Metadata; import org.jspecify.annotations.Nullable; @@ -52,10 +52,10 @@ public abstract class ContextMetadata extends Metadata { private static final class Entry { - final JvmMetadataKey key; + final MetadataKey key; final T value; - Entry(JvmMetadataKey key, T value) { + Entry(MetadataKey key, T value) { this.key = checkNotNull(key, "key"); this.value = checkNotNull(value, "value"); } @@ -82,7 +82,7 @@ private Builder() { /** Add a single metadata key/value pair to the builder. */ @CanIgnoreReturnValue - public Builder add(JvmMetadataKey key, T value) { + public Builder add(MetadataKey key, T value) { // Entries are immutable and get moved into the metadata when it is built, // so these get shared and reduce the size of the metadata storage compared // to storing adjacent key/value pairs. @@ -103,7 +103,7 @@ public static Builder builder() { } /** Returns a space efficient {@code ScopeMetadata} containing a single value. */ - public static ContextMetadata singleton(JvmMetadataKey key, T value) { + public static ContextMetadata singleton(MetadataKey key, T value) { return new SingletonMetadata(key, value); } @@ -127,7 +127,7 @@ private ContextMetadata() { * *

      Use {@link io.spine.logging.jvm.backend.MetadataProcessor MetadataProcessor} to process * metadata consistently with respect to single valued and repeated keys, and use {@link - * Metadata#findValue(JvmMetadataKey)} to look up the “most recent” value for a single + * Metadata#findValue(MetadataKey)} to look up the “most recent” value for a single * valued key. */ public abstract ContextMetadata concatenate(ContextMetadata metadata); @@ -136,7 +136,7 @@ private ContextMetadata() { abstract Entry get(int n); @Override - public JvmMetadataKey getKey(int n) { + public MetadataKey getKey(int n) { return get(n).key; } @@ -166,7 +166,7 @@ Entry get(int n) { @Override @Nullable @SuppressWarnings("unchecked") - public T findValue(JvmMetadataKey key) { + public T findValue(MetadataKey key) { checkCannotRepeat(key); for (var n = entries.length - 1; n >= 0; n--) { var e = entries[n]; @@ -195,7 +195,7 @@ public ContextMetadata concatenate(ContextMetadata metadata) { } } - private static void checkCannotRepeat(JvmMetadataKey key) { + private static void checkCannotRepeat(MetadataKey key) { checkArgument(!key.canRepeat(), "metadata key must be single valued"); } @@ -203,7 +203,7 @@ private static final class SingletonMetadata extends ContextMetadata { private final Entry entry; - private SingletonMetadata(JvmMetadataKey key, T value) { + private SingletonMetadata(MetadataKey key, T value) { this.entry = new Entry(key, value); } @@ -223,7 +223,7 @@ Entry get(int n) { @Override @Nullable @SuppressWarnings("unchecked") - public R findValue(JvmMetadataKey key) { + public R findValue(MetadataKey key) { checkCannotRepeat(key); return entry.key.equals(key) ? (R) entry.value : null; } @@ -267,7 +267,7 @@ Entry get(int n) { @Override @Nullable - public T findValue(JvmMetadataKey key) { + public T findValue(MetadataKey key) { // For consistency, do the same checks as for non-empty instances. checkCannotRepeat(key); return null; diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/NoOpContextDataProvider.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/NoOpContextDataProvider.java index 2d086166e..2514a55df 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/NoOpContextDataProvider.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/NoOpContextDataProvider.java @@ -27,7 +27,7 @@ package io.spine.logging.jvm.context; import io.spine.logging.jvm.Middleman; -import io.spine.logging.jvm.JvmMetadataKey; +import io.spine.logging.jvm.MetadataKey; import io.spine.logging.jvm.StackSize; import io.spine.logging.jvm.context.ScopedLoggingContext.LoggingContextCloseable; @@ -111,7 +111,7 @@ public boolean addTags(Tags tags) { } @Override - public boolean addMetadata(JvmMetadataKey key, T value) { + public boolean addMetadata(MetadataKey key, T value) { logWarningOnceOnly(); return super.addMetadata(key, value); } diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContext.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContext.java index 9b254d007..2362a6e0c 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContext.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContext.java @@ -29,7 +29,7 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.MustBeClosed; import io.spine.logging.jvm.JvmApi; -import io.spine.logging.jvm.JvmMetadataKey; +import io.spine.logging.jvm.MetadataKey; import io.spine.logging.jvm.LoggingScope; import io.spine.logging.jvm.LoggingScopeProvider; import org.jspecify.annotations.Nullable; @@ -183,7 +183,7 @@ public final Builder withTags(Tags tags) { * times on a builder. */ @CanIgnoreReturnValue - public final Builder withMetadata(JvmMetadataKey key, T value) { + public final Builder withMetadata(MetadataKey key, T value) { if (metadata == null) { metadata = ContextMetadata.builder(); } @@ -464,7 +464,7 @@ public boolean addTags(Tags tags) { * new context, rather than adding it to context visible to multiple threads. */ @CanIgnoreReturnValue - public boolean addMetadata(JvmMetadataKey key, T value) { + public boolean addMetadata(MetadataKey key, T value) { checkNotNull(key, "key"); checkNotNull(value, "value"); return false; diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContexts.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContexts.java index d7358ccd4..61a9597e8 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContexts.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContexts.java @@ -29,7 +29,7 @@ import static java.util.concurrent.TimeUnit.MINUTES; import io.spine.logging.jvm.Middleman; -import io.spine.logging.jvm.JvmMetadataKey; +import io.spine.logging.jvm.MetadataKey; import io.spine.logging.jvm.StackSize; import com.google.errorprone.annotations.CanIgnoreReturnValue; @@ -153,7 +153,7 @@ public static boolean addTags(Tags tags) { * contexts are not supported. */ @CanIgnoreReturnValue - public static boolean addMetadata(JvmMetadataKey key, T value) { + public static boolean addMetadata(MetadataKey key, T value) { return warnOnFailure(ScopedLoggingContext.getInstance().addMetadata(key, value)); } diff --git a/jvm/middleware/src/main/kotlin/io/spine/logging/jvm/JvmMetadataKeys.kt b/jvm/middleware/src/main/kotlin/io/spine/logging/jvm/JvmMetadataKeys.kt index f8ed7a453..a35898367 100644 --- a/jvm/middleware/src/main/kotlin/io/spine/logging/jvm/JvmMetadataKeys.kt +++ b/jvm/middleware/src/main/kotlin/io/spine/logging/jvm/JvmMetadataKeys.kt @@ -27,7 +27,7 @@ package io.spine.logging.jvm /** - * Creates a new single [JvmMetadataKey] with the given [label]. + * Creates a new single [MetadataKey] with the given [label]. * * In JVM, if the given type [T] describes a Java primitive, * this method would use a type of the corresponding object wrapper. @@ -36,11 +36,11 @@ package io.spine.logging.jvm * * @param T type of values that can be associated with this key */ -public inline fun singleKey(label: String): JvmMetadataKey = - JvmMetadataKey.single(label, T::class.javaObjectType) +public inline fun singleKey(label: String): MetadataKey = + MetadataKey.single(label, T::class.javaObjectType) /** - * Creates a new repeated [JvmMetadataKey] with the given [label]. + * Creates a new repeated [MetadataKey] with the given [label]. * * In JVM, if the given type [T] describes a Java primitive, * this method would use a type of the corresponding object wrapper. @@ -49,5 +49,5 @@ public inline fun singleKey(label: String): JvmMetadataKey * * @param T type of values that can be associated with this key */ -public inline fun repeatedKey(label: String): JvmMetadataKey = - JvmMetadataKey.repeated(label, T::class.javaObjectType) +public inline fun repeatedKey(label: String): MetadataKey = + MetadataKey.repeated(label, T::class.javaObjectType) diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/JvmMetadataKeySpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/JvmMetadataKeySpec.kt index 1ff293918..6c7a8baf9 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/JvmMetadataKeySpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/JvmMetadataKeySpec.kt @@ -26,8 +26,8 @@ package io.spine.logging.jvm -import io.spine.logging.jvm.JvmMetadataKey.repeated -import io.spine.logging.jvm.JvmMetadataKey.single +import io.spine.logging.jvm.MetadataKey.repeated +import io.spine.logging.jvm.MetadataKey.single import io.spine.logging.jvm.backend.Platform import io.spine.logging.jvm.given.MemoizingKvHandler import io.spine.logging.jvm.given.iterate @@ -41,7 +41,7 @@ import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test /** - * Tests for [JvmMetadataKey]. + * Tests for [MetadataKey]. * * @see * Original Java code of Google Flogger @@ -63,7 +63,7 @@ internal class JvmMetadataKeySpec { val badLabels = mutableListOf("", "foo bar", "_FOO") badLabels.forEach { label -> shouldThrow { - JvmMetadataKey(label, String::class.java, false) + MetadataKey(label, String::class.java, false) } } } @@ -154,8 +154,8 @@ internal class JvmMetadataKeySpec { @Test fun `throw on 'null's`() { val badInstantiations = listOf( - { JvmMetadataKey(null, String::class.java, false) }, - { JvmMetadataKey("label", null, false) }, + { MetadataKey(null, String::class.java, false) }, + { MetadataKey("label", null, false) }, { single(null, String::class.java) }, { single("label", null) }, { repeated(null, String::class.java) }, @@ -175,7 +175,7 @@ internal class JvmMetadataKeySpec { * include that key, even in code, which has no explicit knowledge of it. */ private class ReenteringKey(label: String) : - JvmMetadataKey(label, Any::class.java, true) { + MetadataKey(label, Any::class.java, true) { override fun emit(value: Any, kvh: KeyValueHandler) { val currentDepth = Platform.getCurrentRecursionDepth() diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataHandlerSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataHandlerSpec.kt index d78b39d47..f147da3ce 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataHandlerSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataHandlerSpec.kt @@ -29,7 +29,7 @@ package io.spine.logging.jvm.backend import com.google.common.base.Joiner import com.google.common.collect.Iterators import io.kotest.matchers.shouldBe -import io.spine.logging.jvm.JvmMetadataKey +import io.spine.logging.jvm.MetadataKey import io.spine.logging.jvm.backend.given.FakeMetadata import io.spine.logging.jvm.repeatedKey import io.spine.logging.jvm.singleKey @@ -192,7 +192,7 @@ private fun process( * * @see MetadataHandler.builder */ -private fun appendUnknownValue(key: JvmMetadataKey<*>, value: Any, out: StringBuilder) { +private fun appendUnknownValue(key: MetadataKey<*>, value: Any, out: StringBuilder) { out.append("${key.label}=<<$value>> ") } @@ -202,7 +202,7 @@ private fun appendUnknownValue(key: JvmMetadataKey<*>, value: Any, out: StringBu * @see MetadataHandler.builder */ private fun appendUnknownValues( - key: JvmMetadataKey<*>, + key: MetadataKey<*>, values: Iterator<*>, out: StringBuilder ) { @@ -210,16 +210,16 @@ private fun appendUnknownValues( appendUnknownValue(key, joinedValues, out) } -private fun appendValue(key: JvmMetadataKey<*>, value: Any, out: StringBuilder) { +private fun appendValue(key: MetadataKey<*>, value: Any, out: StringBuilder) { out.append("${key.label}=$value ") } -private fun appendValues(key: JvmMetadataKey<*>, values: Iterator<*>, out: StringBuilder) { +private fun appendValues(key: MetadataKey<*>, values: Iterator<*>, out: StringBuilder) { val joinedValues = Iterators.toString(values) appendValue(key, joinedValues, out) } -private fun appendSum(key: JvmMetadataKey, values: Iterator, out: StringBuilder) { +private fun appendSum(key: MetadataKey, values: Iterator, out: StringBuilder) { var sum = 0 values.forEach { sum += it } out.append("sum(${key.label})=$sum ") diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataProcessorSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataProcessorSpec.kt index 6088a57df..a8d53e071 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataProcessorSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataProcessorSpec.kt @@ -33,7 +33,7 @@ import io.kotest.matchers.collections.shouldContainExactly import io.kotest.matchers.ints.shouldBeLessThanOrEqual import io.kotest.matchers.nulls.shouldBeNull import io.kotest.matchers.shouldBe -import io.spine.logging.jvm.JvmMetadataKey +import io.spine.logging.jvm.MetadataKey import io.spine.logging.jvm.backend.given.FakeMetadata import io.spine.logging.jvm.repeatedKey import io.spine.logging.jvm.singleKey @@ -186,8 +186,8 @@ internal abstract class MetadataProcessorSpec(private val factory: ProcessorFact .add(REP_1, "two") val metadata = factory.processorFor(scope, Metadata.empty()) val handler: MetadataHandler = object : MetadataHandler() { - override fun handle(key: JvmMetadataKey, value: T, context: Void) = Unit - override fun handleRepeated(key: JvmMetadataKey, + override fun handle(key: MetadataKey, value: T, context: Void) = Unit + override fun handleRepeated(key: MetadataKey, values: MutableIterator, context: Void?) { values.hasNext().shouldBeTrue() @@ -222,7 +222,7 @@ private fun entries(metadata: MetadataProcessor): List { * Processes the given [metadata] for a single metadata [key], * returning the formatted entry. */ -private fun handleEntry(metadata: MetadataProcessor, key: JvmMetadataKey<*>): String? { +private fun handleEntry(metadata: MetadataProcessor, key: MetadataKey<*>): String? { val entries = arrayListOf() metadata.handle(key, COLLECTING_HANDLER, entries) entries.size shouldBeLessThanOrEqual 1 @@ -231,12 +231,12 @@ private fun handleEntry(metadata: MetadataProcessor, key: JvmMetadataKey<*>): St private object COLLECTING_HANDLER : MetadataHandler>() { - override fun handle(key: JvmMetadataKey, value: T, out: MutableList) { + override fun handle(key: MetadataKey, value: T, out: MutableList) { val stringified = "%s=%s".format(key.label, value) out.add(stringified) } - override fun handleRepeated(key: JvmMetadataKey, + override fun handleRepeated(key: MetadataKey, values: MutableIterator, out: MutableList) { val stringified = "%s=%s".format(key.label, Iterators.toString(values)) diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/FakeLogData.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/FakeLogData.kt index d9b076bbf..1901be4f3 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/FakeLogData.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/FakeLogData.kt @@ -28,7 +28,7 @@ package io.spine.logging.jvm.backend.given import com.google.errorprone.annotations.CanIgnoreReturnValue import io.spine.logging.jvm.JvmLogSite -import io.spine.logging.jvm.JvmMetadataKey +import io.spine.logging.jvm.MetadataKey import io.spine.logging.jvm.LogContext import io.spine.logging.jvm.backend.LogData import io.spine.logging.jvm.backend.Metadata @@ -111,7 +111,7 @@ class FakeLogData : LogData { } @CanIgnoreReturnValue - fun addMetadata(key: JvmMetadataKey, value: Any?): FakeLogData { + fun addMetadata(key: MetadataKey, value: Any?): FakeLogData { metadata.add(key, key.cast(value)) return this } diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/FakeMetadata.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/FakeMetadata.kt index fc3ed6128..0621da77f 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/FakeMetadata.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/FakeMetadata.kt @@ -27,7 +27,7 @@ package io.spine.logging.jvm.backend.given import com.google.errorprone.annotations.CanIgnoreReturnValue -import io.spine.logging.jvm.JvmMetadataKey +import io.spine.logging.jvm.MetadataKey import io.spine.logging.jvm.backend.Metadata /** @@ -38,7 +38,7 @@ import io.spine.logging.jvm.backend.Metadata */ class FakeMetadata : Metadata() { - private class KeyValuePair(val key: JvmMetadataKey, val value: T) + private class KeyValuePair(val key: MetadataKey, val value: T) private val entries = mutableListOf>() @@ -46,18 +46,18 @@ class FakeMetadata : Metadata() { * Adds a key/value pair to this [Metadata]. */ @CanIgnoreReturnValue - fun add(key: JvmMetadataKey, value: T): FakeMetadata { + fun add(key: MetadataKey, value: T): FakeMetadata { entries.add(KeyValuePair(key, value)) return this } override fun size(): Int = entries.size - override fun getKey(n: Int): JvmMetadataKey<*> = entries[n].key + override fun getKey(n: Int): MetadataKey<*> = entries[n].key override fun getValue(n: Int): Any = entries[n].value!! - override fun findValue(key: JvmMetadataKey): T? { + override fun findValue(key: MetadataKey): T? { val entry = entries.firstOrNull { it.key == key } val casted = key.cast(entry?.value) // It is safe to pass `null` here. return casted diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/MetadataAssertions.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/MetadataAssertions.kt index 87803b627..5603b2cbb 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/MetadataAssertions.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/MetadataAssertions.kt @@ -26,7 +26,7 @@ package io.spine.logging.jvm.backend.given -import io.spine.logging.jvm.JvmMetadataKey +import io.spine.logging.jvm.MetadataKey import io.spine.logging.jvm.backend.Metadata import io.kotest.matchers.collections.shouldContainInOrder import io.kotest.matchers.ints.shouldBeExactly @@ -60,7 +60,7 @@ internal infix fun Metadata.shouldHaveSize(number: Int) { /** * Asserts that this [Metadata] has a [key] with the mapped [values]. */ -internal fun Metadata.shouldContainInOrder(key: JvmMetadataKey, vararg values: T) { +internal fun Metadata.shouldContainInOrder(key: MetadataKey, vararg values: T) { valuesOf(key) shouldContainInOrder values.asList() } @@ -69,34 +69,34 @@ internal fun Metadata.shouldContainInOrder(key: JvmMetadataKey, vararg va * * The given [value] should be the first one, which was mapped to the [key]. */ -internal fun Metadata.shouldHaveFirstValue(key: JvmMetadataKey, value: T) { +internal fun Metadata.shouldHaveFirstValue(key: MetadataKey, value: T) { findValue(key) shouldBe value } /** * Asserts that this [Metadata] does NOT HAVE a value for the given [key]. */ -internal infix fun Metadata.shouldNotContain(key: JvmMetadataKey) { +internal infix fun Metadata.shouldNotContain(key: MetadataKey) { findValue(key).shouldBeNull() } /** * Asserts that this [Metadata] has one or more values for the given [key] */ -internal infix fun Metadata.shouldContain(key: JvmMetadataKey) { +internal infix fun Metadata.shouldContain(key: MetadataKey) { findValue(key).shouldNotBeNull() } /** * Asserts that this [Metadata] has a [key] to which only a single [value] is mapped. */ -internal fun Metadata.shouldUniquelyContain(key: JvmMetadataKey, value: T) { +internal fun Metadata.shouldUniquelyContain(key: MetadataKey, value: T) { findValue(key) shouldBe value val allKeys = (0.. getKey(i) }.toList() allKeys.indexOf(key) shouldBe allKeys.lastIndexOf(key) } -private fun Metadata.valuesOf(key: JvmMetadataKey): List { +private fun Metadata.valuesOf(key: MetadataKey): List { val values: MutableList = ArrayList() for (n in 0..() diff --git a/logging/src/jvmMain/kotlin/io/spine/logging/JvmMetadataKey.kt b/logging/src/jvmMain/kotlin/io/spine/logging/JvmMetadataKey.kt index 5242f7153..5827ae57f 100644 --- a/logging/src/jvmMain/kotlin/io/spine/logging/JvmMetadataKey.kt +++ b/logging/src/jvmMain/kotlin/io/spine/logging/JvmMetadataKey.kt @@ -26,7 +26,7 @@ package io.spine.logging -import io.spine.logging.jvm.JvmMetadataKey as FloggerMetadataKey +import io.spine.logging.jvm.MetadataKey as TMetadataKey import kotlin.reflect.KClass import kotlin.reflect.cast @@ -39,7 +39,7 @@ internal class JvmMetadataKey( override val canRepeat: Boolean ) : MetadataKey { - internal val adapter: FloggerMetadataKey = FMetadataKeyAdapter(label, clazz.java, canRepeat) + internal val adapter: TMetadataKey = FMetadataKeyAdapter(label, clazz.java, canRepeat) companion object { @@ -65,4 +65,4 @@ internal class JvmMetadataKey( * Adapts `JvmMetadataKey` to the cases when `FMetadataKey` instances should be used. */ private class FMetadataKeyAdapter(label: String, clazz: Class, canRepeat: Boolean) : - FloggerMetadataKey(label, clazz, canRepeat) + TMetadataKey(label, clazz, canRepeat) From 14865de3392203d96461fbed8ab35540bb6f411d Mon Sep 17 00:00:00 2001 From: Alexander Yevsyukov Date: Thu, 26 Jun 2025 11:31:24 +0100 Subject: [PATCH 13/28] Update build time --- dependencies.md | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/dependencies.md b/dependencies.md index 942bb7a0b..f84c03102 100644 --- a/dependencies.md +++ b/dependencies.md @@ -724,7 +724,7 @@ The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 20:06:58 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Thu Jun 26 11:28:07 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -1553,7 +1553,7 @@ This report was generated on **Wed Jun 25 20:06:58 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 20:06:59 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Thu Jun 26 11:28:07 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -2366,7 +2366,7 @@ This report was generated on **Wed Jun 25 20:06:59 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 20:06:59 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Thu Jun 26 11:28:08 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -3187,7 +3187,7 @@ This report was generated on **Wed Jun 25 20:06:59 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 20:07:00 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Thu Jun 26 11:28:08 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -4035,7 +4035,7 @@ This report was generated on **Wed Jun 25 20:07:00 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 20:07:00 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Thu Jun 26 11:28:08 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -4875,7 +4875,7 @@ This report was generated on **Wed Jun 25 20:07:00 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 20:07:01 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Thu Jun 26 11:28:08 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -5715,7 +5715,7 @@ This report was generated on **Wed Jun 25 20:07:01 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 20:07:01 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Thu Jun 26 11:28:08 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -6563,7 +6563,7 @@ This report was generated on **Wed Jun 25 20:07:01 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 20:07:02 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Thu Jun 26 11:28:09 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -7415,7 +7415,7 @@ This report was generated on **Wed Jun 25 20:07:02 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 20:07:02 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Thu Jun 26 11:28:09 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -8244,7 +8244,7 @@ This report was generated on **Wed Jun 25 20:07:02 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 20:07:03 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Thu Jun 26 11:28:09 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -8981,7 +8981,7 @@ This report was generated on **Wed Jun 25 20:07:03 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 20:07:03 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Thu Jun 26 11:28:09 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -9706,7 +9706,7 @@ This report was generated on **Wed Jun 25 20:07:03 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 20:07:03 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Thu Jun 26 11:28:09 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -10519,7 +10519,7 @@ This report was generated on **Wed Jun 25 20:07:03 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 20:07:04 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Thu Jun 26 11:28:10 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -11308,7 +11308,7 @@ This report was generated on **Wed Jun 25 20:07:04 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 20:07:04 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Thu Jun 26 11:28:10 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -12296,7 +12296,7 @@ This report was generated on **Wed Jun 25 20:07:04 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 20:07:05 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Thu Jun 26 11:28:10 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -13169,7 +13169,7 @@ This report was generated on **Wed Jun 25 20:07:05 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 20:07:05 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Thu Jun 26 11:28:10 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -13986,4 +13986,4 @@ This report was generated on **Wed Jun 25 20:07:05 WEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 25 20:07:06 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). \ No newline at end of file +This report was generated on **Thu Jun 26 11:28:10 WEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). \ No newline at end of file From 0e912b47fcb9a2c83a6efbbd34c114b622613635 Mon Sep 17 00:00:00 2001 From: Alexander Yevsyukov Date: Thu, 26 Jun 2025 12:13:56 +0100 Subject: [PATCH 14/28] Update `config` --- .gitignore | 35 +- .idea/kotlinc.xml | 2 +- .junie/guidelines.md | 21 + AGENTS.md | 478 ++++++++++++++++++ buildSrc/build.gradle.kts | 1 - buildSrc/src/main/kotlin/DokkaExts.kt | 1 - .../kotlin/io/spine/dependency/lib/Flogger.kt | 42 ++ .../main/kotlin/io/spine/gradle/Runtime.kt | 2 +- .../spine/gradle/report/pom/PomXmlWriter.kt | 6 +- .../src/main/kotlin/jvm-module.gradle.kts | 1 - .../src/main/kotlin/kmp-publish.gradle.kts | 4 +- gradle.properties | 27 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 13 files changed, 582 insertions(+), 40 deletions(-) create mode 100644 .junie/guidelines.md create mode 100644 AGENTS.md create mode 100644 buildSrc/src/main/kotlin/io/spine/dependency/lib/Flogger.kt diff --git a/.gitignore b/.gitignore index 969e83ea2..7c974f46a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,11 @@ # -# Copyright 2022, TeamDev. All rights reserved. +# Copyright 2025, TeamDev. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# https://www.apache.org/licenses/LICENSE-2.0 # # Redistribution and use in source and/or binary forms, with or without # modification, must retain the above copyright notice and the following @@ -31,6 +31,18 @@ # # Therefore, instructions below are superset of instructions required for all the projects. +# Temporary output of AI agents. +.output + +# `jenv` local configuration. +.java-version + +# Internal tool directories. +.fleet/ + +# Kotlin temp directories. +**/.kotlin/ + # IntelliJ IDEA modules and interim config files. *.iml .idea/*.xml @@ -42,16 +54,31 @@ # Do not ignore the following IDEA settings !.idea/misc.xml -!.idea/kotlinc.xml !.idea/codeStyleSettings.xml !.idea/codeStyles/ !.idea/copyright/ +# Ignore IDEA config files under `tests` +/tests/.idea/** + # Gradle interim configs **/.gradle/** +# Temp directory for Gradle TestKit runners +**/.gradle-test-kit/** + +# Integration test log files +/tests/_out/** + # Generated source code **/generated/** +**/*.pb.dart +**/*.pbenum.dart +**/*.pbserver.dart +**/*.pbjson.dart + +# Generated source code with custom path under `tests` +/tests/**/proto-gen/** # Gradle build files **/build/** @@ -104,3 +131,5 @@ pubspec.lock # Ignore the `tmp` directory used for building dependant repositories. /tmp + +.gradle-test-kit/ diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index c515672dd..740d6a98c 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -6,4 +6,4 @@ - \ No newline at end of file + diff --git a/.junie/guidelines.md b/.junie/guidelines.md new file mode 100644 index 000000000..4dd22e46b --- /dev/null +++ b/.junie/guidelines.md @@ -0,0 +1,21 @@ +## Guidelines for Junie and AI Agent from JetBrains + +Read the `AGENTS.md` file at the root of the project to understand: + - the agent responsibilities, + - project overview, + - coding guidelines, + - other relevant topics. + +Also follow the Junie-specific rules described below. + +## Junie Assistance Tips + +When working with Junie AI on the Spine Tool-Base project: + +1. **Project Navigation**: Use `search_project` to find relevant files and code segments. +2. **Code Understanding**: Request file structure with `get_file_structure` before editing. +3. **Code Editing**: Make minimal changes with `search_replace` to maintain project consistency. +4. **Testing**: Verify changes with `run_test` on relevant test files. +5. **Documentation**: Follow KDoc style for documentation. +6. **Kotlin Idioms**: Prefer Kotlin-style solutions over Java-style approaches. +7. **Version Updates**: Remember to update `version.gradle.kts` for PRs. diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..44ca7b768 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,478 @@ +## 📝 Quick Reference Card + +``` +🔑 Key Information: +- Kotlin/Java project with CQRS architecture +- Use ChatGPT for documentation, Codex for code generation, GPT-4o for complex analysis +- Follow coding guidelines in Spine Event Engine docs +- Always include tests with code changes +- Version bump required for all PRs +``` + +## Table of Contents +1. [Purpose](#-purpose) +2. [Project overview](#-project-overview) +3. [Agent responsibilities](#-agent-responsibilities) + - [Agent collaboration workflow](#agent-collaboration-workflow) + - [Tagging pull request messages](#tagging-pull-request-messages) + - [Selecting the right Agent](#selecting-the-right-agent) +4. [Coding guidelines for Agents](#-coding-guidelines-for-agents) +5. [Running builds](#running-builds) +6. [Version policy](#version-policy) +7. [Project structure expectations](#-project-structure-expectations) +8. [Documentation tasks](#-documentation-tasks) +9. [Testing](#-testing) +10. [Safety rules for Agents](#-safety-rules-for-agents) +11. [Refactoring guidelines](#-refactoring-guidelines) +12. [Interaction tips – key to effective collaboration!](#-interaction-tips--key-to-effective-collaboration) +13. [LLM goals](#-llm-goals) + - [Problem-solving framework](#problem-solving-framework-for-complex-tasks) + - [GPT-4o advanced capabilities](#-gpt-4o-advanced-capabilities) +14. [Common tasks](#-common-tasks) +15. [Welcome, Agents!](#-welcome-agents) + +## 🧠 Purpose + +> **EXECUTIVE SUMMARY**: This guide outlines how AI agents (ChatGPT, Codex, GPT-4o) +> collaborate on our Kotlin/Java project. It defines responsibilities, coding standards, +> and workflows to maintain high code quality and architectural integrity. + +This document explains how to use **ChatGPT** and **Codex** in this Kotlin/Java project. + +It outlines: + +- Agent responsibilities (who does what). +- Coding and architectural guidelines agents must follow. +- Instructions for creating and testing agent-generated outputs. + +Whether you are a developer, tester, or contributor, this guide helps you collaborate +with AI to maintain a high-quality codebase. + +### Terminology +- **LLM**: Refers to the general category of language models (e.g., ChatGPT, Codex, Claude, Junie). +- **Agents**: A broader term for LLMs collaborating on this project. +- Use specific names (**ChatGPT**, **Codex**) when they excel at different tasks + (e.g., scaffolding versus explanation). + +--- + +## 🛠️ Project overview + +- **Languages**: Kotlin (primary), Java (secondary). +- **Build tool**: Gradle with Kotlin DSL. +- **Architecture**: Event-driven Command Query Responsibility Segregation (CQRS). +- **Static analysis**: detekt, ErrorProne, Checkstyle, PMD. +- **Testing**: JUnit 5, Kotest Assertions, Codecov. +- **Tools used**: Gradle plugins, IntelliJ IDEA Platform, KSP, KotlinPoet, Dokka. + +--- + +## 🤖 Agent responsibilities + +| Task/Feature | Primary Agent | Supporting Agent | Notes | +|-----------------------------------|---------------|------------------|---------------------------------------------| +| Writing documentation (like KDoc) | ChatGPT | Codex | Use for readable, structured docs. | +| Explaining APIs and architecture | ChatGPT | - | Great for clarity in team workflows. | +| Code generation (e.g., tests) | Codex | ChatGPT | Codex produces quick scaffolding. | +| Code refactoring suggestions | ChatGPT | Codex | Use ChatGPT for design-level improvements. | +| Completing functions or classes | Codex | - | Codex is better for direct completions. | +| Debugging and test suggestions | ChatGPT | Codex | ChatGPT suggests missing scenarios. | +| Advanced architecture analysis | GPT-4o | - | Best for complex CQRS pattern optimization. | +| Kotlin idiom optimization | GPT-4o | Codex | Leverages latest language features. | + +### Agent collaboration workflow + +```mermaid +graph TD + A[Human Developer] -->|Request task| B{Task Type?} + B -->|Documentation| C[ChatGPT] + B -->|Code Generation| D[Codex] + B -->|Architecture Analysis| E[GPT-4o] + C -->|Produce Documentation| F[Review & Merge] + D -->|Generate Code| F + E -->|Optimize & Refactor| F + F -->|Iterate if needed| A +``` + +*Note: The diagram shows the typical workflow and which agent to use for different task types.* + + +### Tagging pull request messages + +Use PR tags for clarity: +```text +feat(chatgpt): Updated README with clearer KDoc examples +fix(codex): Completed missing `when` branches in tests +perf(gpt-4o): Optimized event processing pipeline +``` +#### Why tag pull requests? +Tagging PRs helps the team: + - Track which agent contributed to specific changes. + - Understand whether a PR needs extra human review based on the agent's role. + - Make decisions about multi-agent collaboration in reviews. + +### Selecting the right Agent + +

      +Click to expand the decision tree for agent selection + +``` +Is the task primarily documentation or explanation? +├── Yes → Use ChatGPT +└── No → Continue + +Is the task primarily generating boilerplate code or tests? +├── Yes → Use Codex +└── No → Continue + +Does the task involve complex architectural decisions or advanced Kotlin features? +├── Yes → Use GPT-4o +└── No → Use ChatGPT for analysis, then Codex for implementation +``` + +**Task examples by Agent:** + +- **ChatGPT**: Documentation, conceptual explanations, architectural insights +- **Codex**: Code generation, test scaffolding, completing partially written code +- **GPT-4o**: Advanced architectural patterns, Kotlin idiom optimization, complex refactoring + +
      + +--- + +## 🧾 Coding guidelines for Agents + +### Core principles + +- Adhere to [Spine Event Engine Documentation][spine-docs] for coding style. +- Generate code that compiles cleanly and passes static analysis. +- Respect existing architecture, naming conventions, and project structure. +- Write clear, incremental commits with descriptive messages. +- Include automated tests for any code change that alters functionality. + +### Kotlin best practices + +#### ✅ Prefer +- **Kotlin idioms** over Java-style approaches: + - Extension functions + - `when` expressions + - Smart casts + - Data classes and sealed classes + - Immutable data structures +- **Simple nouns** over composite nouns (`user` > `userAccount`) +- **Generic parameters** over explicit variable types (`val list = mutableList()`) +- **Java interop annotations** only when needed (`@file:JvmName`, `@JvmStatic`) +- **Kotlin DSL** for Gradle files + +#### ❌ Avoid +- Mutable data structures +- Java-style verbosity (builders with setters) +- Redundant null checks (`?.let` misuse) +- Using `!!` unless clearly justified +- Type names in variable names (`userObject`, `itemList`) +- String duplication (use constants in companion objects) +- Mixing Groovy and Kotlin DSLs in build logic +- Reflection unless specifically requested + +### Documentation & comments + +#### KDoc style +- Write concise descriptions for all public and internal APIs. +- Start parameter descriptions with capital letters. +- End parameter descriptions with commas. +- Use inline code with backticks for code references (`example`). +- Format code blocks with fences and language identifiers: + ```kotlin + // Example code + fun example() { + // Implementation + } + ``` + +#### Commenting guidelines +- Avoid inline comments in production code unless necessary. +- Inline comments are helpful in tests. +- When using TODO comments, follow the format on [dedicated page][todo-comments]. +- File and directory names should be formatted as code. + +#### Tex width +- Wrap `.md` text to 80 characters for readability. +- Wrap KDoc comments at 75 characters. + +#### Using periods +- Use periods at the end of complete sentences. +- Use periods for full or multi-clause bullets. +- Use NO periods for short bullets. +- Use NO periods for fragments. +- Use NO periods in titles and headers. +- Use NO periods in parameter descriptions in Javadoc. +- DO USE periods in parameter and property descriptions in KDoc. +- Be consistent within the list! + +### Text formatting + - ✅ Remove double empty lines in the code. + - ✅ Remove trailing space characters in the code. + +--- + +## Safety rules + +- ✅ All code must compile and pass static analysis. +- ✅ Do not auto-update external dependencies. +- ❌ Never use reflection or unsafe code without explicit approval. +- ❌ No analytics or telemetry code. +- ❌ No blocking calls inside coroutines. + +--- + +## Version policy + +
      +Click to expand versioning guidelines + +### We use semver +The version of the project is kept in the `version.gradle.kts` file in the root of the project. + +The version numbers in these files follow the conventions of +[Semantic Versioning 2.0.0](https://semver.org/). + +### Quick checklist for versioning +1. Increment the patch version in `version.gradle.kts`. + Retain zero-padding if applicable: + - Example: `"2.0.0-SNAPSHOT.009"` → `"2.0.0-SNAPSHOT.010"` +2. Commit the version bump separately with this comment: + ```text + Bump version → `$newVersion` + ``` +3. Rebuild using `./gradlew clean build`. +4. Update `pom.xml`, `dependencies.md` and commit changes with: `Update dependency reports` + +Remember: PRs without version bumps will fail CI (conflict resolution detailed above). + +### Resolving conflicts in `version.gradle.kts` +A branch conflict over the version number should be resolved as described below. + * If a merged branch has a number which is less than that of the current branch, the version of + the current branch stays. + * If the merged branch has the number which is greater or equal to that of the current branch, + the number should be increased by one. + +### When to bump the version? + - When a new branch is created. + +
      +--- + +## Running builds + +
      +Click to expand build instructions + +1. When modifying code, run: + ```bash + ./gradlew build + ``` + +2. If Protobuf (`.proto`) files are modified run: + ```bash + ./gradlew clean build + ```` + +3. Documentation-only changes run: + ```bash + ./gradlew dokka + ``` + Documentation-only changes do not require running tests! + +
      +--- + +## 📁 Project structure expectations + +
      +Click to expand project structure details + +```yaml +.github +buildSrc/ + + src/ + ├── main/ + │ ├── kotlin/ # Kotlin source files + │ └── java/ # Legacy Java code + ├── test/ + │ └── kotlin/ # Unit and integration tests + build.gradle.kts # Kotlin-based build configuration + + +build.gradle.kts # Kotlin-based build configuration +settings.gradle.kts # Project structure and settings +README.md # Project overview +AGENTS.md # LLM agent instructions (this file) +version.gradle.kts # Declares the project version. +``` + +
      +--- + +## 📄 Documentation tasks + +
      +Click to expand documentation guidelines + +- Suggest better **names** and **abstractions**. + +#### Documentation checklist +1. Ensure all public and internal APIs have KDoc examples. +2. Add in-line code blocks for clarity. +3. Use `TODO` comments with agent names for unresolved logic sections: + - Example: `// TODO(chatgpt): Refactor `EventStore` for better CQRS compliance.` + +
      + +--- + +## 🧪 Testing + +### Guidelines +- Do not use mocks, use stubs. +- Prefer [Kotest assertions][kotest-assertions] over + assertions from JUnit or Google Truth. + +### Responsibilities + +#### Codex +- Generate unit tests for APIs (handles edge cases/scenarios). +- Supply scaffolds for typical Kotlin patterns (`when`, sealed classes). + +#### ChatGPT +- Suggest test coverage improvements. +- Propose property-based testing or rare edge case scenarios. + +--- + +## 🚨 Safety rules for Agents + +- Do **not** auto-update external dependencies without explicit request. +- Do **not** inject analytics or telemetry code. +- Flag any usage of unsafe constructs (e.g., reflection, I/O on the main thread). +- Avoid generating blocking calls inside coroutines. + +--- + +## ⚙️ Refactoring guidelines + +
      +Click to expand refactoring guidelines + +- Do not replace Kotest assertions with standard Kotlin's Built-In Test Assertions. + +
      + +--- + +## 💬 Interaction tips – key to effective collaboration! + +
      +Click to expand collaboration guidelines + +- Human programmers may use inline comments to guide agents: + ```kotlin + // ChatGPT: Suggest a refactor for better readability. + // Codex: Complete the missing branches in this `when` block. + // ChatGPT: explain this logic. + // Codex: complete this function. + ``` +- Agents should ensure pull request messages are concise and descriptive: + ```text + feat(chatgpt): suggested DSL refactoring for query handlers + fix(codex): completed missing case in sealed class hierarchy + ``` +- Encourage `// TODO:` or `// FIXME:` comments to be clarified by ChatGPT. + +- When agents or humans add TODO comments, they **must** follow the format described on + the [dedicated page][todo-comments]. + +
      + +--- + +## 🧭 LLM goals + +These goals guide how agents (ChatGPT, Codex) are used in this project to: +- Help developers move faster without sacrificing code quality. +- Provide language-aware guidance on Kotlin/Java idioms. +- Lower the barrier to onboarding new contributors. +- Enable collaborative, explainable, and auditable development with AI. + +### Problem-solving framework for complex tasks + +When faced with complex tasks, follow this framework: + +1. **Decompose**: Break down the problem into smaller, manageable parts +2. **Analyze**: Understand the architectural implications of each part +3. **Pattern-Match**: Identify established patterns that apply +4. **Implement**: Write code that follows project conventions +5. **Test**: Ensure comprehensive test coverage +6. **Document**: Provide clear explanations of your solution + +*This framework helps maintain consistency across contributions from different agents.* + +### 🚀 GPT-4o advanced capabilities + +GPT-4o excels at these high-value tasks in our CQRS architecture: + +1. **Architecture-level insights** + - Suggesting architectural improvements in CQRS pattern implementation + - Identifying cross-cutting concerns between command and query sides + - Optimizing event flow and state propagation + +2. **Advanced Kotlin refactoring** + - Converting imperative code to idiomatic Kotlin (sequences, extensions, etc.) + - Applying context receivers and other Kotlin 1.6+ features + - Optimizing coroutine patterns and structured concurrency + +3. **Testing intelligence** + - Identifying missing property-based test scenarios + - Suggesting event sequence combinations that could cause race conditions + - Creating comprehensive test fixtures for complex domain objects + +#### Example prompts for GPT-4o + +Leverage GPT-4o's advanced capabilities with prompts like these: + +```text +# Architecture analysis +"Analyze this CommandHandler implementation and suggest improvements to better align with CQRS principles, especially considering event sourcing implications." + +# Kotlin refactoring +"Refactor this Java-style code to use more idiomatic Kotlin patterns. Pay special attention to immutability, extension functions, and DSL opportunities." + +# Test enhancement +"Review this test suite for our event processing pipeline and suggest additional test scenarios focusing on concurrent event handling edge cases." +``` + +--- + +## 📋 Common tasks + +
      +Click to expand common task instructions + +- **Adding a new dependency**: Update relevant files in `buildSrc` directory. +- **Creating a new module**: Follow existing module structure patterns. +- **Documentation**: Use KDoc style for public and internal APIs. +- **Testing**: Create comprehensive tests using Kotest assertions. + +
      + +--- + +## 👋 Welcome, Agents! + - You are here to help. + - Stay consistent, stay clear, and help this Kotlin/Java codebase become more robust, + elegant, and maintainable. + + +[spine-docs]: https://github.com/SpineEventEngine/documentation/wiki +[kotest-assertions]: https://kotest.io/docs/assertions/assertions.html +[todo-comments]: https://github.com/SpineEventEngine/documentation/wiki/TODO-comments diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index c333f29b1..b41bfb40f 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -169,7 +169,6 @@ dependencies { "com.github.jk1:gradle-license-report:$licenseReportVersion", "com.google.guava:guava:$guavaVersion", "com.google.protobuf:protobuf-gradle-plugin:$protobufPluginVersion", - "com.google.protobuf:protobuf-gradle-plugin:$protobufPluginVersion", "com.gradleup.shadow:shadow-gradle-plugin:$shadowVersion", "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:$detektVersion", "io.kotest:kotest-gradle-plugin:$kotestJvmPluginVersion", diff --git a/buildSrc/src/main/kotlin/DokkaExts.kt b/buildSrc/src/main/kotlin/DokkaExts.kt index 4f6d634cc..03a6e0392 100644 --- a/buildSrc/src/main/kotlin/DokkaExts.kt +++ b/buildSrc/src/main/kotlin/DokkaExts.kt @@ -28,7 +28,6 @@ import io.spine.dependency.build.Dokka import io.spine.gradle.publish.getOrCreate import java.io.File import java.time.LocalDate -import org.gradle.api.NamedDomainObjectProvider import org.gradle.api.Project import org.gradle.api.artifacts.Dependency import org.gradle.api.artifacts.dsl.DependencyHandler diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Flogger.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Flogger.kt new file mode 100644 index 000000000..769c90543 --- /dev/null +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Flogger.kt @@ -0,0 +1,42 @@ +/* + * Copyright 2025, TeamDev. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.dependency.lib + +// https://github.com/google/flogger +@Deprecated("Please use Spine Logging library instead.") +@Suppress("unused", "ConstPropertyName") +object Flogger { + internal const val version = "0.7.4" + const val lib = "com.google.flogger:flogger:$version" + + object Runtime { + const val systemBackend = "com.google.flogger:flogger-system-backend:$version" + const val log4j2Backend = "com.google.flogger:flogger-log4j2-backend:$version" + const val slf4JBackend = "com.google.flogger:flogger-slf4j-backend:$version" + const val grpcContext = "com.google.flogger:flogger-grpc-context:$version" + } +} diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/Runtime.kt b/buildSrc/src/main/kotlin/io/spine/gradle/Runtime.kt index 0e67c108a..fd2a5420d 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/Runtime.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/Runtime.kt @@ -87,7 +87,7 @@ class Cli(private val workingFolder: File) { /** * Asynchronously reads all lines from this [InputStream] and appends them - * to the given [StringWriter]. + * to the passed [StringWriter]. */ fun InputStream.pourTo(dest: StringWriter) { Thread { diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/PomXmlWriter.kt b/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/PomXmlWriter.kt index 21394a7f5..a17947bf2 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/PomXmlWriter.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/PomXmlWriter.kt @@ -48,10 +48,10 @@ internal constructor( * Writes the `pom.xml` file containing dependencies of this project * and its subprojects to the specified location. * - *

      If a file with the specified location exists, its contents are replaced + *

      If a file with the specified location exists, its contents will be substituted * with a new `pom.xml`. * - * @param file a file to write the `pom.xml` contents to + * @param file a file to write `pom.xml` contents to */ fun writeTo(file: File) { val fileWriter = FileWriter(file) @@ -74,7 +74,7 @@ internal constructor( /** * Obtains a string that contains project dependencies as XML. * - *

      The returned string also contains the closing project tag. + *

      Obtained string also contains a closing project tag. */ private fun projectDependencies(): String { val destination = StringWriter() diff --git a/buildSrc/src/main/kotlin/jvm-module.gradle.kts b/buildSrc/src/main/kotlin/jvm-module.gradle.kts index 30c80c2ff..b3d6ef0dd 100644 --- a/buildSrc/src/main/kotlin/jvm-module.gradle.kts +++ b/buildSrc/src/main/kotlin/jvm-module.gradle.kts @@ -30,7 +30,6 @@ import io.spine.dependency.build.Dokka import io.spine.dependency.build.ErrorProne import io.spine.dependency.build.JSpecify import io.spine.dependency.lib.Guava -import io.spine.dependency.lib.Kotlin import io.spine.dependency.lib.Protobuf import io.spine.dependency.local.Reflect import io.spine.dependency.test.Jacoco diff --git a/buildSrc/src/main/kotlin/kmp-publish.gradle.kts b/buildSrc/src/main/kotlin/kmp-publish.gradle.kts index 8fb391dc0..53b0a219f 100644 --- a/buildSrc/src/main/kotlin/kmp-publish.gradle.kts +++ b/buildSrc/src/main/kotlin/kmp-publish.gradle.kts @@ -1,5 +1,5 @@ /* - * Copyright 2024, TeamDev. All rights reserved. + * Copyright 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -64,7 +64,7 @@ plugins { publishing.publications { named("kotlinMultiplatform") { - // Although, the “common artifact” can't be used independently + // Although, the "common artifact" can't be used independently // of target artifacts, it is published with documentation. artifact(project.dokkaKotlinJar()) } diff --git a/gradle.properties b/gradle.properties index 68021b634..a6981f2b8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,29 +1,3 @@ -# -# Copyright 2025, TeamDev. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Redistribution and use in source and/or binary forms, with or without -# modification, must retain the above copyright notice and the following -# disclaimer. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# - # Allow Gradle to auto-detect installed JDKs. org.gradle.java.installations.auto-detect=true @@ -34,6 +8,7 @@ org.gradle.java.installations.auto-download=true #org.gradle.parallel=true #org.gradle.caching=true +# Dokka plugin eats more memory than usual. Therefore, all builds should have enough. org.gradle.jvmargs=-Xmx4096m -XX:MaxMetaspaceSize=1024m -XX:+UseParallelGC # suppress inspection "UnusedProperty" diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ff23a68d7..ca025c83a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From b0d07f72936f05b87e384427f8d72e75bcb4b421 Mon Sep 17 00:00:00 2001 From: Alexander Yevsyukov Date: Thu, 26 Jun 2025 12:32:38 +0100 Subject: [PATCH 15/28] Improve formatting --- .../logging/backend/log4j2/ValueQueue.java | 292 +++++++++--------- .../backend/probe/TypedBackendFactory.kt | 2 +- .../main/kotlin/io/spine/gradle/Runtime.kt | 9 +- .../kotlin/io/spine/gradle/repo/Repository.kt | 2 +- .../spine/gradle/report/pom/PomXmlWriter.kt | 3 +- .../jvm/backend/KeyValueFormatter.java | 250 +++++++-------- .../logging/given/LoggingRateForecasting.kt | 34 +- 7 files changed, 305 insertions(+), 287 deletions(-) diff --git a/backends/log4j2-backend/src/main/java/io/spine/logging/backend/log4j2/ValueQueue.java b/backends/log4j2-backend/src/main/java/io/spine/logging/backend/log4j2/ValueQueue.java index 9922e09ee..ab0506490 100644 --- a/backends/log4j2-backend/src/main/java/io/spine/logging/backend/log4j2/ValueQueue.java +++ b/backends/log4j2-backend/src/main/java/io/spine/logging/backend/log4j2/ValueQueue.java @@ -26,15 +26,16 @@ package io.spine.logging.backend.log4j2; -import static io.spine.logging.jvm.util.Checks.checkNotNull; - import io.spine.logging.jvm.MetadataKey.KeyValueHandler; import io.spine.logging.jvm.context.Tags; +import org.jspecify.annotations.Nullable; + import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Objects; -import org.jspecify.annotations.Nullable; + +import static io.spine.logging.jvm.util.Checks.checkNotNull; /** * A simple FIFO queue linked-list implementation designed to store multiple @@ -57,151 +58,160 @@ * label while being memory efficient in the common case where each label * really does only have one value. */ +@SuppressWarnings("UnnecessarilyQualifiedStaticUsage") final class ValueQueue implements Iterable { - // Since the number of elements is almost never above 1 or 2, a LinkedList saves space. - private final List values = new LinkedList<>(); - - private ValueQueue() {} - - static ValueQueue newQueue(Object item) { - checkNotNull(item, "item"); - ValueQueue valueQueue = new ValueQueue(); - valueQueue.put(item); - return valueQueue; - } - - static Object maybeWrap(Object value, @Nullable Object existingValue) { - checkNotNull(value, "value"); - if (existingValue == null) { - return value; - } else { - // This should only rarely happen, so a few small allocations seems acceptable. - ValueQueue existingQueue = - existingValue instanceof ValueQueue - ? (ValueQueue) existingValue - : ValueQueue.newQueue(existingValue); - existingQueue.put(value); - return existingQueue; + + // Since the number of elements is almost never above 1 or 2, a LinkedList saves space. + private final List values = new LinkedList<>(); + + private ValueQueue() { + } + + static ValueQueue newQueue(Object item) { + checkNotNull(item, "item"); + var valueQueue = new ValueQueue(); + valueQueue.put(item); + return valueQueue; + } + + static Object maybeWrap(Object value, @Nullable Object existingValue) { + checkNotNull(value, "value"); + if (existingValue == null) { + return value; + } else { + // This should only rarely happen, so a few small allocations seems acceptable. + var existingQueue = + existingValue instanceof ValueQueue + ? (ValueQueue) existingValue + : ValueQueue.newQueue(existingValue); + existingQueue.put(value); + return existingQueue; + } + } + + static void appendValues(String label, Object valueOrQueue, KeyValueHandler kvh) { + if (valueOrQueue instanceof ValueQueue) { + for (var value : (ValueQueue) valueOrQueue) { + emit(label, value, kvh); + } + } else { + emit(label, valueOrQueue, kvh); + } + } + + /** + * Helper method for creating and initializing a value queue with a non-nullable value. If value + * is an instance of Tags, each tag will be added to the value queue. + */ + static ValueQueue appendValueToNewQueue(Object value) { + var valueQueue = new ValueQueue(); + ValueQueue.emit(null, value, (k, v) -> valueQueue.put(v)); + return valueQueue; + } + + /** + * Emits a metadata label/value pair to a given {@code KeyValueHandler}, handling {@code Tags} + * values specially. + * + *

      Tags are key-value mappings which cannot be modified or replaced. If you add the tag + * mapping + * {@code "foo" -> true} and later add {@code "foo" -> false}, you get "foo" mapped to both + * true + * and false. This is very deliberate since the key space for tags is global and the risk of + * two + * bits of code accidentally using the same tag name is real (e.g. you add "id=xyz" to a scope, + * but you see "id=abcd" because someone else added "id=abcd" in a context you weren't aware + * of). + * + *

      Given three tag mappings: + *

        + *
      • {@code "baz"} (no value) + *
      • {@code "foo" -> true} + *
      • {@code "foo" -> false} + *
      + * + * the value queue is going to store the mappings as: + *
      {@code
      +     * tags=[baz, foo=false, foo=true]
      +     * }
      + * + *

      Reusing the label 'tags' is intentional as this allows us to store the flatten tags in + * Log4j2's ContextMap. + */ + static void emit(String label, Object value, KeyValueHandler kvh) { + if (value instanceof Tags) { + // Flatten tags to treat them as keys or key/value pairs, + // e.g., tags=[baz=bar, baz=bar2, foo] + ((Tags) value) + .asMap() + .forEach( + (k, v) -> { + if (v.isEmpty()) { + kvh.handle(label, k); + } else { + for (var obj : v) { + kvh.handle(label, k + '=' + obj); + } + } + }); + } else { + kvh.handle(label, value); + } } - } - - static void appendValues(String label, Object valueOrQueue, KeyValueHandler kvh) { - if (valueOrQueue instanceof ValueQueue) { - for (Object value : (ValueQueue) valueOrQueue) { - emit(label, value, kvh); - } - } else { - emit(label, valueOrQueue, kvh); + + @Override + public Iterator iterator() { + return values.iterator(); } - } - - /** - * Helper method for creating and initializing a value queue with a non-nullable value. If value - * is an instance of Tags, each tag will be added to the value queue. - */ - static ValueQueue appendValueToNewQueue(Object value) { - ValueQueue valueQueue = new ValueQueue(); - ValueQueue.emit(null, value, (k, v) -> valueQueue.put(v)); - return valueQueue; - } - - /** - * Emits a metadata label/value pair to a given {@code KeyValueHandler}, handling {@code Tags} - * values specially. - * - *

      Tags are key-value mappings which cannot be modified or replaced. If you add the tag mapping - * {@code "foo" -> true} and later add {@code "foo" -> false}, you get "foo" mapped to both true - * and false. This is very deliberate since the key space for tags is global and the risk of two - * bits of code accidentally using the same tag name is real (e.g. you add "id=xyz" to a scope, - * but you see "id=abcd" because someone else added "id=abcd" in a context you weren't aware of). - * - *

      Given three tag mappings: - *

        - *
      • {@code "baz"} (no value) - *
      • {@code "foo" -> true} - *
      • {@code "foo" -> false} - *
      - * - * the value queue is going to store the mappings as: - *
      {@code
      -   * tags=[baz, foo=false, foo=true]
      -   * }
      - * - *

      Reusing the label 'tags' is intentional as this allows us to store the flatten tags in - * Log4j2's ContextMap. - */ - static void emit(String label, Object value, KeyValueHandler kvh) { - if (value instanceof Tags) { - // Flatten tags to treat them as keys or key/value pairs, e.g. tags=[baz=bar, baz=bar2, foo] - ((Tags) value) - .asMap() - .forEach( - (k, v) -> { - if (v.isEmpty()) { - kvh.handle(label, k); - } else { - for (Object obj : v) { - kvh.handle(label, k + "=" + obj); - } - } - }); - } else { - kvh.handle(label, value); + + void put(Object item) { + checkNotNull(item, "item"); + values.add(item); } - } - - @Override - public Iterator iterator() { - return values.iterator(); - } - - void put(Object item) { - checkNotNull(item, "item"); - values.add(item); - } - - int size() { - return values.size(); - } - - /** - * Returns a string representation of the contents of the specified value queue. - * - *
        - *
      • If the value queue is empty, the method returns an empty string. - *
      • If the value queue contains a single element {@code a}, this method returns {@code - * a.toString()}. - *
      • Otherwise, the contents of the queue are formatted like a {@code List}. - *
      - */ - @Override - public String toString() { - // This case shouldn't actually happen unless you use the value queue - // for storing emitted values. - if (values.isEmpty()) { - return ""; + + int size() { + return values.size(); } - // Consider using MessageUtils.safeToString() here. - if (values.size() == 1) { - return values.get(0).toString(); + + /** + * Returns a string representation of the contents of the specified value queue. + * + *
        + *
      • If the value queue is empty, the method returns an empty string. + *
      • If the value queue contains a single element {@code a}, this method returns {@code + * a.toString()}. + *
      • Otherwise, the contents of the queue are formatted like a {@code List}. + *
      + */ + @Override + public String toString() { + // This case shouldn't actually happen unless you use the value queue + // for storing emitted values. + if (values.isEmpty()) { + return ""; + } + // Consider using MessageUtils.safeToString() here. + if (values.size() == 1) { + return values.get(0) + .toString(); + } + return values.toString(); } - return values.toString(); - } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + var that = (ValueQueue) o; + return values.equals(that.values); } - if (o == null || getClass() != o.getClass()) { - return false; + + @Override + public int hashCode() { + return Objects.hashCode(values); } - ValueQueue that = (ValueQueue) o; - return values.equals(that.values); - } - - @Override - public int hashCode() { - return Objects.hashCode(values); - } } diff --git a/backends/probe-backend/src/main/kotlin/io/spine/logging/backend/probe/TypedBackendFactory.kt b/backends/probe-backend/src/main/kotlin/io/spine/logging/backend/probe/TypedBackendFactory.kt index 6fed1542a..7ead2b4e3 100644 --- a/backends/probe-backend/src/main/kotlin/io/spine/logging/backend/probe/TypedBackendFactory.kt +++ b/backends/probe-backend/src/main/kotlin/io/spine/logging/backend/probe/TypedBackendFactory.kt @@ -40,7 +40,7 @@ import io.spine.logging.jvm.backend.LoggerBackend * * The type is public because it is used in a public inline method. * - * @param T type of the returned backends + * @param T type of the returned backends. */ public fun interface TypedBackendFactory { diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/Runtime.kt b/buildSrc/src/main/kotlin/io/spine/gradle/Runtime.kt index fd2a5420d..f9d3abbd0 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/Runtime.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/Runtime.kt @@ -24,6 +24,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +@file:Suppress("unused") + package io.spine.gradle import java.io.File @@ -35,7 +37,6 @@ import java.util.* /** * Utilities for working with processes from Gradle code. */ -@Suppress("unused") private const val ABOUT = "" /** @@ -52,9 +53,9 @@ class Cli(private val workingFolder: File) { * {@code String} array as a CLI command. If the execution is successful, the command output * is returned; otherwise an {@link IllegalStateException} is thrown. * - * @param command the command to execute - * @return the command line output - * @throws IllegalStateException if the execution fails + * @param command the command to execute. + * @return the command line output. + * @throws IllegalStateException if the execution fails. */ fun execute(vararg command: String): String { val outWriter = StringWriter() diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/repo/Repository.kt b/buildSrc/src/main/kotlin/io/spine/gradle/repo/Repository.kt index a586ffdb9..a378bcbe6 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/repo/Repository.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/repo/Repository.kt @@ -116,7 +116,7 @@ data class Repository( val password = properties.getProperty("user.password") return Credentials(username, password) } - + override fun equals(other: Any?): Boolean = when { this === other -> true other !is Repository -> false diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/PomXmlWriter.kt b/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/PomXmlWriter.kt index a17947bf2..82bb19a21 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/PomXmlWriter.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/PomXmlWriter.kt @@ -51,7 +51,7 @@ internal constructor( *

      If a file with the specified location exists, its contents will be substituted * with a new `pom.xml`. * - * @param file a file to write `pom.xml` contents to + * @param file a file to write `pom.xml` contents to. */ fun writeTo(file: File) { val fileWriter = FileWriter(file) @@ -83,4 +83,3 @@ internal constructor( return destination.toString() } } - diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/KeyValueFormatter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/KeyValueFormatter.java index fdaa90c02..82435c4f0 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/KeyValueFormatter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/backend/KeyValueFormatter.java @@ -1,5 +1,5 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2019, The Flogger Authors; 2025, TeamDev. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,13 +27,16 @@ package io.spine.logging.jvm.backend; import io.spine.logging.jvm.MetadataKey.KeyValueHandler; + import java.util.Arrays; import java.util.HashSet; import java.util.Set; + import org.jspecify.annotations.Nullable; /** - * Formats key/value pairs as a human readable string on the end of log statements. The format is: + * Formats key/value pairs as a human-readable string on the end of log statements. + * The format is: * *

        *   Log Message PREFIX[ key1=value1 key2=value2 ]
      @@ -62,131 +65,136 @@
        * The result is that this string should be fully reparsable (with the exception of replaced unsafe
        * characters) and easily searchable by text based tools such as "grep".
        *
      - * @see 
      - *     Original Java code of Google Flogger
      + * @see 
      + *         Original Java code of Google Flogger
        */
       public final class KeyValueFormatter implements KeyValueHandler {
      -  // If a single-line log message is > NEWLINE_LIMIT characters long, emit a newline first. Having
      -  // a limit prevents scanning very large messages just to discover they do not contain newlines.
      -  private static final int NEWLINE_LIMIT = 1000;
      -
      -  // All fundamental types other than "Character", since that can require escaping.
      -  private static final Set> FUNDAMENTAL_TYPES =
      -      new HashSet>(
      -          Arrays.asList(
      -              Boolean.class,
      -              Byte.class,
      -              Short.class,
      -              Integer.class,
      -              Long.class,
      -              Float.class,
      -              Double.class));
      -
      -  /**
      -   * Helper method to emit metadata key/value pairs in a format consistent with JSON. String
      -   * values which need to be quoted are JSON escaped, while other values are appended without
      -   * quoting or escaping. Labels are expected to be JSON "safe", and are never quoted. This format
      -   * is compatible with various "lightweight" JSON representations.
      -   */
      -  public static void appendJsonFormattedKeyAndValue(String label, Object value, StringBuilder out) {
      -    out.append(label).append('=');
      -    // We could also consider enums as safe if we used name() rather than toString().
      -    if (value == null) {
      -      // Alternately just emit the label without '=' to indicate presence without a value.
      -      out.append(true);
      -    } else if (FUNDAMENTAL_TYPES.contains(value.getClass())) {
      -      out.append(value);
      -    } else {
      -      out.append('"');
      -      appendEscaped(out, value.toString());
      -      out.append('"');
      +
      +    // If a single-line log message is > NEWLINE_LIMIT characters long, emit a newline first. Having
      +    // a limit prevents scanning very large messages just to discover they do not contain newlines.
      +    private static final int NEWLINE_LIMIT = 1000;
      +
      +    // All fundamental types other than "Character", since that can require escaping.
      +    private static final Set> FUNDAMENTAL_TYPES =
      +            new HashSet<>(
      +                    Arrays.asList(
      +                            Boolean.class,
      +                            Byte.class,
      +                            Short.class,
      +                            Integer.class,
      +                            Long.class,
      +                            Float.class,
      +                            Double.class));
      +
      +    /**
      +     * Helper method to emit metadata key/value pairs in a format consistent with JSON. String
      +     * values which need to be quoted are JSON escaped, while other values are appended without
      +     * quoting or escaping. Labels are expected to be JSON "safe", and are never quoted. This format
      +     * is compatible with various "lightweight" JSON representations.
      +     */
      +    public static void appendJsonFormattedKeyAndValue(String label, Object value,
      +                                                      StringBuilder out) {
      +        out.append(label)
      +           .append('=');
      +        // We could also consider enums as safe if we used name() rather than toString().
      +        if (value == null) {
      +            // Alternately just emit the label without '=' to indicate presence without a value.
      +            out.append(true);
      +        } else if (FUNDAMENTAL_TYPES.contains(value.getClass())) {
      +            out.append(value);
      +        } else {
      +            out.append('"');
      +            appendEscaped(out, value.toString());
      +            out.append('"');
      +        }
           }
      -  }
      -
      -  // The prefix to add before the key/value pairs (e.g. [[ foo=bar ])
      -  private final String prefix;
      -  private final String suffix;
      -  // The buffer originally containing the log message, to which we append context.
      -  private final StringBuilder out;
      -  // True once we've handled at least one key/value pair.
      -  private boolean haveSeenValues = false;
      -
      -  /**
      -   * Creates a formatter using the given prefix to append key/value pairs to the current log
      -   * message.
      -   */
      -  public KeyValueFormatter(String prefix, String suffix, StringBuilder out) {
      -    // Non-public class used frequently so skip null checks (callers are responsible).
      -    this.prefix = prefix;
      -    this.suffix = suffix;
      -    this.out = out;
      -  }
      -
      -  @Override
      -  public void handle(String label, @Nullable Object value) {
      -    if (haveSeenValues) {
      -      out.append(' ');
      -    } else {
      -      // At this point 'out' contains only the log message we are appending to.
      -      if (out.length() > 0) {
      -        out.append(out.length() > NEWLINE_LIMIT || out.indexOf("\n") != -1 ? '\n' : ' ');
      -      }
      -      out.append(prefix);
      -      haveSeenValues = true;
      +
      +    // The prefix to add before the key/value pairs (e.g. [[ foo=bar ])
      +    private final String prefix;
      +    private final String suffix;
      +    // The buffer originally containing the log message, to which we append context.
      +    private final StringBuilder out;
      +    // True once we've handled at least one key/value pair.
      +    private boolean haveSeenValues = false;
      +
      +    /**
      +     * Creates a formatter using the given prefix to append key/value pairs to the current log
      +     * message.
      +     */
      +    public KeyValueFormatter(String prefix, String suffix, StringBuilder out) {
      +        // Non-public class used frequently so skip null checks (callers are responsible).
      +        this.prefix = prefix;
      +        this.suffix = suffix;
      +        this.out = out;
           }
      -    appendJsonFormattedKeyAndValue(label, value, out);
      -  }
       
      -  /** Terminates handling of key/value pairs, leaving the originally supplied buffer modified. */
      -  public void done() {
      -    if (haveSeenValues) {
      -      out.append(suffix);
      +    @Override
      +    public void handle(String label, @Nullable Object value) {
      +        if (haveSeenValues) {
      +            out.append(' ');
      +        } else {
      +            // At this point 'out' contains only the log message we are appending to.
      +            if (out.length() > 0) {
      +                out.append(out.length() > NEWLINE_LIMIT || out.indexOf("\n") != -1 ? '\n' : ' ');
      +            }
      +            out.append(prefix);
      +            haveSeenValues = true;
      +        }
      +        appendJsonFormattedKeyAndValue(label, value, out);
           }
      -  }
      -
      -  private static void appendEscaped(StringBuilder out, String s) {
      -    int start = 0;
      -    // Most of the time this loop is executed zero times as there are no escapable chars.
      -    for (int idx = nextEscapableChar(s, start); idx != -1; idx = nextEscapableChar(s, start)) {
      -      out.append(s, start, idx);
      -      start = idx + 1;
      -      char c = s.charAt(idx);
      -      switch (c) {
      -        case '"':
      -        case '\\':
      -          break;
      -
      -        case '\n':
      -          c = 'n';
      -          break;
      -
      -        case '\r':
      -          c = 'r';
      -          break;
      -
      -        case '\t':
      -          c = 't';
      -          break;
      -
      -        default:
      -          // All that remains are unprintable ASCII control characters. It seems reasonable to
      -          // replace them since the calling code is in complete control of these values and they are
      -          // meant to be human readable. Use the Unicode replacement character '�'.
      -          out.append('\uFFFD');
      -          continue;
      -      }
      -      out.append("\\").append(c);
      +
      +    /** Terminates handling of key/value pairs, leaving the originally supplied buffer modified. */
      +    public void done() {
      +        if (haveSeenValues) {
      +            out.append(suffix);
      +        }
           }
      -    out.append(s, start, s.length());
      -  }
      -
      -  private static int nextEscapableChar(String s, int n) {
      -    for (; n < s.length(); n++) {
      -      char c = s.charAt(n);
      -      if (c < 0x20 || c == '"' || c == '\\') {
      -        return n;
      -      }
      +
      +    private static void appendEscaped(StringBuilder out, String s) {
      +        int start = 0;
      +        // Most of the time this loop is executed zero times as there are no escapable chars.
      +        for (int idx = nextEscapableChar(s, start); idx != -1; idx = nextEscapableChar(s, start)) {
      +            out.append(s, start, idx);
      +            start = idx + 1;
      +            char c = s.charAt(idx);
      +            switch (c) {
      +                case '"':
      +                case '\\':
      +                    break;
      +
      +                case '\n':
      +                    c = 'n';
      +                    break;
      +
      +                case '\r':
      +                    c = 'r';
      +                    break;
      +
      +                case '\t':
      +                    c = 't';
      +                    break;
      +
      +                default:
      +                    // All that remains are unprintable ASCII control characters. It seems reasonable to
      +                    // replace them since the calling code is in complete control of these values and they are
      +                    // meant to be human readable. Use the Unicode replacement character '�'.
      +                    out.append('\uFFFD');
      +                    continue;
      +            }
      +            out.append("\\")
      +               .append(c);
      +        }
      +        out.append(s, start, s.length());
      +    }
      +
      +    private static int nextEscapableChar(String s, int n) {
      +        for (; n < s.length(); n++) {
      +            char c = s.charAt(n);
      +            if (c < 0x20 || c == '"' || c == '\\') {
      +                return n;
      +            }
      +        }
      +        return -1;
           }
      -    return -1;
      -  }
       }
      diff --git a/logging/src/jvmTest/kotlin/io/spine/logging/given/LoggingRateForecasting.kt b/logging/src/jvmTest/kotlin/io/spine/logging/given/LoggingRateForecasting.kt
      index 4c05ddb93..cf5632be5 100644
      --- a/logging/src/jvmTest/kotlin/io/spine/logging/given/LoggingRateForecasting.kt
      +++ b/logging/src/jvmTest/kotlin/io/spine/logging/given/LoggingRateForecasting.kt
      @@ -1,5 +1,5 @@
       /*
      - * Copyright 2023, TeamDev. All rights reserved.
      + * Copyright 2025, TeamDev. All rights reserved.
        *
        * Licensed under the Apache License, Version 2.0 (the "License");
        * you may not use this file except in compliance with the License.
      @@ -39,9 +39,9 @@ import io.spine.logging.LoggingApi
        * its execution rate is limited by [LoggingApi.every] method.
        *
        * @param invocations
      - *          number of times a logging statement is invoked
      + *          number of times a logging statement is invoked.
        * @param invocationRateLimit
      - *          the configured rate limitation
      + *          the configured rate limitation.
        */
       @Suppress("SameParameterValue") // Extracted to a method for better readability.
       internal fun expectedRuns(invocations: Int, invocationRateLimit: Int): Int {
      @@ -55,9 +55,9 @@ internal fun expectedRuns(invocations: Int, invocationRateLimit: Int): Int {
        * enum value when the execution rate is limited by [LoggingApi.every] method.
        *
        * @param invocations
      - *          number of times a logging statement is invoked for each enum value
      + *          number of times a logging statement is invoked for each enum value.
        * @param invocationRateLimit
      - *          the configured rate limitation
      + *          the configured rate limitation.
        */
       @Suppress("SameParameterValue") // Extracted to a method for better readability.
       @JvmName("expectedRunsPerTask") // JVM has a problem with the conflicting erasures.
      @@ -75,9 +75,9 @@ internal fun expectedRuns(
        *
        * @param invocations
        *          number of times a logging statement is invoked for each combination
      - *          of enum values
      + *          of enum values.
        * @param invocationRateLimit
      - *          the configured rate limitation
      + *          the configured rate limitation.
        */
       @Suppress("SameParameterValue") // Extracted to a method for better readability.
       @JvmName("expectedRunsPerTasks") // JVM has a problem with the conflicting erasures.
      @@ -104,11 +104,11 @@ internal fun expectedRuns(invocations: InvocationsPerSite): Map
        * its execution rate is limited by [LoggingApi.atMostEvery] method.
        *
        * @param invocations
      - *          number of times a logging statement is invoked
      + *          number of times a logging statement is invoked.
        * @param intervalMillis
      - *          time interval between each two invocations
      + *          time interval between each two invocations.
        * @param intervalLimitMillis
      - *          the configured rate limitation
      + *          the configured rate limitation.
        */
       @Suppress("SameParameterValue") // Extracted to a method for better readability.
       internal fun expectedRuns(invocations: Int, intervalMillis: Long, intervalLimitMillis: Int): Int {
      @@ -132,11 +132,11 @@ internal fun expectedRuns(invocations: Int, intervalMillis: Long, intervalLimitM
        * executed when [interval][LoggingApi.atMostEvery] rate limit is configured.
        *
        * @param invocations
      - *          number of times a logging statement is invoked
      + *          number of times a logging statement is invoked.
        * @param intervalMillis
      - *          time interval between each two invocations
      + *          time interval between each two invocations.
        * @param intervalLimitMillis
      - *          the configured rate limitation
      + *          the configured rate limitation.
        */
       @Suppress("SameParameterValue") // Extracted to a method for better readability.
       internal fun expectedTimestamps(
      @@ -167,13 +167,13 @@ internal fun expectedTimestamps(
        * [invocation][LoggingApi.every] rate limits are configured simultaneously.
        *
        * @param invocations
      - *          number of times a logging statement is invoked
      + *          number of times a logging statement is invoked.
        * @param intervalMillis
      - *          time interval between each two invocations
      + *          time interval between each two invocations.
        * @param intervalLimitMillis
      - *          the configured time rate limitation
      + *          the configured time rate limitation.
        * @param invocationRateLimit
      - *          the configured invocation rate limitation
      + *          the configured invocation rate limitation.
        */
       @Suppress("SameParameterValue") // Extracted to a method for better readability.
       internal fun expectedStamps(
      
      From 98be155339a87d14d67ff983582b4db7acccb974 Mon Sep 17 00:00:00 2001
      From: Alexander Yevsyukov 
      Date: Thu, 26 Jun 2025 12:53:46 +0100
      Subject: [PATCH 16/28] Auto-updated by IDEA
      
      ---
       .idea/inspectionProfiles/Project_Default.xml | 16 ++--------------
       1 file changed, 2 insertions(+), 14 deletions(-)
      
      diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
      index 229f1d344..03dc31b22 100644
      --- a/.idea/inspectionProfiles/Project_Default.xml
      +++ b/.idea/inspectionProfiles/Project_Default.xml
      @@ -255,18 +255,6 @@
             
      * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ public final class ScopeType implements LoggingScopeProvider { /** diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContext.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContext.java index c877352e3..cb4960102 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContext.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContext.java @@ -95,7 +95,7 @@ * of any modification methods called (e.g. {@link #addTags(Tags)}). * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ public abstract class ScopedLoggingContext { diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContexts.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContexts.java index d5dbaa149..ae22f0842 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContexts.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/ScopedLoggingContexts.java @@ -40,7 +40,7 @@ * {@link ScopedLoggingContext#getInstance}. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ public final class ScopedLoggingContexts { private static final Middleman logger = Middleman.forEnclosingClass(); diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/SegmentTrie.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/SegmentTrie.java index 9bf30bc29..f67ea3fa8 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/SegmentTrie.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/SegmentTrie.java @@ -72,7 +72,7 @@ * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ // This class could easily be made a shareable utility class if need by anyone else. abstract class SegmentTrie { diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/Tags.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/Tags.java index 5b72ca4af..a3b2e0a3e 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/Tags.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/Tags.java @@ -73,7 +73,7 @@ * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ public final class Tags { diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/package-info.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/package-info.java index 43b264701..9f52043ae 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/context/package-info.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/context/package-info.java @@ -28,7 +28,7 @@ * Contains implementation of the context metadata. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ @CheckReturnValue package io.spine.logging.jvm.context; diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/package-info.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/package-info.java index ae7ee0d34..86671ba03 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/package-info.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/package-info.java @@ -28,7 +28,7 @@ * Flogger is a fluent API for writing log messages. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ @CheckReturnValue package io.spine.logging.jvm; diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/BraceStyleParameter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/BraceStyleParameter.java index dec261929..4058d1a28 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/BraceStyleParameter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/BraceStyleParameter.java @@ -40,7 +40,7 @@ * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ public class BraceStyleParameter extends Parameter { diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeFormat.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeFormat.java index 6e6aceb4e..7ab1c1f91 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeFormat.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeFormat.java @@ -38,7 +38,7 @@ * discouraged with non-{@code Calendar} arguments. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ public enum DateTimeFormat { // The following conversion characters are used for formatting times: diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeParameter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeParameter.java index b42fab1b9..f7efbbcaa 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeParameter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/DateTimeParameter.java @@ -35,7 +35,7 @@ * This class is immutable and thread-safe, as per the Parameter contract. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ public final class DateTimeParameter extends Parameter { /** diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/Parameter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/Parameter.java index 38465b706..926168074 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/Parameter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/Parameter.java @@ -41,7 +41,7 @@ * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ public abstract class Parameter { diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/ParameterVisitor.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/ParameterVisitor.java index c94758a15..4e9117f20 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/ParameterVisitor.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/ParameterVisitor.java @@ -33,7 +33,7 @@ * A visitor of log message arguments, dispatched by {@code Parameter} instances. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ // TODO: When all other refactoring done, rename to ArgumentVisitor public interface ParameterVisitor { diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/SimpleParameter.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/SimpleParameter.java index 266f2851d..fef5c96af 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/SimpleParameter.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/SimpleParameter.java @@ -43,7 +43,7 @@ * This class is immutable and thread safe, as per the Parameter contract. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ public final class SimpleParameter extends Parameter { diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/package-info.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/package-info.java index 92b89bb7b..c1bb4c3a4 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/package-info.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parameter/package-info.java @@ -28,7 +28,7 @@ * Contains different types of message template parameters. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ @CheckReturnValue package io.spine.logging.jvm.parameter; diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/BraceStyleMessageParser.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/BraceStyleMessageParser.java index 74316cd26..928ff55bd 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/BraceStyleMessageParser.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/BraceStyleMessageParser.java @@ -37,7 +37,7 @@ * {@link DefaultBraceStyleMessageParser}, which provides default behavior for simple place-holders. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ public abstract class BraceStyleMessageParser extends MessageParser { /** diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultBraceStyleMessageParser.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultBraceStyleMessageParser.java index 6280c498f..32be1605e 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultBraceStyleMessageParser.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultBraceStyleMessageParser.java @@ -40,7 +40,7 @@ * a parse error, so adding support for it should not be an issue. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ public class DefaultBraceStyleMessageParser extends BraceStyleMessageParser { private static final BraceStyleMessageParser INSTANCE = new DefaultBraceStyleMessageParser(); diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultPrintfMessageParser.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultPrintfMessageParser.java index 8753e9dcf..edaecb7cd 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultPrintfMessageParser.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/DefaultPrintfMessageParser.java @@ -47,7 +47,7 @@ * This class is immutable and thread safe (and any subclasses must also be so). * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ public class DefaultPrintfMessageParser extends PrintfMessageParser { diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/MessageBuilder.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/MessageBuilder.java index 224b22e57..492701b0d 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/MessageBuilder.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/MessageBuilder.java @@ -40,7 +40,7 @@ * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ public abstract class MessageBuilder { diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/MessageParser.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/MessageParser.java index 41738e401..4f0530339 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/MessageParser.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/MessageParser.java @@ -31,7 +31,7 @@ * and {@link BraceStyleMessageParser}). * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ public abstract class MessageParser { /** diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/ParseException.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/ParseException.java index 38a926bd2..f4401510e 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/ParseException.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/ParseException.java @@ -34,7 +34,7 @@ * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ public final class ParseException extends RuntimeException { diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/PrintfMessageParser.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/PrintfMessageParser.java index 4fb73ddf7..c02c76671 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/PrintfMessageParser.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/PrintfMessageParser.java @@ -37,7 +37,7 @@ * {@link DefaultPrintfMessageParser}, which provides compatibility with {@link String#format}. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ public abstract class PrintfMessageParser extends MessageParser { // Assume that anything outside this set of chars is suspicious and not safe. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/package-info.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/package-info.java index ea3be393d..aa2935896 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/package-info.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/parser/package-info.java @@ -28,7 +28,7 @@ * Contains message parsing utilities. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ @CheckReturnValue package io.spine.logging.jvm.parser; diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/util/Checks.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/util/Checks.java index 536e4ede3..d018bc88c 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/util/Checks.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/util/Checks.java @@ -32,7 +32,7 @@ * Flogger's own version of the Guava {@code Preconditions} class for simple, often used checks. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ public class Checks { diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/util/RecursionDepth.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/util/RecursionDepth.java index 56190fb63..29cad2b4f 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/util/RecursionDepth.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/util/RecursionDepth.java @@ -39,7 +39,7 @@ * Platform.getCurrentRecursionDepth()}. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ public final class RecursionDepth implements Closeable { private static final ThreadLocal holder = new ThreadLocal() { diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/util/StaticMethodCaller.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/util/StaticMethodCaller.java index 7efa9bf51..08e2e8a86 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/util/StaticMethodCaller.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/util/StaticMethodCaller.java @@ -36,7 +36,7 @@ * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ public final class StaticMethodCaller { // TODO(cgdecker): Rename this class; eventually perhaps just roll it into DefaultPlatform diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/util/package-info.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/util/package-info.java index 1d57bd0ef..644fa165f 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/util/package-info.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/util/package-info.java @@ -28,7 +28,7 @@ * Contains utilities for determining log site information. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ @CheckReturnValue package io.spine.logging.jvm.util; diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/AbstractLoggerSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/AbstractLoggerSpec.kt index 158944b4f..23c137fe7 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/AbstractLoggerSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/AbstractLoggerSpec.kt @@ -51,7 +51,7 @@ import org.junit.jupiter.api.Test * See [LogContextSpec] for the most tests related to base logging behavior. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ @DisplayName("`AbstractLogger` should") internal class AbstractLoggerSpec { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/CountingRateLimiterSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/CountingRateLimiterSpec.kt index d1b490568..b8445f00f 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/CountingRateLimiterSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/CountingRateLimiterSpec.kt @@ -42,7 +42,7 @@ import org.junit.jupiter.api.Test * Tests for [CountingRateLimiter]. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ @DisplayName("`CountingRateLimiter` should") internal class CountingRateLimiterSpec { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/DurationRateLimiterSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/DurationRateLimiterSpec.kt index 147de1291..7ba8ea0df 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/DurationRateLimiterSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/DurationRateLimiterSpec.kt @@ -46,7 +46,7 @@ import org.junit.jupiter.api.Test * Tests for [DurationRateLimiter]. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ @DisplayName("`DurationRateLimiter` should") internal class DurationRateLimiterSpec { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/JvmLogSitesSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/JvmLogSitesSpec.kt index e1b659513..75b32e65b 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/JvmLogSitesSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/JvmLogSitesSpec.kt @@ -39,7 +39,7 @@ import org.junit.jupiter.api.Test * Tests for [JvmLogSites]. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ @DisplayName("`JvmLogSites` should") internal class JvmLogSitesSpec { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/JvmMetadataKeySpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/JvmMetadataKeySpec.kt index 6c7a8baf9..40883467c 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/JvmMetadataKeySpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/JvmMetadataKeySpec.kt @@ -44,7 +44,7 @@ import org.junit.jupiter.api.Test * Tests for [MetadataKey]. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ @DisplayName("`JvmMetadataKey` should") internal class JvmMetadataKeySpec { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LogContextSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LogContextSpec.kt index 0f3cff069..a1b12b3f2 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LogContextSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LogContextSpec.kt @@ -66,7 +66,7 @@ import org.junit.jupiter.api.Test * Tests for [LogContext]. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ @DisplayName("`LogContext` should") internal class LogContextSpec { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LogPerBucketingStrategySpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LogPerBucketingStrategySpec.kt index d4d141689..4b6e52395 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LogPerBucketingStrategySpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LogPerBucketingStrategySpec.kt @@ -41,7 +41,7 @@ import org.junit.jupiter.api.Test * [LogPerBucketingStrategy] declares a method named `apply`. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ @DisplayName("`LogPerBucketingStrategy` should provide a strategy that") internal class LogPerBucketingStrategySpec { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LogSiteMapSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LogSiteMapSpec.kt index be49a09d8..6641ac9e3 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LogSiteMapSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LogSiteMapSpec.kt @@ -45,7 +45,7 @@ import org.junit.jupiter.api.Test * Tests for [LogSiteMap]. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ @DisplayName("`LogSiteMap` should") internal class LogSiteMapSpec { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LogSiteStackTraceSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LogSiteStackTraceSpec.kt index a4ebb41c6..925ef2a50 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LogSiteStackTraceSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LogSiteStackTraceSpec.kt @@ -38,7 +38,7 @@ import org.junit.jupiter.api.Test * Tests for [LogSiteStackTrace]. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ @DisplayName("`LogSiteStackTrace` should") internal class LogSiteStackTraceSpec { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LoggerSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LoggerSpec.kt index f6a7f4f24..22c0e25cf 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LoggerSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LoggerSpec.kt @@ -46,7 +46,7 @@ import org.junit.jupiter.api.Test * See [LogContextSpec] for the most tests related to base logging behavior. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ @DisplayName("`FluentLogger2` should") internal class LoggerSpec { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LoggingScopeSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LoggingScopeSpec.kt index fe40c7934..28f73b3d4 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LoggingScopeSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/LoggingScopeSpec.kt @@ -35,7 +35,7 @@ import org.junit.jupiter.api.Test * Tests for [LoggingScope]. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ @DisplayName("`LoggingScope` should") internal class LoggingScopeSpec { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/RateLimitStatusSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/RateLimitStatusSpec.kt index 658dfb137..5021cc875 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/RateLimitStatusSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/RateLimitStatusSpec.kt @@ -45,7 +45,7 @@ import org.junit.jupiter.api.Test * Tests for [RateLimitStatus]. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ @DisplayName("`RateLimitStatusSpec` should") internal class RateLimitStatusSpec { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/SamplingRateLimiterSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/SamplingRateLimiterSpec.kt index c9e3065f6..1d9e04038 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/SamplingRateLimiterSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/SamplingRateLimiterSpec.kt @@ -45,7 +45,7 @@ import org.junit.jupiter.api.Test * Tests for [SamplingRateLimiter]. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ @DisplayName("`SamplingRateLimiter` should") internal class SamplingRateLimiterSpec { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/SpecializedLogSiteKeySpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/SpecializedLogSiteKeySpec.kt index a063ecb89..b44f8fb97 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/SpecializedLogSiteKeySpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/SpecializedLogSiteKeySpec.kt @@ -36,7 +36,7 @@ import org.junit.jupiter.api.Test * Tests for [SpecializedLogSiteKey]. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ @DisplayName("`SpecializedLogSiteKey` should") internal class SpecializedLogSiteKeySpec { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/StackBasedLogSiteSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/StackBasedLogSiteSpec.kt index 3bf7bdcb2..bd7cad3c4 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/StackBasedLogSiteSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/StackBasedLogSiteSpec.kt @@ -38,7 +38,7 @@ import org.junit.jupiter.api.Test * Tests for [StackBasedLogSite]. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ @DisplayName("`StackBasedLogSite` should") internal class StackBasedLogSiteSpec { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/BaseMessageFormatterSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/BaseMessageFormatterSpec.kt index 841202d70..d59d39800 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/BaseMessageFormatterSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/BaseMessageFormatterSpec.kt @@ -40,7 +40,7 @@ import org.junit.jupiter.api.Test * Tests for [BaseMessageFormatter]. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ @DisplayName("`BaseMessageFormatter` should") internal class BaseMessageFormatterSpec { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatCharSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatCharSpec.kt index 3a0d121b0..64b0e3a5d 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatCharSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatCharSpec.kt @@ -47,7 +47,7 @@ import org.junit.jupiter.api.Test * Tests for [FormatChar]. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ @DisplayName("`FormatChar` should") internal class FormatCharSpec { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatOptionsSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatOptionsSpec.kt index cedb1faa5..e705fe5fd 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatOptionsSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatOptionsSpec.kt @@ -52,7 +52,7 @@ import org.junit.jupiter.api.Test * Tests for [FormatOptions]. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ @DisplayName("`FormatOptions` should") internal class FormatOptionsSpec { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatTypeSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatTypeSpec.kt index 58bec63a3..7714e551e 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatTypeSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/FormatTypeSpec.kt @@ -42,7 +42,7 @@ import org.junit.jupiter.api.Test * Tests for [FormatType]. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ @DisplayName("`FormatType` should") internal class FormatTypeSpec { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/KeyValueFormatterSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/KeyValueFormatterSpec.kt index a7c0bf16b..db845caf4 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/KeyValueFormatterSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/KeyValueFormatterSpec.kt @@ -35,7 +35,7 @@ import org.junit.jupiter.api.Test * Tests for [KeyValueFormatter]. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ @DisplayName("`KeyValueFormatter` should") internal class KeyValueFormatterSpec { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MessageUtilsSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MessageUtilsSpec.kt index ee4f95004..f42c4488d 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MessageUtilsSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MessageUtilsSpec.kt @@ -53,7 +53,7 @@ import org.junit.jupiter.api.Test * Tests for [MessageUtils]. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ @DisplayName("`MessageUtils` should") internal class MessageUtilsSpec { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataHandlerSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataHandlerSpec.kt index f147da3ce..139b6db60 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataHandlerSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataHandlerSpec.kt @@ -40,7 +40,7 @@ import org.junit.jupiter.api.Test * Tests for [MetadataHandler]. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ @DisplayName("`MetadataHandler` should") internal class MetadataHandlerSpec { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataKeyValueHandlersSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataKeyValueHandlersSpec.kt index e59c22ae1..270cdb9ed 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataKeyValueHandlersSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataKeyValueHandlersSpec.kt @@ -42,7 +42,7 @@ import org.junit.jupiter.api.Test * Tests for [MetadataKeyValueHandlers]. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ @DisplayName("`MetadataKeyValueHandlers` should") internal class MetadataKeyValueHandlersSpec { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataProcessorSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataProcessorSpec.kt index a8d53e071..1f7135c66 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataProcessorSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/MetadataProcessorSpec.kt @@ -44,7 +44,7 @@ import org.junit.jupiter.api.Test * Tests for [MetadataProcessor]. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ @Suppress("unused") internal abstract class MetadataProcessorSpec(private val factory: ProcessorFactory) { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/SimpleMessageFormatterSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/SimpleMessageFormatterSpec.kt index 55f1363ee..e053a8c72 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/SimpleMessageFormatterSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/SimpleMessageFormatterSpec.kt @@ -42,7 +42,7 @@ import org.junit.jupiter.api.Test * Tests for [SimpleMessageFormatter]. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ @DisplayName("`SimpleMessageFormatter` should") internal class SimpleMessageFormatterSpec { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/FakeLogData.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/FakeLogData.kt index 1901be4f3..436fae2cb 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/FakeLogData.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/FakeLogData.kt @@ -42,7 +42,7 @@ import java.util.logging.Level /** * A mutable [LogData] fot testing backends and other log handling code. * - * @see Original Java code of Google Flogger + * @see Original Java code of Google Flogger for historical context. */ @Suppress("TooManyFunctions") // Many getters and setters. class FakeLogData : LogData { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/FakeMetadata.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/FakeMetadata.kt index 0621da77f..e1d81c299 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/FakeMetadata.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/FakeMetadata.kt @@ -34,7 +34,7 @@ import io.spine.logging.jvm.backend.Metadata * A mutable [Metadata] implementation for testing logging backends * and other log handling code. * - * @see Original Java code of Google Flogger + * @see Original Java code of Google Flogger for historical context. */ class FakeMetadata : Metadata() { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/MemoizingLoggerBackend.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/MemoizingLoggerBackend.kt index ed872ec1c..f709d458b 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/MemoizingLoggerBackend.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/backend/given/MemoizingLoggerBackend.kt @@ -35,7 +35,7 @@ import java.util.logging.Level * * This class is mutable and not thread safe. * - * @see Original Java code of Google Flogger + * @see Original Java code of Google Flogger for historical context. */ class MemoizingLoggerBackend(val name: String = "com.example.MyClass") : LoggerBackend() { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/AbstractContextDataProviderSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/AbstractContextDataProviderSpec.kt index bfc5171a1..7ac6a854a 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/AbstractContextDataProviderSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/AbstractContextDataProviderSpec.kt @@ -62,7 +62,7 @@ private typealias LoggerName = String /** * Set of common tests for [ContextDataProvider]s. * - * @see Original Java code of Google Flogger + * @see Original Java code of Google Flogger for historical context. */ @DisplayName("`ContextDataProvider` should") // This name is to be overridden by inheritors. abstract class AbstractContextDataProviderSpec { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/ContextMetadataSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/ContextMetadataSpec.kt index 787b0fa7c..10c529952 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/ContextMetadataSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/ContextMetadataSpec.kt @@ -43,7 +43,7 @@ import org.junit.jupiter.api.assertThrows * Tests for [ContextMetadata]. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ @DisplayName("`ContextMetadata` should") internal class ContextMetadataSpec { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/LogLevelMapSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/LogLevelMapSpec.kt index beea6db93..6a0497663 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/LogLevelMapSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/LogLevelMapSpec.kt @@ -41,7 +41,7 @@ import org.junit.jupiter.api.Test * Tests for [LogLevelMap]. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ @DisplayName("`LogLevelMap` should") internal class LogLevelMapSpec { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/ScopedLoggingContextSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/ScopedLoggingContextSpec.kt index 8baa6b308..e62c21789 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/ScopedLoggingContextSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/ScopedLoggingContextSpec.kt @@ -41,7 +41,7 @@ import org.junit.jupiter.api.assertThrows * inheriting from `AbstractScopedLoggingContextTest`. Take a look on `flogger-testing` module. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ @DisplayName("`ScopedLoggingContext` should") internal class ScopedLoggingContextSpec { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/SegmentTrieSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/SegmentTrieSpec.kt index ddd826337..4041ad470 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/SegmentTrieSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/SegmentTrieSpec.kt @@ -38,7 +38,7 @@ import org.junit.jupiter.api.assertThrows * Tests for [SegmentTrie]. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ @DisplayName("`SegmentTrie` should return") internal class SegmentTrieSpec { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/TagsSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/TagsSpec.kt index a7037d4a8..bfc816843 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/TagsSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/context/TagsSpec.kt @@ -44,7 +44,7 @@ import org.junit.jupiter.api.assertThrows * Tests for [Tags]. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ @DisplayName("`Tags` should") internal class TagsSpec { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/given/ConfigurableLogger.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/given/ConfigurableLogger.kt index 20cd32a33..4c0bbd845 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/given/ConfigurableLogger.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/given/ConfigurableLogger.kt @@ -41,7 +41,7 @@ import java.util.logging.Level * This logger has specific methods for injecting timestamps * and forcing log statements. * - * @see Original Java code of Google Flogger + * @see Original Java code of Google Flogger for historical context. */ class ConfigurableLogger(backend: LoggerBackend) : AbstractLogger(backend) { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/given/FakeLogSite.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/given/FakeLogSite.kt index ac7bf47c4..506b34acd 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/given/FakeLogSite.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/given/FakeLogSite.kt @@ -33,7 +33,7 @@ import java.util.concurrent.atomic.AtomicInteger /** * A simplified implementation of [JvmLogSite] for testing. * - * @see Original Java code of Google Flogger + * @see Original Java code of Google Flogger for historical context. */ class FakeLogSite( private val className: String, diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parameter/ParameterSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parameter/ParameterSpec.kt index ada4503b4..b88a8b47a 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parameter/ParameterSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parameter/ParameterSpec.kt @@ -37,7 +37,7 @@ import org.junit.jupiter.api.assertThrows * Tests for [Parameter]. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ @DisplayName("`Parameter` should") internal class ParameterSpec { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parameter/SimpleParameterSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parameter/SimpleParameterSpec.kt index 243043d62..a7ce6cf01 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parameter/SimpleParameterSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parameter/SimpleParameterSpec.kt @@ -46,7 +46,7 @@ import org.junit.jupiter.api.Nested * Tests for [SimpleParameter]. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ @DisplayName("`SimpleParameter` should") internal class SimpleParameterSpec { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parser/BraceStyleMessageParserSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parser/BraceStyleMessageParserSpec.kt index c13421953..bb1761ac0 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parser/BraceStyleMessageParserSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parser/BraceStyleMessageParserSpec.kt @@ -40,7 +40,7 @@ import org.junit.jupiter.api.assertThrows * Tests for [BraceStyleMessageParser]. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ @DisplayName("`BraceStyleMessageParser` should") internal class BraceStyleMessageParserSpec { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parser/DefaultBraceStyleMessageParserSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parser/DefaultBraceStyleMessageParserSpec.kt index 98bb96eac..e9778062d 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parser/DefaultBraceStyleMessageParserSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parser/DefaultBraceStyleMessageParserSpec.kt @@ -42,7 +42,7 @@ import org.junit.jupiter.api.assertThrows * Tests for [DefaultBraceStyleMessageParser]. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ @DisplayName("`DefaultBraceStyleMessageParser` should") internal class DefaultBraceStyleMessageParserSpec { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parser/DefaultPrintfMessageParserSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parser/DefaultPrintfMessageParserSpec.kt index 3ef45d422..4a599f60b 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parser/DefaultPrintfMessageParserSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parser/DefaultPrintfMessageParserSpec.kt @@ -39,7 +39,7 @@ import org.junit.jupiter.api.assertThrows * Tests for [DefaultPrintfMessageParser]. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ @DisplayName("`DefaultPrintfMessageParser` should") internal class DefaultPrintfMessageParserSpec { diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parser/PrintfMessageParserSpec.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parser/PrintfMessageParserSpec.kt index 89f1a6ea4..7777b53f2 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parser/PrintfMessageParserSpec.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parser/PrintfMessageParserSpec.kt @@ -42,7 +42,7 @@ import org.junit.jupiter.api.assertThrows * Tests for [PrintfMessageParser]. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ @DisplayName("`PrintfMessageParserSpec` should") @Suppress("DANGEROUS_CHARACTERS") // '%' character is needed in the test name. diff --git a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parser/given/ParserTestEnv.kt b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parser/given/ParserTestEnv.kt index 1e0abe4c8..4fd0288eb 100644 --- a/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parser/given/ParserTestEnv.kt +++ b/jvm/middleware/src/test/kotlin/io/spine/logging/jvm/parser/given/ParserTestEnv.kt @@ -44,7 +44,7 @@ import org.junit.jupiter.api.assertThrows * This files contains test utils for parse-related tests. * * @see - * Original Java code of Google Flogger + * Original Java code of Google Flogger for historical context. */ /** diff --git a/jvm/platform-generator/src/main/java/io/spine/logging/backend/generator/PlatformProviderGenerator.java b/jvm/platform-generator/src/main/java/io/spine/logging/backend/generator/PlatformProviderGenerator.java index cfedb6dac..216d914a0 100644 --- a/jvm/platform-generator/src/main/java/io/spine/logging/backend/generator/PlatformProviderGenerator.java +++ b/jvm/platform-generator/src/main/java/io/spine/logging/backend/generator/PlatformProviderGenerator.java @@ -77,7 +77,7 @@ * (e.g., proguard) observe the dependency correctly, which is not the case * when reflection is used to look up classes. * - * @see Original Java code of Google Flogger + * @see Original Java code of Google Flogger for historical context. */ @SuppressWarnings("DuplicateStringLiteralInspection") // Uses literals with FQN. public final class PlatformProviderGenerator { diff --git a/platforms/jvm-default-platform/src/main/java/io/spine/logging/backend/system/DefaultPlatform.java b/platforms/jvm-default-platform/src/main/java/io/spine/logging/backend/system/DefaultPlatform.java index ecfd02a7b..6de4bff96 100644 --- a/platforms/jvm-default-platform/src/main/java/io/spine/logging/backend/system/DefaultPlatform.java +++ b/platforms/jvm-default-platform/src/main/java/io/spine/logging/backend/system/DefaultPlatform.java @@ -79,7 +79,7 @@ * | {@link Clock} | {@code flogger.clock} | {@link SystemClock}, a millisecond-precision clock | * * - * @see Original Java code of Google Flogger + * @see Original Java code of Google Flogger for historical context. */ // Non-final for testing. public class DefaultPlatform extends Platform { diff --git a/platforms/jvm-default-platform/src/main/java/io/spine/logging/backend/system/StackBasedCallerFinder.java b/platforms/jvm-default-platform/src/main/java/io/spine/logging/backend/system/StackBasedCallerFinder.java index be176db53..c5f3d873f 100644 --- a/platforms/jvm-default-platform/src/main/java/io/spine/logging/backend/system/StackBasedCallerFinder.java +++ b/platforms/jvm-default-platform/src/main/java/io/spine/logging/backend/system/StackBasedCallerFinder.java @@ -39,7 +39,7 @@ *

      See class documentation in {@link LogCallerFinder} for important * implementation restrictions. * - * @see Original Java code of Google Flogger + * @see Original Java code of Google Flogger for historical context. */ public final class StackBasedCallerFinder extends LogCallerFinder { private static final LogCallerFinder INSTANCE = new StackBasedCallerFinder(); diff --git a/platforms/jvm-default-platform/src/main/java/io/spine/logging/backend/system/SystemClock.java b/platforms/jvm-default-platform/src/main/java/io/spine/logging/backend/system/SystemClock.java index 052a94c4a..b19668c22 100644 --- a/platforms/jvm-default-platform/src/main/java/io/spine/logging/backend/system/SystemClock.java +++ b/platforms/jvm-default-platform/src/main/java/io/spine/logging/backend/system/SystemClock.java @@ -36,7 +36,7 @@ *

      See class documentation in {@link Clock} for important * implementation restrictions. * - * @see Original Java code of Google Flogger + * @see Original Java code of Google Flogger for historical context. */ public final class SystemClock extends Clock { private static final SystemClock INSTANCE = new SystemClock(); diff --git a/platforms/jvm-default-platform/src/main/java/io/spine/logging/backend/system/package-info.java b/platforms/jvm-default-platform/src/main/java/io/spine/logging/backend/system/package-info.java index ef22e04d4..1af478dc8 100644 --- a/platforms/jvm-default-platform/src/main/java/io/spine/logging/backend/system/package-info.java +++ b/platforms/jvm-default-platform/src/main/java/io/spine/logging/backend/system/package-info.java @@ -31,7 +31,7 @@ *

      Although {@code system} is not the best name for this package, * the better option, {@code default}, is reserved by Java and cannot be used here. * - * @see Original Java code of Google Flogger + * @see Original Java code of Google Flogger for historical context. */ @CheckReturnValue package io.spine.logging.backend.system; diff --git a/platforms/jvm-default-platform/src/test/kotlin/io/spine/logging/backend/system/DefaultPlatformSpec.kt b/platforms/jvm-default-platform/src/test/kotlin/io/spine/logging/backend/system/DefaultPlatformSpec.kt index 43ed003c2..e70d441a7 100644 --- a/platforms/jvm-default-platform/src/test/kotlin/io/spine/logging/backend/system/DefaultPlatformSpec.kt +++ b/platforms/jvm-default-platform/src/test/kotlin/io/spine/logging/backend/system/DefaultPlatformSpec.kt @@ -48,7 +48,7 @@ import org.junit.jupiter.api.Test * the singleton behavior, since the precise platform loaded at runtime * can vary in details. * - * @see Original Java code of Google Flogger + * @see Original Java code of Google Flogger for historical context. */ @DisplayName("`DefaultPlatform` should") internal class DefaultPlatformSpec { From 390ca77eab56e4f1fcafd8c9f114b25b8b3b17dc Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Thu, 26 Jun 2025 17:11:41 +0100 Subject: [PATCH 28/28] Add API notes in `Middleman` types --- .../src/main/java/io/spine/logging/jvm/Middleman.java | 11 ++++++----- .../main/java/io/spine/logging/jvm/MiddlemanApi.java | 3 +++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/Middleman.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/Middleman.java index ac274f7fc..e7567c314 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/Middleman.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/Middleman.java @@ -37,15 +37,16 @@ * The default implementation of {@link AbstractLogger} which returns the basic {@link MiddlemanApi} * and uses the default parser and system configured backend. * - *

      - * Note that when extending the logging API or specifying a new parser, you will need to create a + *

      Note that when extending the logging API or specifying a new parser, you will need to create a * new logger class (rather than extending this one). Unlike the {@link LogContext} class, * which must be extended in order to modify the logging API, this class is not generified and thus * cannot be modified to produce a different logging API. * - *

      - * The choice to prevent direct extension of loggers was made deliberately to ensure that users of - * a specific logger implementation always get the same behavior. + *

      The choice to prevent direct extension of loggers was made to ensure that users + * of a specific logger implementation always get the same behavior. + * + * @apiNote It is expected that this class is going to be merged + * with {@code io.spine.logging.JvmLogger} of the {@code logging} module. * * @see * Original Java code of Google Flogger for historical context. diff --git a/jvm/middleware/src/main/java/io/spine/logging/jvm/MiddlemanApi.java b/jvm/middleware/src/main/java/io/spine/logging/jvm/MiddlemanApi.java index b405b195c..d208fb866 100644 --- a/jvm/middleware/src/main/java/io/spine/logging/jvm/MiddlemanApi.java +++ b/jvm/middleware/src/main/java/io/spine/logging/jvm/MiddlemanApi.java @@ -53,6 +53,9 @@ * context-specific methods ({@code isLowOnMemory()}, {@code isThrashing()} etc...). * However, each of these sub-APIs must eventually return the original logging API. * + * @apiNote It is expected that this class is going to be merged + * with {@code io.spine.logging.LoggingApi} of the {@code logging} module. + * * @see * Original Java code of Google Flogger for historical context. */