Skip to content
Merged
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
10 changes: 10 additions & 0 deletions TUnit.Core/Logging/DefaultLogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ private static string FormatValue(object? value)

public override async ValueTask LogAsync<TState>(LogLevel logLevel, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
{
if (!IsEnabled(logLevel))
{
return;
}

var message = GenerateMessage(formatter(state, exception), exception, logLevel);

if (logLevel >= LogLevel.Error)
Expand All @@ -61,6 +66,11 @@ public override async ValueTask LogAsync<TState>(LogLevel logLevel, TState state

public override void Log<TState>(LogLevel logLevel, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
{
if (!IsEnabled(logLevel))
{
return;
}

var message = GenerateMessage(formatter(state, exception), exception, logLevel);

if (logLevel >= LogLevel.Error)
Expand Down
79 changes: 79 additions & 0 deletions TUnit.Engine/CommandLineProviders/LogLevelCommandProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
using Microsoft.Testing.Platform.CommandLine;
using Microsoft.Testing.Platform.Extensions;
using Microsoft.Testing.Platform.Extensions.CommandLine;
using LogLevel = TUnit.Core.Logging.LogLevel;

namespace TUnit.Engine.CommandLineProviders;

internal class LogLevelCommandProvider(IExtension extension) : ICommandLineOptionsProvider
{
public const string LogLevelOption = "log-level";

public Task<bool> IsEnabledAsync()
{
return extension.IsEnabledAsync();
}

public string Uid => extension.Uid;

public string Version => extension.Version;

public string DisplayName => extension.DisplayName;

public string Description => extension.Description;

public IReadOnlyCollection<CommandLineOption> GetCommandLineOptions()
{
return
[
new CommandLineOption(LogLevelOption, "Minimum log level for test output: Trace, Debug, Information, Warning, Error, Critical, None (default: Information)", ArgumentArity.ExactlyOne, false)
];
}

public Task<ValidationResult> ValidateOptionArgumentsAsync(CommandLineOption commandOption, string[] arguments)
{
if (commandOption.Name == LogLevelOption && arguments.Length != 1)
{
return ValidationResult.InvalidTask("A single log level must be provided: Trace, Debug, Information, Warning, Error, Critical, or None");
}

if (commandOption.Name == LogLevelOption)
{
var logLevelArg = arguments[0];
if (!IsValidLogLevel(logLevelArg))
{
return ValidationResult.InvalidTask($"Invalid log level '{arguments[0]}'. Valid options: Trace, Debug, Information, Warning, Error, Critical, None");
}
}

return ValidationResult.ValidTask;
}

public Task<ValidationResult> ValidateCommandLineOptionsAsync(ICommandLineOptions commandLineOptions)
{
return ValidationResult.ValidTask;
}

private static bool IsValidLogLevel(string logLevel)
{
return Enum.TryParse<LogLevel>(logLevel, ignoreCase: true, out _);
}

/// <summary>
/// Parses log level from command line arguments
/// </summary>
public static LogLevel ParseLogLevel(string[] arguments)
{
if (arguments.Length == 0)
{
return LogLevel.Information;
}

if (Enum.TryParse<LogLevel>(arguments[0], ignoreCase: true, out var result))
{
return result;
}

return LogLevel.Information;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public static void AddTUnit(this ITestApplicationBuilder testApplicationBuilder)
testApplicationBuilder.CommandLine.AddProvider(() => new FailFastCommandProvider(extension));
testApplicationBuilder.CommandLine.AddProvider(() => new ReflectionModeCommandProvider(extension));
testApplicationBuilder.CommandLine.AddProvider(() => new DisableLogoCommandProvider(extension));
testApplicationBuilder.CommandLine.AddProvider(() => new LogLevelCommandProvider(extension));

// Adaptive parallelism command providers
testApplicationBuilder.CommandLine.AddProvider(() => new ParallelismStrategyCommandProvider(extension));
Expand Down
5 changes: 4 additions & 1 deletion TUnit.Engine/Framework/TUnitServiceProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ public TUnitServiceProvider(IExtension extension,
VerbosityService = Register(new VerbosityService(CommandLineOptions));
DiscoveryDiagnostics.Initialize(VerbosityService);

var logLevelProvider = Register(new LogLevelProvider(CommandLineOptions));

// Determine execution mode early to create appropriate services
var useSourceGeneration = SourceRegistrar.IsEnabled = GetUseSourceGeneration(CommandLineOptions);

Expand All @@ -98,7 +100,8 @@ public TUnitServiceProvider(IExtension extension,
extension,
outputDevice,
loggerFactory.CreateLogger<TUnitFrameworkLogger>(),
VerbosityService));
VerbosityService,
logLevelProvider));

// Create initialization services early as they're needed by other services
DataSourceInitializer = Register(new DataSourceInitializer());
Expand Down
5 changes: 3 additions & 2 deletions TUnit.Engine/Logging/TUnitFrameworkLogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@

namespace TUnit.Engine.Logging;

public class TUnitFrameworkLogger(IExtension extension, IOutputDevice outputDevice, ILogger logger, VerbosityService verbosityService)
public class TUnitFrameworkLogger(IExtension extension, IOutputDevice outputDevice, ILogger logger, VerbosityService verbosityService, LogLevelProvider logLevelProvider)
: IOutputDeviceDataProducer, Core.Logging.ILogger
{
private readonly bool _hideTestOutput = verbosityService.HideTestOutput;
private readonly LogLevel _minimumLogLevel = logLevelProvider.LogLevel;

private readonly MTPLoggerAdapter _adapter = new(logger);

Expand Down Expand Up @@ -90,7 +91,7 @@ private static ConsoleColor GetConsoleColor(LogLevel logLevel)

public bool IsEnabled(LogLevel logLevel)
{
return !_hideTestOutput && logger.IsEnabled(MTPLoggerAdapter.Map(logLevel));
return !_hideTestOutput && logLevel >= _minimumLogLevel && logger.IsEnabled(MTPLoggerAdapter.Map(logLevel));
}

public async Task LogErrorAsync(string message)
Expand Down
10 changes: 5 additions & 5 deletions TUnit.Engine/Services/LogLevelProvider.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
using Microsoft.Testing.Platform.CommandLine;
using TUnit.Core.Enums;
using TUnit.Core.Logging;
using TUnit.Engine.CommandLineProviders;

namespace TUnit.Engine.Services;

internal class LogLevelProvider(ICommandLineOptions commandLineOptions)
public class LogLevelProvider(ICommandLineOptions commandLineOptions)
{
internal static LogLevel? _logLevel;
public LogLevel LogLevel => _logLevel ??= GetLogLevel();

private LogLevel GetLogLevel()
{
if (commandLineOptions.TryGetOptionArgumentList("log-level", out var values)
&& Enum.TryParse<LogLevel>(values.FirstOrDefault(), out var parsedResult))
if (commandLineOptions.TryGetOptionArgumentList(LogLevelCommandProvider.LogLevelOption, out var values))
{
return parsedResult;
return LogLevelCommandProvider.ParseLogLevel(values);
}

return LogLevel.Information;
Expand Down
5 changes: 5 additions & 0 deletions docs/docs/reference/command-line-flags.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ Please note that for the coverage and trx report, you need to install [additiona
--list-tests
List available tests.

--log-level
Minimum log level for test output.
The available values are 'Trace', 'Debug', 'Information', 'Warning', 'Error', 'Critical', and 'None'.
Default is 'Information'.

--minimum-expected-tests
Specifies the minimum number of tests that are expected to run.

Expand Down
Loading