1

我对我们的日志记录看起来多么臃肿有疑问。

我们在这样的结构中记录每个方法:

namespace MyNamespace
{
  public class MyClass
  {
    private readonly ILogger _logger;

    public MyClass(ILogger logger)
    {
      _logger = logger;
    }

    public string AppendString(string originalText, string addedText)
    {
      using (new Tracer(_logger).TraceMethod(
        "MyNameSpace.MyClass.MyMethod()",
        () => new Dictionary<string, object>
        {
          {"originalText", originalText},
          {"addedText", addedText}
        }))
      {
        _logger.WriteInformation("Some extra info");
        return originalText + addedText;
      }
    }
  }

  public class Tracer : IDisposable
  {
    private readonly ILogger _logger;
    private string _methodName;

    public Tracer(ILogger logger)
    {
      _logger = logger;
    }

    public Tracer TraceMethod(string methodName, Func<IDictionary<string, object>> arguments)
    {
      _logger.WriteVerbose($"Entering method {methodName} with arguments {arguments}");
      _methodName = methodName;
      return this;
    }

    public void Dispose()
    {
      _logger.WriteVerbose($"Exiting method {_methodName}");
    }
  }
}

所以我们要记录:

  • 方法的输入 - 总是

  • 方法的退出 - 总是

  • 额外信息 - 适当时

但是,正如你所看到的,这个将 2 个字符串合并在一起的小逻辑变得非常臃肿。在每一种方法中看到这种膨胀是非常令人沮丧的。

我们已经研究了 Fody 和 Postsharp 等框架中的 Aspects。使用这些框架,我们将能够在所有方法上添加 [LogMethod] 属性,这将自动添加日志记录 OnMethodEntry 和 OnMethodExit。这看起来很有趣,但我们仍然会遇到一些问题。

  1. 我们如何才能在方法对方法的基础上记录我们认为合适的参数?这会有所不同,我们当然不想记录所有输入参数,因为它可能是一个巨大的 xml。我们还希望将这些参数记录在与“OnMethodEntry”日志相同的日志消息中。

  2. 我们仍然需要一个 ILogger 实例作为方法注入。ILogger 的实例化添加了一个会话 ID。这个之前设置的 sessionId 很重要。有没有办法以不同的方式解决 ILogger?如果我们不将 ILogger 发送到构造函数,我们如何能够使用相同的 ILogger 实例在方法内部登录?

4

3 回答 3

2

考虑一下装饰器模式,您可以在其中创建一个LoggingMyClass仅包含日志记录代码的代码,然后委托给真实的代码MyClass来完成工作。这是一个简洁的模式,但是根据您需要装饰的类的数量,代码量会迅速增长。但是,它将允许您自定义所需的日志记录。

最小化代码量的另一种方法是使用 Castle 的DynamicProxy之类的东西进行拦截。这不是一种易于访问的技术,并且可能无法为您提供所需的定制。不过值得调查。

如果我们不将 ILogger 发送到构造函数,我们如何能够使用相同的 ILogger 实例在方法内部登录?

您可以考虑为记录器使用AmbientContext。然而,我在最新一本书中注意到,这种模式已经失宠。

于 2018-03-09T09:19:50.953 回答
2

PostSharp Diagnostics 通过以下方式解决这些场景:

  1. 参数的“智能”格式:

    一个。您可以实现自定义格式化程序并包含您想要的逻辑。但是,格式化程序只会接收参数值,而不是参数元数据。

    湾。如果您的格式化逻辑需要依赖于参数元数据(例如,您定义了一个定义自定义属性),您可以实现我们所说的自定义日志记录后端,并且您将覆盖SetParameter 方法

  2. 使用注入的 ILogger:

    一个。我真的不建议将记录器作为依赖项注入。尽管它是正统的,但与面向方面的解决方案一起使用是不切实际的。PostSharp Diagnostics 在后台为每种类型创建一个 ILogger,而不是针对每个实例。

    湾。如果您选择不注入 ILogger,PostSharp Diagnostics 允许您轻松混合自动日志记录和手动日志记录。手动记录将显示在正确的上下文中。

    C。也就是说,您可以创建一个 自定义日志记录后端(或适配器)来使用您的实例级 ILogger。你需要将你的记录器暴露给一个接口,比如 ILoggable。然后您的自定义适配器可以使用 ILoggable.ILogger。这没有什么困难。但是,它不能与 2.b 很好地结合,因为使用我们的框架发出的手动日志记录不包含有关this实例的信息(从 PostSharp 5.0 开始)。但是,您可以使用自己的 ILogger,而不是使用 PostSharp 的 Logger 类记录自定义记录。

于 2018-03-09T21:02:15.140 回答
0

您可以考虑使用方面和自定义注释来指定要记录的参数(如果有)和反射来处理注释的解决方案。我没有完全理解您的第二个问题,但在我看来,在注释处理器中以某种方式处理它更合适。

于 2019-01-27T05:59:39.250 回答