Mas*_*ton 10 c# serilog asp.net-core
我遇到了一个问题,我正在努力寻找一个干净的解决方案,谷歌搜索并没有让我变得更聪明。
情况
(1) 我们有自己的程序集,用于为我们的任何项目(一致的日志输出、主题等)设置和添加 Serilog 记录器,并且该程序集没有对任何消耗项目(位于不同的存储库中)的引用。让我们称之为CompanySerilog大会。
(2) 消费项目之一是外部可访问的 API,其“合同”对象在 ExternalContracts 程序集中定义。即请求和响应对象,以及用作这些对象一部分的任何枚举。可以将此 ExternalContracts 程序集提供给针对 API 进行集成的开发人员。
(3) 我们要记录所有请求,并使用一个IActionFilter使用 Serilog 结构化日志记录方法注销每个请求对象。例如循环遍历上下文中的每个参数并最终执行_logger.LogDebug("With {name} of {@requestObject}", name, value);
问题
一些请求对象具有我们想要屏蔽的敏感数据,但是:
CompanySerilog使用标准的.Destructure扩展,但不知道,或者想知道,要求的具体对象,因为这些可能是从Api1,Api2等等,这将意味着要添加到每一个参考消耗项目。Destructurama.Attributed)添加属性,但这意味着我们的ExternalContracts程序集现在需要对该 NuGet 包的引用,而后者又需要对所有必需的 Serilog 包的引用。严格来说,ExternalContracts 程序集中不需要日志记录问题:这是我们的问题,而不是我们 API 的使用者正如我所说,我一直在努力想出解决这个问题的方法,但在使用 IDestructuringPolicy 以及它是否合适,或者转换是否应该发挥作用方面找不到太多信息。到目前为止,我只能想到以下选项,但我希望其他人遇到了这个问题,并且有一种非常聪明和干净的方式来支持这个用例。
解决方案?
停止进行结构化日志记录,只需ToString()为每个请求对象定义一个掩蔽我们不想记录的值。这很简单,不需要讨厌的项目交叉引用或将日志记录问题添加到外部合同中。但这确实意味着不可能进行结构化日志记录。
将所有需要的日志引用添加到外部合约中。这将允许我们继续使用内置销毁,但意味着我们 API 的使用者将拥有一个包含日志程序集的 ExternalContracts 程序集
通过引用将使用此程序集的每个项目,.Destructure在配置登录时设置值CompanySerilog。不会发生!
还有什么?请!
Mas*_*ton 10
我们提出了两个潜在的解决方案,如果有人遇到类似的问题,我将分享它们 - 两者都涉及使用IDestructuringPolicy.
解决方案1
IDestructuringPolicy在CompanySerilog程序集中有一个泛型。
public class SensitiveDataDestructuringPolicy : IDestructuringPolicy
{
public bool TryDestructure(object value, ILogEventPropertyValueFactory propertyValueFactory, out LogEventPropertyValue result)
{
var props = value.GetType().GetTypeInfo().DeclaredProperties;
var logEventProperties = new List<LogEventProperty>();
foreach (var propertyInfo in props)
{
switch (propertyInfo.Name.ToLower())
{
case "cardnumber":
case "password":
logEventProperties.Add(new LogEventProperty(propertyInfo.Name,propertyValueFactory.CreatePropertyValue("***")));
break;
default:
logEventProperties.Add(new LogEventProperty(propertyInfo.Name, propertyValueFactory.CreatePropertyValue(propertyInfo.GetValue(value))));
break;
}
}
result = new StructureValue(logEventProperties);
return true;
}
}
Run Code Online (Sandbox Code Playgroud)
并在设置记录器时,使用以下类型的配置:
var logger = new LoggerConfiguration()
// snipped out all the other things that need configuring
// ...
.Destructure.With<SensitiveDataDestructuringPolicy>
.CreateLogger();
Run Code Online (Sandbox Code Playgroud)
这种方法的优点:
这种方法的缺点:
最后,由于第一个解决方案的缺点,我们采用了不同的方法。
解决方案2
使用该方法CompanySerilog创建记录器,在使用它的任何程序集中查找 IDestructuringPolicies。
public static ILogger Create()
{
var destructuringPolicies = GetAllDestructuringPolicies();
var logger = new LoggerConfiguration()
// snipped out all the other things that need configuring
// ...
.Destructure.With(destructuringPolicies)
.CreateLogger();
//Set the static instance of Serilog.Log with the same config
Log.Logger = logger;
logger.Debug($"Found {destructuringPolicies.Length} destructuring policies");
return logger;
}
/// <summary>
/// Finds all classes that implement IDestructuringPolicy, in the assembly that is calling this
/// </summary>
/// <returns></returns>
private static IDestructuringPolicy[] GetAllDestructuringPolicies()
{
var policies = Assembly.GetEntryAssembly().GetTypes().Where(x => typeof(IDestructuringPolicy).IsAssignableFrom(x));
var instances = policies.Select(x => (IDestructuringPolicy)Activator.CreateInstance(x));
return instances.ToArray();
}
Run Code Online (Sandbox Code Playgroud)
现在这个CompanySerilog程序集的任何使用者都负责定义它想要如何记录敏感数据,通过IDestructuringPolicy为它关心的每个类定义一个。例如:
public class RegisterNewUserDestructuringPolicy : IDestructuringPolicy
{
public bool TryDestructure(object value, ILogEventPropertyValueFactory propertyValueFactory, out LogEventPropertyValue result)
{
var request = value as RegisterNewUserRequest;
if (request == null)
{
result = null;
return false;
}
var logEventProperties = new List<LogEventProperty>
{
new LogEventProperty(nameof(request.Claims), propertyValueFactory.CreatePropertyValue(request.Claims)),
new LogEventProperty(nameof(request.Email), propertyValueFactory.CreatePropertyValue(request.Email)),
new LogEventProperty(nameof(request.Password), propertyValueFactory.CreatePropertyValue("****")),
new LogEventProperty(nameof(request.Roles), propertyValueFactory.CreatePropertyValue(request.Roles)),
new LogEventProperty(nameof(request.UserName),
propertyValueFactory.CreatePropertyValue(request.UserName))
};
result = new StructureValue(logEventProperties);
return true;
}
}
Run Code Online (Sandbox Code Playgroud)
与解决方案 1 相比,这种方法的优势在于我们现在正在处理具体类型,如果该类型没有策略,则不会被反射。
| 归档时间: |
|
| 查看次数: |
2634 次 |
| 最近记录: |