NuGet Package(s)
MartinCostello.Logging.XUnit
Version
0.6.0
Describe the bug
#214 adds support for capturing states added via BeginScope(), bug neglects the state passed to public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter) in XUnitLogger. This inadvertently omits state from many sourced, notably logging code generated with LogPropertiesAtrribute (see Behind LogProperties and the new telemetry logging source generator for usage/examples.
Expected behaviour
The state passed to public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter) should be passed to public virtual void WriteMessage(LogLevel logLevel, int eventId, string? message, Exception? exception) and in turn private static void GetScopeInformation(StringBuilder builder) when IncludeScopes is true. This state should be included in the formatted output in addition to all state added through scopes. below is the relevant code in XUnitLogger:
|
if (!string.IsNullOrEmpty(message) || exception != null) |
|
{ |
|
WriteMessage(logLevel, eventId.Id, message, exception); |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Writes a message to the <see cref="ITestOutputHelper"/> or <see cref="IMessageSink"/> associated with the instance. |
|
/// </summary> |
|
/// <param name="logLevel">The message to write will be written on this level.</param> |
|
/// <param name="eventId">The Id of the event.</param> |
|
/// <param name="message">The message to write.</param> |
|
/// <param name="exception">The exception related to this message.</param> |
|
public virtual void WriteMessage(LogLevel logLevel, int eventId, string? message, Exception? exception) |
|
{ |
|
ITestOutputHelper? outputHelper = _outputHelperAccessor?.OutputHelper; |
|
IMessageSink? messageSink = _messageSinkAccessor?.MessageSink; |
|
|
|
if (outputHelper is null && messageSink is null) |
|
{ |
|
return; |
|
} |
|
|
|
StringBuilder? logBuilder = _logBuilder; |
|
_logBuilder = null; |
|
|
|
logBuilder ??= new StringBuilder(); |
|
|
|
string logLevelString = GetLogLevelString(logLevel); |
|
|
|
logBuilder.Append(LogLevelPadding); |
|
logBuilder.Append(Name); |
|
logBuilder.Append('['); |
|
logBuilder.Append(eventId); |
|
logBuilder.Append(']'); |
|
logBuilder.AppendLine(); |
|
|
|
if (IncludeScopes) |
|
{ |
|
GetScopeInformation(logBuilder); |
|
} |
|
|
|
bool hasMessage = !string.IsNullOrEmpty(message); |
|
|
|
if (hasMessage) |
|
{ |
|
logBuilder.Append(MessagePadding); |
|
|
|
int length = logBuilder.Length; |
|
logBuilder.Append(message); |
|
logBuilder.Replace(Environment.NewLine, NewLineWithMessagePadding, length, message!.Length); |
|
} |
|
|
|
if (exception != null) |
|
{ |
|
if (hasMessage) |
|
{ |
|
logBuilder.AppendLine(); |
|
} |
|
|
|
logBuilder.Append(exception); |
|
} |
|
|
|
// Prefix the formatted message so it renders like this: |
|
// [{timestamp}] {logLevelString}{message} |
|
logBuilder.Insert(0, logLevelString); |
|
logBuilder.Insert(0, "] "); |
|
logBuilder.Insert(0, Clock().ToString(_timestampFormat, CultureInfo.CurrentCulture)); |
|
logBuilder.Insert(0, '['); |
|
|
|
string line = logBuilder.ToString(); |
|
|
|
try |
|
{ |
|
outputHelper?.WriteLine(line); |
|
|
|
if (messageSink != null) |
|
{ |
|
var sinkMessage = _messageSinkMessageFactory(line); |
|
messageSink.OnMessage(sinkMessage); |
|
} |
|
} |
|
catch (InvalidOperationException) |
|
{ |
|
// Ignore exception if the application tries to log after the test ends |
|
// but before the ITestOutputHelper is detached, e.g. "There is no currently active test." |
|
} |
|
|
|
logBuilder.Clear(); |
|
|
|
if (logBuilder.Capacity > 1024) |
|
{ |
|
logBuilder.Capacity = 1024; |
|
} |
|
|
|
_logBuilder = logBuilder; |
|
} |
Actual behaviour
The state variable is completely ignored when formatting the output message when IncludeScopes is true.
Steps to reproduce
I think the description is sufficient.
Exception(s) (if any)
.NET Version
9.0.301
Anything else?
No response
NuGet Package(s)
MartinCostello.Logging.XUnit
Version
0.6.0
Describe the bug
#214 adds support for capturing states added via BeginScope(), bug neglects the state passed to
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)inXUnitLogger. This inadvertently omits state from many sourced, notably logging code generated withLogPropertiesAtrribute(see BehindLogPropertiesand the new telemetry logging source generator for usage/examples.Expected behaviour
The
statepassed topublic void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)should be passed topublic virtual void WriteMessage(LogLevel logLevel, int eventId, string? message, Exception? exception)and in turnprivate static void GetScopeInformation(StringBuilder builder)whenIncludeScopesistrue. This state should be included in the formatted output in addition to all state added through scopes. below is the relevant code inXUnitLogger:xunit-logging/src/Shared/XUnitLogger.cs
Lines 150 to 246 in 0062198
Actual behaviour
The
statevariable is completely ignored when formatting the output message whenIncludeScopesistrue.Steps to reproduce
I think the description is sufficient.
Exception(s) (if any)
.NET Version
9.0.301
Anything else?
No response