Добавить пользовательские свойства в запрос телеметрии на уровне контроллера - PullRequest
0 голосов
/ 20 февраля 2019

Я пытаюсь добавить определенные свойства в запрос телеметрии для каждого маршрута.Немного покопавшись, я обнаружил, что могу создать свой собственный TelemetryInitializer, внедрив ITelemetryInitializer.Сделав это, мне удалось добавить глобальные свойства в запрос.Тем не менее, мне все еще нужно добавить определенные свойства на уровне контроллера.У вас есть идеи, как мне этого добиться?

Я пытался внедрить TelemetryClient в контроллер, но если я его использую, свойства разделяются между запросами.

Вот как япопытался войти в контроллер:

private TelemetryClient telemetryClient;

public ValueController(TelemetryClient telemetryClient)
{
    this.telemetryClient = telemetryClient;
}

[HttpGet]
public async Task<IActionResult> RouteOne([FromQuery(Name = "param1")]string param1, [FromQuery(Name = "param2")]string param2)
{                     
      telemetryClient.Context.GlobalProperties["param1"] = param1;
      telemetryClient.Context.GlobalProperties["param2"] = param2;
}

[HttpGet]
public async Task<IActionResult> RouteTwo([FromQuery(Name = "param3")]string param3, [FromQuery(Name = "param4")]string param4)
{                     
      telemetryClient.Context.GlobalProperties["param3"] = param3;
      telemetryClient.Context.GlobalProperties["param4"] = param4;
}

И это реализация ITelemetryInitializer:

public class CustomPropertiesTelemetryInitializer : ITelemetryInitializer
{
    private readonly IHttpContextAccessor httpContextAccessor;

    public CustomPropertiesTelemetryInitializer(IHttpContextAccessor httpContextAccessor)
    {
        this.httpContextAccessor = httpContextAccessor;
    }

    public void Initialize(ITelemetry telemetry)
    {
        telemetry.Context.GlobalProperties["RequestId"] = httpContextAccessor.HttpContext.GetProperty("requestId");
        telemetry.Context.GlobalProperties["Ip"] = httpContextAccessor.HttpContext?.Connection.RemoteIpAddress.ToString();
        telemetry.Context.GlobalProperties["RoutePath"] = httpContextAccessor.HttpContext?.Request.Path;           
    }
}

Ответы [ 2 ]

0 голосов
/ 20 февраля 2019

Ключевым моментом здесь является использование структуры DI.Вы можете использовать его для передачи данных или сервисов в рамках запроса в ваши ITelemetryInitializer.

(Эти примеры основаны на стандартной инфраструктуре внедрения зависимостей ASP.Net. Этот шаблон должен работать с любой структурой DI, но его необходимо немного отрегулировать.)

Сначала создайте класс для представления вашей телеметрии в области запросов.Я использовал простой DTO, но это также может быть сервис, который знает, как извлекать / генерировать данные самостоятельно.Зарегистрируйте его, используя AddScoped.«Scoped» означает, что новый экземпляр будет создаваться для каждого HTTP-запроса, а затем этот экземпляр будет повторно использоваться в этом запросе.

Поскольку я использовал DTO, я не стал беспокоиться об интерфейсе-вы должны использовать интерфейс, если класс содержит любую логику, которую вы хотите смоделировать в модульных тестах.

public class RequestScopedTelemetry 
{
    public string MyCustomProperty { get; set; }
}
services.AddScoped<RequestScopedTelemetry>();

Теперь создайте ITelemetryInitializer и зарегистрируйте его как одиночный.App Insights обнаружит и использует его через инфраструктуру DI.

class RequestScopedTelemetryInitializer : ITelemetryInitializer
{
    readonly IHttpContextAccessor httpContextAccessor;

    public RequestScopedTelemetryInitializer(IHttpContextAccessor httpContextAccessor)
        => this.httpContextAccessor = httpContextAccessor;

    public void Initialize(ITelemetry telemetry)
    {
        // Attempt to resolve the request-scoped telemetry from the DI container
        var requestScopedTelemetry = httpContextAccessor
            .HttpContext?
            .RequestServices?
            .GetService<RequestScopedTelemetry>();

        // RequestScopedTelemetry is only available within an active request scope
        // If no telemetry available, just move along...
        if (requestScopedTelemetry == null)
            return;

        // If telemetry was available, add it to the App Insights telemetry collection
        telemetry.Context.GlobalProperties[nameof(RequestScopedTelemetry.MyCustomProperty)]
            = requestScopedTelemetry.MyCustomProperty;
    }
}
services.AddSingleton<ITelemetryInitializer, RequestScopedTelemetryInitializer>();

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

public class ExampleController : ControllerBase
{
    readonly RequestScopedTelemetry telemetry;

    public ValuesController(RequestScopedTelemetry telemetry)
        => this.telemetry = telemetry;

    [HttpGet]
    public ActionResult Get()
    {
        telemetry.MyCustomProperty = "MyCustomValue";

        // Do what you want to

        return Ok();
    }
}
0 голосов
/ 20 февраля 2019

Если добавленные вами свойства всегда похожи на «paramxxx», то есть обходной путь (но на самом деле это не очень элегантно).

В конструкторе контроллера проверьте GlobalProperties, если он содержит ключ типа «paramxxx»":

public ValueController(TelemetryClient telemetryClient)
{
    this.telemetryClient = telemetryClient;
    var props = this.telemetryClient.Context.GlobalProperties;
            foreach (var p in props)
            {
                if (p.Key.Contains("param"))
                {
                    props.Remove(p.Key);
                }
            }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...