c# - Serilog:记录不同类型的日志事件

标签 c# .net logging serilog

我的 API 由不同类型的消费者访问。有外部应用程序,通过网络界面用户。

我将尝试用一个例子来解释: 所以在方法调用中,我想记录谁或什么访问了它。

如果是外部应用程序,我想记录这样的内容(使用模板):

"[{Caller}] {Timestamp:HH:mm:ss} [{Level}] (RequestId:{RequestId} | Key:{Key} | AppVersion:{Version}) {Message}{NewLine}{Exception}"

如果是用户触发的操作,我想记录如下内容:

"[{Caller}] {Timestamp:HH:mm:ss} [{Level}] FullName:{FullName} | Organization:{Organization} | AppVersion:{Version}) {Message}{NewLine}{Exception}"

这两种类型的方法调用者都可以从 Thread.CurrentPrincipal.Identity 访问,但每个都实现不同类型的身份,具有不同的自定义属性。

我的代码看起来像:

public void DoSomething()
{
    Log.Information("DoSomething called");
}

如果我配置了类似这样的记录器:

var logger = new LoggerConfiguration()
                   .Enrich.WithProperty("Version", appVersion)
                   .Enrich.WithProperty("Caller", caller)
                   .Enrich.With(new MyEnricher())
                   .WriteTo.ColoredConsole(outputTemplate: "[{Caller}] {Timestamp:HH:mm:ss} [{Level}] FullName:{FullName} | Organization:{Organization} | AppVersion:{Version}) {Message}{NewLine}{Exception}")
                   .CreateLogger();

如果由外部应用程序(线程标识)触发调用,它永远不会显示 Key 和 RequestId。

我将 MyEnricher 添加到记录器中,类似于:

public class MyEnricher : ILogEventEnricher
{
    public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
    {
        var identity = Thread.CurrentPrincipal.Identity;
        if (identity is ExternalIdentity)
        {
            var externalIdentity = Thread.CurrentPrincipal.Identity as ExternalIdentity;
            logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("Key", externalIdentity.Key));
            logEvent.AddOrUpdateProperty(propertyFactory.CreateProperty("RequestId", externalIdentity.RequestId));
        }
        else
        {
            var userIdentity = Thread.CurrentPrincipal.Identity as UserIdentity;

            logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("FullName", userIdentity.FullName));
            logEvent.AddOrUpdateProperty(propertyFactory.CreateProperty("Organization", userIdentity.OrganizationName));
        }
}

据我从在线文档和示例中了解到的,日志记录模板仅在配置记录器时设置,在实际创建之前。我无法通过 LogEvent 访问和修改 enricher 中的模板,因为它是只读的(只有 getter)。

我知道可能的消息格式,但这不是我在这种特殊情况下要找的格式。

对于外部应用程序访问,我希望在日志中看到的最终结果是这样的:

17 Jan 2016 10:11:42.524 [API] 10:11:40 [Information] (RequestId: 123 | Key: XXX-1 | AppVersion:1.2.1) DoSomething called

当为用户登录时:

17 Jan 2016 11:12:42.524 [WEB] 11:12:40 [Information] (FullName: Anonymous | Organization: MyOrg | AppVersion:1.2.1) DoSomething called

我的问题是:如何(如果可能)记录(并在日志中查看)具有不同属性的不同类型的事件以登录模板?是否可以在运行时动态操作模板?我不希望模板包含来自这两种或许多其他可能事件类型的所有可能标记,并且它们的属性定义在一个地方(在一种情况下,其中许多都是空白的)。

最佳答案

如果您可以接受与您的示例略有不同的格式,您可以在此处使用解构:

[{Caller}] {Timestamp:HH:mm:ss} [{Level}] ({Principal}) {Message}{NewLine}{Exception}"

然后在你的 enricher 中:

public class MyEnricher : ILogEventEnricher
{
    public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
    {
        var identity = Thread.CurrentPrincipal.Identity;
        if (identity is ExternalIdentity)
        {
            var externalIdentity = Thread.CurrentPrincipal.Identity as ExternalIdentity;
            logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("Principal", new {
                externalIdentity.Key,
                externalIdentity.RequestId
            }, true));
        }
        else
        {
            var userIdentity = Thread.CurrentPrincipal.Identity as UserIdentity;
            logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("Principal", new {
                userIdentity.FullName,
                userIdentity.OrganizationName
            }, true));
        }
    }
}

(注意 true 触发匿名对象的序列化。)

这将以键值对语法输出委托(delegate)人的各种属性。

否则,使用自定义 ITextFormatter 来执行此操作(基于 Serilog 的 DisplayFormatter 的代码)是可行的方法。 ColoredConsole 不接受自定义文本格式化程序,但是:

WriteTo.Sink(new RollingFileSink(@"Logs\app-{Date}.txt", formatter))

将允许一个通过。

关于c# - Serilog:记录不同类型的日志事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34837339/

相关文章:

c# - Unity 的 Mathf.PingPong 实际上是做什么的?

c# - 从 Dropbox 上的公开共享文件夹下载图像

.net - WinUI3 应用程序抛出异常 - 我错过了什么?

c# - 如何比较 .NET 中的执行路径?

java - 在 Java 中创建 XML 日志文件

c# - WPF 在任务栏上最小化单击

c# - 了解 C# 中的异步(套接字)

c# - 检查 .NET 4 Full Framework 是否已安装

docker-compose 在容器重新启动时重放过去的输出

go - Logrus条目没有“缓冲区”字段