

























项目简介:本仓库是一个实战指南与示例集合,展示了如何在不同版本的 ABP 框架(从传统的 .NET Framework 4.6.2 到现代的 Volo.Abp)中集成 OpenTelemetry (OTel),并将可观测性数据(Tracing, Logs, Metrics)统一输出到开源观测平台 SigNoz。
作为开发者,你是否曾为这些问题困扰过?
如果你对以上任何一点深感共鸣,那么是时候了解 OpenTelemetry(简称OTel) 和 SigNoz 这个组合了。它们一个定义了开放标准,一个提供了开箱即用的实现。
想象一下,你的应用是一个由微服务、数据库、消息队列组成的复杂城市。过去,每个组件(或APM厂商)都说着自己的“方言”(私有协议),导致沟通成本极高。
OpenTelemetry (OTel) 就是为解决这个问题而生的。 它由CNCF孵化,目标是为可观测性数据(追踪、指标、日志)提供一套与供应商无关的、统一的采集和传输标准。你可以把它理解为可观测性领域的“普通话”或“USB-C接口”。
它的核心优势在于:
Signoz 是一个基于 OpenTelemetry、ClickHouse、Go、TypeScript/React 等技术栈构建的开源可观测性平台,用于统一采集、分析和可视化日志、指标和链路追踪数据。
技术架构

SigNoz - 日志性能基准测试(与ElasticSearch、Loki比较)
ClickHouse vs. Elasticsearch:十亿行数据的较量
使用 Docker Compose 快速安装:
https://signoz.io/docs/install/docker/
git clone -b main https://github.com/SigNoz/signoz.git && cd signoz/deploy/
cd docker
docker compose up -d --remove-orphans

安装完成后,访问 http://127.0.0.1:8080 即可看到 SigNoz 的仪表盘。

本仓库包含针对不同 ABP 版本的集成方案,请根据你的项目背景选择:
| 项目名称 | 框架版本 | 说明 | 快速跳转 |
|---|---|---|---|
| AbpFramework | .NET Framework 4.6.2 | 适用于传统的 ABP (Legacy) 项目,集成 log4net 日志导出。 | 查看详情 |
| AbpCore | .NET Core 3.1+ | 适用于标准的 ABP 框架(基于 .NET Core 版本)。 | 查看详情 |
| VoloAbp | .NET 6/8+ | 适用于最新的 Volo.Abp (vNext) 框架集成。 | 查看详情 |
集成通过AOP(面向切面编程)拦截器实现了应用内方法的自动追踪,并在以下监控维度中清晰地展现了效果:






以下是一个简单的服务类方法,其调用链将被追踪。方法内记录了日志,便于在Traces和Logs中关联观察。
public virtual void Test()
{
Logger.LogInformation($"{nameof(BookAppService)}.{nameof(Test)}");
TestPublic();
TestPublicVirtual();
TestPrivate();
}
public virtual void TestPublic()
{
Logger.LogInformation($"{nameof(BookAppService)}.{nameof(TestPublic)}");
}
public virtual void TestPublicVirtual()
{
Logger.LogInformation($"{nameof(BookAppService)}.{nameof(TestPublicVirtual)}");
}
private void TestPrivate()
{
Logger.LogInformation($"{nameof(BookAppService)}.{nameof(TestPrivate)}");
}
VoloAbp中通过定义的OTelActivityInterceptor,它继承自Volo.Abp框架的AbpInterceptor。该拦截器负责在目标方法执行前后自动创建和停止OpenTelemetry的Activity,从而实现无侵入式的耗时追踪。AbpFramework OTelActivityInterceptor 与AbpCore OTelActivityInterceptor基本类似
public class OTelActivityInterceptor : AbpInterceptor, ITransientDependency
{
private readonly ActivitySource _activitySource;
//private readonly IJsonSerializer _jsonSerializer;
private readonly ILogger<OTelActivityInterceptor> _logger;
private readonly IConfiguration _configuration;
private readonly OTelOptions _oTelOptions;
public OTelActivityInterceptor(
ActivitySource activitySource,
//IJsonSerializer jsonSerializer,
ILogger<OTelActivityInterceptor> logger,
IConfiguration configuration,
IOptionsSnapshot<OTelOptions> oTelOptions
)
{
_activitySource = activitySource;
//_jsonSerializer = jsonSerializer;
_logger = logger;
_configuration = configuration;
_oTelOptions = oTelOptions.Value;
}
public override async Task InterceptAsync(IAbpMethodInvocation invocation)
{
_logger.LogDebug($"方法调用前:{invocation.Method.DeclaringType?.Name}.{invocation.Method.Name}");
if (!_oTelOptions.Enabled)
{
await invocation.ProceedAsync();
return;
}
if (!OTelActivityHelper.IsOTelActivityMethod(invocation.Method, out var oTelActivityAttribute))
{
await invocation.ProceedAsync();
return;
}
// https://opentelemetry.io/docs/languages/dotnet/traces/best-practices/
Activity activity = null;
try
{
activity = _activitySource.StartActivity(invocation.Method.DeclaringType?.Name + "." + invocation.Method.Name);
//if (activity != null && activity.IsAllDataRequested == true)
//{
// activity.SetTag("", "");
//}
}
finally
{
await invocation.ProceedAsync();
activity?.Stop();
activity?.Dispose();
}
_logger.LogDebug($"方法调用后:{invocation.Method.DeclaringType?.Name}.{invocation.Method.Name}");
}
}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。