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

OpenTelemetry+Blazor Hybrid:Spans/Activities无法输出至控制台/文件

解决方案:.NET8 Blazor Hybrid中OpenTelemetry+NLog的正确配置

1. 修复ActivitySource.StartActivity返回null的核心问题

关键调整点

  • 保证名称完全匹配:TelemetryConstants.ActivitySource的Name必须和AddSource(TelemetryConstants.ServiceName)中的名称完全一致,否则OTel监听器无法识别自定义Activity。
  • 避免无效Activity创建:在Telemetry类中提前检查是否有活跃的监听器,防止创建无意义的Activity实例:
public Telemetry([CallerMemberName] string methodName = "")
{
    _MethodName = methodName;
    // 先判断是否有监听器,再创建Activity
    if (TelemetryConstants.ActivitySource.HasListeners())
    {
        _Activity = TelemetryConstants.ActivitySource.StartActivity(_MethodName);
        AddTag("operation.datetimeoffset.utcnow.begin", DateTimeOffset.UtcNow.ToString(_DateFormat));
    }
}

2. 过滤冗余日志并优化性能

当前大量无价值的Microsoft.AspNetCore.Components.RenderTree.Renderer日志、全局Trace级别是性能卡顿的主要原因,修改日志配置:

builder.Logging.ClearProviders();
// 降低全局最低日志级别为Debug,减少冗余输出
builder.Logging.SetMinimumLevel(LogLevel.Debug);
// 直接屏蔽Blazor渲染树的日志
builder.Logging.AddFilter("Microsoft.AspNetCore.Components.RenderTree", LogLevel.None);
builder.Logging.AddNLog();

3. 简化OpenTelemetry配置,避免重复导出

你当前的配置同时启用了追踪和日志的OTel导出,导致重复输出和性能损耗,调整为只保留自定义Activity的追踪配置:

builder.Services.AddOpenTelemetry()
    .ConfigureResource(resource => 
        resource.AddService(serviceName: TelemetryConstants.ServiceName, serviceVersion: TelemetryConstants.ServiceVersion)
    )
    .WithTracing(tracing =>
    {
        tracing
            .AddSource(TelemetryConstants.ServiceName)
            // 仅采样自定义Activity,排除.NET默认库的追踪
            .SetSampler(new AlwaysOnSampler())
            .AddConsoleExporter(options =>
            {
                options.Targets = OpenTelemetry.Exporter.ConsoleExporterOutputTargets.Debug;
            });
    });

// 移除重复的Logging.AddOpenTelemetry()配置

4. 将Activity耗时等信息输出到NLog文件

方式一:在Telemetry类中直接记录日志

修改Telemetry类,注入ILogger并在Dispose时计算耗时写入日志:

private readonly ILogger<Telemetry> _logger;

// 通过依赖注入获取Logger
public Telemetry(ILogger<Telemetry> logger, [CallerMemberName] string methodName = "")
{
    _logger = logger;
    _MethodName = methodName;
    if (TelemetryConstants.ActivitySource.HasListeners())
    {
        _Activity = TelemetryConstants.ActivitySource.StartActivity(_MethodName);
        AddTag("operation.begin", DateTimeOffset.UtcNow.ToString(_DateFormat));
    }
}

public void Dispose()
{
    if (_Activity != null)
    {
        var endTime = DateTimeOffset.UtcNow;
        AddTag("operation.end", endTime.ToString(_DateFormat));
        // 计算并记录耗时
        var beginTime = DateTimeOffset.Parse(_Activity.Tags.First(t => t.Key == "operation.begin").Value);
        var duration = endTime - beginTime;
        _logger.LogInformation("Activity {ActivityName} finished, Duration: {Duration}ms", _MethodName, duration.TotalMilliseconds);
        _Activity.Dispose();
    }
    GC.SuppressFinalize(this);
}

使用时通过依赖注入获取Telemetry:

using (var telemetry = _serviceProvider.GetRequiredService<Telemetry>())
using (_Logger.BeginScope($"{nameof(DeleteTblEventChoice)}:{eventChoiceId}"))
{
    _Logger.LogDebug($"Delete {nameof(tblEventChoices)} with ID: [{eventChoiceId}]");
    return _TblEventChoicesRepository.DeleteTblEventChoice(eventChoiceId);
}

方式二:使用OTel直接导出Activity到NLog

安装OpenTelemetry.Exporter.NLog包后,在Tracing配置中添加NLog导出器:

.WithTracing(tracing =>
{
    tracing
        .AddSource(TelemetryConstants.ServiceName)
        .AddNLogExporter();
});

同时在NLog.config中配置对应的日志目标,接收OTel追踪数据。

5. 完整MauiProgram.cs配置示例

var builder = MauiApp.CreateBuilder();

// 其他服务注册逻辑...

// OpenTelemetry配置
builder.Services.AddOpenTelemetry()
    .ConfigureResource(resource => 
        resource.AddService(serviceName: TelemetryConstants.ServiceName, serviceVersion: TelemetryConstants.ServiceVersion)
    )
    .WithTracing(tracing =>
    {
        tracing
            .AddSource(TelemetryConstants.ServiceName)
            .SetSampler(new AlwaysOnSampler())
            .AddConsoleExporter(options =>
            {
                options.Targets = OpenTelemetry.Exporter.ConsoleExporterOutputTargets.Debug;
            });
            // 若使用NLog导出Activity,取消注释并安装对应包
            // .AddNLogExporter();
    });

// 日志配置
builder.Logging.ClearProviders();
builder.Logging.SetMinimumLevel(LogLevel.Debug);
builder.Logging.AddFilter("Microsoft.AspNetCore.Components.RenderTree", LogLevel.None);
builder.Logging.AddNLog();

// 注册Telemetry为瞬态服务
builder.Services.AddTransient<Telemetry>();

var app = builder.Build();

// 应用启动逻辑...

验证要点

  • StartActivity不再返回null
  • 控制台和NLog文件仅输出自定义Activity的耗时日志及必要业务日志
  • 应用运行无明显卡顿

内容的提问来源于stack exchange,提问作者B-M

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 08:25:17