Serilog多个文件appsettings.json

8
我正在尝试配置Serilog将日志写入多个文件,但始终无法成功。使用此配置只会将日志写入第二个文件?
{
  "AllowedHosts": "*",
  "Serilog": {
    "Using": [ "Serilog.Sinks.File" ],
    "MinimumLevel": "Debug",
    "WriteTo": [
      {
        "Name": "File",
        "Args": {
          "path": "c:\\temp\\audit-.log",
          "rollingInterval": "Day",
          "restrictedToMinimumLevel": "Information"
        }
      },
      {
        "Name": "File",
        "Args": {
          "path": "c:\\temp\\error-.log",
          "rollingInterval": "Day",
          "restrictedToMinimumLevel": "Error"
        }
      }
    ]
  }
}

是否有办法从appsettings.json中加载多个具有不同配置的记录器到软件中。类似这样的内容?

var errorLogConfiguration = new ConfigurationBuilder()
    .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
    .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", optional: true)
    .AddEnvironmentVariables()
    .Build();

_log = new LoggerConfiguration()
    .ReadFrom
    .Configuration(errorLogConfiguration)
    .CreateLogger();
6个回答

7
我找到了解决方案。创建了appsettings.json、ErrorLog和AuditLog三个独立的部分。
  "ErrorLog": {
    "Using": [ "Serilog.Sinks.File" ],
    "MinimumLevel": "Debug",
    "WriteTo": [
      {
        "Name": "File",
        "Args": {
          "path": "c:\\temp\\error-.log",
          "rollingInterval": "Day",
          "restrictedToMinimumLevel": "Error"
        }
      }
    ]
  },
  "AuditLog": {
    "Using": [ "Serilog.Sinks.File" ],
    "MinimumLevel": "Debug",
    "WriteTo": [
      {
        "Name": "File",
        "Args": {
          "path": "c:\\temp\\audit-.log",
          "rollingInterval": "Day",
          "restrictedToMinimumLevel": "Information"
        }
      }
    ]
  }

现在我可以创建2个单独的记录器:

            var errorLogConfiguration = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", optional: true)
                .AddEnvironmentVariables()
                .Build();

            var errorSection = errorLogConfiguration.GetSection("ErrorLog");
            var auditSection = errorLogConfiguration.GetSection("AuditLog");

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

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

哪个更适合我的需求。

7

在由于Serilog以及任何一个sink的简单文档而苦苦挣扎数日后,我终于找到了不需要创建任何单独记录器的解决方法:

"Serilog": {
    "Using": [ "Serilog.Sinks.Async" ],
    "MinimumLevel": "Verbose",
    "Enrich": [ "FromLogContext", "WithDemystifiedStackTraces" ],
    "WriteTo:Information": {
        "Name": "Async",
        "Args": {
            "Configure": [
                {
                    "Name": "RollingFile",
                    "Args": {
                        "RestrictedToMinimumLevel": "Information",
                        "Formatter": "FOOINC.API.Configuration.Logging.CustomRenderedCompactJsonFormatter, FOOINC.API.Configuration",
                        "PathFormat": "_logs\\info\\info-log.json"
                    }
                }
            ]
        }
    },
    "WriteTo:Error": {
        "Name": "Async",
        "Args": {
            "Configure": [
                {
                    "Name": "RollingFile",
                    "Args": {
                        "RestrictedToMinimumLevel": "Error",
                        "Formatter": "FOOINC.API.Configuration.Logging.CustomRenderedCompactJsonFormatter, FOOINC.API.Configuration",
                        "PathFormat": "_logs\\errors\\error-log.json"
                    }
                }
            ]
        }
    }
}

希望这能对大家有所帮助!

请解释解决方案的想法。如果您这样做了,我会点赞的。 - hivert
这个想法很简单,我们需要两种类型的记录器,一个没有过滤器,另一个专门用于错误(用于不同的目的),而且我们不想要不同的Serilog实例。除此之外,通过这种设置,我们可以将日志(经过筛选或未经筛选)输出到其他类型的接收器,如debug、seq等。 - EVIL

5

在缺少Serilog文档的情况下,我经历了一段时间的错误、重试和几乎放弃后,得出了以下结论。他们在GitHub上有一个讨论:https://github.com/serilog/serilog-filters-expressions/issues/27。几乎每个讨论都得出同样的结论,即需要创建一个SUBLOGGER。这是我的实现方式。为了此实现,您需要以下插件:

  • Serilog Filter
  • Serilog Sink
  • Serilog Async

    "Serilog": {
    "Using": [ "Serilog.Sinks.File" ],
    "MinimumLevel": {
      "Default": "Information",
      "Override": {
        "Microsoft": "Warning",
        "System": "Warning"
      }
    },
    "WriteTo:Information": { //this name here can be changed
      "Name": "Logger", //this name here is essential
      "Args": {
        "configureLogger": {
          "Filter": [
            {
              "Name": "ByIncludingOnly",
              "Args": {
                "expression": "@Level = 'Information'"
              }
            }
          ],
          "WriteTo": [
            {
              "Name": "Async", //i use async plugin from serilog
              "Args": {
                "configure": [
                  {
                    "Name": "File",
                    "Args": {
                      "path": "Logs/Log_.txt",
                      "formatter": "Serilog.Formatting.Json.JsonFormatter, Serilog",
                      "rollingInterval": "Day",
                      "retainedFileCountLimit": 7
                    }
                  }
                ]
              }
            }
          ]
        }
      }
    },
    

3

关于通过配置文件设置日志记录器的设置,文档很少。有人可以提供帮助吗?只需要一个使用日志记录器设置的示例。在这个示例中,所有的日志都写入到一个名为sample.txt的文件中。调用特定API/api/health的日志会被写入到另一个文件中,并且不包含在sample.txt中。例如,IMyLogger-将写入到单独的SampleMy.txt中。您可以添加许多部分,并根据不同的标准划分日志。最好将本地日志记录级别设置为最小值,它们将被全局级别覆盖。全局过滤器将排除所有子日志记录器的日志(我不使用它)。PS抱歉我的英语不好。

"Serilog": {
    "MinimumLevel": "Information", //<- global error level. Ovveride all local error level
    "WriteTo": [
      {
        "Name": "Console"
      },
      {
        "Name": "Logger",
        "Args": {
          "configureLogger": {
            "MinimumLevel": "Debug", // <- local error level. 
            //Only records with Information logging level will be written to the log file
           //but if ovveride global level to Debug, and dont override local error level -> it will still be global
            "WriteTo": [
              {
                "Name": "File",
                "Args": {
                  "path": "log\\SampleHealthCheck-.txt", //write health-check log in different file
                  "rollingInterval": "Day",
                  "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] [CorrId:{CorrelationId}] [Op:{OperationId}] [U:{UserName}] {Message:lj}{NewLine}{Exception}"
                }
              }
            ],
            "Filter": [
              {
                "Name": "ByIncludingOnly",
                "Args": {
                  "expression": "RequestPath like '%/api/health'"
                }
              }
            ]
          }
        }
      },
      {
        "Name": "Logger",
        "Args": {
          "configureLogger": {
            "MinimumLevel": "Debug",
            "WriteTo": [
              {
                "Name": "File",
                "Args": {
                  "path": "log\\SampleMy-.txt", //Write some log in different file. Control through code 
                  "rollingInterval": "Day",
                  "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] [CorrId:{CorrelationId}] [Op:{OperationId}] [U:{UserName}] {Message:lj}{NewLine}{Exception}"
                }
              }
            ],
            "Filter": [
              {
                "Name": "ByIncludingOnly",
                "Args": {
                  "expression": "SourceContext = 'MyProject.IMyLogger'"
                }
              }
            ]
          }
        }
      },
      {
        "Name": "Logger",
        "Args": {
          "configureLogger": {
            "MinimumLevel": "Information",
            "WriteTo": [
              {
                "Name": "File",
                "Args": {
                  "path": "log\\Sample-.txt", //all logs, without health-check
                  "rollingInterval": "Day",
                  "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] [CorrId:{CorrelationId}] [Op:{OperationId}] [U:{UserName}] {Message:lj}{NewLine}{Exception}"
                }
              }
            ],
            "Filter": [
              {
                "Name": "ByExcluding",
                "Args": {
                  "expression": "RequestPath like '%/api/health'"
                }
              }
            ]
          }
        }
      }
    ],
    "Enrich": [
      "WithProcessName"
    ],
    "Properties": {
      "Application": "Sample",
      "Environment": "Test"
    }
  }

public class MyCommandHandler : IRequestHandler<MyCommand, Unit>
{
    private readonly ILogger _myLogger;
    private static int _count;

    public MyCommandHandler()
    {
        _myLogger = Log.ForContext<IMyLogger>();
    }

    public async Task<Unit> Handle(MyCommand request, CancellationToken cancellationToken)
    {
        _count++;

        Log.Debug("MyCommandHandler Count call = {count}",_count ); //write sample.txt
        Log.Information("MyCommandHandler Count call = {count}",_count ); //write in sample.txt
        Log.Error("MyCommandHandler Count call = {count}",_count); //write in sample.txt

        _myLogger.Information("Log from IMyLogger", _count); //write in sample.txt and in sampleMy.txt

        return Unit.Value;
    }
}

2
我从一篇博客中找到了一个很酷的解决方案,确实表现得非常出色。如果有任何问题,请告诉我。我也与大家分享这篇博客https://www.techrepository.in/blog/posts/writing-logs-to-different-files-serilog-asp-net-core。此外,要过滤日志,您需要使用Serilog.Eexpressions nuget包。希望你能从这里找到你想要的东西。
"Serilog": {
"Using": [ "Serilog.Sinks.File", "Serilog.Expressions"  ],
"MinimumLevel": {
  "Default": "Debug"
},
"WriteTo": [
  {
    "Name": "Logger",
    "Args": {
      "configureLogger": {
        "Filter": [
          {
            "Name": "ByIncludingOnly",
            "Args": {
              "expression": "@l = 'Error' or @l = 'Fatal' or @l = 'Warning'"
            }
          }
        ],
        "WriteTo": [
          {
            "Name": "File",
            "Args": {
              "path": "../logs/error_.log",
              "outputTemplate": "{Timestamp:o} [{Level:u3}] ({SourceContext}) {Message}{NewLine}{Exception}",
              "rollingInterval": "Day"
            }
          }
        ]
      }
    }
  },
  {
    "Name": "Logger",
    "Args": {
      "configureLogger": {
        "Filter": [
          {
            "Name": "ByIncludingOnly",
            "Args": {
              "expression": "@l = 'Information' or @l = 'Debug'"
            }
          }
        ],
        "WriteTo": [
          {
            "Name": "File",
            "Args": {
              "path": "../logs/debug_.log",
              "outputTemplate": "{Timestamp:o} [{Level:u3}] ({SourceContext}) {Message}{NewLine}{Exception}",
              "rollingInterval": "Day"
            }
          }
        ]
      }
    }
  }
]},

百分之百有效。试试看吧!


-1

我对这个问题进行了一些测试。好消息是你的配置有效。你的错误文件可能没有被创建,因为没有错误被记录。

当第一条消息被记录到日志文件中时,Serilog会创建日志文件。如果你运行这个简单的程序并(取消)注释错误日志记录,你可以确认这一点。

class Program
{
    static void Main(string[] args)
    {
        var errorLogConfiguration = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("settings.json", optional: false, reloadOnChange: true)
            .Build();

        var log = new LoggerConfiguration()
            .ReadFrom
            .Configuration(errorLogConfiguration)
            .CreateLogger();
        log.Warning("Warning");
        log.Error("Error");
    }
}

那个配置实际上不起作用,是的,我确实记录了错误。 - TuomasK
你能告诉我你使用的nuget包版本吗? 我讨厌这句话,但它在“我的”机器上可以运行。 - Pretasoc
没问题。 <PackageReference Include="Serilog.AspNetCore" Version="2.1.1" /> <PackageReference Include="Serilog.Settings.Configuration" Version="3.0.1" /> <PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" /> <PackageReference Include="Serilog.Sinks.File" Version="4.0.0" /> - TuomasK
1
好的,那么问题可能与asp.net-core有关。我使用的是一个简单的控制台应用程序。但既然你已经找到了另一种解决方案,我就不会再进一步调查这个问题了。 - Pretasoc

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