diff --git a/src/Shared/LoggingHelpers.cs b/src/Shared/LoggingHelpers.cs index c6e593e7ddc..8329ae1d412 100644 --- a/src/Shared/LoggingHelpers.cs +++ b/src/Shared/LoggingHelpers.cs @@ -37,6 +37,12 @@ public static void WriteDashboardSummary(ILogger logger, string? dashboardUrl, s ? $"{dashboardAuthority}/login?t={token}" : null; + if (loginUrl is not null) + { + // dotnet watch looks for this exact log message to launch the dashboard. Do not change it. + logger.LogInformation("Login to the dashboard at {LoginUrl}", loginUrl); + } + var templateBuilder = new StringBuilder(); var parameters = new List(); diff --git a/tests/Aspire.Dashboard.Tests/Integration/FrontendBrowserTokenAuthTests.cs b/tests/Aspire.Dashboard.Tests/Integration/FrontendBrowserTokenAuthTests.cs index 140c74c467f..325df3ad705 100644 --- a/tests/Aspire.Dashboard.Tests/Integration/FrontendBrowserTokenAuthTests.cs +++ b/tests/Aspire.Dashboard.Tests/Integration/FrontendBrowserTokenAuthTests.cs @@ -405,6 +405,15 @@ public async Task LogOutput_NoToken_GeneratedTokenLogged() Assert.Equal(LogLevel.Warning, w.LogLevel); }, w => + { + Assert.Equal("Login to the dashboard at {LoginUrl}", LogTestHelpers.GetValue(w, "{OriginalFormat}")); + + var loginUrl = (string)LogTestHelpers.GetValue(w, "LoginUrl")!; + var uri = new Uri(loginUrl, UriKind.Absolute); + var queryString = HttpUtility.ParseQueryString(uri.Query); + Assert.NotNull(queryString["t"]); + }, + w => { Assert.StartsWith("Aspire Dashboard", (string)LogTestHelpers.GetValue(w, "{OriginalFormat}")!); diff --git a/tests/Aspire.Dashboard.Tests/LoggingHelpersTests.cs b/tests/Aspire.Dashboard.Tests/LoggingHelpersTests.cs index 9efc2c4bbd0..e02c5e5f8b3 100644 --- a/tests/Aspire.Dashboard.Tests/LoggingHelpersTests.cs +++ b/tests/Aspire.Dashboard.Tests/LoggingHelpersTests.cs @@ -23,7 +23,15 @@ public void WriteDashboardSummary_WithTokenAndOtlpEndpoints_LogsSummaryAndStruct "http://localhost:18890", "abc123"); - var write = Assert.Single(sink.Writes); + Assert.Equal(2, sink.Writes.Count); + + var loginWrite = sink.Writes.ElementAt(0); + Assert.Equal(LogLevel.Information, loginWrite.LogLevel); + Assert.Equal("Login to the dashboard at http://localhost:18888/login?t=abc123", loginWrite.Message); + Assert.Equal("Login to the dashboard at {LoginUrl}", LogTestHelpers.GetValue(loginWrite, "{OriginalFormat}")); + Assert.Equal("http://localhost:18888/login?t=abc123", LogTestHelpers.GetValue(loginWrite, "LoginUrl")); + + var write = sink.Writes.ElementAt(1); Assert.Equal(LogLevel.Information, write.LogLevel); Assert.NotNull(write.Message); var lines = GetMessageLines(write.Message!); @@ -169,7 +177,9 @@ public void WriteDashboardSummary_WithoutOtlpEndpoints_DoesNotIncludeOtlpLines() otlpHttpUrl: null, token: "abc123"); - var write = Assert.Single(sink.Writes); + Assert.Equal(2, sink.Writes.Count); + + var write = sink.Writes.ElementAt(1); Assert.NotNull(write.Message); var lines = GetMessageLines(write.Message!); @@ -198,8 +208,9 @@ public void WriteDashboardSummary_IsContainer_IncludesContainerMessage() token: "abc123", isContainer: true); - Assert.Equal(2, sink.Writes.Count); - var containerWrite = sink.Writes.Skip(1).First(); + Assert.Equal(3, sink.Writes.Count); + + var containerWrite = sink.Writes.ElementAt(2); Assert.Equal("Dashboard is running in a container. Access the dashboard from the host using port forwarding.", containerWrite.Message); } diff --git a/tests/Aspire.Hosting.Tests/Dashboard/DashboardEventHandlersTests.cs b/tests/Aspire.Hosting.Tests/Dashboard/DashboardEventHandlersTests.cs index 6ae294327ea..0069422ad8b 100644 --- a/tests/Aspire.Hosting.Tests/Dashboard/DashboardEventHandlersTests.cs +++ b/tests/Aspire.Hosting.Tests/Dashboard/DashboardEventHandlersTests.cs @@ -271,6 +271,12 @@ public async Task ResourceReadyEvent_LogsDashboardUrlFromAllocatedEndpoint(strin Assert.Equal(allocatedPort, uri.Port); Assert.Equal(expectedScheme, uri.Scheme); + var loginLog = testSink.Writes.FirstOrDefault(l => + LogTestHelpers.GetValue(l, "{OriginalFormat}")?.ToString() == "Login to the dashboard at {LoginUrl}"); + + Assert.NotNull(loginLog); + Assert.Equal($"{expectedScheme}://{expectedHost}:{allocatedPort}/login?t=test-token", LogTestHelpers.GetValue(loginLog, "LoginUrl")); + var summaryLog = testSink.Writes.FirstOrDefault(l => LogTestHelpers.GetValue(l, "{OriginalFormat}")?.ToString()?.Contains("OTLP/gRPC:") == true);