.NET Core - привязка входящего запроса с Request-Id к исходящим HTTP-запросам

Мы ищем способ ПОДКЛЮЧИТЬ Request-Id (или Correlation-Id) к нескольким запросам API, как показано на рисунке ниже:

.NET Core - привязка входящего запроса с Request-Id к исходящим HTTP-запросам

Идея состоит в том, чтобы иметь один единственный идентификатор для отслеживания конкретного запроса через несколько API в наших журналах. Мы используем стандартный ILogger, который поставляется с .NET Core 2.1.

Что мы пробовали до сих пор

  • Мы попытались использовать Request-Id в заголовке запроса, который успешно регистрируется, но мы не можем получить значение, чтобы добавить его в последующий HTTP-запрос к другим API.

  • Мы заметили, что есть также CorrelationId, который регистрируется. Однако мы не можем понять, как его обновить.

  • Кроме того, мы заметили, что на TraceIdentity доступен HttpContextAccessor, который потенциально может решить нашу задачу. Но мы не знаем, как использовать это для решения нашей проблемы.

Мы не можем использовать Application Insights и хотим полагаться на собственную инфраструктуру ведения журналов. Мы не можем найти ничего особенного в документации.

Есть ли готовое решение, которое мы можем использовать, не предлагая собственное решение?

почему вы не можете получить значение заголовка Request-Id? Если для входящего запроса установлен заголовок Request-Id, ядро ​​asp.net использует его значение как CorrelationId в сообщениях журнала. это делается автоматически.

Jehof 13.09.2018 14:19

Идентификатор запроса, который регистрируется, - это TraceIdentifier.

Jehof 13.09.2018 14:23

Привет, @Jehof, как уже упоминалось, мы не смогли найти способ получить request-id в последующих запросах. Не могли бы вы дать нам образец кода для достижения этой цели?

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

Ответы 3

Я использовал Serilog для входа в ядро ​​dotnet и нажимал свойства LogContext с помощью промежуточного программного обеспечения -

CorrelationMiddleware.cs

    public class CorrelationMiddleware
    {
    readonly RequestDelegate _next;

    public CorrelationMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        context.Request.Headers.TryGetValue(Headers.Correlation, out StringValues correlationId);

        using (LogContext.PushProperty("Correlation-Id", correlationId.FirstOrDefault()))
        {
            await _next.Invoke(context);
        }
    }
}

Зарегистрируйте это в своем методе настройки Startup.cs:

app.UseMiddleware<CorrelationLogger>();

Затем при исходящем http-вызове вы можете добавить заголовок в HttpRequestMessage, добавив

request.Headers.Add(Headers.Correlation, GetHeader("Correlation-Id"));

При поиске в журналах мы можем выполнить поиск по идентификатору корреляции и просмотреть полный список всех API ...

Привет, @David, мы, безусловно, можем использовать этот подход, и это запасной вариант. Но мы хотели избежать этого, поскольку у сервисов API могли быть разные владельцы команд. Вместо создания собственного «настраиваемого» промежуточного программного обеспечения мы искали что-то из коробки, что может быть единообразным для разных команд, и больше «стандартного», выходящего из официальный ASP.NET Core SDK. Надеюсь, я понимаю.

Ankit Vijay 14.09.2018 01:54

Не уверен, связано ли это напрямую, но мы сталкиваемся с той же проблемой при сопоставлении запросов между API и службами в проектах Service Fabric. В итоге мы установили и получили correlationId из CallContext (внутри System.Runtime.Remoting.Messaging). Случайно только что написал что-то об этом здесь. Пожалуйста, посмотрите, поможет ли это.

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

Я задал тот же вопрос @davidfowl в Твиттере. Он ответил:

No there's nothing out of the box for this. There's an end to end that works with app insights but it isn't very fleshed out. You might consider just using the same middleware across teams. if There's a work item to address this in 3.0 https://github.com/aspnet/Hosting/issues/1350

Итак, из того, что сейчас кажется, что пользовательское промежуточное ПО - единственный путь вперед. Это может измениться в будущем выпуске.

Обновлять

В итоге мы создали специальное промежуточное ПО, как предлагал @DavidMcEleney. Однако, помимо этого, мы добавили CorrelationId в свойство AsyncLocal. Это помогло нам получить доступ к CorrelationId в любом месте кода, если / когда это необходимо. Вот код получения / установки CorrelationId:

using System;
using System.Threading;

public static class CorrelationContext
{
    private static readonly AsyncLocal<string> CorrelationId = new AsyncLocal<string>();

    public static void SetCorrelationId(string correlationId)
    {
        if (string.IsNullOrWhiteSpace(correlationId))
        {
            throw new ArgumentException(nameof(correlationId), "Correlation id cannot be null or empty");
        }

        if (!string.IsNullOrWhiteSpace(CorrelationId.Value))
        {
            throw new InvalidOperationException("Correlation id is already set");
        }

        CorrelationId.Value = correlationId;
    }

    public static string GetCorrelationId()
    {
        return CorrelationId.Value;
    }
}

Для использования в CorrelationMiddleware.cs

public class CorrelationMiddleware
{
    private readonly RequestDelegate _next;

    public CorrelationMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        context.Request.Headers.TryGetValue("Correlation-Id-Header", out var correlationIds);

        var correlationId = correlationIds.FirstOrDefault() ?? Guid.NewGuid().ToString();

        CorrelationContext.SetCorrelationId(correlationId);

        using (LogContext.PushProperty("Correlation-Id", correlationId))
        {
            await _next.Invoke(context);
        }
    }
}

Если нам понадобится доступ к CorrelationId в любом месте кода позже, мы просто вызываем: CorrelationContext.GetCorrelationId();

Ага, я это видел. Спасибо еще раз.

Ankit Vijay 14.09.2018 23:17

пожалуйста, также проверьте другую бесплатную библиотеку: github.com/albumprinter/CorrelationTracking/wiki

Ivan Akcheurov 01.07.2019 19:54

Привет @AnkitVijay Я знаю, что этому вопросу один год, но мне было интересно: почему вы решили создать статическую функцию, а не регистрировать службу для каждого запроса, сохраняя значение? Он был бы доступен для всех других сервисов через DI и, как мне кажется, можно было бы избежать всей сложности AsyncLocal.

dpnevmatikos 24.06.2020 15:27

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