Skip to content

Commit

Permalink
Merge pull request #313 from martincostello/custom-timestamp-format
Browse files Browse the repository at this point in the history
Custom timestamp format
  • Loading branch information
martincostello committed May 22, 2022
2 parents e21b1a5 + 18a6af8 commit c522f21
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 30 deletions.
4 changes: 2 additions & 2 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@
<SignAssembly>true</SignAssembly>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<AssemblyVersion>0.2.0.0</AssemblyVersion>
<VersionPrefix>0.2.2</VersionPrefix>
<AssemblyVersion>0.3.0.0</AssemblyVersion>
<VersionPrefix>0.3.0</VersionPrefix>
<VersionSuffix Condition=" '$(VersionSuffix)' == '' AND '$(GITHUB_ACTIONS)' != '' ">beta$([System.Convert]::ToInt32(`$(GITHUB_RUN_NUMBER)`).ToString(`0000`))</VersionSuffix>
<VersionPrefix Condition=" $(GITHUB_REF.StartsWith(`refs/tags/v`)) ">$(GITHUB_REF.Replace('refs/tags/v', ''))</VersionPrefix>
<VersionSuffix Condition=" $(GITHUB_REF.StartsWith(`refs/tags/v`)) "></VersionSuffix>
Expand Down
45 changes: 26 additions & 19 deletions src/Logging.XUnit/XUnitLogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace MartinCostello.Logging.XUnit;
/// </summary>
public partial class XUnitLogger : ILogger
{
//// Based on https://github.com/aspnet/Logging/blob/master/src/Microsoft.Extensions.Logging.Console/ConsoleLogger.cs
//// Based on https://github.com/dotnet/runtime/blob/65067052e433eda400c5e7cc9f7b21c84640f901/src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLogger.cs#L41-L66

/// <summary>
/// The padding to use for log levels.
Expand All @@ -36,6 +36,11 @@ public partial class XUnitLogger : ILogger
[ThreadStatic]
private static StringBuilder? _logBuilder;

/// <summary>
/// The format string used to format the timestamp in log messages.
/// </summary>
private readonly string _timestampFormat;

/// <summary>
/// Gets or sets the filter to use.
/// </summary>
Expand All @@ -50,8 +55,9 @@ private XUnitLogger(string name, XUnitLoggerOptions? options)
{
Name = name ?? throw new ArgumentNullException(nameof(name));

_filter = options?.Filter ?? ((_, _) => true);
_filter = options?.Filter ?? (static (_, _) => true);
_messageSinkMessageFactory = options?.MessageSinkMessageFactory ?? (message => new DiagnosticMessage(message));
_timestampFormat = options?.TimestampFormat ?? "u";
IncludeScopes = options?.IncludeScopes ?? false;
}

Expand All @@ -63,8 +69,8 @@ private XUnitLogger(string name, XUnitLoggerOptions? options)
/// </exception>
public Func<string?, LogLevel, bool> Filter
{
get { return _filter; }
set { _filter = value ?? throw new ArgumentNullException(nameof(value)); }
get => _filter;
set => _filter = value ?? throw new ArgumentNullException(nameof(value));
}

/// <summary>
Expand All @@ -80,7 +86,7 @@ private XUnitLogger(string name, XUnitLoggerOptions? options)
/// <summary>
/// Gets or sets a delegate representing the system clock.
/// </summary>
internal Func<DateTimeOffset> Clock { get; set; } = () => DateTimeOffset.Now;
internal Func<DateTimeOffset> Clock { get; set; } = static () => DateTimeOffset.Now;

/// <inheritdoc />
public IDisposable BeginScope<TState>(TState state)
Expand Down Expand Up @@ -156,7 +162,8 @@ public virtual void WriteMessage(LogLevel logLevel, int eventId, string? message
logBuilder.Append(Name);
logBuilder.Append('[');
logBuilder.Append(eventId);
logBuilder.AppendLine("]");
logBuilder.Append(']');
logBuilder.AppendLine();

if (IncludeScopes)
{
Expand Down Expand Up @@ -184,11 +191,17 @@ public virtual void WriteMessage(LogLevel logLevel, int eventId, string? message
logBuilder.Append(exception.ToString());
}

string formatted = logBuilder.ToString();
// 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
{
var line = $"[{Clock():u}] {logLevelString}{formatted}";
if (outputHelper != null)
{
outputHelper.WriteLine(line);
Expand Down Expand Up @@ -228,17 +241,11 @@ private static string GetLogLevelString(LogLevel logLevel)
return logLevel switch
{
LogLevel.Critical => "crit",

LogLevel.Debug => "dbug",

LogLevel.Error => "fail",

LogLevel.Information => "info",

LogLevel.Trace => "trce",

LogLevel.Warning => "warn",

_ => throw new ArgumentOutOfRangeException(nameof(logLevel)),
};
}
Expand Down Expand Up @@ -267,10 +274,10 @@ private static void GetScopeInformation(StringBuilder builder)
foreach (var property in StringifyScope(elem))
{
builder.Append(MessagePadding)
.Append(DepthPadding(depth))
.Append("=> ")
.Append(property)
.AppendLine();
.Append(DepthPadding(depth))
.Append("=> ")
.Append(property)
.AppendLine();
}

depth++;
Expand All @@ -288,7 +295,7 @@ private static IEnumerable<string> StringifyScope(XUnitLogScope scope)
{
foreach (var pair in pairs)
{
yield return pair.Key + ": " + pair.Value;
yield return $"{pair.Key}: {pair.Value}";
}
}
else if (scope.State is IEnumerable<string> entries)
Expand Down
6 changes: 3 additions & 3 deletions src/Logging.XUnit/XUnitLoggerExtensions.IMessageSink.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public static ILoggingBuilder AddXUnit(this ILoggingBuilder builder, IMessageSin
throw new ArgumentNullException(nameof(accessor));
}

return builder.AddXUnit(accessor, (_) => { });
return builder.AddXUnit(accessor, static (_) => { });
}

/// <summary>
Expand Down Expand Up @@ -104,7 +104,7 @@ public static ILoggingBuilder AddXUnit(this ILoggingBuilder builder, IMessageSin
throw new ArgumentNullException(nameof(messageSink));
}

return builder.AddXUnit(messageSink, (_) => { });
return builder.AddXUnit(messageSink, static (_) => { });
}

/// <summary>
Expand Down Expand Up @@ -227,7 +227,7 @@ public static ILoggerFactory AddXUnit(this ILoggerFactory factory, IMessageSink
throw new ArgumentNullException(nameof(messageSink));
}

return factory.AddXUnit(messageSink, (_) => { });
return factory.AddXUnit(messageSink, static (_) => { });
}

/// <summary>
Expand Down
8 changes: 4 additions & 4 deletions src/Logging.XUnit/XUnitLoggerExtensions.ITestOutputHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public static ILoggingBuilder AddXUnit(this ILoggingBuilder builder)
throw new ArgumentNullException(nameof(builder));
}

return builder.AddXUnit(new AmbientTestOutputHelperAccessor(), (_) => { });
return builder.AddXUnit(new AmbientTestOutputHelperAccessor(), static (_) => { });
}

/// <summary>
Expand All @@ -57,7 +57,7 @@ public static ILoggingBuilder AddXUnit(this ILoggingBuilder builder, ITestOutput
throw new ArgumentNullException(nameof(accessor));
}

return builder.AddXUnit(accessor, (_) => { });
return builder.AddXUnit(accessor, static (_) => { });
}

/// <summary>
Expand Down Expand Up @@ -125,7 +125,7 @@ public static ILoggingBuilder AddXUnit(this ILoggingBuilder builder, ITestOutput
throw new ArgumentNullException(nameof(outputHelper));
}

return builder.AddXUnit(outputHelper, (_) => { });
return builder.AddXUnit(outputHelper, static (_) => { });
}

/// <summary>
Expand Down Expand Up @@ -248,7 +248,7 @@ public static ILoggerFactory AddXUnit(this ILoggerFactory factory, ITestOutputHe
throw new ArgumentNullException(nameof(outputHelper));
}

return factory.AddXUnit(outputHelper, (_) => { });
return factory.AddXUnit(outputHelper, static (_) => { });
}

/// <summary>
Expand Down
12 changes: 10 additions & 2 deletions src/Logging.XUnit/XUnitLoggerOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,23 @@ public XUnitLoggerOptions()
/// <summary>
/// Gets or sets the category filter to apply to logs.
/// </summary>
public Func<string?, LogLevel, bool> Filter { get; set; } = (c, l) => true; // By default log everything
public Func<string?, LogLevel, bool> Filter { get; set; } = static (c, l) => true; // By default log everything

/// <summary>
/// Gets or sets the message sink message factory to use when writing to a <see cref="IMessageSink"/>.
/// </summary>
public Func<string, IMessageSinkMessage> MessageSinkMessageFactory { get; set; } = m => new DiagnosticMessage(m);
public Func<string, IMessageSinkMessage> MessageSinkMessageFactory { get; set; } = static (m) => new DiagnosticMessage(m);

/// <summary>
/// Gets or sets a value indicating whether to include scopes.
/// </summary>
public bool IncludeScopes { get; set; }

/// <summary>
/// Gets or sets format string used to format the timestamp in log messages. Defaults to <c>u</c>.
/// </summary>
#if NET7_0_OR_GREATER
[StringSyntax(StringSyntaxAttribute.DateTimeFormat)] // TODO Light up after .NET 7 ships https://github.com/martincostello/xunit-logging/issues/315
#endif
public string? TimestampFormat { get; set; }
}
1 change: 1 addition & 0 deletions tests/Logging.XUnit.Tests/IntegrationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ public static void Can_Configure_xunit_For_ILoggerFactory_With_Options_Factory()
var options = new XUnitLoggerOptions()
{
Filter = (_, level) => level >= LogLevel.Error,
TimestampFormat = "yyyy-MM-dd HH:mm:ss.fff",
};

var logger = BootstrapFactory((builder) => builder.AddXUnit(mock.Object, () => options));
Expand Down

0 comments on commit c522f21

Please sign in to comment.