Comments 11
Возможно я не совсем правильно понял ваш вопрос.
Связать события публикуемые в DiagnosticSource порожденные «одним конкретным запросом одного конкретного юзера» — как раз таки это и делается в примере с CorrelationId. Т.е. когда в сервис приходит запрос, он помечается CorrelationId (либо через заголовок, либо генерируется новый). Этот CorrelationId доступен через статическое свойство, его можно получить где угодно и он будет отличаться для разных запросов разных пользователей, но будет одинаковый в рамках одного запроса одного пользователя.
И я не понял про «сопоставления логов» только для «пользовательских сообщений» микросервисов. Что понимается под "только пользовательскими сообщениями". Если поясните на примере, то постараюсь более внятно ответить =)
Про микросервисы — вы с них начали и вот в них с ними как раз все ясно — это наш код, что хотим то и публикуем. Решили публиковать все наши события с CorrelationId — берем и публкуем — и мы красавчики.
SqlClient само собой публикует события только с теми параметрами, которые у него есть. Но в обработчике мы можем получить доступ куда угодно, хоть к CorrelationId, хоть к IHttpContextAccessor (через конструктор заинжектить) и там уже можно придумать любую логику.
Зависит от задачи, которую вы хотели бы решить.
Я не нашел чтобы github.com/stevejgordon/CorrelationId как-то решал это и вообще как-то взаимодействовал с DiagnosticSource поэтому вообще не очень понимаю почему он в одном ряду был приведен. Добавляет токены в хеадер это немного другая задача…
Задачу можно поставить так: c HttpRequest пришел Header c X-CorrelationId и если имя юзера выславшего request = «Test» надо логить все порожденные этим HttpRequest'ом и только им события SqlClient и HttpClinet, и логить с данным X-CorrelationId.
Ну вот как раз эту задачу вы можете решить через DiagnosticSource. Нужно сделать наблюдатель, который на входящем http запросе будет проверять необходимость логирования через httpcontext. А на остальных событиях от SqlClient и HttpClinet нужно проверять этот признак и делать логирование. Если я правильно понял.
Да ваша статья показывает что можно решить и мою задачу, но один риск виден: как поведут себя множественные обсерверы ведь на каждый request от «тестеровщика» я бы создавал свой обсервер (и инжектирвала его значеним CorrelationId при этом в потоке реквеста назначал и AsyncLocal<Guid?> далее решая логить или нет сравнивая ижектированное значение с полученным от AsyncLocal<Guid?>) а после окончания requestа убирал бы.
И еще же остается неопределенным насколько гарантировано что все обсерверы во всех конфигурациях и для всех NnnClient работают правильно с AsyncLocal<Guid?> — это установленно эмпирически как я понимаю, в документации ничего об этом нет? Ведь чисто теоритически контекст исполнения метода обсервара может быть совсем «оторванным» таким что AsyncLocal<Guid?> вернет null.
Каждый обсервер — синглтон, он создаётся один раз на старте приложения, подписывается на DiagnosticListerer.AllListeners
, получает и обрабатывает все события.
AsyncLocal<T>
это просто класс, который умеет хранить состояние в асинхронном коде (в логическом потоке выполнения, который реально может обрабатываться разными потоками).
Если в начале обработки http запроса установить значение в AsyncLocal, то его можно прочитать где угодно из этого же экземпляра до окончания http запроса. Для разных (параллельно выполняющихся) http запросов это значение будет своё.
«Каждый обсервер — синглтон… на старте приложения»ну это же не обязательно, по крайей мере я ожидаю от архитектруы что скорее всего можно когда хочу тогда и создаю и убираю, вель тоже самое можно и с EFCore LoggerFactory (для реквеста нужного юзера создал вребозе LoggerFactory и убрал с окончанием реквеста — это реализовано stackoverflow.com/questions/43680174/entity-framework-core-log-queries-for-a-single-db-context-instance/47490737#47490737 ).
Для разных (параллельно выполняющихся) http запросов это значение будет своёэто да, можно ожидать от обсервера, но не факт со всеми NnnClient'ами. Я просто примерно представляю как можно написать код который выполнется в том же логическом потоке но ломает `AsyncLocal` и хотелось бы гарантий документации что вызов «методов обсервера» происходит так что `AsyncLocal` «не ломается». Ну ладно это такое.
Спасибо за идеи.
Их нельзя регать на реквест, т.к. каждый обсервер обрабатывает все события по всем реквестам.
Использование DiagnosticSource в .NET Core: практика