using System.Collections;
using Microsoft.Extensions.Logging;
namespace MS.Microservice.Core.Security.SensitiveData;
public static class SensitiveLogExtensions
{
/// Projects a flat DTO before submitting structured values to any ILogger backend.
public static void LogSensitive(this ILogger logger, LogLevel level, string eventName, T value) where T : class
{
if (!logger.IsEnabled(level)) return;
ArgumentException.ThrowIfNullOrWhiteSpace(eventName);
var fields = SensitiveValues.Project(value);
logger.Log(level, new EventId(5100, eventName), new ProtectedState(eventName, fields), null,
static (state, _) => state.ToString());
}
private sealed class ProtectedState(string name, IReadOnlyDictionary fields)
: IReadOnlyList>
{
private readonly KeyValuePair[] _values =
[.. fields, new("{OriginalFormat}", name)];
public int Count => _values.Length;
public KeyValuePair this[int index] => _values[index];
public IEnumerator> GetEnumerator() => ((IEnumerable>)_values).GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public override string ToString() => name + " " + string.Join(", ", fields.Select(field => $"{field.Key}={field.Value}"));
}
}