Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/Cli.Tests/CustomLoggerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ public void LogOutput_UsesAbbreviatedLogLevelLabels(LogLevel logLevel, string ex
string actual = expectStderr ? stderr : stdout;
string other = expectStderr ? stdout : stderr;

Assert.IsTrue(actual.StartsWith(expectedPrefix),
$"Expected output to start with '{expectedPrefix}' but got: '{actual}'");
Assert.IsTrue(actual.Contains(expectedPrefix),
$"Expected output to contain '{expectedPrefix}' but got: '{actual}'");
Comment on lines +80 to +81
StringAssert.Contains(actual, Message);
Assert.AreEqual(string.Empty, other,
$"Did not expect output on the other stream but got: '{other}'");
Expand Down
8 changes: 6 additions & 2 deletions src/Cli/CustomLoggerProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ public ILogger CreateLogger(string categoryName)

public class CustomConsoleLogger : ILogger
{
private const string UtcTimestampFormat = "yyyy-MM-dd'T'HH:mm:ss.fff'Z'";

private readonly LogLevel _minimumLogLevel;

// Minimum LogLevel for CLI output.
Expand Down Expand Up @@ -124,13 +126,14 @@ public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Except
// Apply colors so the abbreviation matches the visual style of engine logs.
// try/finally guarantees the original colors are restored even if Write throws,
// otherwise the console would be left tinted (e.g. red on error) for subsequent output.
string mcpTimestamp = DateTime.UtcNow.ToString(UtcTimestampFormat);
ConsoleColor mcpOriginalForeGroundColor = Console.ForegroundColor;
ConsoleColor mcpOriginalBackGroundColor = Console.BackgroundColor;
try
{
Console.ForegroundColor = _logLevelToForeGroundConsoleColorMap.GetValueOrDefault(logLevel, ConsoleColor.White);
Console.BackgroundColor = _logLevelToBackGroundConsoleColorMap.GetValueOrDefault(logLevel, ConsoleColor.Black);
Console.Error.Write($"{mcpAbbreviation}:");
Console.Error.Write($"{mcpTimestamp} {mcpAbbreviation}:");
}
finally
{
Expand All @@ -153,6 +156,7 @@ public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Except
}

TextWriter writer = logLevel >= LogLevel.Error ? Console.Error : Console.Out;
string timestamp = DateTime.UtcNow.ToString(UtcTimestampFormat);
// try/finally guarantees the original colors are restored even if Write throws,
// otherwise the console would be left tinted (e.g. red on error) for subsequent output.
ConsoleColor originalForeGroundColor = Console.ForegroundColor;
Expand All @@ -161,7 +165,7 @@ public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Except
{
Console.ForegroundColor = _logLevelToForeGroundConsoleColorMap.GetValueOrDefault(logLevel, ConsoleColor.White);
Console.BackgroundColor = _logLevelToBackGroundConsoleColorMap.GetValueOrDefault(logLevel, ConsoleColor.Black);
writer.Write($"{abbreviation}:");
writer.Write($"{timestamp} {abbreviation}:");
}
finally
{
Expand Down
21 changes: 19 additions & 2 deletions src/Service/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.ApplicationInsights;
using Microsoft.Extensions.Logging.Console;
using OpenTelemetry.Exporter;
using OpenTelemetry.Logs;
using OpenTelemetry.Resources;
Expand Down Expand Up @@ -194,6 +195,11 @@ public static IHostBuilder CreateHostBuilder(string[] args, bool runMcpStdio, st
else
{
logging.SetMinimumLevel(LogLevelProvider.CurrentLogLevel);
logging.AddSimpleConsole(options =>
{
options.TimestampFormat = "yyyy-MM-dd'T'HH:mm:ss.fff'Z' ";
options.UseUtcTimestamp = true;
});
Comment on lines +198 to +202
}

// Add filter for dynamic log level changes (e.g., via MCP logging/setLevel)
Expand Down Expand Up @@ -464,15 +470,26 @@ public static ILoggerFactory GetLoggerFactoryForLogLevel(
// When LogLevel.None, skip the console logger entirely for true silence.
if (LogLevelProvider.CurrentLogLevel != LogLevel.None)
{
builder.AddConsole(options =>
builder.AddSimpleConsole(options =>
{
options.TimestampFormat = "yyyy-MM-dd'T'HH:mm:ss.fff'Z' ";
options.UseUtcTimestamp = true;
});
// Route all levels to stderr to keep stdout clean for MCP JSON-RPC.
// Uses Services.Configure (not AddConsole) so no second provider is registered.
builder.Services.Configure<ConsoleLoggerOptions>(options =>
{
options.LogToStandardErrorThreshold = LogLevel.Trace;
});
}
}
else
{
builder.AddConsole();
builder.AddSimpleConsole(options =>
{
options.TimestampFormat = "yyyy-MM-dd'T'HH:mm:ss.fff'Z' ";
options.UseUtcTimestamp = true;
});
}
});
}
Expand Down
Loading