You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从C#应用直接导出OpenTelemetry(Otel)数据至Azure Data Explorer(ADX)后端?

直接从C#应用导出OpenTelemetry数据到Azure Data Explorer(无需Collector)

方案概述

你可以通过自定义OpenTelemetry导出器结合Azure Data Explorer(ADX)的批量摄入API实现直接导出,无需依赖OpenTelemetry Collector。以下是具体实现步骤:

步骤1:准备ADX环境

  • 创建ADX集群和目标数据库
  • 为C#应用创建服务主体,并赋予该主体数据库的ingestor权限(用于写入数据)
  • 在ADX中创建对应Otel数据类型的表,示例结构:
    // 轨迹表示例
    .create table Traces (Timestamp:datetime, TraceId:string, SpanId:string, ParentSpanId:string, Name:string, Duration:timespan, Attributes:dynamic, StatusCode:string, StatusDescription:string)
    // 指标表示例
    .create table Metrics (Timestamp:datetime, Name:string, Value:real, Labels:dynamic)
    // 日志表示例
    .create table Logs (Timestamp:datetime, Severity:string, Message:string, Attributes:dynamic)
    

步骤2:安装必要的NuGet包

  • 基础OpenTelemetry包:
    Install-Package OpenTelemetry
    Install-Package OpenTelemetry.Extensions.Hosting
    Install-Package OpenTelemetry.Instrumentation.AspNetCore // Web应用需安装
    
  • ADX SDK包(用于调用摄入API):
    Install-Package Microsoft.Azure.Kusto.Data
    Install-Package Microsoft.Azure.Kusto.Ingest
    

步骤3:实现自定义OpenTelemetry导出器

以导出轨迹数据为例,创建实现BaseExporter<Activity>的导出器:

using OpenTelemetry;
using OpenTelemetry.Trace;
using Microsoft.Azure.Kusto.Ingest;
using System.Collections.Generic;
using System.Threading;
using Newtonsoft.Json;

public class AdxTraceExporter : BaseExporter<Activity>
{
    private readonly IKustoIngestClient _ingestClient;
    private readonly string _databaseName;
    private readonly string _tableName;

    public AdxTraceExporter(string adxIngestUri, string databaseName, string tableName, string clientId, string clientSecret, string tenantId)
    {
        _databaseName = databaseName;
        _tableName = tableName;

        var kustoConnString = new KustoConnectionStringBuilder(adxIngestUri)
            .WithAadApplicationKeyAuthentication(clientId, clientSecret, tenantId);
        
        _ingestClient = KustoIngestFactory.CreateQueuedIngestClient(kustoConnString);
    }

    public override ExportResult Export(in Batch<Activity> batch)
    {
        var traceRows = new List<string>();
        foreach (var activity in batch)
        {
            // 将Activity转换为ADX兼容的CSV行格式
            var attributesJson = JsonConvert.SerializeObject(activity.Attributes.ToDictionary(kv => kv.Key, kv => kv.Value));
            var row = $"{activity.StartTimeUtc:yyyy-MM-dd HH:mm:ss.fff},{activity.TraceId},{activity.SpanId},{activity.ParentSpanId}," +
                      $"\"{activity.Name}\",{activity.Duration.TotalMilliseconds},{attributesJson}," +
                      $"\"{activity.Status}\",\"{activity.StatusDescription ?? string.Empty}\"";
            traceRows.Add(row);
        }

        // 批量提交至ADX
        var ingestProps = new KustoIngestionProperties(_databaseName, _tableName)
        {
            Format = DataSourceFormat.Csv,
            IgnoreFirstRecord = false
        };

        _ingestClient.IngestFromString(traceRows, ingestProps);
        return ExportResult.Success;
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            _ingestClient?.Dispose();
        }
        base.Dispose(disposing);
    }
}

步骤4:在C#应用中配置OpenTelemetry

在Program.cs中注册导出器并启用相关 instrumentation:

var builder = WebApplication.CreateBuilder(args);

// 配置OpenTelemetry追踪
builder.Services.AddOpenTelemetry()
    .WithTracing(tracing => tracing
        .AddAspNetCoreInstrumentation()
        .AddConsoleExporter() // 可选,本地调试用
        .AddExporter(sp => new AdxTraceExporter(
            adxIngestUri: builder.Configuration["Adx:IngestUri"],
            databaseName: builder.Configuration["Adx:Database"],
            tableName: "Traces",
            clientId: builder.Configuration["Adx:ClientId"],
            clientSecret: builder.Configuration["Adx:ClientSecret"],
            tenantId: builder.Configuration["Adx:TenantId"])));

var app = builder.Build();
// 其他应用配置...
app.Run();

关键注意事项

  • 批量写入优化:ADX适合批量写入,建议在导出器中设置批量阈值(比如攒够100条再提交),避免频繁小批量写入影响性能
  • 数据格式校验:确保Otel数据转换后的格式与ADX表结构完全匹配,比如datetime格式、dynamic类型的JSON序列化规则
  • 权限验证:服务主体必须拥有ADX数据库的ingestor权限,否则会写入失败
  • 异常处理:生产环境需添加异常捕获和重试逻辑,避免数据丢失

内容的提问来源于stack exchange,提问作者shivi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 10:37:29