.NET OpenTelemetry

Материал из Документация Ключ-АСТРОМ
Версия от 09:35, 15 октября 2025; IKuznetsov (обсуждение | вклад)
(разн.) ← Предыдущая | Текущая версия (разн.) | Следующая → (разн.)

В этом пошаговом руководстве показано, как добавить возможность наблюдения в ваше .NET-приложение с помощью библиотек и инструментов .NET OpenTelemetry.

Особенность Поддержка
Автоматические инструменты Да
Трассировки Да
Метрики Да
Логи Да

Предустановка

  • Ключ-АСТРОМ версии 1.254+
  • Для трассировки включен контекст трассировки W3C.
    1. Перейдите в Настройки > Предпочтения > Функции ЕдиногоАгента.
    2. Включите опцию Отправлять HTTP-заголовки контекста трассировки W3C.

Получение данных для доступа к Ключ-АСТРОМ

Определение базовых URL API

Подробную информацию о сборке базового URL-адреса конечной точки OTLP см. в разделе Экспорт с помощью OTLP. URL-адрес должен заканчиваться на /api/v2/otlp.

Получение токена доступа API

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

Экспорт с помощью OTLP содержит более подробную информацию о формате и необходимых областях доступа.

Выберите, как вы хотите инструментировать свое приложение

Для .NET OpenTelemetry поддерживает автоматическое и ручное инструментирование (или их комбинацию).

Какой инструментарий выбрать?

Рекомендуется начать с автоматического измерения и добавить ручное измерение, если автоматический подход не работает или не дает достаточно информации.

Автоматическое инструментирование приложения (необязательно)

Автоматизированное инструментирование .NET можно настроить как во время разработки, так и позже, после развертывания.

Расширение с помощью ЕдиногоАгента

В настоящее время невозможно автоматически дополнять сервисы информацией, относящейся к хосту. Для этого потребуется перейти на ручное инструментирование.

В процессе разработки

1. Установите OpenTelemetry.Extensions.Hosting.

dotnet add package OpenTelemetry.Extensions.Hosting

2. Установите соответствующую библиотеку инструментов для вашей платформы .NET (полный список доступен здесь).

dotnet add package OpenTelemetry.Instrumentation.[FRAMEWORK_NAME]

После развертывания

  1. Загрузите последнюю версию автоматического установщика для целевой операционной системы.
  2. Запустите (в Unix) или импортируйте (в Windows) автоматический установщик, чтобы установить и настроить все необходимые библиотеки автоматического инструментирования.
  3. Запустите ваше приложение.

Помимо описанной выше настройки инструментария, необходимо также настроить соответствующие параметры экспорта с помощью переменных среды. Это включает URL конечной точки, токен аутентификации и временные настройки для метрик.

OTEL_EXPORTER_OTLP_ENDPOINT=[URL]

OTEL_EXPORTER_OTLP_HEADERS="Authorization=Api-Token [TOKEN]"

OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE=delta

Инструментирование приложения вручную (необязательно)

Настройка

Шаги настройки немного различаются в зависимости от того, инструментируете ли вы обычное приложение .NET или приложение ASP.NET.

.NET

1. Установите следующие пакеты.

dotnet add package Microsoft.Extensions.Logging

dotnet add package OpenTelemetry.Extensions.Hosting

dotnet add package OpenTelemetry

dotnet add package OpenTelemetry.Api

dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol

2. Добавьте следующие операторы using в класс запуска, который инициирует загрузку вашего приложения.

using OpenTelemetry;

using OpenTelemetry.Trace;

using OpenTelemetry.Exporter;

using OpenTelemetry.Metrics;

using OpenTelemetry.Logs;

using OpenTelemetry.Resources;

using OpenTelemetry.Context.Propagation;

using System.Diagnostics;

using System.Diagnostics.Metrics;

using Microsoft.Extensions.Logging;

3. Добавьте эти поля в класс запуска, причем первые два должны содержать данные о доступе, если вы используете экспорт OTLP.

private static string DT_API_URL = ""; // TODO: Provide your SaaS/Managed URL here

private static string DT_API_TOKEN = ""; // TODO: Provide the OpenTelemetry-scoped access token here

private const string activitySource = "astromkey.DotNetApp.Sample"; // TODO: Provide a descriptive name for your application here

public static readonly ActivitySource MyActivitySource = new ActivitySource(activitySource);

private static ILoggerFactory loggerFactoryOT;

4. Добавьте метод initOpenTelemetry в класс запуска и вызовите его как можно раньше при запуске приложения. Это инициализирует OpenTelemetry для бэкенда Ключ-АСТРОМ и создаст поставщиков трассировки и метрик по умолчанию.

private static void initOpenTelemetry(IServiceCollection services)

{

    List<KeyValuePair<string, object>> dt_metadata = new List<KeyValuePair<string, object>>();

    foreach (string name in new string[] {"dt_metadata_e617c525669e072eebe3d0f08212e8f2.properties",

                                          "/var/lib/astromkey/enrichment/dt_metadata.properties",

                                          "/var/lib/astromkey/enrichment/dt_host_metadata.properties"}) {

        try {

            foreach (string line in System.IO.File.ReadAllLines(name.StartsWith("/var") ? name : System.IO.File.ReadAllText(name))) {

                var keyvalue = line.Split("=");

                dt_metadata.Add( new KeyValuePair<string, object>(keyvalue[0], keyvalue[1]));

            }

        }

        catch { }

    }

   

    Action<ResourceBuilder> configureResource = r => r

        .AddService(serviceName: "dotnet-quickstart") //TODO Replace with the name of your application

        .AddAttributes(dt_metadata);

   

    services.AddOpenTelemetry()

        .ConfigureResource(configureResource)

        .WithTracing(builder => {

            builder

                .SetSampler(new AlwaysOnSampler())

                .AddSource(MyActivitySource.Name)

                .AddOtlpExporter(options =>

                {

                    options.Endpoint = new Uri(Environment.GetEnvironmentVariable("DT_API_URL")+ "/v1/traces");

                    options.Protocol = OpenTelemetry.Exporter.OtlpExportProtocol.HttpProtobuf;

                    options.Headers = $"Authorization=Api-Token {Environment.GetEnvironmentVariable("DT_API_TOKEN")}";

                });

        })

        .WithMetrics(builder => {

            builder

                .AddMeter("my-meter")

                .AddOtlpExporter((OtlpExporterOptions exporterOptions, MetricReaderOptions readerOptions) =>

                {

                    exporterOptions.Endpoint = new Uri(Environment.GetEnvironmentVariable("DT_API_URL")+ "/v1/metrics");

                    exporterOptions.Headers = $"Authorization=Api-Token {Environment.GetEnvironmentVariable("DT_API_TOKEN")}";

                    exporterOptions.Protocol = OpenTelemetry.Exporter.OtlpExportProtocol.HttpProtobuf;

                    readerOptions.TemporalityPreference = MetricReaderTemporalityPreference.Delta;

                });

            });

   

    var resourceBuilder = ResourceBuilder.CreateDefault();

    configureResource!(resourceBuilder);

   

    loggerFactoryOT = LoggerFactory.Create(builder => {

        builder

            .AddOpenTelemetry(options => {

                options.SetResourceBuilder(resourceBuilder).AddOtlpExporter(options => {

                    options.Endpoint = new Uri(Environment.GetEnvironmentVariable("DT_API_URL")+ "/v1/logs");

                    options.Headers = $"Authorization=Api-Token {Environment.GetEnvironmentVariable("DT_API_TOKEN")}";

                    options.ExportProcessorType = OpenTelemetry.ExportProcessorType.Batch;

                    options.Protocol = OtlpExportProtocol.HttpProtobuf;

                });

            })

            .AddConsole();

    });

    Sdk.CreateTracerProviderBuilder()

        .SetSampler(new AlwaysOnSampler())

        .AddSource(MyActivitySource.Name)

        .ConfigureResource(configureResource);

    // add-logging

}

Расширение данных Ключ-АСТРОМ

Операции чтения файлов, анализирующие файлы dt_metadata в примере кода, пытаются прочитать файлы данных ЕдиногоАгента, чтобы расширить запрос OTLP и гарантировать, что вся соответствующая информация о топологии доступна в Ключ-АСТРОМ.

ASP.NET

1. Установите следующие пакеты.

dotnet add package Microsoft.Extensions.Logging

dotnet add package OpenTelemetry.Extensions.Hosting

dotnet add package OpenTelemetry

dotnet add package OpenTelemetry.Api

dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol

dotnet add package OpenTelemetry.Instrumentation.AspNetCore

dotnet add package OpenTelemetry.Instrumentation.Http

dotnet add package OpenTelemetry.Instrumentation.Runtime

2. Добавьте следующие операторы using в класс запуска, который инициирует загрузку вашего приложения.

using OpenTelemetry;

using OpenTelemetry.Trace;

using OpenTelemetry.Exporter;

using OpenTelemetry.Metrics;

using OpenTelemetry.Logs;

using OpenTelemetry.Resources;

using OpenTelemetry.Context.Propagation;

using System.Diagnostics;

using System.Diagnostics.Metrics;

using Microsoft.Extensions.Logging;

using OpenTelemetry.Instrumentation.AspNetCore;

3. Добавьте эти поля в класс запуска, причем первые два должны содержать данные о доступе, если вы используете экспорт OTLP.

private static string DT_API_URL = ""; // TODO: Provide your SaaS/Managed URL here

private static string DT_API_TOKEN = ""; // TODO: Provide the OpenTelemetry-scoped access token here

private const string activitySource = "astromkey.DotNetApp.Sample"; // TODO: Provide a descriptive name for your application here

public static readonly ActivitySource MyActivitySource = new ActivitySource(activitySource);

private static ILoggerFactory loggerFactoryOT;

4. Добавьте метод initOpenTelemetry в класс запуска и вызовите его как можно раньше при запуске приложения. Это инициализирует OpenTelemetry для бэкенда Ключ-АСТРОМ и создаст поставщиков трассировки и метрик по умолчанию.

private static void initOpenTelemetry(){

    var port = System.Environment.GetEnvironmentVariable("PORT") ?? "8080";

    var appBuilder = WebApplication.CreateBuilder();

    appBuilder.WebHost.ConfigureKestrel(options =>{

        options.ListenAnyIP(Convert.ToInt32(port)); // hardcoding the port

    });

    List<KeyValuePair<string, object>> dt_metadata = new List<KeyValuePair<string, object>>();

    foreach (string name in new string[] {"dt_metadata_e617c525669e072eebe3d0f08212e8f2.properties",

                                          "/var/lib/astromkey/enrichment/dt_metadata.properties",

                                          "/var/lib/astromkey/enrichment/dt_host_metadata.properties"}) {

        try {

            foreach (string line in System.IO.File.ReadAllLines(name.StartsWith("/var") ? name : System.IO.File.ReadAllText(name))) {

                var keyvalue = line.Split("=");

                dt_metadata.Add( new KeyValuePair<string, object>(keyvalue[0], keyvalue[1]));

            }

        }

        catch { }

    }

    Action<ResourceBuilder> configureResource = r => r

        .AddService(serviceName: "dotnetManual") //TODO Replace with the name of your application

        .AddAttributes(dt_metadata);

    appBuilder.Services.AddOpenTelemetry()

        .ConfigureResource(configureResource)

        .WithTracing(builder =>{

            appBuilder.Services.Configure<AspNetCoreTraceInstrumentationOptions>(appBuilder.Configuration.GetSection("AspNetCoreInstrumentation"));

            builder

                .AddSource(MyActivitySource.Name)

                .SetSampler(new AlwaysOnSampler())

                .AddHttpClientInstrumentation()

                .AddAspNetCoreInstrumentation()

                .AddOtlpExporter(otlpOptions =>{

                    otlpOptions.Endpoint = new Uri(Environment.GetEnvironmentVariable("DT_API_URL")+ "/v1/traces");

                    otlpOptions.Protocol = OpenTelemetry.Exporter.OtlpExportProtocol.HttpProtobuf;

                    otlpOptions.Headers = $"Authorization=Api-Token {Environment.GetEnvironmentVariable("DT_API_TOKEN")}";

                });

        })

        .WithMetrics(builder =>{

            builder

                .AddMeter("my-meter")

                // .AddMeter(Instrumentation.MeterName)

                .AddRuntimeInstrumentation()

                .AddHttpClientInstrumentation()

                .AddAspNetCoreInstrumentation()

                .AddOtlpExporter((OtlpExporterOptions exporterOptions, MetricReaderOptions readerOptions) => {

                    exporterOptions.Endpoint = new Uri(Environment.GetEnvironmentVariable("DT_API_URL")+ "/v1/metrics");

                    exporterOptions.Headers = $"Authorization=Api-Token {Environment.GetEnvironmentVariable("DT_API_TOKEN")}";

                    exporterOptions.Protocol = OpenTelemetry.Exporter.OtlpExportProtocol.HttpProtobuf;

                    readerOptions.TemporalityPreference = MetricReaderTemporalityPreference.Delta;

            });

            appBuilder.Logging.ClearProviders();

            appBuilder.Logging.AddOpenTelemetry(options =>

            {

                var resourceBuilder = ResourceBuilder.CreateDefault();

                configureResource(resourceBuilder);

                options.SetResourceBuilder(resourceBuilder);

                options.AddOtlpExporter(otlpOptions => {

                    otlpOptions.Endpoint = new Uri(Environment.GetEnvironmentVariable("DT_API_URL")+ "/v1/logs");

                    otlpOptions.Headers = $"Authorization=Api-Token {Environment.GetEnvironmentVariable("DT_API_TOKEN")}";

                    otlpOptions.ExportProcessorType = OpenTelemetry.ExportProcessorType.Batch;

                    otlpOptions.Protocol = OtlpExportProtocol.HttpProtobuf;

                });

            });

            appBuilder.Services.AddControllers();

            appBuilder.Services.AddEndpointsApiExplorer();

            var app = appBuilder.Build();

            app.MapControllers();

            app.Run();

    });

}

Расширение данных Ключ-АСТРОМ

Операции чтения файлов, анализирующие файлы dt_metadata в примере кода, пытаются прочитать файлы данных ЕдиногоАгента, чтобы расширить запрос OTLP и гарантировать, что вся соответствующая информация о топологии доступна в Ключ-АСТРОМ.

Добавление трассировки

Используя шаг настройки MyActivitySource, теперь мы можем начать новые действия (трассировки):

using var activity = Startup.MyActivitySource.StartActivity("Call to /myendpoint", ActivityKind.Consumer, parentContext.ActivityContext);

activity?.SetTag("http.method", "GET");

activity?.SetTag("net.protocol.version", "1.1");

В приведенном выше коде мы:

  • Создали новое действие (span) и назвали его «Call to /myendpoint».
  • Добавили два тега (атрибута), следуя семантическому соглашению об именовании, специфичному для действия этого диапазона: информация о методе HTTP и версии

Активность будет автоматически установлена ​​как текущая и активная область до тех пор, пока поток выполнения не выйдет за пределы области действия текущего метода. Последующие активности автоматически станут дочерними областями.

Сбор метрик

1. Для создания новых метрических инструментов нам сначала нужен объект метрики.

private static readonly Meter meter = new Meter("my-meter", "1.0.0");  //TODO Replace with the name of your meter

2. С помощью meter мы теперь можем создавать отдельные инструменты, например, метрики.

private static readonly Counter<long> counter = meter.CreateCounter<long>("request_counter");

3. Теперь мы можем вызвать метод Add() для записи новых значений counter с помощью нашей метрики и сохранения дополнительных атрибутов (например, action.type).

counter.Add(1, new("ip", "an ip address here"), new("some other key", "some other value"));

Подключение логов

Используя переменную loggerFactoryOT, которую мы инициализировали в разделе «Настройка», мы теперь можем создавать отдельные экземпляры регистратора, которые будут передавать регистрируемую информацию напрямую в настроенную конечную точку OpenTelemetry в Ключ-АСТРОМ.

var logger = loggerFactoryOT.CreateLogger<Startup>();

services.AddSingleton<ILoggerFactory>(loggerFactoryOT);

services.AddSingleton(logger);

logger.LogInformation(eventId: 123, "Log line");

Обеспечение распространения контекста (необязательно)

Распространение контекста особенно важно, когда задействованы сетевые вызовы (например, REST).

Если вы используете автоматическое инструментирование и ваши сетевые библиотеки также им охватываются, то это будет автоматически реализовано библиотеками инструментирования. В противном случае ваш код должен это учитывать.

Извлечение контекста при получении запроса

В следующем примере мы предполагаем, что получили сетевой вызов через System.Web.HttpRequest, и определяем экземпляр CompositeTextMapPropagator для извлечения контекстной информации из HTTP-заголовков. Затем мы передаем этот экземпляр в Extract(), возвращая объект контекста, что позволяет нам продолжить предыдущую трассировку с нашими интервалами.

private CompositeTextMapPropagator propagator = new CompositeTextMapPropagator(new TextMapPropagator[] {

    new TraceContextPropagator(),

    new BaggagePropagator(),

});

private static readonly Func<HttpRequest, string, IEnumerable<string>> valueGetter = (request, name) => request.Headers[name];

var parentContext = propagator.Extract(default, HttpContext.Request, valueGetter);

using var activity = MyActivitySource.StartActivity("my-span", ActivityKind.Consumer, parentContext.ActivityContext);

Внедрение контекста при отправке запросов

В следующем примере мы отправляем REST-запрос к другой службе и предоставляем наш существующий контекст как часть HTTP-заголовков нашего запроса.

Для этого мы определяем экземпляр TextMapPropagator, который добавляет соответствующую информацию. После создания экземпляра REST-объекта мы передаём его вместе с контекстом и экземпляром сеттера в Inject(), который добавит необходимые заголовки к запросу.

private CompositeTextMapPropagator propagator = new CompositeTextMapPropagator(new TextMapPropagator[] {

    new TraceContextPropagator(),

    new BaggagePropagator()

});

private static Action<HttpRequestMessage, string, string> _headerValueSetter => (request, name, value) => {

    request.Headers.Remove(name);

    request.Headers.Add(name, value);

};

propagator.Inject(new PropagationContext(activity!.Context, Baggage.Current), request, _headerValueSetter);

Настройка сбора данных в соответствии с требованиями конфиденциальности (необязательно)

Хотя Ключ-АСТРОМ автоматически собирает все атрибуты OpenTelemetry, в веб-интерфейсе Ключ-АСТРОМ сохраняются и отображаются только значения атрибутов, указанные в списке разрешенных. Это предотвращает случайное сохранение персональных данных, позволяя вам соблюдать требования к конфиденциальности и контролировать объем хранимых данных мониторинга.

Чтобы просматривать пользовательские атрибуты, необходимо сначала разрешить их использование в веб-интерфейсе Ключ-АСТРОМ.

Проверка загрузки данных в Ключ-АСТРОМ

После завершения инструментирования вашего приложения выполните несколько тестовых действий для создания и отправки демонстрационных трассировок, метрик и логов, а также проверьте, что они были правильно загружены в Ключ-АСТРОМ.

Чтобы сделать это для трассировок, перейдите в раздел Трассировки и выберите вкладку Распределенные трассировки. Если вы используете ЕдиныйАгент, выберите PurePaths .

Для просмотра метрик и логов перейдите в раздел Метрики или Логов или Логи и события.