使用 Serilog 将此信息记录到另一个文件中

3
我有一个.NET 5.0的控制台应用程序,里面使用了Serilog NuGet包。appsettings.json中的Serilog部分看起来像这样:
"Enrich": [ "FromLogContext", "WithMachineName", "WithProcessId", "WithThreadId" ],
"WriteTo": [
  {
    "Name": "Console",
    "Args": {
      "outputTemplate": "[{Timestamp:HH:mm:ss.fff} [{Level}] {SourceContext} {Message}{NewLine}{Exception}",
      "theme": "Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme::Code, Serilog.Sinks.Console"
    }
  },
  {
    "Name": "File",
    "Args": {
      "path": "/Logs/SharedTreatment_logs.txt",
      "outputTemplate": "{Timestamp:G} {SourceContext} [{Level}] {Message}{NewLine:1}{Exception:1}",
      "formatter": "Serilog.Formatting.Json.JsonFormatter, Serilog",
      "fileSizeLimitBytes": 1000000,
      "rollOnFileSizeLimit": "true",
      "shared": "true",
      "flushToDiskInterval": 3
    }

  }
]

这段代码已被加载:

    Serilog.Debugging.SelfLog.Enable(Console.Error);
    
                var configuration = new ConfigurationBuilder()
                                .AddJsonFile("appsettings.json")
                                .Build();
    
                var logger = loggerConfiguration.ReadFrom.Configuration(configuration).CreateLogger();
                
                Log.Logger = logger?.ForContext<T>() ?? throw new ArgumentNullException(nameof(logger));

Host.CreateDefaultBuilder(args).UseSerilog((hostingContext, loggerConfiguration) => loggerConfiguration.ReadFrom.Configuration(hostingContext.Configuration))

解决方案中的每个类都获得了ILogger注入,例如ILogger<MyClass> logger

问题在于如何在这样的类中创建一个新的日志记录器,该记录器使用来自appsettings.json的另一个日志配置部分记录到另一个文件中?

更新: 经过大量搜索和测试,我认为我找到了一种方法来做到这一点。但是我仍然不确定它是否是正确的方法或最佳方法?

我必须创建2个子记录器,一个用于排除文件的主记录,另一个仅记录文件,如下所示:

{
  "Serilog": {
    "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ],
    "MinimumLevel": "Debug",
    "Enrich": [ "FromLogContext" ],
    "WriteTo": [
      {
        "Name": "Console",
        "Args": {
          "outputTemplate": "[{Timestamp:HH:mm:ss.fff} [{Level}] {SourceContext} {Message}{NewLine}{Exception}",
          "theme": "Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme::Code, Serilog.Sinks.Console"
        }
      },
      {
        "Name": "Logger",
        "Args": {
          "configureLogger": {
            "Filter": [
              {
                "Name": "ByIncludingOnly",
                "Args": {
                  "expression": "@p['LogToFile']"
                }
              }
            ],
            "WriteTo": [
              {
                "Name": "File",
                "Args": {
                  "path": "Logs/SharedTreatment_logs_Second.txt",
                  "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff} [{Level:u3}] {Message:lj}{NewLine}{Exception}"
                }
              }
            ]
          }
        }
      },
      {
        "Name": "Logger",
        "Args": {
          "configureLogger": {
            "Filter": [
              {
                "Name": "ByExcluding",
                "Args": {
                  "expression": "@p['LogToFile']"
                }
              }
            ],
            "WriteTo": [
              {
                "Name": "File",
                "Args": {
                  "path": "Logs/SharedTreatment_logs.txt",
                  "outputTemplate": "{Timestamp:G} {SourceContext} [{Level}] {Message}{NewLine:1}{Exception:1}",
                  "formatter": "Serilog.Formatting.Json.JsonFormatter, Serilog",
                  "fileSizeLimitBytes": 1000000,
                  "rollOnFileSizeLimit": "true",
                  "shared": "true",
                  "flushToDiskInterval": 3
                }
              }
            ]
          }
        }
      }


    ]
  }
}

以下是 C# 代码的样例:

static void Main(string[] args)
        {
           
            Console.WriteLine("Hello World!");
            Log.Logger = new LoggerConfiguration().DefaultLoggerSetup<Program>();
            using (LogContext.PushProperty("LogToFile", true))
            {
                Log.Information("LogToFileTest");
            }

            Log.Information("Just log");
            Log.CloseAndFlush();

        }

创建了两个文件,筛选后的日志就在它们应该在的地方。


这里有一个答案在链接上。你可以通过Json配置来配置2个sinks和一个过滤表达式。 - Hazrelle
3个回答

5

您不需要单独注入另一个ILogger。Serilog可以自己处理。 只需使用子记录器并添加一些WriteTo.Logger即可。然后,您可以在代码中的某个位置使用ILogger,它会根据您的配置自动保存日志。

例如:

Log.Logger = new LoggerConfiguration()
    .WriteTo.Logger(lc => lc
        .Filter.ByExcluding(Matching.FromSource("AnySource"))
        .WriteTo.File("first.txt", new JsonFormatter()))
    .WriteTo.Logger(lc => lc
        .Filter.ByIncludingOnly(Matching.FromSource("AnySource"))
        .WriteTo.File("second.txt", new JsonFormatter()))
    .WriteTo.Logger(config => config
        .Filter.ByIncludingOnly(e => e.Level == LogEventLevel.Debug)
        .WriteTo.File("third.txt", new JsonFormatter()))
        (...)
    .CreateLogger();

你可以使用应用程序设置来告诉Verilog按照以下方式执行:
  {
  "Serilog": {
    "Using": ["Serilog.Settings.Configuration"],
    "Filter": [
      {
        "Name": "ByExcluding",
        "Args": {
          "expression": "EndsWith(RequestPath, '/SomeEndpoint')"
        }
      }
    ]

您可以在此处在此处查看更多信息。


谢谢,调用日志方法时是否可以设置一个键,并在配置文件中仅过滤具有此键的日志?然后确保这些日志不会显示在主日志流中?到目前为止,我看到的所有示例都是在子记录器上过滤命名空间或类似内容。 - Banshee
@Banshee 过滤器使用 Serilog 表达式 [Filter.ByIncludingOnly(expr)],通过表达式,您可以做很多事情。在这里看一下:https://github.com/serilog/serilog-expressions。我认为您应该有一些挑战去完成它 :) - Mohammad
仍然不清楚如何从appsettings.config中过滤特定属性?我找到的所有示例都是通过代码实现的。 - Banshee

0
为了解决这个问题,我不得不在appsettings.json中创建一个独立的日志条目,如下所示:
{
          "Name": "Logger",
          "Args": {
            "configureLogger": {
              "Filter": [
                {
                  "Name": "ByIncludingOnly",
                  "Args": {
                    "expression": "@p['LogToFile']"
                  }
                }
              ],
              "WriteTo": [
                {
                  "Name": "File",
                  "Args": {
                    "path": "Logs/SharedTreatment_logs_Second.txt",
                    "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff} [{Level:u3}] {Message:lj}{NewLine}{Exception}"
                  }
                }
              ]
            }
          }
        },

我必须像这样将特定的日志记录推送到此记录器:

using (LogContext.PushProperty("LogToFile", true))
                { _logger.LogInformation("Incoming Message   MessageGuid : {MessageGuid} , MessageChainGuid : {MessageChainGuid}, SharedTreatment : {SharedTreatment}", incomingMessage.MessageGuid, incomingMessage.MessageChainGuid, incomingMessage.SharedTreatment); }

0

ILogger 是一个 Singleton(请参阅这里) & 问题(此处请参阅 ILogger<T>

我个人认为更好的选择是,在appsettings.json内创建多个单独的sections,例如ErrorLogSecondErrorLogAuditLog

  • 第一步创建如下所示的appsettings.json中的部分

  "ErrorLog": {
    "Using": [ "Serilog.Sinks.File" ],
    "MinimumLevel": "Debug",
    "WriteTo": [
      {
        "Name": "File",
        "Args": {
          "path": "c:\\temp\\error1-.log",
          "rollingInterval": "Day",
          "restrictedToMinimumLevel": "Error"
        }
      }
    ]
  },
  "SecondErrorLog": {
    "Using": [ "Serilog.Sinks.File" ],
    "MinimumLevel": "Debug",
    "WriteTo": [
      {
        "Name": "File",
        "Args": {
          // your Second Error Log or Audit Log etc.
          "path": "c:\\temp\\error2-.log",
          "rollingInterval": "Day",
          "restrictedToMinimumLevel": "Information"
        }
      }
    ]
  }

第二步,现在在您的代码中,您可以访问、审计等。
var myDualErrorLogConfiguration = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
            .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", optional: true)
            .AddEnvironmentVariables()
            .Build();

        // now get your First Error Log or Audit Log etc.
        var errorSection = myDualErrorLogConfiguration.GetSection("ErrorLog");
       
        // your Second Error Log or Audit Log etc.
        var auditSection = myDualErrorLogConfiguration.GetSection("SecondErrorLog");

        _log = new LoggerConfiguration()
            .ReadFrom
            .ConfigurationSection(errorSection)
            .CreateLogger();

        _secondLog = new LoggerConfiguration()
            .ReadFrom
            .ConfigurationSection(auditSection)
            .CreateLogger();

更新2:

让我们退一步,针对您想要做的事情,即使用不同配置的多个记录器,您需要一个ILoggerFactory来创建和配置这些记录器,请参见下面的示例,来源于Hooman。这将帮助您创建所需的不同记录器。

ILoggerFactory factory = new LoggerFactory().AddConsole();    // add console provider
factory.AddProvider(new LoggerFileProvider("c:\\FirstErrorLog.txt"));   // add file provider
Logger logger = factory.CreateLogger(); // <-- creates a console logger & file logger

现在你可以将它注入到你的构造函数中

public SomeController(ISomeRepository someRepository, ILoggerFactory logger)
{
    _someRepository = someRepository;
    _logger = logger.CreateLogger("SomeApi.Controllers.TodoController");
}

谢谢,但我正在使用注入来获取特定类记录器到该类中。根据您的建议,我怀疑我必须在program.cs启动时创建不同的记录器,然后以某种方式将它们注入到注入构建中。就像说ILogger<MyClass>这个我不想让Serilog处理,而是在这里发送我的自定义特殊记录器。 - Banshee
谢谢,但即使使用更新2,如何记录到不同的输出仍然不清楚,对我来说,我的帖子更新后似乎更容易? - Banshee

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接