Skip to content
26 changes: 22 additions & 4 deletions src/ModularPipelines/Console/ModuleOutputBuffer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Microsoft.Extensions.Logging;
using ModularPipelines.Engine;
using ModularPipelines.Helpers;
using ModularPipelines.Logging;
using Spectre.Console;

namespace ModularPipelines.Console;
Expand Down Expand Up @@ -761,20 +762,34 @@ internal sealed class BufferedLogEvent<TState>(
LogLevel level,
EventId eventId,
TState originalState,
object obfuscatedState,
object? obfuscatedState,
Exception? exception,
Func<TState, Exception?, string> formatter,
ISecretObfuscator secretObfuscator) : IBufferedLogEvent
{
private readonly Exception? _obfuscatedException =
ObfuscatedLogException.Create(exception, secretObfuscator);

public LogLevel Level => level;

public void WriteTo(ILogger logger)
{
if (obfuscatedState is TState typedState)
{
logger.Log(
level,
eventId,
typedState,
_obfuscatedException,
FormatTyped);
return;
}

logger.Log(
level,
eventId,
obfuscatedState,
exception,
_obfuscatedException,
Format);
}

Expand All @@ -785,12 +800,15 @@ public void WriteTo(ILogger logger)
? null
: secretObfuscator.Obfuscate(exception.ToString(), null);

private string Format(object state, Exception? logException)
private string Format(object? state, Exception? logException)
{
var formatted = formatter(originalState, logException);
var formatted = formatter(originalState, exception);
return secretObfuscator.Obfuscate(formatted, null) ?? string.Empty;
}

private string FormatTyped(TState state, Exception? logException)
=> Format(state!, logException);

private static string FormatLevel(LogLevel logLevel) =>
logLevel switch
{
Expand Down
7 changes: 4 additions & 3 deletions src/ModularPipelines/Logging/CommandLogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,15 @@ private CommandLoggingOptions GetEffectiveLoggingOptions(CommandLineToolOptions?

private void LogDryRunCommand(CommandLoggingOptions options, string workingDirectory, string? input)
{
if (!ShouldShowInput(options))
var logger = Logger;
if (!ShouldShowInput(options) || !logger.IsEnabled(LogLevel.Information))
{
return;
}

Logger.LogInformation("{WorkingDirectory}> {Input} [DRY-RUN]",
logger.LogInformation("{WorkingDirectory}> {Input} [DRY-RUN]",
workingDirectory,
input);
_secretObfuscator.Obfuscate(input, null));
}

private void LogOutputLine(
Expand Down
25 changes: 21 additions & 4 deletions src/ModularPipelines/Logging/FormattedLogValuesObfuscator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public object TryObfuscateValues(object state)
{
if (state is not IReadOnlyList<KeyValuePair<string, object?>> values)
{
return state;
return ObfuscateValue(state);
}

KeyValuePair<string, object?>[]? obfuscatedValues = null;
Expand All @@ -46,9 +46,8 @@ public object TryObfuscateValues(object state)
continue;
}

var originalValue = property.Value.ToString() ?? string.Empty;
var obfuscatedValue = _secretObfuscator.Obfuscate(originalValue, null);
if (obfuscatedValue.Equals(originalValue, StringComparison.Ordinal))
var obfuscatedValue = ObfuscateValue(property.Value);
if (ReferenceEquals(obfuscatedValue, property.Value))
{
continue;
}
Expand All @@ -59,6 +58,24 @@ public object TryObfuscateValues(object state)

return obfuscatedValues ?? state;
}

private object ObfuscateValue(object value)
{
string originalValue;
try
{
originalValue = value.ToString() ?? string.Empty;
}
catch (Exception)
{
return value;
}

var obfuscatedValue = _secretObfuscator.Obfuscate(originalValue, null);
return obfuscatedValue.Equals(originalValue, StringComparison.Ordinal)
? value
: obfuscatedValue;
}
}

/// <summary>
Expand Down
4 changes: 3 additions & 1 deletion src/ModularPipelines/Logging/ModuleLogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,9 @@ public override void Log<TState>(LogLevel logLevel, EventId eventId, TState stat
return;
}

var obfuscatedState = _formattedLogValuesObfuscator.TryObfuscateValues(state!);
var obfuscatedState = state is null
? null
: _formattedLogValuesObfuscator.TryObfuscateValues(state);
var logEvent = new BufferedLogEvent<TState>(
logLevel,
eventId,
Expand Down
13 changes: 11 additions & 2 deletions src/ModularPipelines/Logging/ModuleLoggerProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ internal class ModuleLoggerProvider : IInternalModuleLoggerProvider
private readonly IServiceProvider _serviceProvider;
private readonly IStackTraceModuleDetector _stackTraceDetector;
private readonly ILoggerFactory _loggerFactory;
private readonly ISecretObfuscator _secretObfuscator;
private readonly IFormattedLogValuesObfuscator _formattedLogValuesObfuscator;
private readonly object _lock = new();

private IModuleLogger? _moduleLogger;
Expand All @@ -28,11 +30,15 @@ internal class ModuleLoggerProvider : IInternalModuleLoggerProvider
public ModuleLoggerProvider(
IServiceProvider serviceProvider,
IStackTraceModuleDetector stackTraceDetector,
ILoggerFactory loggerFactory)
ILoggerFactory loggerFactory,
ISecretObfuscator secretObfuscator,
IFormattedLogValuesObfuscator formattedLogValuesObfuscator)
{
_serviceProvider = serviceProvider;
_stackTraceDetector = stackTraceDetector;
_loggerFactory = loggerFactory;
_secretObfuscator = secretObfuscator;
_formattedLogValuesObfuscator = formattedLogValuesObfuscator;
}

/// <summary>
Expand Down Expand Up @@ -83,7 +89,10 @@ public IModuleLogger GetLogger()
{
// No module context - return a pipeline-level logger that doesn't create a separate output section
// This handles logging during initialization (e.g., GitInformation), condition evaluation, etc.
return _pipelineLevelLogger ??= new PipelineLevelLogger(_loggerFactory.CreateLogger("ModularPipelines.Pipeline"));
return _pipelineLevelLogger ??= new PipelineLevelLogger(
_loggerFactory.CreateLogger("ModularPipelines.Pipeline"),
_secretObfuscator,
_formattedLogValuesObfuscator);
}

return _moduleLogger = GetLogger(detectedType);
Expand Down
Loading
Loading