К моему API обращаются разные типы потребителей. Есть внешние приложения и пользователи через веб-интерфейс.
Я попытаюсь объяснить это на примере: Итак, при вызове метода я хотел бы регистрировать, кто или что получил к нему доступ.
В случае внешнего приложения я хотел бы записать что-то вроде этого (используя шаблон):
"[{Caller}] {Timestamp:HH:mm:ss} [{Level}] (RequestId:{RequestId} | Key:{Key} | AppVersion:{Version}) {Message}{NewLine}{Exception}"
и в случае действия, инициированного пользователем, я хотел бы зарегистрировать что-то вроде:
"[{Caller}] {Timestamp:HH:mm:ss} [{Level}] FullName:{FullName} | Organization:{Organization} | AppVersion:{Version}) {Message}{NewLine}{Exception}"
Доступ к обоим типам вызывающих методов осуществляется из Thread.CurrentPrincipal.Identity
, но каждый из них реализует разные типы удостоверений с разными настраиваемыми свойствами.
Мой код будет выглядеть так:
public void DoSomething()
{
Log.Information("DoSomething called");
}
Если у меня есть регистратор, настроенный примерно так:
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();
он никогда не будет отображать 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));
}
}
Насколько я смог понять из документации и примеров в Интернете, шаблон регистрации устанавливается только в момент настройки регистратора, до его фактического создания. Мне не удалось получить доступ и изменить шаблон в enricher через LogEvent, поскольку он доступен только для чтения (имеет только геттер).
Мне известно о возможном форматировании сообщений, но в данном случае я не ищу этого.
Конечный результат, который я хотел бы видеть в журналах, для внешнего доступа к приложению выглядит примерно так:
17 января 2016 г. 10: 11: 42.524 [API] 10:11:40 [Информация] (RequestId: 123 | Key: XXX-1 | AppVersion: 1.2.1) Вызывается DoSomething
и при входе для пользователя:
17 января 2016 г. 11: 12: 42.524 [WEB] 11:12:40 [Информация] (Полное имя: Аноним | Организация: MyOrg | Версия приложения: 1.2.1) Вызывается DoSomething
Мой вопрос: как (если возможно) я могу регистрировать (и видеть это в журналах) различные типы событий с разными свойствами для входа в шаблон? Можно ли манипулировать шаблоном во время выполнения на лету? Я не хотел бы иметь шаблон со всеми возможными токенами из обоих или многих других возможных типов событий, а также их свойства, определенные в одном месте (многие из которых пусты в одном или другом случае).