From 514a4d7bbb75f281a878677114fb6428de99e4d8 Mon Sep 17 00:00:00 2001 From: Ruben Cerna Date: Thu, 9 Apr 2026 17:00:13 -0700 Subject: [PATCH 1/4] Fix cli loglevel --- src/Cli/ConfigGenerator.cs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/Cli/ConfigGenerator.cs b/src/Cli/ConfigGenerator.cs index c89da760e4..6863eab367 100644 --- a/src/Cli/ConfigGenerator.cs +++ b/src/Cli/ConfigGenerator.cs @@ -2597,18 +2597,27 @@ public static bool TryStartEngineWithOptions(StartOptions options, FileSystemRun minimumLogLevel = (LogLevel)options.LogLevel; _logger.LogInformation("Setting minimum LogLevel: {minimumLogLevel}.", minimumLogLevel); + args.Add("--LogLevel"); + args.Add(minimumLogLevel.ToString()); } else { minimumLogLevel = deserializedRuntimeConfig.GetConfiguredLogLevel(); HostMode hostModeType = deserializedRuntimeConfig.IsDevelopmentMode() ? HostMode.Development : HostMode.Production; + bool isValueFromDefault = !deserializedRuntimeConfig.IsLogLevelNull() && deserializedRuntimeConfig.Runtime!.Telemetry!.LoggerLevel! + .SingleOrDefault(kvp => kvp.Key.Equals("default", StringComparison.OrdinalIgnoreCase)).Value != null; - _logger.LogInformation($"Setting default minimum LogLevel: {minimumLogLevel} for {hostModeType} mode.", minimumLogLevel, hostModeType); + // Check if we set the minimum LogLevel from the config file or if it is based on the host mode. + if (isValueFromDefault) + { + _logger.LogInformation($"Using default minimum LogLevel: {minimumLogLevel} from the 'Default' namespace in config file.", minimumLogLevel, hostModeType); + } + else + { + _logger.LogInformation($"Setting default minimum LogLevel: {minimumLogLevel} for {hostModeType} mode.", minimumLogLevel, hostModeType); + } } - args.Add("--LogLevel"); - args.Add(minimumLogLevel.ToString()); - // This will add args to disable automatic redirects to https if specified by user if (options.IsHttpsRedirectionDisabled) { From e8b0767a70a783fd5d1bc639e391a33586974bd2 Mon Sep 17 00:00:00 2001 From: Ruben Cerna Date: Mon, 13 Apr 2026 11:16:30 -0700 Subject: [PATCH 2/4] Add testing --- src/Cli.Tests/EndToEndTests.cs | 74 ++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/src/Cli.Tests/EndToEndTests.cs b/src/Cli.Tests/EndToEndTests.cs index 9648f119c5..a8228b151c 100644 --- a/src/Cli.Tests/EndToEndTests.cs +++ b/src/Cli.Tests/EndToEndTests.cs @@ -3,6 +3,7 @@ using Azure.DataApiBuilder.Config.Converters; using Azure.DataApiBuilder.Product; +using Azure.DataApiBuilder.Service; using Cli.Constants; using Microsoft.Data.SqlClient; @@ -857,6 +858,79 @@ public void TestEngineStartUpWithVerboseAndLogLevelOptions(string logLevelOption StringAssert.Contains(output, $"User provided config file: {TEST_RUNTIME_CONFIG_FILE}", StringComparison.Ordinal); } + /// + /// Validates that `dab start` correctly sets + /// based on whether the --LogLevel CLI flag is provided. + /// + /// When the --LogLevel flag is provided, IsLogLevelOverriddenByCli should be true. + /// When the --LogLevel flag is omitted (log level comes from the config file), + /// IsLogLevelOverriddenByCli should be false. + /// + /// The --LogLevel CLI flag value, or null to omit the flag. + /// Expected value of Startup.IsLogLevelOverriddenByCli. + [DataTestMethod] + [DataRow(null, false, DisplayName = "No CLI flag => IsLogLevelOverriddenByCli is false, log level resolved from config file.")] + [DataRow(LogLevel.Error, true, DisplayName = "CLI --LogLevel flag provided => IsLogLevelOverriddenByCli is true.")] + public void TestStartCommandResolvesLogLevelFromConfigOrFlag( + LogLevel? cliLogLevel, + bool expectedIsOverridden) + { + // Build a base config with a log-level property in the telemetry section and empty entities. + string baseConfig = @" + { + ""$schema"": """ + DAB_DRAFT_SCHEMA_TEST_PATH + @""", + ""data-source"": { + ""database-type"": ""mssql"", + ""connection-string"": """ + SAMPLE_TEST_CONN_STRING + @""" + }, + ""runtime"": { + ""rest"": { + ""path"": ""/api"", + ""enabled"": true + }, + ""graphql"": { + ""path"": ""/graphql"", + ""enabled"": true, + ""allow-introspection"": true + }, + ""host"": { + ""mode"": ""development"", + ""cors"": { + ""origins"": [], + ""allow-credentials"": false + }, + ""authentication"": { + ""provider"": ""Unauthenticated"" + } + }, + ""telemetry"": { + ""log-level"": { + ""default"": ""Warning"" + } + } + }, + ""entities"": {} + }"; + + // Merge in an entity so the config is not rejected for having an empty entities section. + string configWithLogLevel = AddPropertiesToJson(baseConfig, BASIC_ENTITY_WITH_ANONYMOUS_ROLE); + _fileSystem!.File.WriteAllText(TEST_RUNTIME_CONFIG_FILE, configWithLogLevel); + + StartOptions options = new( + verbose: false, + logLevel: cliLogLevel, + isHttpsRedirectionDisabled: false, + mcpStdio: false, + mcpRole: null, + config: TEST_RUNTIME_CONFIG_FILE); + + // TryStartEngineWithOptions will fail because the connection string is invalid, + // but Startup.IsLogLevelOverriddenByCli is set before the engine attempts to start. + TryStartEngineWithOptions(options, _runtimeConfigLoader!, _fileSystem!); + + Assert.AreEqual(expectedIsOverridden, Startup.IsLogLevelOverriddenByCli); + } + /// /// Validates that valid usage of verbs and associated options produce exit code 0 (CliReturnCode.SUCCESS). /// Verifies that explicitly implemented verbs (add, update, init, start) and appropriately From 0b9a0b92a018c28a9535bd417c4f8407c75448fa Mon Sep 17 00:00:00 2001 From: Ruben Cerna Date: Mon, 13 Apr 2026 13:28:58 -0700 Subject: [PATCH 3/4] Fix test --- src/Cli.Tests/EndToEndTests.cs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/Cli.Tests/EndToEndTests.cs b/src/Cli.Tests/EndToEndTests.cs index a8228b151c..849e3a9c72 100644 --- a/src/Cli.Tests/EndToEndTests.cs +++ b/src/Cli.Tests/EndToEndTests.cs @@ -863,19 +863,17 @@ public void TestEngineStartUpWithVerboseAndLogLevelOptions(string logLevelOption /// based on whether the --LogLevel CLI flag is provided. /// /// When the --LogLevel flag is provided, IsLogLevelOverriddenByCli should be true. - /// When the --LogLevel flag is omitted (log level comes from the config file), - /// IsLogLevelOverriddenByCli should be false. + /// When the --LogLevel flag is omitted (log level comes from the config file), IsLogLevelOverriddenByCli should be false. /// /// The --LogLevel CLI flag value, or null to omit the flag. /// Expected value of Startup.IsLogLevelOverriddenByCli. [DataTestMethod] [DataRow(null, false, DisplayName = "No CLI flag => IsLogLevelOverriddenByCli is false, log level resolved from config file.")] [DataRow(LogLevel.Error, true, DisplayName = "CLI --LogLevel flag provided => IsLogLevelOverriddenByCli is true.")] - public void TestStartCommandResolvesLogLevelFromConfigOrFlag( + public async Task TestStartCommandResolvesLogLevelFromConfigOrFlag( LogLevel? cliLogLevel, bool expectedIsOverridden) { - // Build a base config with a log-level property in the telemetry section and empty entities. string baseConfig = @" { ""$schema"": """ + DAB_DRAFT_SCHEMA_TEST_PATH + @""", @@ -924,9 +922,12 @@ public void TestStartCommandResolvesLogLevelFromConfigOrFlag( mcpRole: null, config: TEST_RUNTIME_CONFIG_FILE); - // TryStartEngineWithOptions will fail because the connection string is invalid, - // but Startup.IsLogLevelOverriddenByCli is set before the engine attempts to start. - TryStartEngineWithOptions(options, _runtimeConfigLoader!, _fileSystem!); + // Run TryStartEngineWithOptions on a background task because StartEngine blocks until the host shuts down. + Task engineTask = Task.Run(() => + TryStartEngineWithOptions(options, _runtimeConfigLoader!, _fileSystem!)); + + // Wait for the engine to finish loading the config. + await Task.WhenAny(engineTask, Task.Delay(TimeSpan.FromSeconds(5))); Assert.AreEqual(expectedIsOverridden, Startup.IsLogLevelOverriddenByCli); } From d74ad9400a51b8bab901f14960c3513d9601fa61 Mon Sep 17 00:00:00 2001 From: Ruben Cerna Date: Mon, 13 Apr 2026 13:48:14 -0700 Subject: [PATCH 4/4] Changes based on copilot comments --- src/Cli.Tests/EndToEndTests.cs | 6 +++--- src/Cli/ConfigGenerator.cs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Cli.Tests/EndToEndTests.cs b/src/Cli.Tests/EndToEndTests.cs index 849e3a9c72..745de4fd46 100644 --- a/src/Cli.Tests/EndToEndTests.cs +++ b/src/Cli.Tests/EndToEndTests.cs @@ -868,8 +868,8 @@ public void TestEngineStartUpWithVerboseAndLogLevelOptions(string logLevelOption /// The --LogLevel CLI flag value, or null to omit the flag. /// Expected value of Startup.IsLogLevelOverriddenByCli. [DataTestMethod] - [DataRow(null, false, DisplayName = "No CLI flag => IsLogLevelOverriddenByCli is false, log level resolved from config file.")] - [DataRow(LogLevel.Error, true, DisplayName = "CLI --LogLevel flag provided => IsLogLevelOverriddenByCli is true.")] + [DataRow(null, false, DisplayName = "IsLogLevelOverriddenByCli is false")] + [DataRow(LogLevel.Error, true, DisplayName = "IsLogLevelOverriddenByCli is true")] public async Task TestStartCommandResolvesLogLevelFromConfigOrFlag( LogLevel? cliLogLevel, bool expectedIsOverridden) @@ -927,7 +927,7 @@ public async Task TestStartCommandResolvesLogLevelFromConfigOrFlag( TryStartEngineWithOptions(options, _runtimeConfigLoader!, _fileSystem!)); // Wait for the engine to finish loading the config. - await Task.WhenAny(engineTask, Task.Delay(TimeSpan.FromSeconds(5))); + await Task.Delay(TimeSpan.FromSeconds(5)); Assert.AreEqual(expectedIsOverridden, Startup.IsLogLevelOverriddenByCli); } diff --git a/src/Cli/ConfigGenerator.cs b/src/Cli/ConfigGenerator.cs index 6863eab367..a7eb79ffbd 100644 --- a/src/Cli/ConfigGenerator.cs +++ b/src/Cli/ConfigGenerator.cs @@ -2610,11 +2610,11 @@ public static bool TryStartEngineWithOptions(StartOptions options, FileSystemRun // Check if we set the minimum LogLevel from the config file or if it is based on the host mode. if (isValueFromDefault) { - _logger.LogInformation($"Using default minimum LogLevel: {minimumLogLevel} from the 'Default' namespace in config file.", minimumLogLevel, hostModeType); + _logger.LogInformation("Using default minimum LogLevel: {minimumLogLevel} from the 'Default' namespace in config file.", minimumLogLevel); } else { - _logger.LogInformation($"Setting default minimum LogLevel: {minimumLogLevel} for {hostModeType} mode.", minimumLogLevel, hostModeType); + _logger.LogInformation("Setting default minimum LogLevel: {minimumLogLevel} for {hostModeType} mode.", minimumLogLevel, hostModeType); } }