Skip to content

Commit 7906474

Browse files
[dsrouter] log redirected console output (#5524)
Context: #5494 Context: #5241 Fixes: #5435 We added `--dsrouter` switch to both `dotnet-trace` and `dotnet-gcdump`, which runs `dotnet-dsrouter` as a child process. Many of `dotnet-dsrouter`'s console messages are pretty useful for developers, but we are simply ignoring them: private static async Task ReadAndIgnoreAllStreamAsync(StreamReader streamToIgnore, CancellationToken cancelToken) { Memory<char> memory = new char[4096]; while (await streamToIgnore.ReadAsync(memory, cancelToken).ConfigureAwait(false) != 0) { } } To make this a bit more useful, we now log the output to either `Console.Out` or `Console.Error` where appropriate. If we simply did: string line; while ((line = await streamToRead.ReadLineAsync(cancelToken).ConfigureAwait(false)) != null) { output.WriteLine(line); } This would work fine, but we'd lose all coloring. `dotnet-dsrouter` uses `SimpleConsoleFormatter` to colorize its output: https://github.com/dotnet/runtime/blob/aadcceeb03ce0ecbc2ad645de0feb10189daa64c/src/libraries/Microsoft.Extensions.Logging.Console/src/SimpleConsoleFormatter.cs#L163-L199 So, for now, a very simple solution is to check the known prefixes and add coloring. This looks to have a pretty good result. I also dropped the duplicate message: WARNING: dotnet-dsrouter is a development tool not intended for production environments. Now that we print all of `dotnet-dsrouter`'s output, we can handle this case and color it yellow. <img width="2524" height="582" alt="image" src="https://github.com/user-attachments/assets/4924ec93-c616-4511-83f8-f318f4ce4471" />
1 parent fcaeae3 commit 7906474

File tree

2 files changed

+86
-9
lines changed

2 files changed

+86
-9
lines changed

src/Tools/Common/Commands/Utils.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,6 @@ public static int FindProcessIdWithName(string name)
4646
// <returns>processId</returns>
4747
public static int LaunchDSRouterProcess(string dsrouterCommand)
4848
{
49-
ConsoleColor currentColor = Console.ForegroundColor;
50-
Console.ForegroundColor = ConsoleColor.Yellow;
51-
Console.WriteLine("WARNING: dotnet-dsrouter is a development tool not intended for production environments.");
52-
Console.ForegroundColor = currentColor;
5349
Console.WriteLine("For finer control over the dotnet-dsrouter options, run it separately and connect to it using -p" + Environment.NewLine);
5450

5551
return DsRouterProcessLauncher.Launcher.Start(dsrouterCommand, default);

src/Tools/Common/DsRouterProcessLauncher.cs

Lines changed: 86 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,92 @@ internal sealed partial class DsRouterProcessLauncher
2424
internal static DsRouterProcessLauncher Launcher = new();
2525
private bool _processStarted;
2626

27-
private static async Task ReadAndIgnoreAllStreamAsync(StreamReader streamToIgnore, CancellationToken cancelToken)
27+
private static async Task ReadAndLogAllLinesAsync(StreamReader streamToRead, TextWriter output, CancellationToken cancelToken)
2828
{
29-
Memory<char> memory = new char[4096];
30-
while (await streamToIgnore.ReadAsync(memory, cancelToken).ConfigureAwait(false) != 0)
29+
string line;
30+
while ((line = await streamToRead.ReadLineAsync(cancelToken).ConfigureAwait(false)) != null)
3131
{
32+
// Just log with no colors if redirected
33+
if (Console.IsOutputRedirected)
34+
{
35+
output.WriteLine(line);
36+
continue;
37+
}
38+
39+
// Console coloring is not preserved, so this is a naive approach based on SimpleConsoleFormatter's output:
40+
// https://github.com/dotnet/runtime/blob/aadcceeb03ce0ecbc2ad645de0feb10189daa64c/src/libraries/Microsoft.Extensions.Logging.Console/src/SimpleConsoleFormatter.cs#L163-L199
41+
42+
ConsoleColor foregroundColor = Console.ForegroundColor;
43+
ConsoleColor backgroundColor = Console.BackgroundColor;
44+
try
45+
{
46+
// Specific dotnet-dsrouter warning message
47+
if (line.StartsWith("WARNING: dotnet-dsrouter", StringComparison.OrdinalIgnoreCase))
48+
{
49+
Console.ForegroundColor = ConsoleColor.Yellow;
50+
output.WriteLine(line);
51+
continue;
52+
}
53+
54+
// SimpleConsoleFormatter prefixes
55+
if (line.StartsWith("crit:", StringComparison.OrdinalIgnoreCase))
56+
{
57+
Console.ForegroundColor = ConsoleColor.White;
58+
Console.BackgroundColor = ConsoleColor.DarkRed;
59+
output.Write("crit");
60+
}
61+
else if (line.StartsWith("fail:", StringComparison.OrdinalIgnoreCase))
62+
{
63+
Console.ForegroundColor = ConsoleColor.Black;
64+
Console.BackgroundColor = ConsoleColor.DarkRed;
65+
output.Write("fail");
66+
}
67+
else if (line.StartsWith("warn:", StringComparison.OrdinalIgnoreCase))
68+
{
69+
Console.ForegroundColor = ConsoleColor.Yellow;
70+
Console.BackgroundColor = ConsoleColor.Black;
71+
output.Write("warn");
72+
}
73+
else if (line.StartsWith("info:", StringComparison.OrdinalIgnoreCase))
74+
{
75+
Console.ForegroundColor = ConsoleColor.DarkGreen;
76+
Console.BackgroundColor = ConsoleColor.Black;
77+
output.Write("info");
78+
}
79+
else if (line.StartsWith("dbug:", StringComparison.OrdinalIgnoreCase))
80+
{
81+
Console.ForegroundColor = ConsoleColor.Gray;
82+
Console.BackgroundColor = ConsoleColor.Black;
83+
output.Write("dbug");
84+
}
85+
else if (line.StartsWith("trce:", StringComparison.OrdinalIgnoreCase))
86+
{
87+
Console.ForegroundColor = ConsoleColor.Gray;
88+
Console.BackgroundColor = ConsoleColor.Black;
89+
output.Write("trce");
90+
}
91+
else
92+
{
93+
output.WriteLine(line);
94+
continue; // If it doesn't match any prefix, just write the line as is
95+
}
96+
}
97+
finally
98+
{
99+
Console.ForegroundColor = foregroundColor;
100+
Console.BackgroundColor = backgroundColor;
101+
}
102+
103+
// If we get here, we logged a prefix, so we can log the rest of the line
104+
if (line.Length > 4)
105+
{
106+
output.WriteLine(line.AsSpan().Slice(4));
107+
}
108+
else
109+
{
110+
// If the line is just the prefix, we still need to write a new line
111+
output.WriteLine();
112+
}
32113
}
33114
}
34115

@@ -69,8 +150,8 @@ public int Start(string dsrouterCommand, CancellationToken ct)
69150
return -1;
70151
}
71152

72-
_stdErrTask = ReadAndIgnoreAllStreamAsync(_childProc.StandardError, ct);
73-
_stdOutTask = ReadAndIgnoreAllStreamAsync(_childProc.StandardOutput, ct);
153+
_stdErrTask = ReadAndLogAllLinesAsync(_childProc.StandardError, Console.Error, ct);
154+
_stdOutTask = ReadAndLogAllLinesAsync(_childProc.StandardOutput, Console.Out, ct);
74155
Task.Delay(1000, ct).Wait(ct);
75156
return !_childProc.HasExited ? _childProc.Id : -2;
76157
}

0 commit comments

Comments
 (0)