我对 C# 有点业余,正在开发 .NET Framwork 4.7.2 WPF 应用程序,其主要目的是允许用户运行类中的代码(所有这些都保存在“Scripts”文件夹中)程序)将在嵌入式浏览器中执行一组特定的任务。我正在使用 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
文件中,以便用户稍后在程序中访问和研究它。
我已经查看了这个问题,寻找一种基于类过滤日志记录的方法,但是,看起来我必须为我拥有的每个脚本手动放入这段代码:
.WriteTo.Logger(lc => lc
.Filter.ByIncludingOnly(Matching.FromSource<MyClass>())
.WriteTo.RollingFile("logs/DBStats-{Date}.log", outputTemplate: "{Message}{NewLine}"))
这些脚本类将根据用户的意愿不断地添加和删除到程序中,所以我认为这行不通。我希望在任何脚本类中完成的任何日志记录都会自动写入该脚本各自的数据文件夹中。
我也研究了Serilog sub-loggers,但还没有找到使用它来解决这个问题的方法。
配置记录器时可以执行的操作是扫描所有脚本类,并为它们设置过滤器。
根据您的评论,我们假设您的课程如下所示:
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");
}
}
public class ScriptOne : ScriptBase { }
public class ScriptTwo : ScriptBase { }
然后我们可以使用 SourceContext 来设置
Matching.FromSource()
过滤器。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 log location 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 the script logging.
new ScriptOne().Test("Hello");
new ScriptTwo().Test("World");
}
}
注意:以上所有内容都是独立的。在您的项目中实现这些代码之前,请随意在新的控制台项目中使用这些代码。