From 9eff425f2b6ad59e6e205b736ce2611417971d60 Mon Sep 17 00:00:00 2001 From: Roberto Cortez Date: Fri, 26 Jul 2024 10:30:25 +0100 Subject: [PATCH] Move logging to @ConfigMapping --- .../BuildTimeConfigBuilderCustomizer.java | 33 ++ .../deployment/console/ConsoleConfig.java | 30 +- .../deployment/console/ConsoleHelper.java | 11 +- .../deployment/console/ConsoleProcessor.java | 23 +- .../logging/LoggingResourceProcessor.java | 99 ++-- ...rye.config.SmallRyeConfigBuilderCustomizer | 1 + .../runtime/console/ConsoleRuntimeConfig.java | 13 +- .../quarkus/runtime/logging/AsyncConfig.java | 27 -- .../logging/CategoryBuildTimeConfig.java | 25 - .../runtime/logging/CategoryConfig.java | 37 -- .../runtime/logging/CleanupFilterConfig.java | 22 - .../runtime/logging/ConsoleConfig.java | 68 --- .../quarkus/runtime/logging/FileConfig.java | 105 ----- .../runtime/logging/LogBuildTimeConfig.java | 42 +- .../io/quarkus/runtime/logging/LogConfig.java | 113 ----- .../runtime/logging/LogRuntimeConfig.java | 427 ++++++++++++++++++ .../runtime/logging/LoggingSetupRecorder.java | 422 ++++++++--------- .../quarkus/runtime/logging/SyslogConfig.java | 112 ----- .../io/quarkus/runtime/util/ColorSupport.java | 18 - .../ConfigInstantiatorTestCase.java | 17 - .../deployment/UndertowBuildStep.java | 2 +- .../logstream/LogStreamProcessor.java | 3 +- .../vertx/http/runtime/VertxHttpRecorder.java | 2 +- .../src/main/resources/application.properties | 2 +- .../io/quarkus/test/common/LauncherUtil.java | 2 +- .../quarkus/test/common/PropertyTestUtil.java | 4 +- 26 files changed, 809 insertions(+), 851 deletions(-) create mode 100644 core/deployment/src/main/java/io/quarkus/deployment/configuration/BuildTimeConfigBuilderCustomizer.java create mode 100644 core/deployment/src/main/resources/META-INF/services/io.smallrye.config.SmallRyeConfigBuilderCustomizer delete mode 100644 core/runtime/src/main/java/io/quarkus/runtime/logging/AsyncConfig.java delete mode 100644 core/runtime/src/main/java/io/quarkus/runtime/logging/CategoryBuildTimeConfig.java delete mode 100644 core/runtime/src/main/java/io/quarkus/runtime/logging/CategoryConfig.java delete mode 100644 core/runtime/src/main/java/io/quarkus/runtime/logging/CleanupFilterConfig.java delete mode 100644 core/runtime/src/main/java/io/quarkus/runtime/logging/ConsoleConfig.java delete mode 100644 core/runtime/src/main/java/io/quarkus/runtime/logging/FileConfig.java delete mode 100644 core/runtime/src/main/java/io/quarkus/runtime/logging/LogConfig.java create mode 100644 core/runtime/src/main/java/io/quarkus/runtime/logging/LogRuntimeConfig.java delete mode 100644 core/runtime/src/main/java/io/quarkus/runtime/logging/SyslogConfig.java delete mode 100644 core/runtime/src/main/java/io/quarkus/runtime/util/ColorSupport.java diff --git a/core/deployment/src/main/java/io/quarkus/deployment/configuration/BuildTimeConfigBuilderCustomizer.java b/core/deployment/src/main/java/io/quarkus/deployment/configuration/BuildTimeConfigBuilderCustomizer.java new file mode 100644 index 0000000000000..d3172781dbc4e --- /dev/null +++ b/core/deployment/src/main/java/io/quarkus/deployment/configuration/BuildTimeConfigBuilderCustomizer.java @@ -0,0 +1,33 @@ +package io.quarkus.deployment.configuration; + +import java.util.List; +import java.util.Map; + +import io.quarkus.runtime.LaunchMode; +import io.quarkus.runtime.console.ConsoleRuntimeConfig; +import io.quarkus.runtime.logging.LogBuildTimeConfig; +import io.quarkus.runtime.logging.LogRuntimeConfig; +import io.quarkus.runtime.logging.LoggingSetupRecorder; +import io.smallrye.config.SmallRyeConfigBuilder; +import io.smallrye.config.SmallRyeConfigBuilderCustomizer; + +/** + * Even if the Log and Console mappings are marked as runtime, they are also used during build time. + *

+ * We cannot register the mappings in the core runtime module because {@link io.smallrye.config.SmallRyeConfig} + * requires ASM to load the mappings. When we run a Quarkus test, Quarkus will generate the bytecode for the mappings, + * so we don't need ASM. In a non-Quarkus tests, ASM must be present in the classpath, which we want + * to avoid (even if they are in the test scope). The logging mappings shouldn't be loaded when running a non-Quarkus + * test because they are not required. + * + * @see LoggingSetupRecorder#initializeBuildTimeLogging(LogRuntimeConfig, LogBuildTimeConfig, ConsoleRuntimeConfig, Map, List, + * LaunchMode) + */ +public class BuildTimeConfigBuilderCustomizer implements SmallRyeConfigBuilderCustomizer { + @Override + public void configBuilder(final SmallRyeConfigBuilder builder) { + builder.withMapping(LogBuildTimeConfig.class) + .withMapping(LogRuntimeConfig.class) + .withMapping(ConsoleRuntimeConfig.class); + } +} diff --git a/core/deployment/src/main/java/io/quarkus/deployment/console/ConsoleConfig.java b/core/deployment/src/main/java/io/quarkus/deployment/console/ConsoleConfig.java index e5b683ebd966d..4be3678eca66e 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/console/ConsoleConfig.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/console/ConsoleConfig.java @@ -1,27 +1,31 @@ package io.quarkus.deployment.console; -import io.quarkus.runtime.annotations.ConfigItem; +import java.util.Optional; + +import io.quarkus.runtime.annotations.ConfigPhase; import io.quarkus.runtime.annotations.ConfigRoot; +import io.smallrye.config.ConfigMapping; +import io.smallrye.config.WithDefault; /** * Console */ -@ConfigRoot -public class ConsoleConfig { - +@ConfigMapping(prefix = "quarkus.console") +@ConfigRoot(phase = ConfigPhase.BUILD_TIME) +public interface ConsoleConfig { /** * If test results and status should be displayed in the console. *

* If this is false results can still be viewed in the dev console. */ - @ConfigItem(defaultValue = "true") - public boolean enabled; + @WithDefault("true") + boolean enabled(); /** * Disables the ability to enter input on the console. */ - @ConfigItem(defaultValue = "false") - public boolean disableInput; + @WithDefault("false") + boolean disableInput(); /** * Disable the testing status/prompt message at the bottom of the console @@ -29,7 +33,13 @@ public class ConsoleConfig { *

* Use this option if your terminal does not support ANSI escape sequences. */ - @ConfigItem(defaultValue = "false") - public boolean basic; + @WithDefault("false") + boolean basic(); + /** + * If color should be enabled or disabled. + *

+ * If this is not present then an attempt will be made to guess if the terminal supports color + */ + Optional color(); } diff --git a/core/deployment/src/main/java/io/quarkus/deployment/console/ConsoleHelper.java b/core/deployment/src/main/java/io/quarkus/deployment/console/ConsoleHelper.java index 06c2e5746427b..dd154e249de90 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/console/ConsoleHelper.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/console/ConsoleHelper.java @@ -11,22 +11,19 @@ import io.quarkus.deployment.dev.testing.TestConfig; import io.quarkus.dev.console.BasicConsole; import io.quarkus.dev.console.QuarkusConsole; -import io.quarkus.runtime.console.ConsoleRuntimeConfig; -import io.quarkus.runtime.util.ColorSupport; public class ConsoleHelper { - public static synchronized void installConsole(TestConfig config, ConsoleConfig consoleConfig, - ConsoleRuntimeConfig consoleRuntimeConfig, io.quarkus.runtime.logging.ConsoleConfig logConfig, boolean test) { + public static synchronized void installConsole(TestConfig config, ConsoleConfig consoleConfig, boolean test) { if (QuarkusConsole.installed) { return; } - boolean colorEnabled = ColorSupport.isColorEnabled(consoleRuntimeConfig, logConfig); + boolean colorEnabled = consoleConfig.color().orElse(QuarkusConsole.hasColorSupport()); QuarkusConsole.installed = true; //if there is no color we need a basic console //note that we never enable input for tests //surefire communicates of stdin, so this can mess with it - boolean inputSupport = !test && !config.disableConsoleInput.orElse(consoleConfig.disableInput); + boolean inputSupport = !test && !config.disableConsoleInput.orElse(consoleConfig.disableInput()); if (!inputSupport) { //note that in this case we don't hold onto anything from this class loader //which is important for the test suite @@ -37,7 +34,7 @@ public static synchronized void installConsole(TestConfig config, ConsoleConfig new TerminalConnection(new Consumer() { @Override public void accept(Connection connection) { - if (connection.supportsAnsi() && !config.basicConsole.orElse(consoleConfig.basic)) { + if (connection.supportsAnsi() && !config.basicConsole.orElse(consoleConfig.basic())) { QuarkusConsole.INSTANCE = new AeshConsole(connection); } else { LinkedBlockingDeque queue = new LinkedBlockingDeque<>(); diff --git a/core/deployment/src/main/java/io/quarkus/deployment/console/ConsoleProcessor.java b/core/deployment/src/main/java/io/quarkus/deployment/console/ConsoleProcessor.java index 2def2767f3676..7c5516b3603bb 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/console/ConsoleProcessor.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/console/ConsoleProcessor.java @@ -18,7 +18,6 @@ import org.aesh.command.CommandException; import org.aesh.command.CommandResult; import org.aesh.command.invocation.CommandInvocation; -import org.eclipse.microprofile.config.ConfigProvider; import org.jboss.logging.Logger; import io.quarkus.deployment.Capabilities; @@ -41,7 +40,6 @@ import io.quarkus.deployment.ide.EffectiveIdeBuildItem; import io.quarkus.deployment.ide.Ide; import io.quarkus.dev.console.QuarkusConsole; -import io.quarkus.runtime.console.ConsoleRuntimeConfig; public class ConsoleProcessor { @@ -59,25 +57,18 @@ public class ConsoleProcessor { */ @BuildStep(onlyIf = IsDevelopment.class) @Produce(TestSetupBuildItem.class) - ConsoleInstalledBuildItem setupConsole(TestConfig config, - BuildProducer testListenerBuildItemBuildProducer, - LaunchModeBuildItem launchModeBuildItem, ConsoleConfig consoleConfig) { + ConsoleInstalledBuildItem setupConsole( + final TestConfig config, + final ConsoleConfig consoleConfig, + final LaunchModeBuildItem launchModeBuildItem, + final BuildProducer testListenerBuildItemBuildProducer) { if (consoleInstalled) { return ConsoleInstalledBuildItem.INSTANCE; } consoleInstalled = true; - if (config.console.orElse(consoleConfig.enabled)) { - //this is a bit of a hack, but we can't just inject this normally - //this is a runtime property value, but also a build time property value - //as when running in dev mode they are both basically equivalent - ConsoleRuntimeConfig consoleRuntimeConfig = new ConsoleRuntimeConfig(); - consoleRuntimeConfig.color = ConfigProvider.getConfig().getOptionalValue("quarkus.console.color", Boolean.class); - io.quarkus.runtime.logging.ConsoleConfig loggingConsoleConfig = new io.quarkus.runtime.logging.ConsoleConfig(); - loggingConsoleConfig.color = ConfigProvider.getConfig().getOptionalValue("quarkus.console.color", - Boolean.class); - ConsoleHelper.installConsole(config, consoleConfig, consoleRuntimeConfig, loggingConsoleConfig, - launchModeBuildItem.isTest()); + if (config.console.orElse(consoleConfig.enabled())) { + ConsoleHelper.installConsole(config, consoleConfig, launchModeBuildItem.isTest()); ConsoleStateManager.init(QuarkusConsole.INSTANCE, launchModeBuildItem.getDevModeType().get()); //note that this bit needs to be refactored so it is no longer tied to continuous testing if (TestSupport.instance().isEmpty() || config.continuousTesting == TestConfig.Mode.DISABLED diff --git a/core/deployment/src/main/java/io/quarkus/deployment/logging/LoggingResourceProcessor.java b/core/deployment/src/main/java/io/quarkus/deployment/logging/LoggingResourceProcessor.java index cec9fc34fd9e1..a94f8fdc3894f 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/logging/LoggingResourceProcessor.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/logging/LoggingResourceProcessor.java @@ -1,5 +1,7 @@ package io.quarkus.deployment.logging; +import static io.quarkus.runtime.logging.LoggingSetupRecorder.initializeBuildTimeLogging; + import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -35,6 +37,7 @@ import org.aesh.command.completer.OptionCompleter; import org.aesh.command.invocation.CommandInvocation; import org.aesh.command.option.Option; +import org.eclipse.microprofile.config.ConfigProvider; import org.jboss.jandex.AnnotationInstance; import org.jboss.jandex.AnnotationTarget; import org.jboss.jandex.ClassInfo; @@ -112,19 +115,18 @@ import io.quarkus.logging.LoggingFilter; import io.quarkus.runtime.LaunchMode; import io.quarkus.runtime.RuntimeValue; -import io.quarkus.runtime.configuration.ConfigInstantiator; import io.quarkus.runtime.console.ConsoleRuntimeConfig; -import io.quarkus.runtime.logging.CategoryBuildTimeConfig; -import io.quarkus.runtime.logging.CleanupFilterConfig; import io.quarkus.runtime.logging.DecorateStackUtil; import io.quarkus.runtime.logging.DiscoveredLogComponents; import io.quarkus.runtime.logging.InheritableLevel; import io.quarkus.runtime.logging.LogBuildTimeConfig; +import io.quarkus.runtime.logging.LogBuildTimeConfig.CategoryBuildTimeConfig; import io.quarkus.runtime.logging.LogCleanupFilterElement; -import io.quarkus.runtime.logging.LogConfig; import io.quarkus.runtime.logging.LogFilterFactory; import io.quarkus.runtime.logging.LogMetricsHandlerRecorder; +import io.quarkus.runtime.logging.LogRuntimeConfig; import io.quarkus.runtime.logging.LoggingSetupRecorder; +import io.smallrye.config.SmallRyeConfig; public final class LoggingResourceProcessor { @@ -159,10 +161,10 @@ SystemPropertyBuildItem setProperty() { void setMinLevelForInitialConfigurator(LogBuildTimeConfig logBuildTimeConfig, BuildProducer systemPropertyBuildItemBuildProducer, BuildProducer nativeImageSystemPropertyBuildItemBuildProducer) { - Level effectiveMinLevel = logBuildTimeConfig.minLevel; + Level effectiveMinLevel = logBuildTimeConfig.minLevel(); // go through the category config and if there exists a min-level lower than the root min-level, use it - for (CategoryBuildTimeConfig categoryBuildTimeConfig : logBuildTimeConfig.categories.values()) { - InheritableLevel inheritableLevel = categoryBuildTimeConfig.minLevel; + for (CategoryBuildTimeConfig categoryBuildTimeConfig : logBuildTimeConfig.categories().values()) { + InheritableLevel inheritableLevel = categoryBuildTimeConfig.minLevel(); if (inheritableLevel.isInherited()) { continue; } @@ -234,23 +236,26 @@ void miscSetup( @BuildStep @Record(ExecutionTime.RUNTIME_INIT) - LoggingSetupBuildItem setupLoggingRuntimeInit(RecorderContext context, LoggingSetupRecorder recorder, LogConfig log, - LogBuildTimeConfig buildLog, - CombinedIndexBuildItem combinedIndexBuildItem, - LogCategoryMinLevelDefaultsBuildItem categoryMinLevelDefaults, - Optional streamingLogStreamHandlerBuildItem, - List handlerBuildItems, - List namedHandlerBuildItems, - List consoleFormatItems, - List fileFormatItems, - List syslogFormatItems, - Optional possibleBannerBuildItem, - List logStreamBuildItems, - BuildProducer shutdownListenerBuildItemBuildProducer, - LaunchModeBuildItem launchModeBuildItem, - List logCleanupFilters, - BuildProducer reflectiveClassBuildItemBuildProducer, - BuildProducer serviceProviderBuildItemBuildProducer) { + LoggingSetupBuildItem setupLoggingRuntimeInit( + final RecorderContext context, + final LoggingSetupRecorder recorder, + final LogRuntimeConfig logRuntimeConfig, + final LogBuildTimeConfig logBuildTimeConfig, + final CombinedIndexBuildItem combinedIndexBuildItem, + final LogCategoryMinLevelDefaultsBuildItem categoryMinLevelDefaults, + final Optional streamingLogStreamHandlerBuildItem, + final List handlerBuildItems, + final List namedHandlerBuildItems, + final List consoleFormatItems, + final List fileFormatItems, + final List syslogFormatItems, + final Optional possibleBannerBuildItem, + final List logStreamBuildItems, + final BuildProducer shutdownListenerBuildItemBuildProducer, + final LaunchModeBuildItem launchModeBuildItem, + final List logCleanupFilters, + final BuildProducer reflectiveClassBuildItemBuildProducer, + final BuildProducer serviceProviderBuildItemBuildProducer) { if (!launchModeBuildItem.isAuxiliaryApplication() || launchModeBuildItem.getAuxiliaryDevModeType().orElse(null) == DevModeType.TEST_ONLY) { final List>> handlers = handlerBuildItems.stream() @@ -299,25 +304,29 @@ LoggingSetupBuildItem setupLoggingRuntimeInit(RecorderContext context, LoggingSe } shutdownListenerBuildItemBuildProducer.produce(new ShutdownListenerBuildItem( - recorder.initializeLogging(log, buildLog, discoveredLogComponents, + recorder.initializeLogging(logRuntimeConfig, logBuildTimeConfig, discoveredLogComponents, categoryMinLevelDefaults.content, alwaysEnableLogStream, streamingDevUiLogHandler, handlers, namedHandlers, possibleConsoleFormatters, possibleFileFormatters, possibleSyslogFormatters, possibleSupplier, launchModeBuildItem.getLaunchMode(), true))); - LogConfig logConfig = new LogConfig(); - ConfigInstantiator.handleObject(logConfig); + + List additionalLogCleanupFilters = new ArrayList<>(logCleanupFilters.size()); for (LogCleanupFilterBuildItem i : logCleanupFilters) { - CleanupFilterConfig value = new CleanupFilterConfig(); LogCleanupFilterElement filterElement = i.getFilterElement(); - value.ifStartsWith = filterElement.getMessageStarts(); - value.targetLevel = filterElement.getTargetLevel() == null ? org.jboss.logmanager.Level.DEBUG - : filterElement.getTargetLevel(); - logConfig.filters.put(filterElement.getLoggerName(), value); + additionalLogCleanupFilters.add(new LogCleanupFilterElement( + filterElement.getLoggerName(), + filterElement.getTargetLevel() == null ? org.jboss.logmanager.Level.DEBUG + : filterElement.getTargetLevel(), + filterElement.getMessageStarts())); } - ConsoleRuntimeConfig crc = new ConsoleRuntimeConfig(); - ConfigInstantiator.handleObject(crc); - LoggingSetupRecorder.initializeBuildTimeLogging(logConfig, buildLog, categoryMinLevelDefaults.content, - crc, launchModeBuildItem.getLaunchMode()); + + SmallRyeConfig config = ConfigProvider.getConfig().unwrap(SmallRyeConfig.class); + LogRuntimeConfig logRuntimeConfigInBuild = config.getConfigMapping(LogRuntimeConfig.class); + ConsoleRuntimeConfig consoleRuntimeConfig = config.getConfigMapping(ConsoleRuntimeConfig.class); + + initializeBuildTimeLogging(logRuntimeConfigInBuild, logBuildTimeConfig, consoleRuntimeConfig, + categoryMinLevelDefaults.content, additionalLogCleanupFilters, launchModeBuildItem.getLaunchMode()); + ((QuarkusClassLoader) Thread.currentThread().getContextClassLoader()).addCloseTask(new Runnable() { @Override public void run() { @@ -417,7 +426,7 @@ public void accept(LogRecord logRecord, Consumer logRecordConsumer) { lastUserCode = stackTrace[i]; if (launchMode.getLaunchMode().equals(LaunchMode.DEVELOPMENT) - && logBuildTimeConfig.decorateStacktraces) { + && logBuildTimeConfig.decorateStacktraces()) { String decoratedString = DecorateStackUtil.getDecoratedString(srcMainJava, elem); if (decoratedString != null) { @@ -503,7 +512,7 @@ void setUpDarkeningDefault(Consumer rtcCon void registerMetrics(LogMetricsHandlerRecorder recorder, LogBuildTimeConfig log, BuildProducer metrics, BuildProducer logHandler, Optional metricsCapability) { - if (metricsCapability.isPresent() && log.metricsEnabled) { + if (metricsCapability.isPresent() && log.metricsEnabled()) { recorder.initCounters(); metrics.produce(new MetricsFactoryConsumerBuildItem(recorder.registerMetrics())); logHandler.produce(new LogHandlerBuildItem(recorder.getLogHandler())); @@ -515,21 +524,22 @@ void setUpMinLevelLogging(LogBuildTimeConfig log, LogCategoryMinLevelDefaultsBuildItem categoryMinLevelDefaults, final BuildProducer generatedTraceLogger) { ClassOutput output = new GeneratedClassGizmoAdaptor(generatedTraceLogger, false); - if (allRootMinLevelOrHigher(log.minLevel.intValue(), log.categories, categoryMinLevelDefaults.content)) { - generateDefaultLoggers(log.minLevel, output); + if (allRootMinLevelOrHigher(log.minLevel().intValue(), log.categories(), categoryMinLevelDefaults.content)) { + generateDefaultLoggers(log.minLevel(), output); } else { - generateCategoryMinLevelLoggers(log.categories, categoryMinLevelDefaults.content, log.minLevel, output); + generateCategoryMinLevelLoggers(log.categories(), categoryMinLevelDefaults.content, log.minLevel(), output); } } - private static boolean allRootMinLevelOrHigher(int rootMinLogLevel, + private static boolean allRootMinLevelOrHigher( + int rootMinLogLevel, Map categories, Map categoryMinLevelDefaults) { Set allConfiguredCategoryNames = new LinkedHashSet<>(categories.keySet()); allConfiguredCategoryNames.addAll(categoryMinLevelDefaults.keySet()); for (String categoryName : allConfiguredCategoryNames) { InheritableLevel categoryMinLevel = LoggingSetupRecorder.getLogLevelNoInheritance(categoryName, categories, - CategoryBuildTimeConfig::getMinLevel, categoryMinLevelDefaults); + CategoryBuildTimeConfig::minLevel, categoryMinLevelDefaults); if (!categoryMinLevel.isInherited() && categoryMinLevel.getLevel().intValue() < rootMinLogLevel) { return false; } @@ -574,7 +584,8 @@ private static void generateMinLevelCompute(Map for (Map.Entry entry : categories.entrySet()) { final String category = entry.getKey(); final int categoryLevelIntValue = LoggingSetupRecorder - .getLogLevel(category, categories, CategoryBuildTimeConfig::getMinLevel, categoryMinLevelDefaults, + .getLogLevel(category, categories, CategoryBuildTimeConfig::minLevel, + categoryMinLevelDefaults, rootMinLevel) .intValue(); diff --git a/core/deployment/src/main/resources/META-INF/services/io.smallrye.config.SmallRyeConfigBuilderCustomizer b/core/deployment/src/main/resources/META-INF/services/io.smallrye.config.SmallRyeConfigBuilderCustomizer new file mode 100644 index 0000000000000..473610c839df9 --- /dev/null +++ b/core/deployment/src/main/resources/META-INF/services/io.smallrye.config.SmallRyeConfigBuilderCustomizer @@ -0,0 +1 @@ +io.quarkus.deployment.configuration.BuildTimeConfigBuilderCustomizer diff --git a/core/runtime/src/main/java/io/quarkus/runtime/console/ConsoleRuntimeConfig.java b/core/runtime/src/main/java/io/quarkus/runtime/console/ConsoleRuntimeConfig.java index 9821fa4cdf4c3..edc4a71a0ae0b 100644 --- a/core/runtime/src/main/java/io/quarkus/runtime/console/ConsoleRuntimeConfig.java +++ b/core/runtime/src/main/java/io/quarkus/runtime/console/ConsoleRuntimeConfig.java @@ -2,21 +2,20 @@ import java.util.Optional; -import io.quarkus.runtime.annotations.ConfigItem; import io.quarkus.runtime.annotations.ConfigPhase; import io.quarkus.runtime.annotations.ConfigRoot; +import io.smallrye.config.ConfigMapping; /** * Console */ -@ConfigRoot(name = "console", phase = ConfigPhase.RUN_TIME) -public class ConsoleRuntimeConfig { - +@ConfigMapping(prefix = "quarkus.console") +@ConfigRoot(phase = ConfigPhase.RUN_TIME) +public interface ConsoleRuntimeConfig { /** * If color should be enabled or disabled. - * + *

* If this is not present then an attempt will be made to guess if the terminal supports color */ - @ConfigItem - public Optional color; + Optional color(); } diff --git a/core/runtime/src/main/java/io/quarkus/runtime/logging/AsyncConfig.java b/core/runtime/src/main/java/io/quarkus/runtime/logging/AsyncConfig.java deleted file mode 100644 index a51f21a282647..0000000000000 --- a/core/runtime/src/main/java/io/quarkus/runtime/logging/AsyncConfig.java +++ /dev/null @@ -1,27 +0,0 @@ -package io.quarkus.runtime.logging; - -import org.jboss.logmanager.handlers.AsyncHandler.OverflowAction; - -import io.quarkus.runtime.annotations.ConfigGroup; -import io.quarkus.runtime.annotations.ConfigItem; - -@ConfigGroup -public class AsyncConfig { - - /** - * Indicates whether to log asynchronously - */ - @ConfigItem(name = ConfigItem.PARENT) - boolean enable; - /** - * The queue length to use before flushing writing - */ - @ConfigItem(defaultValue = "512") - int queueLength; - - /** - * Determine whether to block the publisher (rather than drop the message) when the queue is full - */ - @ConfigItem(defaultValue = "block") - OverflowAction overflow; -} diff --git a/core/runtime/src/main/java/io/quarkus/runtime/logging/CategoryBuildTimeConfig.java b/core/runtime/src/main/java/io/quarkus/runtime/logging/CategoryBuildTimeConfig.java deleted file mode 100644 index c05383d6e7c4b..0000000000000 --- a/core/runtime/src/main/java/io/quarkus/runtime/logging/CategoryBuildTimeConfig.java +++ /dev/null @@ -1,25 +0,0 @@ -package io.quarkus.runtime.logging; - -import io.quarkus.runtime.annotations.ConfigGroup; -import io.quarkus.runtime.annotations.ConfigItem; - -@ConfigGroup -public class CategoryBuildTimeConfig { - /** - * The minimum log level for this category. - * By default, all categories are configured with DEBUG minimum level. - *

- * To get runtime logging below DEBUG, e.g., TRACE, - * adjust the minimum level at build time. The right log level needs to be provided at runtime. - *

- * As an example, to get TRACE logging, - * minimum level needs to be at TRACE, and the runtime log level needs to match that. - */ - @ConfigItem(defaultValue = "inherit") - public InheritableLevel minLevel; - - // for method refs - public InheritableLevel getMinLevel() { - return minLevel; - } -} diff --git a/core/runtime/src/main/java/io/quarkus/runtime/logging/CategoryConfig.java b/core/runtime/src/main/java/io/quarkus/runtime/logging/CategoryConfig.java deleted file mode 100644 index 560f5420b7e92..0000000000000 --- a/core/runtime/src/main/java/io/quarkus/runtime/logging/CategoryConfig.java +++ /dev/null @@ -1,37 +0,0 @@ -package io.quarkus.runtime.logging; - -import java.util.List; -import java.util.Optional; - -import io.quarkus.runtime.annotations.ConfigGroup; -import io.quarkus.runtime.annotations.ConfigItem; - -@ConfigGroup -public class CategoryConfig { - - /** - * The log level for this category. - *

- * Note that to get log levels below INFO, - * the minimum level build-time configuration option also needs to be adjusted. - */ - @ConfigItem(defaultValue = "inherit") - InheritableLevel level; - - /** - * The names of the handlers to link to this category. - */ - @ConfigItem - Optional> handlers; - - /** - * Specify whether this logger should send its output to its parent Logger - */ - @ConfigItem(defaultValue = "true") - boolean useParentHandlers; - - // for method refs - public InheritableLevel getLevel() { - return level; - } -} diff --git a/core/runtime/src/main/java/io/quarkus/runtime/logging/CleanupFilterConfig.java b/core/runtime/src/main/java/io/quarkus/runtime/logging/CleanupFilterConfig.java deleted file mode 100644 index a2e0656cf9444..0000000000000 --- a/core/runtime/src/main/java/io/quarkus/runtime/logging/CleanupFilterConfig.java +++ /dev/null @@ -1,22 +0,0 @@ -package io.quarkus.runtime.logging; - -import java.util.List; -import java.util.logging.Level; - -import io.quarkus.runtime.annotations.ConfigGroup; -import io.quarkus.runtime.annotations.ConfigItem; - -@ConfigGroup -public class CleanupFilterConfig { - /** - * The message prefix to match - */ - @ConfigItem(defaultValue = "inherit") - public List ifStartsWith; - - /** - * The new log level for the filtered message. Defaults to DEBUG. - */ - @ConfigItem(defaultValue = "DEBUG") - public Level targetLevel; -} diff --git a/core/runtime/src/main/java/io/quarkus/runtime/logging/ConsoleConfig.java b/core/runtime/src/main/java/io/quarkus/runtime/logging/ConsoleConfig.java deleted file mode 100644 index f919912faca2d..0000000000000 --- a/core/runtime/src/main/java/io/quarkus/runtime/logging/ConsoleConfig.java +++ /dev/null @@ -1,68 +0,0 @@ -package io.quarkus.runtime.logging; - -import java.util.Optional; -import java.util.logging.Level; - -import io.quarkus.runtime.annotations.ConfigGroup; -import io.quarkus.runtime.annotations.ConfigItem; - -@ConfigGroup -public class ConsoleConfig { - - /** - * If console logging should be enabled - */ - @ConfigItem(defaultValue = "true") - boolean enable; - - /** - * If console logging should go to {@link System#err} instead of {@link System#out}. - */ - @ConfigItem(defaultValue = "false") - boolean stderr; - - /** - * The log format. Note that this value is ignored if an extension is present that takes - * control of console formatting (e.g., an XML or JSON-format extension). - */ - @ConfigItem(defaultValue = "%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c{3.}] (%t) %s%e%n") - String format; - - /** - * The console log level. - */ - @ConfigItem(defaultValue = "ALL") - Level level; - - /** - * If the console logging should be in color. If undefined, Quarkus takes - * best guess based on the operating system and environment. - * Note that this value is ignored if an extension is present that takes - * control of console formatting (e.g., an XML or JSON-format extension). - *

- * This has been deprecated and replaced with quarkus.console.color, - * as Quarkus now provides more console-based functionality than just logging. - */ - @ConfigItem - @Deprecated - public Optional color; - - /** - * Specify how much the colors should be darkened. - * Note that this value is ignored if an extension is present that takes - * control of console formatting (e.g., an XML or JSON-format extension). - */ - @ConfigItem(defaultValue = "0") - int darken; - - /** - * The name of the filter to link to the console handler. - */ - @ConfigItem - Optional filter; - - /** - * Console async logging config - */ - AsyncConfig async; -} diff --git a/core/runtime/src/main/java/io/quarkus/runtime/logging/FileConfig.java b/core/runtime/src/main/java/io/quarkus/runtime/logging/FileConfig.java deleted file mode 100644 index 1ba1be87d240a..0000000000000 --- a/core/runtime/src/main/java/io/quarkus/runtime/logging/FileConfig.java +++ /dev/null @@ -1,105 +0,0 @@ -package io.quarkus.runtime.logging; - -import java.io.File; -import java.nio.charset.Charset; -import java.time.format.DateTimeFormatter; -import java.util.Optional; -import java.util.logging.Level; - -import io.quarkus.runtime.annotations.ConfigGroup; -import io.quarkus.runtime.annotations.ConfigItem; -import io.quarkus.runtime.configuration.MemorySize; - -@ConfigGroup -public class FileConfig { - - /** - * Default file name where logs should be stored. - */ - public static final String DEFAULT_LOG_FILE_NAME = "quarkus.log"; - - /** - * If file logging should be enabled - */ - @ConfigItem - boolean enable; - - /** - * The log format - */ - @ConfigItem(defaultValue = "%d{yyyy-MM-dd HH:mm:ss,SSS} %h %N[%i] %-5p [%c{3.}] (%t) %s%e%n") - String format; - - /** - * The level of logs to be written into the file. - */ - @ConfigItem(defaultValue = "ALL") - Level level; - - /** - * The name of the file in which logs will be written. - */ - @ConfigItem(defaultValue = DEFAULT_LOG_FILE_NAME) - File path; - - /** - * The name of the filter to link to the file handler. - */ - @ConfigItem - Optional filter; - - /** - * The character encoding used - */ - @ConfigItem - Optional encoding; - - /** - * File async logging config - */ - AsyncConfig async; - - /** - * File rotation config. - * The time interval is determined by the content of the fileSuffix property. - * The size interval is determined by the content of the maxFileSize property. - * If both are used, the rotating will be based on time, then on size. - */ - RotationConfig rotation; - - @ConfigGroup - public static class RotationConfig { - /** - * The maximum log file size, after which a rotation is executed. - */ - @ConfigItem(defaultValue = "10M") - MemorySize maxFileSize; - - /** - * The maximum number of backups to keep. - */ - @ConfigItem(defaultValue = "5") - int maxBackupIndex; - - /** - * The file handler rotation file suffix. - * When used, the file will be rotated based on its suffix. - *

- * The suffix must be in a date-time format that is understood by {@link DateTimeFormatter}. - *

- * Example fileSuffix: .yyyy-MM-dd - *

- * Note: If the suffix ends with .zip or .gz, the rotation file will also be compressed. - */ - @ConfigItem - Optional fileSuffix; - - /** - * Indicates whether to rotate log files on server initialization. - *

- * You need to either set a {@code max-file-size} or configure a {@code file-suffix} for it to work. - */ - @ConfigItem(defaultValue = "true") - boolean rotateOnBoot; - } -} diff --git a/core/runtime/src/main/java/io/quarkus/runtime/logging/LogBuildTimeConfig.java b/core/runtime/src/main/java/io/quarkus/runtime/logging/LogBuildTimeConfig.java index a201118e2d666..2f10528e52249 100644 --- a/core/runtime/src/main/java/io/quarkus/runtime/logging/LogBuildTimeConfig.java +++ b/core/runtime/src/main/java/io/quarkus/runtime/logging/LogBuildTimeConfig.java @@ -4,33 +4,36 @@ import java.util.logging.Level; import io.quarkus.runtime.annotations.ConfigDocSection; -import io.quarkus.runtime.annotations.ConfigItem; import io.quarkus.runtime.annotations.ConfigPhase; import io.quarkus.runtime.annotations.ConfigRoot; +import io.smallrye.config.ConfigMapping; +import io.smallrye.config.WithDefault; +import io.smallrye.config.WithName; /** * Logging */ -@ConfigRoot(name = "log", phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED) -public class LogBuildTimeConfig { - +@ConfigMapping(prefix = "quarkus.log") +@ConfigRoot(phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED) +public interface LogBuildTimeConfig { /** * If enabled and a metrics extension is present, logging metrics are published. */ - @ConfigItem(name = "metrics.enabled", defaultValue = "false") - public boolean metricsEnabled; + @WithName("metrics.enabled") + @WithDefault("false") + boolean metricsEnabled(); /** * The default minimum log level. */ - @ConfigItem(defaultValue = "DEBUG") - public Level minLevel; + @WithDefault("DEBUG") + Level minLevel(); /** * This will decorate the stacktrace in dev mode to show the line in the code that cause the exception */ - @ConfigItem(defaultValue = "true") - public Boolean decorateStacktraces; + @WithDefault("true") + boolean decorateStacktraces(); /** * Minimum logging categories. @@ -39,7 +42,22 @@ public class LogBuildTimeConfig { * A configuration that applies to a category will also apply to all sub-categories of that category, * unless there is a more specific matching sub-category configuration. */ - @ConfigItem(name = "category") + @WithName("category") @ConfigDocSection - public Map categories; + Map categories(); + + interface CategoryBuildTimeConfig { + /** + * The minimum log level for this category. + * By default, all categories are configured with DEBUG minimum level. + *

+ * To get runtime logging below DEBUG, e.g., TRACE, + * adjust the minimum level at build time. The right log level needs to be provided at runtime. + *

+ * As an example, to get TRACE logging, + * minimum level needs to be at TRACE, and the runtime log level needs to match that. + */ + @WithDefault("inherit") + InheritableLevel minLevel(); + } } diff --git a/core/runtime/src/main/java/io/quarkus/runtime/logging/LogConfig.java b/core/runtime/src/main/java/io/quarkus/runtime/logging/LogConfig.java deleted file mode 100644 index 094b5a730e542..0000000000000 --- a/core/runtime/src/main/java/io/quarkus/runtime/logging/LogConfig.java +++ /dev/null @@ -1,113 +0,0 @@ -package io.quarkus.runtime.logging; - -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.logging.Level; - -import io.quarkus.runtime.annotations.ConfigDocSection; -import io.quarkus.runtime.annotations.ConfigItem; -import io.quarkus.runtime.annotations.ConfigPhase; -import io.quarkus.runtime.annotations.ConfigRoot; - -/** - * Logging - */ -@ConfigRoot(phase = ConfigPhase.RUN_TIME) -public final class LogConfig { - - /** - * The log level of the root category, which is used as the default log level for all categories. - * - * JBoss Logging supports Apache-style log levels: - * - * * {@link org.jboss.logmanager.Level#FATAL} - * * {@link org.jboss.logmanager.Level#ERROR} - * * {@link org.jboss.logmanager.Level#WARN} - * * {@link org.jboss.logmanager.Level#INFO} - * * {@link org.jboss.logmanager.Level#DEBUG} - * * {@link org.jboss.logmanager.Level#TRACE} - * - * In addition, it also supports the standard JDK log levels. - * - * @asciidoclet - */ - @ConfigItem(defaultValue = "INFO") - public Level level; - - /** - * Console logging. - *

- * Console logging is enabled by default. - */ - @ConfigDocSection - public ConsoleConfig console; - - /** - * File logging. - *

- * Logging to a file is also supported but not enabled by default. - */ - @ConfigDocSection - public FileConfig file; - - /** - * Syslog logging. - *

- * Logging to a syslog is also supported but not enabled by default. - */ - @ConfigDocSection - public SyslogConfig syslog; - - /** - * Logging categories. - *

- * Logging is done on a per-category basis. Each category can be independently configured. - * A configuration that applies to a category will also apply to all sub-categories of that category, - * unless there is a more specific matching sub-category configuration. - */ - @ConfigItem(name = "category") - @ConfigDocSection - public Map categories; - - /** - * Console handlers. - *

- * The named console handlers configured here can be linked on one or more categories. - */ - @ConfigItem(name = "handler.console") - @ConfigDocSection - public Map consoleHandlers; - - /** - * File handlers. - *

- * The named file handlers configured here can be linked to one or more categories. - */ - @ConfigItem(name = "handler.file") - @ConfigDocSection - public Map fileHandlers; - - /** - * Syslog handlers. - *

- * The named syslog handlers configured here can be linked to one or more categories. - */ - @ConfigItem(name = "handler.syslog") - @ConfigDocSection - public Map syslogHandlers; - - /** - * Log cleanup filters - internal use. - */ - @ConfigItem(name = "filter") - @ConfigDocSection - public Map filters; - - /** - * The names of additional handlers to link to the root category. - * These handlers are defined in consoleHandlers, fileHandlers, or syslogHandlers. - */ - @ConfigItem - Optional> handlers; -} diff --git a/core/runtime/src/main/java/io/quarkus/runtime/logging/LogRuntimeConfig.java b/core/runtime/src/main/java/io/quarkus/runtime/logging/LogRuntimeConfig.java new file mode 100644 index 0000000000000..16ad7c2c869c8 --- /dev/null +++ b/core/runtime/src/main/java/io/quarkus/runtime/logging/LogRuntimeConfig.java @@ -0,0 +1,427 @@ +package io.quarkus.runtime.logging; + +import java.io.File; +import java.net.InetSocketAddress; +import java.nio.charset.Charset; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.logging.Level; + +import org.jboss.logmanager.handlers.AsyncHandler.OverflowAction; +import org.jboss.logmanager.handlers.SyslogHandler.Facility; +import org.jboss.logmanager.handlers.SyslogHandler.Protocol; +import org.jboss.logmanager.handlers.SyslogHandler.SyslogType; + +import io.quarkus.runtime.annotations.ConfigDocSection; +import io.quarkus.runtime.annotations.ConfigPhase; +import io.quarkus.runtime.annotations.ConfigRoot; +import io.quarkus.runtime.configuration.CharsetConverter; +import io.quarkus.runtime.configuration.InetSocketAddressConverter; +import io.quarkus.runtime.configuration.MemorySize; +import io.quarkus.runtime.configuration.MemorySizeConverter; +import io.smallrye.config.ConfigMapping; +import io.smallrye.config.WithConverter; +import io.smallrye.config.WithDefault; +import io.smallrye.config.WithName; +import io.smallrye.config.WithParentName; + +/** + * Logging + */ +@ConfigMapping(prefix = "quarkus.log") +@ConfigRoot(phase = ConfigPhase.RUN_TIME) +public interface LogRuntimeConfig { + /** + * The log level of the root category, which is used as the default log level for all categories. + *

+ * JBoss Logging supports Apache-style log levels: + *

+ * * {@link org.jboss.logmanager.Level#FATAL} + * * {@link org.jboss.logmanager.Level#ERROR} + * * {@link org.jboss.logmanager.Level#WARN} + * * {@link org.jboss.logmanager.Level#INFO} + * * {@link org.jboss.logmanager.Level#DEBUG} + * * {@link org.jboss.logmanager.Level#TRACE} + * + * In addition, it also supports the standard JDK log levels. + * + * @asciidoclet + */ + @WithDefault("INFO") + Level level(); + + /** + * Console logging. + *

+ * Console logging is enabled by default. + */ + @ConfigDocSection + ConsoleConfig console(); + + /** + * File logging. + *

+ * Logging to a file is also supported but not enabled by default. + */ + @ConfigDocSection + FileConfig file(); + + /** + * Syslog logging. + *

+ * Logging to a syslog is also supported but not enabled by default. + */ + @ConfigDocSection + SyslogConfig syslog(); + + /** + * Logging categories. + *

+ * Logging is done on a per-category basis. Each category can be independently configured. + * A configuration that applies to a category will also apply to all sub-categories of that category, + * unless there is a more specific matching sub-category configuration. + */ + @WithName("category") + @ConfigDocSection + Map categories(); + + /** + * Console handlers. + *

+ * The named console handlers configured here can be linked on one or more categories. + */ + @WithName("handler.console") + @ConfigDocSection + Map consoleHandlers(); + + /** + * File handlers. + *

+ * The named file handlers configured here can be linked to one or more categories. + */ + @WithName("handler.file") + @ConfigDocSection + Map fileHandlers(); + + /** + * Syslog handlers. + *

+ * The named syslog handlers configured here can be linked to one or more categories. + */ + @WithName("handler.syslog") + @ConfigDocSection + Map syslogHandlers(); + + /** + * Log cleanup filters - internal use. + */ + @WithName("filter") + @ConfigDocSection + Map filters(); + + /** + * The names of additional handlers to link to the root category. + * These handlers are defined in consoleHandlers, fileHandlers, or syslogHandlers. + */ + Optional> handlers(); + + interface CategoryConfig { + /** + * The log level for this category. + *

+ * Note that to get log levels below INFO, + * the minimum level build-time configuration option also needs to be adjusted. + */ + @WithDefault("inherit") + InheritableLevel level(); + + /** + * The names of the handlers to link to this category. + */ + Optional> handlers(); + + /** + * Specify whether this logger should send its output to its parent Logger + */ + @WithDefault("true") + boolean useParentHandlers(); + } + + interface FileConfig { + /** + * Default file name where logs should be stored. + */ + String DEFAULT_LOG_FILE_NAME = "quarkus.log"; + + /** + * If file logging should be enabled + */ + @WithDefault("false") + boolean enable(); + + /** + * The log format + */ + @WithDefault("%d{yyyy-MM-dd HH:mm:ss,SSS} %h %N[%i] %-5p [%c{3.}] (%t) %s%e%n") + String format(); + + /** + * The level of logs to be written into the file. + */ + @WithDefault("ALL") + Level level(); + + /** + * The name of the file in which logs will be written. + */ + @WithDefault(DEFAULT_LOG_FILE_NAME) + File path(); + + /** + * The name of the filter to link to the file handler. + */ + Optional filter(); + + /** + * The character encoding used + */ + Optional<@WithConverter(CharsetConverter.class) Charset> encoding(); + + /** + * File async logging config + */ + AsyncConfig async(); + + /** + * File rotation config. + * The time interval is determined by the content of the fileSuffix property. + * The size interval is determined by the content of the maxFileSize property. + * If both are used, the rotating will be based on time, then on size. + */ + RotationConfig rotation(); + + interface RotationConfig { + /** + * The maximum log file size, after which a rotation is executed. + */ + @WithDefault("10M") + @WithConverter(MemorySizeConverter.class) + MemorySize maxFileSize(); + + /** + * The maximum number of backups to keep. + */ + @WithDefault("5") + int maxBackupIndex(); + + /** + * The file handler rotation file suffix. + * When used, the file will be rotated based on its suffix. + *

+ * The suffix must be in a date-time format that is understood by {@link DateTimeFormatter}. + *

+ * Example fileSuffix: .yyyy-MM-dd + *

+ * Note: If the suffix ends with .zip or .gz, the rotation file will also be compressed. + */ + Optional fileSuffix(); + + /** + * Indicates whether to rotate log files on server initialization. + *

+ * You need to either set a {@code max-file-size} or configure a {@code file-suffix} for it to work. + */ + @WithDefault("true") + boolean rotateOnBoot(); + } + } + + interface ConsoleConfig { + /** + * If console logging should be enabled + */ + @WithDefault("true") + boolean enable(); + + /** + * If console logging should go to {@link System#err} instead of {@link System#out}. + */ + @WithDefault("false") + boolean stderr(); + + /** + * The log format. Note that this value is ignored if an extension is present that takes + * control of console formatting (e.g., an XML or JSON-format extension). + */ + @WithDefault("%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c{3.}] (%t) %s%e%n") + String format(); + + /** + * The console log level. + */ + @WithDefault("ALL") + Level level(); + + /** + * If the console logging should be in color. If undefined, Quarkus takes + * best guess based on the operating system and environment. + * Note that this value is ignored if an extension is present that takes + * control of console formatting (e.g., an XML or JSON-format extension). + *

+ * This has been deprecated and replaced with quarkus.console.color, + * as Quarkus now provides more console-based functionality than just logging. + */ + @Deprecated + Optional color(); + + /** + * Specify how much the colors should be darkened. + * Note that this value is ignored if an extension is present that takes + * control of console formatting (e.g., an XML or JSON-format extension). + */ + @WithDefault("0") + int darken(); + + /** + * The name of the filter to link to the console handler. + */ + Optional filter(); + + /** + * Console async logging config + */ + AsyncConfig async(); + } + + interface SyslogConfig { + /** + * If syslog logging should be enabled + */ + @WithDefault("false") + boolean enable(); + + /** + * + * The IP address and port of the Syslog server + */ + @WithDefault("localhost:514") + @WithConverter(InetSocketAddressConverter.class) + InetSocketAddress endpoint(); + + /** + * The app name used when formatting the message in RFC5424 format + */ + Optional appName(); + + /** + * The name of the host the messages are being sent from + */ + Optional hostname(); + + /** + * Sets the facility used when calculating the priority of the message as defined by RFC-5424 and RFC-3164 + */ + @WithDefault("user-level") + Facility facility(); + + /** + * Set the {@link SyslogType syslog type} this handler should use to format the message sent + */ + @WithDefault("rfc5424") + SyslogType syslogType(); + + /** + * Sets the protocol used to connect to the Syslog server + */ + @WithDefault("tcp") + Protocol protocol(); + + /** + * If enabled, the message being sent is prefixed with the size of the message + */ + @WithDefault("false") + boolean useCountingFraming(); + + /** + * Set to {@code true} to truncate the message if it exceeds maximum length + */ + @WithDefault("true") + boolean truncate(); + + /** + * Enables or disables blocking when attempting to reconnect a + * {@link Protocol#TCP + * TCP} or {@link Protocol#SSL_TCP SSL TCP} protocol + */ + @WithDefault("false") + boolean blockOnReconnect(); + + /** + * The log message format + */ + @WithDefault("%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c{3.}] (%t) %s%e%n") + String format(); + + /** + * The log level specifying what message levels will be logged by the Syslog logger + */ + @WithDefault("ALL") + Level level(); + + /** + * The name of the filter to link to the file handler. + */ + Optional filter(); + + /** + * The maximum length, in bytes, of the message allowed to be sent. The length includes the header and the message. + *

+ * If not set, the default value is {@code 2048} when {@code sys-log-type} is {@code rfc5424} (which is the default) + * and {@code 1024} when {@code sys-log-type} is {@code rfc3164} + */ + Optional<@WithConverter(MemorySizeConverter.class) MemorySize> maxLength(); + + /** + * Syslog async logging config + */ + AsyncConfig async(); + } + + interface CleanupFilterConfig { + /** + * The message prefix to match + */ + @WithDefault("inherit") + List ifStartsWith(); + + /** + * The new log level for the filtered message. Defaults to DEBUG. + */ + @WithDefault("DEBUG") + Level targetLevel(); + } + + interface AsyncConfig { + + /** + * Indicates whether to log asynchronously + */ + @WithParentName + @WithDefault("false") + boolean enable(); + + /** + * The queue length to use before flushing writing + */ + @WithDefault("512") + int queueLength(); + + /** + * Determine whether to block the publisher (rather than drop the message) when the queue is full + */ + @WithDefault("block") + OverflowAction overflow(); + } +} diff --git a/core/runtime/src/main/java/io/quarkus/runtime/logging/LoggingSetupRecorder.java b/core/runtime/src/main/java/io/quarkus/runtime/logging/LoggingSetupRecorder.java index 1dd3b0e396c80..6cea3eb817823 100644 --- a/core/runtime/src/main/java/io/quarkus/runtime/logging/LoggingSetupRecorder.java +++ b/core/runtime/src/main/java/io/quarkus/runtime/logging/LoggingSetupRecorder.java @@ -1,5 +1,7 @@ package io.quarkus.runtime.logging; +import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; import static org.wildfly.common.net.HostName.getQualifiedHostName; import static org.wildfly.common.os.Process.getProcessName; @@ -9,12 +11,13 @@ import java.math.BigInteger; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Optional; +import java.util.Set; import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Function; @@ -27,6 +30,8 @@ import java.util.logging.LogManager; import java.util.logging.LogRecord; +import org.eclipse.microprofile.config.ConfigProvider; +import org.eclipse.microprofile.config.spi.ConfigSource; import org.jboss.logmanager.ExtFormatter; import org.jboss.logmanager.LogContext; import org.jboss.logmanager.LogContextInitializer; @@ -45,15 +50,22 @@ import io.quarkus.bootstrap.logging.InitialConfigurator; import io.quarkus.dev.console.CurrentAppExceptionHighlighter; +import io.quarkus.dev.console.QuarkusConsole; import io.quarkus.dev.testing.ExceptionReporting; import io.quarkus.runtime.ImageMode; import io.quarkus.runtime.LaunchMode; import io.quarkus.runtime.RuntimeValue; import io.quarkus.runtime.annotations.Recorder; -import io.quarkus.runtime.configuration.ConfigInstantiator; +import io.quarkus.runtime.configuration.QuarkusConfigBuilderCustomizer; import io.quarkus.runtime.console.ConsoleRuntimeConfig; +import io.quarkus.runtime.logging.LogBuildTimeConfig.CategoryBuildTimeConfig; +import io.quarkus.runtime.logging.LogRuntimeConfig.CategoryConfig; +import io.quarkus.runtime.logging.LogRuntimeConfig.CleanupFilterConfig; +import io.quarkus.runtime.logging.LogRuntimeConfig.ConsoleConfig; +import io.quarkus.runtime.logging.LogRuntimeConfig.FileConfig; import io.quarkus.runtime.shutdown.ShutdownListener; -import io.quarkus.runtime.util.ColorSupport; +import io.smallrye.config.SmallRyeConfig; +import io.smallrye.config.SmallRyeConfigBuilder; @Recorder public class LoggingSetupRecorder { @@ -72,25 +84,45 @@ public static void handleFailedStart() { } public static void handleFailedStart(RuntimeValue>> banner) { - LogConfig config = new LogConfig(); - ConfigInstantiator.handleObject(config); - LogBuildTimeConfig buildConfig = new LogBuildTimeConfig(); - ConfigInstantiator.handleObject(buildConfig); - ConsoleRuntimeConfig consoleRuntimeConfig = new ConsoleRuntimeConfig(); - ConfigInstantiator.handleObject(consoleRuntimeConfig); - new LoggingSetupRecorder(new RuntimeValue<>(consoleRuntimeConfig)).initializeLogging(config, buildConfig, - DiscoveredLogComponents.ofEmpty(), - Collections.emptyMap(), - false, null, - Collections.emptyList(), - Collections.emptyList(), - Collections.emptyList(), - Collections.emptyList(), - Collections.emptyList(), banner, LaunchMode.DEVELOPMENT, false); + SmallRyeConfig config = ConfigProvider.getConfig().unwrap(SmallRyeConfig.class); + // There may be cases where a Config with the mappings is already available, but we can't be sure, so we wrap + // the original Config and map the logging classes. + SmallRyeConfig loggingConfig = new SmallRyeConfigBuilder() + .withCustomizers(new QuarkusConfigBuilderCustomizer()) + .withMapping(LogBuildTimeConfig.class) + .withMapping(LogRuntimeConfig.class) + .withMapping(ConsoleRuntimeConfig.class) + .withSources(new ConfigSource() { + @Override + public Set getPropertyNames() { + Set properties = new HashSet<>(); + config.getPropertyNames().forEach(properties::add); + return properties; + } + + @Override + public String getValue(final String propertyName) { + return config.getRawValue(propertyName); + } + + @Override + public String getName() { + return "Logging Config"; + } + }).build(); + LogRuntimeConfig logRuntimeConfig = loggingConfig.getConfigMapping(LogRuntimeConfig.class); + LogBuildTimeConfig logBuildTimeConfig = loggingConfig.getConfigMapping(LogBuildTimeConfig.class); + ConsoleRuntimeConfig consoleRuntimeConfig = loggingConfig.getConfigMapping(ConsoleRuntimeConfig.class); + new LoggingSetupRecorder(new RuntimeValue<>(consoleRuntimeConfig)).initializeLogging(logRuntimeConfig, + logBuildTimeConfig, + DiscoveredLogComponents.ofEmpty(), emptyMap(), false, null, emptyList(), emptyList(), emptyList(), emptyList(), + emptyList(), banner, LaunchMode.DEVELOPMENT, false); } - public ShutdownListener initializeLogging(LogConfig config, LogBuildTimeConfig buildConfig, - DiscoveredLogComponents discoveredLogComponents, + public ShutdownListener initializeLogging( + final LogRuntimeConfig config, + final LogBuildTimeConfig buildConfig, + final DiscoveredLogComponents discoveredLogComponents, final Map categoryDefaultMinLevels, final boolean enableWebStream, final RuntimeValue> streamingDevUiConsoleHandler, @@ -100,36 +132,34 @@ public ShutdownListener initializeLogging(LogConfig config, LogBuildTimeConfig b final List>> possibleFileFormatters, final List>> possibleSyslogFormatters, final RuntimeValue>> possibleBannerSupplier, - LaunchMode launchMode, - boolean includeFilters) { + final LaunchMode launchMode, + final boolean includeFilters) { ShutdownNotifier shutdownNotifier = new ShutdownNotifier(); - final Map categories = config.categories; - final LogContext logContext = LogContext.getLogContext(); - final Logger rootLogger = logContext.getLogger(""); + Map categories = config.categories(); + LogContext logContext = LogContext.getLogContext(); + Logger rootLogger = logContext.getLogger(""); - if (config.level.intValue() < buildConfig.minLevel.intValue()) { + if (config.level().intValue() < buildConfig.minLevel().intValue()) { log.warnf( "Root log level %s set below minimum logging level %s, promoting it to %s. Set the build time configuration property 'quarkus.log.min-level' to '%s' to avoid this warning", - config.level, buildConfig.minLevel, buildConfig.minLevel, config.level); - - rootLogger.setLevel(buildConfig.minLevel); + config.level(), buildConfig.minLevel(), buildConfig.minLevel(), config.level()); + rootLogger.setLevel(buildConfig.minLevel()); } else { - rootLogger.setLevel(config.level); + rootLogger.setLevel(config.level()); } ErrorManager errorManager = new OnlyOnceErrorManager(); - final Map filters = config.filters; + Map filters = config.filters(); List filterElements; if (filters.isEmpty()) { - filterElements = Collections.emptyList(); + filterElements = emptyList(); } else { filterElements = new ArrayList<>(filters.size()); filters.forEach(new BiConsumer<>() { @Override public void accept(String loggerName, CleanupFilterConfig config) { - filterElements.add( - new LogCleanupFilterElement(loggerName, config.targetLevel, config.ifStartsWith)); + filterElements.add(new LogCleanupFilterElement(loggerName, config.targetLevel(), config.ifStartsWith())); } }); } @@ -139,14 +169,13 @@ public void accept(String loggerName, CleanupFilterConfig config) { } Map namedFilters = createNamedFilters(discoveredLogComponents); + ArrayList handlers = new ArrayList<>( + 3 + additionalHandlers.size() + (config.handlers().isPresent() ? config.handlers().get().size() : 0)); - final ArrayList handlers = new ArrayList<>( - 3 + additionalHandlers.size() + (config.handlers.isPresent() ? config.handlers.get().size() : 0)); - - if (config.console.enable) { - final Handler consoleHandler = configureConsoleHandler(config.console, consoleRuntimeConfig.getValue(), - errorManager, cleanupFiler, namedFilters, possibleConsoleFormatters, possibleBannerSupplier, - launchMode, includeFilters); + if (config.console().enable()) { + Handler consoleHandler = configureConsoleHandler(config.console(), consoleRuntimeConfig.getValue(), errorManager, + cleanupFiler, + namedFilters, possibleConsoleFormatters, possibleBannerSupplier, launchMode, includeFilters); errorManager = consoleHandler.getErrorManager(); handlers.add(consoleHandler); } @@ -169,15 +198,14 @@ public void close() throws SecurityException { }); } - if (config.file.enable) { - handlers.add( - configureFileHandler(config.file, errorManager, cleanupFiler, namedFilters, possibleFileFormatters, - includeFilters)); + if (config.file().enable()) { + handlers.add(configureFileHandler(config.file(), errorManager, cleanupFiler, namedFilters, possibleFileFormatters, + includeFilters)); } - if (config.syslog.enable) { - final Handler syslogHandler = configureSyslogHandler(config.syslog, errorManager, cleanupFiler, - namedFilters, possibleSyslogFormatters, includeFilters); + if (config.syslog().enable()) { + Handler syslogHandler = configureSyslogHandler(config.syslog(), errorManager, cleanupFiler, namedFilters, + possibleSyslogFormatters, includeFilters); if (syslogHandler != null) { handlers.add(syslogHandler); } @@ -204,11 +232,11 @@ public void close() throws SecurityException { possibleConsoleFormatters, possibleFileFormatters, possibleSyslogFormatters, errorManager, cleanupFiler, namedFilters, launchMode, shutdownNotifier, includeFilters) - : Collections.emptyMap(); + : emptyMap(); if (!categories.isEmpty()) { Map additionalNamedHandlersMap; if (additionalNamedHandlers.isEmpty()) { - additionalNamedHandlersMap = Collections.emptyMap(); + additionalNamedHandlersMap = emptyMap(); } else { additionalNamedHandlersMap = new HashMap<>(); for (RuntimeValue> runtimeValue : additionalNamedHandlers) { @@ -220,25 +248,7 @@ public void close() throws SecurityException { namedHandlers.putAll(additionalNamedHandlersMap); - categories.forEach(new BiConsumer<>() { - @Override - public void accept(String categoryName, CategoryConfig config) { - final Level logLevel = getLogLevel(categoryName, categories, CategoryConfig::getLevel, - Collections.emptyMap(), buildConfig.minLevel); - final Level minLogLevel = getLogLevel(categoryName, buildConfig.categories, - CategoryBuildTimeConfig::getMinLevel, categoryDefaultMinLevels, buildConfig.minLevel); - - if (logLevel.intValue() < minLogLevel.intValue()) { - log.warnf( - "Log level %s for category '%s' set below minimum logging level %s, promoting it to %s. Set the build time configuration property 'quarkus.log.category.\"%s\".min-level' to '%s' to avoid this warning", - logLevel, - categoryName, minLogLevel, minLogLevel, categoryName, logLevel); - - config.level = InheritableLevel.of(minLogLevel.toString()); - } - } - }); - categories.forEach(new CategoryLoggerConsumer(logContext, namedHandlers, errorManager)); + setUpCategoryLoggers(buildConfig, categoryDefaultMinLevels, categories, logContext, errorManager, namedHandlers); } for (RuntimeValue> additionalHandler : additionalHandlers) { @@ -250,7 +260,7 @@ public void accept(String categoryName, CategoryConfig config) { handlers.add(handler); } } - addNamedHandlersToRootHandlers(config.handlers, namedHandlers, handlers, errorManager); + addNamedHandlersToRootHandlers(config.handlers(), namedHandlers, handlers, errorManager); InitialConfigurator.DELAYED_HANDLER.setAutoFlush(false); InitialConfigurator.DELAYED_HANDLER.setHandlers(handlers.toArray(LogContextInitializer.NO_HANDLERS)); return shutdownNotifier; @@ -258,7 +268,7 @@ public void accept(String categoryName, CategoryConfig config) { private static Map createNamedFilters(DiscoveredLogComponents discoveredLogComponents) { if (discoveredLogComponents.getNameToFilterClass().isEmpty()) { - return Collections.emptyMap(); + return emptyMap(); } Map nameToFilter = new HashMap<>(); @@ -280,84 +290,62 @@ public void accept(String name, String className) { * WARNING: this method is part of the recorder but is actually called statically at build time. * You may not push RuntimeValue's to it. */ - public static void initializeBuildTimeLogging(LogConfig config, LogBuildTimeConfig buildConfig, - Map categoryDefaultMinLevels, - ConsoleRuntimeConfig consoleConfig, - LaunchMode launchMode) { + public static void initializeBuildTimeLogging( + final LogRuntimeConfig config, + final LogBuildTimeConfig buildConfig, + final ConsoleRuntimeConfig consoleConfig, + final Map categoryDefaultMinLevels, + final List additionalLogCleanupFilters, + final LaunchMode launchMode) { + ShutdownNotifier dummy = new ShutdownNotifier(); - final Map categories = config.categories; - final LogContext logContext = LogContext.getLogContext(); - final Logger rootLogger = logContext.getLogger(""); + Map categories = config.categories(); + LogContext logContext = LogContext.getLogContext(); + Logger rootLogger = logContext.getLogger(""); - rootLogger.setLevel(config.level); + rootLogger.setLevel(config.level()); ErrorManager errorManager = new OnlyOnceErrorManager(); - final Map filters = config.filters; - List filterElements = new ArrayList<>(filters.size()); + Map filters = config.filters(); + List filterElements = new ArrayList<>(filters.size() + additionalLogCleanupFilters.size()); for (Entry entry : filters.entrySet()) { - filterElements.add( - new LogCleanupFilterElement(entry.getKey(), entry.getValue().targetLevel, entry.getValue().ifStartsWith)); + filterElements.add(new LogCleanupFilterElement(entry.getKey(), entry.getValue().targetLevel(), + entry.getValue().ifStartsWith())); + } + for (LogCleanupFilterElement logCleanupFilter : additionalLogCleanupFilters) { + filterElements.add(new LogCleanupFilterElement(logCleanupFilter.getLoggerName(), logCleanupFilter.getTargetLevel(), + logCleanupFilter.getMessageStarts())); } LogCleanupFilter logCleanupFilter = new LogCleanupFilter(filterElements, dummy); - final ArrayList handlers = new ArrayList<>(3); - - if (config.console.enable) { - final Handler consoleHandler = configureConsoleHandler(config.console, consoleConfig, errorManager, - logCleanupFilter, Collections.emptyMap(), Collections.emptyList(), - new RuntimeValue<>(Optional.empty()), launchMode, false); + ArrayList handlers = new ArrayList<>(3); + if (config.console().enable()) { + Handler consoleHandler = configureConsoleHandler(config.console(), consoleConfig, errorManager, logCleanupFilter, + emptyMap(), emptyList(), new RuntimeValue<>(Optional.empty()), launchMode, false); errorManager = consoleHandler.getErrorManager(); handlers.add(consoleHandler); } - Map namedHandlers = createNamedHandlers(config, consoleConfig, Collections.emptyList(), - Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), errorManager, logCleanupFilter, - Collections.emptyMap(), launchMode, dummy, false); - - for (Map.Entry entry : categories.entrySet()) { - final String categoryName = entry.getKey(); - final Level logLevel = getLogLevel(categoryName, categories, CategoryConfig::getLevel, - Collections.emptyMap(), buildConfig.minLevel); - final Level minLogLevel = getLogLevel(categoryName, buildConfig.categories, CategoryBuildTimeConfig::getMinLevel, - categoryDefaultMinLevels, buildConfig.minLevel); - - if (logLevel.intValue() < minLogLevel.intValue()) { - String category = entry.getKey(); - log.warnf("Log level %s for category '%s' set below minimum logging level %s, promoting it to %s. " - + - "Set the build time configuration property 'quarkus.log.category.\"%s\".min-level' to '%s' to avoid this warning", - logLevel, - category, minLogLevel, minLogLevel, category, logLevel); + Map namedHandlers = createNamedHandlers(config, consoleConfig, emptyList(), + emptyList(), emptyList(), emptyList(), errorManager, logCleanupFilter, + emptyMap(), launchMode, dummy, false); - entry.getValue().level = InheritableLevel.of(minLogLevel.toString()); - } - } + setUpCategoryLoggers(buildConfig, categoryDefaultMinLevels, categories, logContext, errorManager, namedHandlers); - for (Map.Entry entry : categories.entrySet()) { - final String name = entry.getKey(); - final Logger categoryLogger = logContext.getLogger(name); - final CategoryConfig categoryConfig = entry.getValue(); - if (!categoryConfig.level.isInherited()) { - categoryLogger.setLevel(categoryConfig.level.getLevel()); - } - categoryLogger.setUseParentHandlers(categoryConfig.useParentHandlers); - if (categoryConfig.handlers.isPresent()) { - addNamedHandlersToCategory(categoryConfig, namedHandlers, categoryLogger, errorManager); - } - } - addNamedHandlersToRootHandlers(config.handlers, namedHandlers, handlers, errorManager); + addNamedHandlersToRootHandlers(config.handlers(), namedHandlers, handlers, errorManager); InitialConfigurator.DELAYED_HANDLER.setAutoFlush(false); InitialConfigurator.DELAYED_HANDLER.setBuildTimeHandlers(handlers.toArray(LogContextInitializer.NO_HANDLERS)); } - private boolean shouldCreateNamedHandlers(LogConfig logConfig, + private boolean shouldCreateNamedHandlers( + LogRuntimeConfig logRuntimeConfig, List>> additionalNamedHandlers) { - if (!logConfig.categories.isEmpty()) { + if (!logRuntimeConfig.categories().isEmpty()) { return true; } - if (logConfig.handlers.isPresent()) { - return !logConfig.handlers.get().isEmpty(); + if (logRuntimeConfig.handlers().isPresent()) { + return !logRuntimeConfig.handlers().get().isEmpty(); } return !additionalNamedHandlers.isEmpty(); } @@ -394,7 +382,8 @@ public static InheritableLevel getLogLevelNoInheritance(String categoryName, return inheritableLevel; } - private static Map createNamedHandlers(LogConfig config, ConsoleRuntimeConfig consoleRuntimeConfig, + private static Map createNamedHandlers( + LogRuntimeConfig config, ConsoleRuntimeConfig consoleRuntimeConfig, List>> additionalNamedHandlers, List>> possibleConsoleFormatters, List>> possibleFileFormatters, @@ -403,9 +392,9 @@ private static Map createNamedHandlers(LogConfig config, Consol Map namedFilters, LaunchMode launchMode, ShutdownNotifier shutdownHandler, boolean includeFilters) { Map namedHandlers = new HashMap<>(); - for (Entry consoleConfigEntry : config.consoleHandlers.entrySet()) { + for (Entry consoleConfigEntry : config.consoleHandlers().entrySet()) { ConsoleConfig namedConsoleConfig = consoleConfigEntry.getValue(); - if (!namedConsoleConfig.enable) { + if (!namedConsoleConfig.enable()) { continue; } final Handler consoleHandler = configureConsoleHandler(namedConsoleConfig, consoleRuntimeConfig, @@ -413,18 +402,18 @@ private static Map createNamedHandlers(LogConfig config, Consol includeFilters); addToNamedHandlers(namedHandlers, consoleHandler, consoleConfigEntry.getKey()); } - for (Entry fileConfigEntry : config.fileHandlers.entrySet()) { + for (Entry fileConfigEntry : config.fileHandlers().entrySet()) { FileConfig namedFileConfig = fileConfigEntry.getValue(); - if (!namedFileConfig.enable) { + if (!namedFileConfig.enable()) { continue; } final Handler fileHandler = configureFileHandler(namedFileConfig, errorManager, cleanupFilter, namedFilters, possibleFileFormatters, includeFilters); addToNamedHandlers(namedHandlers, fileHandler, fileConfigEntry.getKey()); } - for (Entry sysLogConfigEntry : config.syslogHandlers.entrySet()) { - SyslogConfig namedSyslogConfig = sysLogConfigEntry.getValue(); - if (!namedSyslogConfig.enable) { + for (Entry sysLogConfigEntry : config.syslogHandlers().entrySet()) { + LogRuntimeConfig.SyslogConfig namedSyslogConfig = sysLogConfigEntry.getValue(); + if (!namedSyslogConfig.enable()) { continue; } final Handler syslogHandler = configureSyslogHandler(namedSyslogConfig, errorManager, cleanupFilter, @@ -436,7 +425,7 @@ private static Map createNamedHandlers(LogConfig config, Consol Map additionalNamedHandlersMap; if (additionalNamedHandlers.isEmpty()) { - additionalNamedHandlersMap = Collections.emptyMap(); + additionalNamedHandlersMap = emptyMap(); } else { additionalNamedHandlersMap = new HashMap<>(); for (RuntimeValue> runtimeValue : additionalNamedHandlers) { @@ -465,10 +454,11 @@ public void run() { }); } - private static void addNamedHandlersToCategory(CategoryConfig categoryConfig, Map namedHandlers, + private static void addNamedHandlersToCategory( + CategoryConfig categoryConfig, Map namedHandlers, Logger categoryLogger, ErrorManager errorManager) { - for (String categoryNamedHandler : categoryConfig.handlers.get()) { + for (String categoryNamedHandler : categoryConfig.handlers().get()) { Handler handler = namedHandlers.get(categoryNamedHandler); if (handler != null) { categoryLogger.addHandler(handler); @@ -485,6 +475,43 @@ public void run() { } } + private static void setUpCategoryLoggers( + final LogBuildTimeConfig buildConfig, + final Map categoryDefaultMinLevels, + final Map categories, + final LogContext logContext, + final ErrorManager errorManager, + final Map namedHandlers) { + + for (Entry entry : categories.entrySet()) { + String categoryName = entry.getKey(); + CategoryConfig categoryConfig = entry.getValue(); + InheritableLevel categoryLevel = categoryConfig.level(); + + Level logLevel = getLogLevel(categoryName, categories, CategoryConfig::level, emptyMap(), buildConfig.minLevel()); + Level minLogLevel = getLogLevel(categoryName, buildConfig.categories(), CategoryBuildTimeConfig::minLevel, + categoryDefaultMinLevels, buildConfig.minLevel()); + if (logLevel.intValue() < minLogLevel.intValue()) { + String category = entry.getKey(); + log.warnf( + "Log level %s for category '%s' set below minimum logging level %s, promoting it to %s. " + + "Set the build time configuration property 'quarkus.log.category.\"%s\".min-level' to '%s' to avoid this warning", + logLevel, category, minLogLevel, minLogLevel, category, logLevel); + + categoryLevel = InheritableLevel.of(minLogLevel.toString()); + } + + Logger categoryLogger = logContext.getLogger(categoryName); + if (!categoryLevel.isInherited()) { + categoryLogger.setLevel(categoryLevel.getLevel()); + } + categoryLogger.setUseParentHandlers(categoryConfig.useParentHandlers()); + if (categoryConfig.handlers().isPresent()) { + addNamedHandlersToCategory(categoryConfig, namedHandlers, categoryLogger, errorManager); + } + } + } + private static void addNamedHandlersToRootHandlers(Optional> handlerNames, Map namedHandlers, ArrayList effectiveHandlers, ErrorManager errorManager) { if (handlerNames.isEmpty()) { @@ -514,8 +541,9 @@ public void initializeLoggingForImageBuild() { } } - private static Handler configureConsoleHandler(final ConsoleConfig config, - ConsoleRuntimeConfig consoleRuntimeConfig, + private static Handler configureConsoleHandler( + final ConsoleConfig config, + final ConsoleRuntimeConfig consoleRuntimeConfig, final ErrorManager defaultErrorManager, final LogCleanupFilter cleanupFilter, final Map namedFilters, @@ -541,26 +569,26 @@ private static Handler configureConsoleHandler(final ConsoleConfig config, if (possibleBannerSupplier != null && possibleBannerSupplier.getValue().isPresent()) { bannerSupplier = possibleBannerSupplier.getValue().get(); } - if (ColorSupport.isColorEnabled(consoleRuntimeConfig, config)) { - formatter = new ColorPatternFormatter(config.darken, config.format); + if (isColorEnabled(consoleRuntimeConfig, config)) { + formatter = new ColorPatternFormatter(config.darken(), config.format()); color = true; } else { - formatter = new PatternFormatter(config.format); + formatter = new PatternFormatter(config.format()); } if (bannerSupplier != null) { formatter = new TextBannerFormatter(bannerSupplier, ExtFormatter.wrap(formatter, false)); } } final ConsoleHandler consoleHandler = new ConsoleHandler( - config.stderr ? ConsoleHandler.Target.SYSTEM_ERR : ConsoleHandler.Target.SYSTEM_OUT, formatter); - consoleHandler.setLevel(config.level); + config.stderr() ? ConsoleHandler.Target.SYSTEM_ERR : ConsoleHandler.Target.SYSTEM_OUT, formatter); + consoleHandler.setLevel(config.level()); consoleHandler.setErrorManager(defaultErrorManager); - applyFilter(includeFilters, defaultErrorManager, cleanupFilter, config.filter, namedFilters, consoleHandler); + applyFilter(includeFilters, defaultErrorManager, cleanupFilter, config.filter(), namedFilters, consoleHandler); - Handler handler = config.async.enable ? createAsyncHandler(config.async, config.level, consoleHandler) + Handler handler = config.async().enable() ? createAsyncHandler(config.async(), config.level(), consoleHandler) : consoleHandler; - if (color && launchMode.isDevOrTest() && !config.async.enable) { + if (color && launchMode.isDevOrTest() && !config.async().enable()) { final Handler delegate = handler; handler = new Handler() { @Override @@ -597,18 +625,18 @@ private static Handler configureFileHandler(final FileConfig config, final Error final List>> possibleFileFormatters, final boolean includeFilters) { FileHandler handler; - FileConfig.RotationConfig rotationConfig = config.rotation; - if (rotationConfig.fileSuffix.isPresent()) { + FileConfig.RotationConfig rotationConfig = config.rotation(); + if (rotationConfig.fileSuffix().isPresent()) { PeriodicSizeRotatingFileHandler periodicSizeRotatingFileHandler = new PeriodicSizeRotatingFileHandler(); - periodicSizeRotatingFileHandler.setSuffix(rotationConfig.fileSuffix.get()); - periodicSizeRotatingFileHandler.setRotateSize(rotationConfig.maxFileSize.asLongValue()); - periodicSizeRotatingFileHandler.setRotateOnBoot(rotationConfig.rotateOnBoot); - periodicSizeRotatingFileHandler.setMaxBackupIndex(rotationConfig.maxBackupIndex); + periodicSizeRotatingFileHandler.setSuffix(rotationConfig.fileSuffix().get()); + periodicSizeRotatingFileHandler.setRotateSize(rotationConfig.maxFileSize().asLongValue()); + periodicSizeRotatingFileHandler.setRotateOnBoot(rotationConfig.rotateOnBoot()); + periodicSizeRotatingFileHandler.setMaxBackupIndex(rotationConfig.maxBackupIndex()); handler = periodicSizeRotatingFileHandler; } else { SizeRotatingFileHandler sizeRotatingFileHandler = new SizeRotatingFileHandler( - rotationConfig.maxFileSize.asLongValue(), rotationConfig.maxBackupIndex); - sizeRotatingFileHandler.setRotateOnBoot(rotationConfig.rotateOnBoot); + rotationConfig.maxFileSize().asLongValue(), rotationConfig.maxBackupIndex()); + sizeRotatingFileHandler.setRotateOnBoot(rotationConfig.rotateOnBoot()); handler = sizeRotatingFileHandler; } @@ -624,34 +652,34 @@ private static Handler configureFileHandler(final FileConfig config, final Error } } if (formatter == null) { - formatter = new PatternFormatter(config.format); + formatter = new PatternFormatter(config.format()); } handler.setFormatter(formatter); handler.setAppend(true); try { - handler.setFile(config.path); + handler.setFile(config.path()); } catch (FileNotFoundException e) { errorManager.error("Failed to set log file", e, ErrorManager.OPEN_FAILURE); } handler.setErrorManager(errorManager); - handler.setLevel(config.level); + handler.setLevel(config.level()); handler.setFilter(cleanupFilter); - if (config.encoding.isPresent()) { + if (config.encoding().isPresent()) { try { - handler.setEncoding(config.encoding.get().name()); + handler.setEncoding(config.encoding().get().name()); } catch (UnsupportedEncodingException e) { errorManager.error("Failed to set character encoding", e, ErrorManager.GENERIC_FAILURE); } } - applyFilter(includeFilters, errorManager, cleanupFilter, config.filter, namedFilters, handler); + applyFilter(includeFilters, errorManager, cleanupFilter, config.filter(), namedFilters, handler); if (formatterWarning) { handler.getErrorManager().error("Multiple file formatters were activated", null, ErrorManager.GENERIC_FAILURE); } - if (config.async.enable) { - return createAsyncHandler(config.async, config.level, handler); + if (config.async().enable()) { + return createAsyncHandler(config.async(), config.level(), handler); } return handler; } @@ -672,24 +700,24 @@ private static void applyFilter(boolean includeFilters, ErrorManager errorManage } } - private static Handler configureSyslogHandler(final SyslogConfig config, final ErrorManager errorManager, + private static Handler configureSyslogHandler(final LogRuntimeConfig.SyslogConfig config, final ErrorManager errorManager, final LogCleanupFilter logCleanupFilter, final Map namedFilters, final List>> possibleSyslogFormatters, final boolean includeFilters) { try { - final SyslogHandler handler = new SyslogHandler(config.endpoint.getHostString(), config.endpoint.getPort()); - handler.setAppName(config.appName.orElse(getProcessName())); - handler.setHostname(config.hostname.orElse(getQualifiedHostName())); - handler.setFacility(config.facility); - handler.setSyslogType(config.syslogType); - handler.setProtocol(config.protocol); - handler.setBlockOnReconnect(config.blockOnReconnect); - handler.setTruncate(config.truncate); - handler.setUseCountingFraming(config.useCountingFraming); - handler.setLevel(config.level); - if (config.maxLength.isPresent()) { - BigInteger maxLen = config.maxLength.get().asBigInteger(); + final SyslogHandler handler = new SyslogHandler(config.endpoint().getHostString(), config.endpoint().getPort()); + handler.setAppName(config.appName().orElse(getProcessName())); + handler.setHostname(config.hostname().orElse(getQualifiedHostName())); + handler.setFacility(config.facility()); + handler.setSyslogType(config.syslogType()); + handler.setProtocol(config.protocol()); + handler.setBlockOnReconnect(config.blockOnReconnect()); + handler.setTruncate(config.truncate()); + handler.setUseCountingFraming(config.useCountingFraming()); + handler.setLevel(config.level()); + if (config.maxLength().isPresent()) { + BigInteger maxLen = config.maxLength().get().asBigInteger(); if (maxLen.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) > 0) { errorManager.error( "Using 2GB as the value of maxLength for SyslogHandler as it is the maximum allowed value", null, @@ -719,21 +747,21 @@ private static Handler configureSyslogHandler(final SyslogConfig config, final E } } if (formatter == null) { - formatter = new PatternFormatter(config.format); + formatter = new PatternFormatter(config.format()); } handler.setFormatter(formatter); handler.setErrorManager(errorManager); handler.setFilter(logCleanupFilter); - applyFilter(includeFilters, errorManager, logCleanupFilter, config.filter, namedFilters, handler); + applyFilter(includeFilters, errorManager, logCleanupFilter, config.filter(), namedFilters, handler); if (formatterWarning) { handler.getErrorManager().error("Multiple syslog formatters were activated", null, ErrorManager.GENERIC_FAILURE); } - if (config.async.enable) { - return createAsyncHandler(config.async, config.level, handler); + if (config.async().enable()) { + return createAsyncHandler(config.async(), config.level(), handler); } return handler; } catch (IOException e) { @@ -742,36 +770,22 @@ private static Handler configureSyslogHandler(final SyslogConfig config, final E } } - private static AsyncHandler createAsyncHandler(AsyncConfig asyncConfig, Level level, Handler handler) { - final AsyncHandler asyncHandler = new AsyncHandler(asyncConfig.queueLength); - asyncHandler.setOverflowAction(asyncConfig.overflow); + private static AsyncHandler createAsyncHandler(LogRuntimeConfig.AsyncConfig asyncConfig, Level level, Handler handler) { + final AsyncHandler asyncHandler = new AsyncHandler(asyncConfig.queueLength()); + asyncHandler.setOverflowAction(asyncConfig.overflow()); asyncHandler.addHandler(handler); asyncHandler.setLevel(level); return asyncHandler; } - private static class CategoryLoggerConsumer implements BiConsumer { - private final LogContext logContext; - private final Map namedHandlers; - private final ErrorManager errorManager; - - CategoryLoggerConsumer(LogContext logContext, Map namedHandlers, ErrorManager errorManager) { - this.logContext = logContext; - this.namedHandlers = namedHandlers; - this.errorManager = errorManager; + private static boolean isColorEnabled(ConsoleRuntimeConfig consoleConfig, ConsoleConfig logConfig) { + if (consoleConfig.color().isPresent()) { + return consoleConfig.color().get(); } - - @Override - public void accept(String name, CategoryConfig categoryConfig) { - final Logger categoryLogger = logContext.getLogger(name); - if (!categoryConfig.level.isInherited()) { - categoryLogger.setLevel(categoryConfig.level.getLevel()); - } - categoryLogger.setUseParentHandlers(categoryConfig.useParentHandlers); - if (categoryConfig.handlers.isPresent()) { - addNamedHandlersToCategory(categoryConfig, namedHandlers, categoryLogger, errorManager); - } + if (logConfig.color().isPresent()) { + return logConfig.color().get(); } + return QuarkusConsole.hasColorSupport(); } private static class AdditionalNamedHandlersConsumer implements BiConsumer { diff --git a/core/runtime/src/main/java/io/quarkus/runtime/logging/SyslogConfig.java b/core/runtime/src/main/java/io/quarkus/runtime/logging/SyslogConfig.java deleted file mode 100644 index 767a0a5b92c85..0000000000000 --- a/core/runtime/src/main/java/io/quarkus/runtime/logging/SyslogConfig.java +++ /dev/null @@ -1,112 +0,0 @@ -package io.quarkus.runtime.logging; - -import java.net.InetSocketAddress; -import java.util.Optional; -import java.util.logging.Level; - -import org.jboss.logmanager.handlers.SyslogHandler.Facility; -import org.jboss.logmanager.handlers.SyslogHandler.Protocol; -import org.jboss.logmanager.handlers.SyslogHandler.SyslogType; - -import io.quarkus.runtime.annotations.ConfigGroup; -import io.quarkus.runtime.annotations.ConfigItem; -import io.quarkus.runtime.configuration.MemorySize; - -@ConfigGroup -public class SyslogConfig { - - /** - * If syslog logging should be enabled - */ - @ConfigItem - boolean enable; - - /** - * - * The IP address and port of the Syslog server - */ - @ConfigItem(defaultValue = "localhost:514") - InetSocketAddress endpoint; - - /** - * The app name used when formatting the message in RFC5424 format - */ - @ConfigItem - Optional appName; - - /** - * The name of the host the messages are being sent from - */ - @ConfigItem - Optional hostname; - - /** - * Sets the facility used when calculating the priority of the message as defined by RFC-5424 and RFC-3164 - */ - @ConfigItem(defaultValue = "user-level") - Facility facility; - - /** - * Set the {@link SyslogType syslog type} this handler should use to format the message sent - */ - @ConfigItem(defaultValue = "rfc5424") - SyslogType syslogType; - - /** - * Sets the protocol used to connect to the Syslog server - */ - @ConfigItem(defaultValue = "tcp") - Protocol protocol; - - /** - * If enabled, the message being sent is prefixed with the size of the message - */ - @ConfigItem - boolean useCountingFraming; - - /** - * Set to {@code true} to truncate the message if it exceeds maximum length - */ - @ConfigItem(defaultValue = "true") - boolean truncate; - - /** - * Enables or disables blocking when attempting to reconnect a - * {@link org.jboss.logmanager.handlers.SyslogHandler.Protocol#TCP - * TCP} or {@link org.jboss.logmanager.handlers.SyslogHandler.Protocol#SSL_TCP SSL TCP} protocol - */ - @ConfigItem - boolean blockOnReconnect; - - /** - * The log message format - */ - @ConfigItem(defaultValue = "%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c{3.}] (%t) %s%e%n") - String format; - - /** - * The log level specifying what message levels will be logged by the Syslog logger - */ - @ConfigItem(defaultValue = "ALL") - Level level; - - /** - * The name of the filter to link to the file handler. - */ - @ConfigItem - Optional filter; - - /** - * The maximum length, in bytes, of the message allowed to be sent. The length includes the header and the message. - *

- * If not set, the default value is {@code 2048} when {@code sys-log-type} is {@code rfc5424} (which is the default) - * and {@code 1024} when {@code sys-log-type} is {@code rfc3164} - */ - @ConfigItem - Optional maxLength; - - /** - * Syslog async logging config - */ - AsyncConfig async; -} diff --git a/core/runtime/src/main/java/io/quarkus/runtime/util/ColorSupport.java b/core/runtime/src/main/java/io/quarkus/runtime/util/ColorSupport.java deleted file mode 100644 index 3192a97607fb8..0000000000000 --- a/core/runtime/src/main/java/io/quarkus/runtime/util/ColorSupport.java +++ /dev/null @@ -1,18 +0,0 @@ -package io.quarkus.runtime.util; - -import io.quarkus.dev.console.QuarkusConsole; -import io.quarkus.runtime.console.ConsoleRuntimeConfig; -import io.quarkus.runtime.logging.ConsoleConfig; - -public class ColorSupport { - - public static boolean isColorEnabled(ConsoleRuntimeConfig consoleConfig, ConsoleConfig logConfig) { - if (consoleConfig.color.isPresent()) { - return consoleConfig.color.get(); - } - if (logConfig.color.isPresent()) { - return logConfig.color.get(); - } - return QuarkusConsole.hasColorSupport(); - } -} diff --git a/core/runtime/src/test/java/io/quarkus/runtime/configuration/ConfigInstantiatorTestCase.java b/core/runtime/src/test/java/io/quarkus/runtime/configuration/ConfigInstantiatorTestCase.java index b242d41ba572c..657dbc226c7b0 100644 --- a/core/runtime/src/test/java/io/quarkus/runtime/configuration/ConfigInstantiatorTestCase.java +++ b/core/runtime/src/test/java/io/quarkus/runtime/configuration/ConfigInstantiatorTestCase.java @@ -10,7 +10,6 @@ import org.eclipse.microprofile.config.Config; import org.eclipse.microprofile.config.spi.ConfigProviderResolver; import org.eclipse.microprofile.config.spi.ConfigSource; -import org.jboss.logmanager.Level; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -18,7 +17,6 @@ import io.quarkus.runtime.annotations.ConfigGroup; import io.quarkus.runtime.annotations.ConfigItem; import io.quarkus.runtime.annotations.ConfigRoot; -import io.quarkus.runtime.logging.LogConfig; import io.smallrye.config.SmallRyeConfigBuilder; /** @@ -74,21 +72,6 @@ static void releaseTestConfig() { } } - @Test - public void handleLogConfig() { - LogConfig logConfig = new LogConfig(); - ConfigInstantiator.handleObject(logConfig); - - assertThat(logConfig.level).isEqualTo(Level.INFO); - assertThat(logConfig.categories).hasSize(2); - // note: category assertions are a bit awkward because most fields and classes are just package visible - // (level.level selects the actual level member of InheritableLevel.ActualLevel) - assertThat(logConfig.categories.get("foo.bar")) - .hasFieldOrPropertyWithValue("level.level", Level.DEBUG); - assertThat(logConfig.categories.get("baz")) - .hasFieldOrPropertyWithValue("level.level", Level.TRACE); - } - @Test public void handleMapOfMapConfig() { MapOfMapsConfig mapOfMapsConfig = new MapOfMapsConfig(); diff --git a/extensions/undertow/deployment/src/main/java/io/quarkus/undertow/deployment/UndertowBuildStep.java b/extensions/undertow/deployment/src/main/java/io/quarkus/undertow/deployment/UndertowBuildStep.java index 240a96eb87f83..db3fba29da4b8 100644 --- a/extensions/undertow/deployment/src/main/java/io/quarkus/undertow/deployment/UndertowBuildStep.java +++ b/extensions/undertow/deployment/src/main/java/io/quarkus/undertow/deployment/UndertowBuildStep.java @@ -699,7 +699,7 @@ public ServletDeploymentManagerBuildItem build(List servlets, bc.getValue(), launchMode.getLaunchMode(), shutdownContext, - logBuildTimeConfig.decorateStacktraces, + logBuildTimeConfig.decorateStacktraces(), scrMainJava, knownClasses)); diff --git a/extensions/vertx-http/deployment/src/main/java/io/quarkus/devui/deployment/logstream/LogStreamProcessor.java b/extensions/vertx-http/deployment/src/main/java/io/quarkus/devui/deployment/logstream/LogStreamProcessor.java index f02835a6ffae8..08b75f7e01d1b 100644 --- a/extensions/vertx-http/deployment/src/main/java/io/quarkus/devui/deployment/logstream/LogStreamProcessor.java +++ b/extensions/vertx-http/deployment/src/main/java/io/quarkus/devui/deployment/logstream/LogStreamProcessor.java @@ -46,7 +46,8 @@ public void handler(BuildProducer streamingLogHand LoggingDecorateBuildItem loggingDecorateBuildItem, LogStreamRecorder recorder) { RuntimeValue> mutinyLogHandler = recorder.mutinyLogHandler( - logBuildTimeConfig.decorateStacktraces, loggingDecorateBuildItem.getSrcMainJava().toString(), + logBuildTimeConfig.decorateStacktraces(), + loggingDecorateBuildItem.getSrcMainJava().toString(), loggingDecorateBuildItem.getKnowClasses()); streamingLogHandlerBuildItem.produce(new StreamingLogHandlerBuildItem((RuntimeValue) mutinyLogHandler)); } diff --git a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/VertxHttpRecorder.java b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/VertxHttpRecorder.java index 406bf15d64b44..51df4af963922 100644 --- a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/VertxHttpRecorder.java +++ b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/VertxHttpRecorder.java @@ -624,7 +624,7 @@ private void setupAccessLogHandler(Optional> mainRouterRunt } private boolean decorateStacktrace(LaunchMode launchMode, LogBuildTimeConfig logBuildTimeConfig) { - return logBuildTimeConfig.decorateStacktraces && launchMode.equals(LaunchMode.DEVELOPMENT); + return logBuildTimeConfig.decorateStacktraces() && launchMode.equals(LaunchMode.DEVELOPMENT); } private void addHotReplacementHandlerIfNeeded(Router router) { diff --git a/integration-tests/vertx/src/main/resources/application.properties b/integration-tests/vertx/src/main/resources/application.properties index 02330731a3884..0f2643b980c34 100644 --- a/integration-tests/vertx/src/main/resources/application.properties +++ b/integration-tests/vertx/src/main/resources/application.properties @@ -1,3 +1,3 @@ vertx.event-loops.size=2 quarkus.log.file.enable=true -quarkus.log.file=quarkus.log \ No newline at end of file +quarkus.log.file.path=quarkus.log \ No newline at end of file diff --git a/test-framework/common/src/main/java/io/quarkus/test/common/LauncherUtil.java b/test-framework/common/src/main/java/io/quarkus/test/common/LauncherUtil.java index 544514617d488..22a4ed3fcca75 100644 --- a/test-framework/common/src/main/java/io/quarkus/test/common/LauncherUtil.java +++ b/test-framework/common/src/main/java/io/quarkus/test/common/LauncherUtil.java @@ -38,7 +38,7 @@ private LauncherUtil() { } public static Config installAndGetSomeConfig() { - final SmallRyeConfig config = ConfigUtils.configBuilder(false, LaunchMode.NORMAL).build(); + SmallRyeConfig config = ConfigUtils.configBuilder(false, LaunchMode.NORMAL).build(); QuarkusConfigFactory.setConfig(config); return config; } diff --git a/test-framework/common/src/main/java/io/quarkus/test/common/PropertyTestUtil.java b/test-framework/common/src/main/java/io/quarkus/test/common/PropertyTestUtil.java index dfd24daba6e28..7e75825709e36 100644 --- a/test-framework/common/src/main/java/io/quarkus/test/common/PropertyTestUtil.java +++ b/test-framework/common/src/main/java/io/quarkus/test/common/PropertyTestUtil.java @@ -1,5 +1,7 @@ package io.quarkus.test.common; +import static io.quarkus.runtime.logging.LogRuntimeConfig.FileConfig; + import java.io.File; import java.nio.file.Files; import java.nio.file.Path; @@ -7,8 +9,6 @@ import java.util.Arrays; import java.util.List; -import io.quarkus.runtime.logging.FileConfig; - public class PropertyTestUtil { private static final String LOG_FILE_PATH_PROPERTY = "quarkus.log.file.path";