Как классифицировать журналы Serilog по пользовательским идентификаторам и настроить для них определенные уровни ведения журнала?

Я знаю, что можно использовать MinimalLevel.Override, который затем определяет конкретный уровень ведения журнала для каждого пространства имен или типа, но что, если я хочу зарегистрировать его с помощью чего-то более специфичного для моего контекста или требований?

Например, в моем приложении я хочу иметь определенную группу журналирования для всего, что связано с сущностью «Пользователи». Однако это не привязано к конкретному пространству имен или классу, это может быть код в контроллерах, репозитории или любой пользовательской службе. При отладке чего-либо, связанного с пользователями, я хотел бы включить для этого подробное ведение журнала, но не увеличивать его для каких-либо других журналов, служб или контроллеров, даже если они используют пространство имен совместно с пользователями. Опять же, «Пользователи» — это всего лишь пример — он может быть связан с определенным типом SQL-запросов, которые я делаю, всякий раз, когда используется какой-либо сервис, только когда выполняется определенное условие глубоко внутри некоторого кода и т. д. — возможно, я хочу, чтобы все SQL-запросы должны регистрироваться только в состоянии «Ошибка», за исключением некоторых, которые должны быть подробными.

Сначала я попробовал сделать это с помощью переключателей

Log.Logger = new LoggerConfiguration()
    .ReadFrom.Configuration(builder.Configuration)
    .MinimumLevel.Override("Case1", SerilogSwitches.Case1)
    .MinimumLevel.Override("Case2", SerilogSwitches.Case2)
    .CreateLogger();

Проблема в том, что «Case1» и «Case2» должны соответствовать определенному пространству имен или типу, который мне не подходит.

Я также рассмотрел возможность создания конкретного контекста журнала для каждого из этих случаев, используя Log.ForContext.

var logger1 = Log.ForContext("Context", "Case1");
var logger2 = Log.ForContext("Context", "Case2");

Хотя это позволило бы мне выбрать, какой регистратор использовать в любой момент, а затем легче находить и фильтровать журналы для этого конкретного контекста, все они по-прежнему регистрируются на одном и том же уровне — я не думаю, что смогу изменить уровень журналирования для конкретный контекст, например, Case1 — «Информация», а Case2 — «Ошибка».

Любая помощь приветствуется

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
50
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы можете попробовать использовать WriteTo.Conditional, чтобы определить конфигурацию в зависимости от значения «Контекст». Например, следующий образец:

Log.Logger = new LoggerConfiguration()
    .WriteTo.Conditional((evt) => {
        var contextValue = ((ScalarValue)evt.Properties.GetValueOrDefault("Context")).Value;
        return ( contextValue== "case1"); 
        } , wt => wt.Console(restrictedToMinimumLevel:LogEventLevel.Information,outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}]({Context}) {Message:lj}{NewLine}{Exception}"))

    .WriteTo.Conditional((evt) => {
        var contextValue = ((ScalarValue)evt.Properties.GetValueOrDefault("Context")).Value;
        return (contextValue == "case2");
    }, wt => wt.Console(restrictedToMinimumLevel: LogEventLevel.Error, outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}]({Context}) {Message:lj}{NewLine}{Exception}"))
    .CreateLogger();

Тест

            Log.ForContext("Context","case1").Information("case1 info");
            Log.ForContext("Context", "case2").Information("case2 info");
            Log.ForContext("Context", "case2").Error("case2 error");

Результат

Ответ принят как подходящий

В вашем примере:

Log.Logger = new LoggerConfiguration()
    .ReadFrom.Configuration(builder.Configuration)
    .MinimumLevel.Override("Case1", SerilogSwitches.Case1)
    // ...

Использование SourceContext приведет к сопоставлению переопределения уровня и применению определенных уровней:

var logger1 = Log.ForContext("SourceContext", "Case1");

(Для этого существует константа, называемая Serilog.Core.Constants.SourceContextPropertyName.)

Вы потеряете имя типа, которое в противном случае обычно появлялось бы в этом значении, но это может быть приемлемым компромиссом, если этого требует ваш сценарий - и вы все равно можете записать имя типа дополнительно, используя что-то вроде:

var logger1 = Log
    .ForContext("SourceContext", "Case1")
    .ForContext("SourceType", typeof(MyClass));

Другие вопросы по теме