Pull to refresh

Comments 11

Я правильно понял что вы при помощи CorrelationId решаете проблему «сопоставления логов» только для «пользовательских сообщений» микросервисов? А связать SqlClient и HttpClient события публикуемые в DiagnosticSource порожденные «одним конкретным запросом одного конкретного юзера» возможности нет, это невозможно. Т.е. невозможно SqlClient и HttpClient задать CorrelationId и сказать — вот с ним и публикуй в этом потоке и во всех порожденных?

Возможно я не совсем правильно понял ваш вопрос.


Связать события публикуемые в DiagnosticSource порожденные «одним конкретным запросом одного конкретного юзера» — как раз таки это и делается в примере с CorrelationId. Т.е. когда в сервис приходит запрос, он помечается CorrelationId (либо через заголовок, либо генерируется новый). Этот CorrelationId доступен через статическое свойство, его можно получить где угодно и он будет отличаться для разных запросов разных пользователей, но будет одинаковый в рамках одного запроса одного пользователя.


И я не понял про «сопоставления логов» только для «пользовательских сообщений» микросервисов. Что понимается под "только пользовательскими сообщениями". Если поясните на примере, то постараюсь более внятно ответить =)

Спасибо. Я рассуждаю так. SqlClient публикует события и мы очень хотим чтобы он публиковал их с CorrelationId. Но SqlClient писали не мы а MS как же он будет публиковать события с CorrelationId если в нем этой публикации просто нет — он публикует вообще все события процесса. Можно поставить фильтр на этот поток из «всех событий» что-то типа`if(CorrelationId.Current == thisHttpContext.Request.CorrelationId) log(...)` но я такого когда у вас не нашел (извиняюсь заранее, частенько у меня «тунелька»).

Про микросервисы — вы с них начали и вот в них с ними как раз все ясно — это наш код, что хотим то и публикуем. Решили публиковать все наши события с CorrelationId — берем и публкуем — и мы красавчики.

SqlClient само собой публикует события только с теми параметрами, которые у него есть. Но в обработчике мы можем получить доступ куда угодно, хоть к CorrelationId, хоть к IHttpContextAccessor (через конструктор заинжектить) и там уже можно придумать любую логику.


Зависит от задачи, которую вы хотели бы решить.

Спасибо, это я и имел ввиду говоря «можно поставить фильтр». Но хотелось бы код увидеть. Он наверняка есть на я на GitHub Prometheus но я сходу не нашел.

Я не нашел чтобы github.com/stevejgordon/CorrelationId как-то решал это и вообще как-то взаимодействовал с DiagnosticSource поэтому вообще не очень понимаю почему он в одном ряду был приведен. Добавляет токены в хеадер это немного другая задача…

Задачу можно поставить так: c HttpRequest пришел Header c X-CorrelationId и если имя юзера выславшего request = «Test» надо логить все порожденные этим HttpRequest'ом и только им события SqlClient и HttpClinet, и логить с данным X-CorrelationId.

github.com/stevejgordon/CorrelationId никак не связан с DiagnosticSource. Я просто привёл альтернативную реализацию этого механизма (CorrelationId) через DiagnosticSource.

Ну вот как раз эту задачу вы можете решить через DiagnosticSource. Нужно сделать наблюдатель, который на входящем http запросе будет проверять необходимость логирования через httpcontext. А на остальных событиях от SqlClient и HttpClinet нужно проверять этот признак и делать логирование. Если я правильно понял.
Наконец понял вашу задачу а заодно и при чем github.com/stevejgordon/CorrelationId. Действительно «тунелька», думал вы решаете туже задачу что и я. Спасибо за терпение.

Да ваша статья показывает что можно решить и мою задачу, но один риск виден: как поведут себя множественные обсерверы ведь на каждый 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` «не ломается». Ну ладно это такое.

Спасибо за идеи.

> ну это же не обязательно
Их нельзя регать на реквест, т.к. каждый обсервер обрабатывает все события по всем реквестам.
Да вы правы можно и синглтоном обойтись все равно за AsyncLocal ходить. И даже не correlatioId получать из AsyncLocal а функцию лога (делегат). Если null — то и не логишь. А устанавливать делегат только для юзеров-тестеров. Надо пробовать.
Sign up to leave a comment.