From 514a4d7bbb75f281a878677114fb6428de99e4d8 Mon Sep 17 00:00:00 2001 From: Ruben Cerna Date: Thu, 9 Apr 2026 17:00:13 -0700 Subject: [PATCH 1/6] 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/6] 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/6] 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/6] 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); } } From e08074c75b4dc74898dd0e5088ab6667ffa9d0c0 Mon Sep 17 00:00:00 2001 From: Ruben Cerna Date: Wed, 15 Apr 2026 15:01:19 -0700 Subject: [PATCH 5/6] Changes based on comments --- src/Cli.Tests/EndToEndTests.cs | 3 +++ src/Cli/ConfigGenerator.cs | 18 ++++-------------- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/src/Cli.Tests/EndToEndTests.cs b/src/Cli.Tests/EndToEndTests.cs index 745de4fd46..0f5179e5b4 100644 --- a/src/Cli.Tests/EndToEndTests.cs +++ b/src/Cli.Tests/EndToEndTests.cs @@ -903,6 +903,9 @@ public async Task TestStartCommandResolvesLogLevelFromConfigOrFlag( }, ""telemetry"": { ""log-level"": { + ""Azure.DataApiBuilder.Core.Services.ISqlMetadataProvider"": ""Information"", + ""Azure.DataApiBuilder.Core"": ""Debug"", + ""Azure.DataApiBuilder.Service.Controllers.RestController"": ""Error"", ""default"": ""Warning"" } } diff --git a/src/Cli/ConfigGenerator.cs b/src/Cli/ConfigGenerator.cs index a7eb79ffbd..40c0a3c0ec 100644 --- a/src/Cli/ConfigGenerator.cs +++ b/src/Cli/ConfigGenerator.cs @@ -2596,28 +2596,18 @@ 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 { + // GetConfiguredLogLevel will only return the 'Default' LogLevel value from the config file. + // If it doesn't exist, it will return the default LogLevel based on the environment (Debug for Development and Error for Production). 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; - - // 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); - } - else - { - _logger.LogInformation("Setting default minimum LogLevel: {minimumLogLevel} for {hostModeType} mode.", minimumLogLevel, hostModeType); - } } + _logger.LogInformation("Setting minimum LogLevel: {minimumLogLevel}.", minimumLogLevel); + // This will add args to disable automatic redirects to https if specified by user if (options.IsHttpsRedirectionDisabled) { From 7451c31e6bac5539a43f7fdcb83e1aad4fd556b5 Mon Sep 17 00:00:00 2001 From: Ruben Cerna Date: Wed, 15 Apr 2026 17:55:13 -0700 Subject: [PATCH 6/6] Changes based on comments --- src/Cli/ConfigGenerator.cs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/Cli/ConfigGenerator.cs b/src/Cli/ConfigGenerator.cs index c1c494b760..8231aa15a4 100644 --- a/src/Cli/ConfigGenerator.cs +++ b/src/Cli/ConfigGenerator.cs @@ -2605,15 +2605,8 @@ public static bool TryStartEngineWithOptions(StartOptions options, FileSystemRun minimumLogLevel = (LogLevel)options.LogLevel; args.Add("--LogLevel"); args.Add(minimumLogLevel.ToString()); + _logger.LogInformation("Setting minimum LogLevel: {minimumLogLevel}.", minimumLogLevel); } - else - { - // GetConfiguredLogLevel will only return the 'Default' LogLevel value from the config file. - // If it doesn't exist, it will return the default LogLevel based on the environment (Debug for Development and Error for Production). - minimumLogLevel = deserializedRuntimeConfig.GetConfiguredLogLevel(); - } - - _logger.LogInformation("Setting minimum LogLevel: {minimumLogLevel}.", minimumLogLevel); // This will add args to disable automatic redirects to https if specified by user if (options.IsHttpsRedirectionDisabled)