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

.NET6 API对接Datadog错误追踪属性解析/导出异常问题

问题:.NET6 API + OpenTelemetry + Datadog 异常属性转换错误

我有一个.NET6 API项目,使用OpenTelemetry(otel)进行埋点,追踪数据发送至Datadog,采用otel/opentelemetry-collector-contrib:latest镜像接收应用遥测数据后转发至Datadog。

配置了ExceptionMiddleware捕获所有异常并创建Span属性,同时参照Datadog官方文档配置Otel处理器,将exception属性转换为Datadog标准的error属性,但出现以下异常情况:

  • exception.type被错误转换为error.message
  • exception.message被忽略
  • error.type丢失
    仅exception.stacktrace正常转换为error.stack。即使直接在代码中设置error属性,也会出现完全相同的问题。

ExceptionMiddleware代码

public async Task InvokeAsync(HttpContext context)
{
    string userId = GetUserId(context);
    try
    {
        await this._next(context);
    }
    catch (BusinessException bex)
    {
        LogWarning(bex);
        UpdateSpan(bex, userId);
        await this.HandleBadRequest(bex.Message, bex.StackTrace, context);
    }
    catch (Exception ex)
    {
        LogError(ex);
        string errorId = UpdateSpan(ex, userId);

        await this.HandleInternalServerError($"ErrorId: {errorId}", ex.StackTrace, context);
    }
}

private static string UpdateSpan(Exception ex, string userId)
{
    Activity activity = Activity.Current;
    if (activity == null)
        return _defaultActivityId;

    string errorId = activity.Id.ToString();
    activity?.SetStatus(ActivityStatusCode.Error, ex.Source);

    activity?.SetTag("exception.message", ex.Message);
    activity?.SetTag("exception.stacktrace", ex.StackTrace);
    activity?.SetTag("exception.type", ex.Source);

    return errorId;
}

private void LogWarning(BusinessException bex)
{
    Dictionary<string, object> errorDict = BuildExceptionAtributes(bex);

    using (_logger.BeginScope(errorDict))
    {
        _logger.LogWarning(bex.Message);

    };
}

private void LogError(Exception ex)
{
    Dictionary<string, object> errorDict = BuildExceptionAtributes(ex);

    using (_logger.BeginScope(errorDict))
    {
        _logger.LogError(ex.Message);
    };
}


private static Dictionary<string, object> BuildExceptionAtributes(Exception ex)
{
    var errorDict = new Dictionary<string, object>()
    {
        // otel
        ["exception.message"] = ex.Message,
        ["exception.stacktrace"] = ex.StackTrace,
        ["exception.type"] = ex.Source,
    };
    return errorDict;
}

Otel处理器配置(config.yaml)

# This is a configuration file for the OpenTelemetry Collector intended to be
# used in conjunction with the OTLP Exporter example (see ../TestOtlpExporter.cs)
#
# For more information about the OpenTelemetry Collector see:
#   https://github.com/open-telemetry/opentelemetry-collector
#
receivers:
  otlp:
    protocols:
      grpc:
      http:

exporters:
  logging:
    verbosity: detailed
  datadog:
    api:
      key: some-key
      # site: 

processors:
  # https://github.com/open-telemetry/opentelemetry-collector/blob/main/processor/batchprocessor/README.md
  batch:
  attributes/insert:
    actions:
      - key: "error.message"
        action: "insert"
        from_attribute: "exception.message"
  attributes/insert2:
    actions:
      - key: "error.stack"
        action: "insert"
        from_attribute: "exception.stacktrace"
  attributes/insert3:
    actions:
      - key: "error.type"
        action: "insert"
        from_attribute: "exception.type"
      

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [batch, attributes/insert, attributes/insert2, attributes/insert3]
      exporters: [logging, datadog]
    metrics:
      receivers: [otlp]
      exporters: [logging, datadog]
    logs:
      receivers: [otlp]
      exporters: [logging, datadog]

直接设置error属性的代码

private static string UpdateSpan(Exception ex, string userId)
{
    Activity activity = Activity.Current;
    if (activity == null)
        return _defaultActivityId;

    string errorId = activity.Id.ToString();
    activity?.SetStatus(ActivityStatusCode.Error, ex.Source);
    activity?.SetTag("kinvo.user.id", userId);

    activity?.SetTag("exception.message", ex.Message);
    activity?.SetTag("exception.stacktrace", ex.StackTrace);
    activity?.SetTag("exception.type", ex.Source);

    // sending directly
    activity?.SetTag("error.message", ex.Message);
    activity?.SetTag("error.stack", ex.StackTrace);
    activity?.SetTag("error.type", ex.Source);

    return errorId;
}

异常输出示例

{
    "exception": {
        "message": "Object reference not set to an instance of an object.",
        "stacktrace": "at blablabla.GetConnection(Int64 userId, Nullable`1 version) in blablabla.cs:line 36",
        "type": "blablabla.WebApi"
    },
    "error": {
        "message": "blablabla.WebApi",
        "stack": "at blablabla.GetConnection(Int64 userId, Nullable`1 version) in blablabla.cs:line 36",
        "type": "does-not-show"
    }
}

解决方案

1. 修正Exception.type的赋值错误

当前代码中exception.type使用ex.Source(异常来源程序集名称),而非真正的异常类型。需替换为ex.GetType().FullName获取完全限定的异常类型名:

// UpdateSpan方法中修改
activity?.SetTag("exception.type", ex.GetType().FullName);

// BuildExceptionAtributes方法中同步修改
["exception.type"] = ex.GetType().FullName,

2. 移除手动属性转换,依赖Datadog自动映射

Datadog的Otel Exporter原生支持将OpenTelemetry的exception.*属性自动映射为Datadog标准error.*属性,手动配置的attributes处理器会与自动映射逻辑冲突,导致属性覆盖。简化配置如下:

processors:
  batch:

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [batch]
      exporters: [logging, datadog]
    metrics:
      receivers: [otlp]
      exporters: [logging, datadog]
    logs:
      receivers: [otlp]
      exporters: [logging, datadog]

3. 修正Span状态描述

将Span状态的描述信息从ex.Source改为ex.Message,确保错误信息准确:

activity?.SetStatus(ActivityStatusCode.Error, ex.Message);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 17:43:17