Jan*_*kan 4 .net c# logging serilog
我的 API 被不同类型的消费者访问。有外部应用程序,用户通过 Web 界面。
我会试着用一个例子来解释:所以在一个方法调用中,我想记录谁或什么访问了它。
在外部应用程序的情况下,我想记录这样的事情(使用模板):
"[{Caller}] {Timestamp:HH:mm:ss} [{Level}] (RequestId:{RequestId} | Key:{Key} | AppVersion:{Version}) {Message}{NewLine}{Exception}"
Run Code Online (Sandbox Code Playgroud)
如果是用户触发的操作,我想记录如下内容:
"[{Caller}] {Timestamp:HH:mm:ss} [{Level}] FullName:{FullName} | Organization:{Organization} | AppVersion:{Version}) {Message}{NewLine}{Exception}"
Run Code Online (Sandbox Code Playgroud)
两种类型的方法调用者都可以从 访问Thread.CurrentPrincipal.Identity,但每种方法都实现了不同类型的标识,具有不同的自定义属性。
我的代码看起来像:
public void DoSomething()
{
Log.Information("DoSomething called");
}
Run Code Online (Sandbox Code Playgroud)
如果我配置了类似以下内容的记录器:
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();
Run Code Online (Sandbox Code Playgroud)
如果由外部应用程序(线程身份)触发调用,它将永远不会显示 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));
}
}
Run Code Online (Sandbox Code Playgroud)
据我从在线文档和示例中了解到,日志模板仅在配置记录器时设置,在实际创建之前。我无法通过 LogEvent 访问和修改丰富器中的模板,因为它是只读的(只有 getter)。
我知道可能的消息格式,但这不是我在这种特殊情况下要寻找的。
我想在日志中看到的最终结果,对于外部应用程序访问是这样的:
2016 年 1 月 17 日 10:11:42.524 [API] 10:11:40 [信息] (RequestId: 123 | Key: XXX-1 | AppVersion:1.2.1) DoSomething called
当为用户登录时:
2016 年 1 月 17 日 11:12:42.524 [WEB] 11:12:40 [信息](全名:匿名 | 组织:MyOrg | AppVersion:1.2.1)DoSomething called
我的问题是:我如何(如果可能)记录(并在日志中查看)具有不同属性的不同类型的事件以登录模板?是否可以在运行时即时操作模板?我不希望模板包含来自两种或许多其他可能的事件类型的所有可能的标记,并且它们的属性在一个地方定义(在一种情况下,其中许多是空白的)。
如果您可以接受与示例略有不同的格式,则可以在此处使用解构:
"[{Caller}] {Timestamp:HH:mm:ss} [{Level}] ({Principal}) {Message}{NewLine}{Exception}"
然后在你的浓缩器中:
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));
}
}
}
Run Code Online (Sandbox Code Playgroud)
(注意true触发匿名对象的序列化。)
这将以键值对语法输出主体的各种属性。
否则,使用自定义ITextFormatter来做到这一点(基于 Serilog 的代码DisplayFormatter)是要走的路。ColoredConsole不接受自定义文本格式化程序,但是:
WriteTo.Sink(new RollingFileSink(@"Logs\app-{Date}.txt", formatter))
Run Code Online (Sandbox Code Playgroud)
将允许一个通过。