wpf 如何将Serilog Logging输出按发生日志记录的类分开?

li9yvcax  于 7个月前  发布在  其他
关注(0)|答案(1)|浏览(124)

我是C#的业余爱好者,正在开发一个. NETFramework4.7.2WPF应用程序,它的主要目的是允许用户运行类中的代码(所有这些都保存在程序中的一个“脚本”文件夹中),它将在嵌入式浏览器中执行某一组任务。我正在使用Serilog进行日志记录,而现在,我的程序在我的App.xaml.cs文件中设置为将所有日志输出到“Logs”文件夹,如下所示:

Log.Logger = new LoggerConfiguration()
    .WriteTo.File("./Logs/Log - .log", rollingInterval: RollingInterval.Day, outputTemplate: "{Timestamp:HH:mm:ss.fff} [{Level:u3}] {Message}{NewLine}{Exception}")
    .WriteTo.Debug()
    .WriteTo.Console()
    .MinimumLevel.Debug()
    .CreateLogger();

字符串
该程序为保存在“Scripts”文件夹中的每个类生成一个数据文件夹,以存储输入/输出数据。这些类中的每个类还使用Serilog,以便在脚本运行时记录脚本中的各种内容。是否有一种方法可以让Serilog将这些脚本类中完成的任何日志保存到单独的日志文件中,然后将位于每个相应类的数据文件夹中?这样做的目的是将类似Log.Information("Finished task #1...");的任何内容以及脚本中代码的任何错误保留在其自己的.log文件中,以便用户以后可以在程序.
我已经研究过this question,希望找到一种基于类过滤日志记录的方法,但是,看起来我必须为我拥有的每个脚本手动添加以下代码块:

.WriteTo.Logger(lc => lc
                .Filter.ByIncludingOnly(Matching.FromSource<MyClass>())
                .WriteTo.RollingFile("logs/DBStats-{Date}.log", outputTemplate: "{Message}{NewLine}"))


这些脚本类会根据用户的意愿不断地添加和删除到程序中,所以我认为这是行不通的。我希望在任何脚本类中完成的任何日志都能自动写入该脚本的相应数据文件夹中。
我也研究过Serilog sub-loggers,但还没有想出用它来解决这个问题的方法。

g0czyy6m

g0czyy6m1#

在配置记录器时,您可以做的是扫描所有脚本类,并为它们设置过滤器。
根据您的评论,我们假设您的类看起来像这样:

public abstract class ScriptBase {
  protected ILogger logger;

  // Enrich the logger with SourceContext, in this case, the class type.
  // Child classes will be enriched with their own class names.
  public ScriptBase() { logger = Log.ForContext(this.GetType()); }
  
  public void Test(string s) {
    logger.Debug($"{s} debug");
    logger.Information($"{s} info");
    logger.Error($"{s} error");
  }
}
public class ScriptOne : ScriptBase { }
public class ScriptTwo : ScriptBase { }

字符串
然后我们可以使用SourceContext来设置Matching.FromSource()过滤器。
这将假设你的脚本类是在启动时加载的,并且你没有在运行时动态加载DLL。

using System;
using System.Linq;
using Serilog;
using Serilog.Events;
using Serilog.Filters;

class Program {
  // Include Context in the template, to make the `Everything` log easier to read.
  const string template = "{Timestamp:HH:mm:ss.fff} [{Level:u3}] {SourceContext}: {Message}{NewLine}{Exception}";
  const RollingInterval interval = RollingInterval.Day;
  const string logDir = "c:/temp/logs"; // or wherever

  static void Main() {
    // We'll build up the Logger Config in a few steps.
    var logConfig = new LoggerConfiguration()
      // Allow Debug and above globally. We can override this per sink later.
      .MinimumLevel.Debug()
      ;

    // Step 1. Find ALL classes inheriting from ScriptBase.
    var scriptTypes = AppDomain.CurrentDomain.GetAssemblies()
      .SelectMany(assembly => assembly.GetTypes())
      .Where(typ => typeof(ScriptBase).IsAssignableFrom(typ))
      ;

    // Step 2. For each of the classes found above, 
    // configure the directory using filters.
    foreach (var type in scriptTypes) {
      logConfig = logConfig
        .WriteTo.Logger(lc => lc
          // Filter by the class name
          .Filter.ByIncludingOnly(Matching.FromSource(type.FullName))
          // And use it as subdirectory
          .WriteTo.File($"{logDir}/{type.Name}/Log-.log",
            rollingInterval: interval, outputTemplate: template
          )
        );
    }

    // Step 3. The rest of the config.
    logConfig = logConfig
      // Global file sink for everything
      .WriteTo.File($"{logDir}/EverythingLog-.log",
        rollingInterval: interval, outputTemplate: template,
        // Let's only log Info for the global file
        restrictedToMinimumLevel: LogEventLevel.Information
      )
      // And maybe restrict the Console sink to Warnings/Errors
      .WriteTo.Console(restrictedToMinimumLevel: LogEventLevel.Warning)
      ;

    // Use the config above to initialise the logger.
    Log.Logger = logConfig.CreateLogger();

    // Now let's test the different scripts.
    new ScriptOne().Test("Hello");
    new ScriptTwo().Test("World");
  }
}


注意:上面的代码是自包含的。在你的项目中实现它们之前,可以在一个新的控制台项目中随意使用它。

相关问题