Elastic APM 在多个层面上支持 OpenTelemetry。一个易于理解的场景(我们之前在博客中介绍过)是 APM Server 中对 OpenTelemetry 协议 (OTLP) 的直接支持。这意味着您可以将任何 OpenTelemetry Agent 连接到 Elastic APM Server,APM Server 将愉快地接收该数据,将其摄入到 Elasticsearch® 中,并且您可以在 Kibana® 的 APM 应用程序中查看 OpenTelemetry 数据。
这篇博文将展示一个不同的用例:在 Elastic APM 中,我们有我们自己的 APM Agent。其中一些的下载量达数千万次,并且其中一些早于 OpenTelemetry。当然,我们意识到 OpenTelemetry 非常重要,并且它将长期存在,因此我们希望使这些 Agent 与 OpenTelemetry 兼容,并使用本博客中的OpenTelemetry 可视化来演示它们。
我们今天的大多数 Elastic APM Agent 都能够将 OpenTelemetry Span 作为追踪的一部分进行发送。这意味着,如果您的应用程序中有任何组件发出 OpenTelemetry Span,它将成为 Elastic APM Agent 捕获的追踪的一部分。这可能是您使用的已由 OpenTelemetry API 检测的库,也可能是应用程序开发人员为手动检测添加到应用程序代码中的任何其他 OpenTelemetry Span。
Elastic APM Agent 的此功能不仅报告这些 Span,而且还正确地维护所有 Span 之间的父子关系,使 OpenTelemetry 成为这些 Agent 的一等公民。例如,如果 Elastic APM Agent 通过自动检测为特定操作启动一个 Span,然后在该 Span 内 OpenTelemetry API 启动另一个 Span,则 OpenTelemetry Span 将成为 Agent 创建的外部 Span 的子 Span。这反映在 Span 的 parent.id 字段中。反过来也是如此:如果通过 OpenTelemetry API 创建一个 Span,并且在该 Span 内 Elastic APM Agent 捕获另一个 Span,则 Elastic APM Agent 创建的 Span 将成为通过 OpenTelemetry API 创建的另一个 Span 的子 Span。
以下 Agent 中存在此功能
在 Elastic .NET APM Agent 中捕获 OpenTelemetry Span
作为第一个示例,让我们以一个 ASP.NET Core 应用程序为例。我们将 .NET Elastic APM Agent 放入此应用程序中,并启用该功能,该功能会自动桥接 OpenTelemetry Span,因此 Elastic APM Agent 将使这些 Span 成为其报告的追踪的一部分。
以下代码片段显示了一个控制器
namespace SampleAspNetCoreApp.Controllers
{
public class HomeController : Controller
{
private readonly SampleDataContext _sampleDataContext;
private ActivitySource _activitySource = new ActivitySource("HomeController");
public HomeController(SampleDataContext sampleDataContext) => _sampleDataContext = sampleDataContext;
public async Task<IActionResult> Index()
{
await ReadGitHubStars();
return View();
}
public async Task ReadGitHubStars()
{
using var activity = _activitySource.StartActivity();
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Add("User-Agent", "APM-Sample-App");
var responseMsg = await httpClient.GetAsync("https://api.github.com/repos/elastic/apm-agent-dotnet");
var responseStr = await responseMsg.Content.ReadAsStringAsync();
// …use responseStr
}
}
}
Index 方法调用 ReadGitHubStars 方法,然后我们只从该方法返回相应的视图。
传入的 HTTP 调用和 HttpClient 发出的传出 HTTP 调用均由 Elastic APM Agent 自动捕获 — 这是我们长期以来拥有的自动检测的一部分。
ReadGitHubStars 是我们使用 OpenTelemetry API 的地方。.NET 中的 OpenTelemetry 使用 ActivitySource 和 Activity API。_activitySource.StartActivity() 调用只是创建一个 OpenTelemetry Span,它通过使用 CallerMemberNameAttribute C# 语言功能自动获取方法的名称,并且此 Span 将在方法运行完成时结束。
此外,在此 Span 内,我们使用 HttpClient 类型调用 GitHub API。对于此类型,.NET Elastic APM Agent 再次提供自动检测,因此 HTTP 调用也将由 Agent 自动捕获为一个 Span。
以下是 Kibana 中此事务的水流图
如您所见,Agent 能够捕获作为追踪一部分的 OpenTelemetry Span。
通过使用 Python Elastic APM Agent 桥接 Python 中的 OpenTelemetry Span
让我们看看它在 Python 中的工作方式。这个想法是相同的,因此先前介绍的所有概念也适用于此示例。
我们以一个非常简单的 Django 示例为例
from django.http import HttpResponse
from elasticapm.contrib.opentelemetry import Tracer
import requests
def index(request):
tracer = Tracer(__name__)
with tracer.start_as_current_span("ReadGitHubStars"):
url = "https://api.github.com/repos/elastic/apm-agent-python"
response = requests.get(url)
return HttpResponse(response)
在 Python 中启用捕获 OpenTelemetry Span 的第一步是从 elasticapm.contrib.opentelemetry 导入 Tracer 实现。
然后,在此 Tracer 上,您可以启动一个新的 Span — 在这种情况下,我们手动命名 Span 为 ReadGitHubStars。
与之前的示例类似,对 http://127.0.0.1:8000/otelsample/ 的调用由 Elastic APM Python Agent 捕获,然后下一个 Span 由 OpenTelemetry API 创建,如您所见,它由 Agent 自动捕获,最后,对 GitHub API 的 HTTP 调用再次由 Agent 的自动检测捕获。
以下是它在水流图中的显示方式
正如之前提到的,代理会维护所有 OTel span 的父子关系。让我们来看看 GET api.github.com 调用的 parent.id。
如你所见,这个 span 的 id 是 c98401c94d40b87a。
如果我们查看 ReadGitHubStars OpenTelemetry span 的 span.id,我们可以看到这个 span 的 id 正好是 c98401c94d40b87a — 因此 APM 代理在内部维护了 OpenTelemetry 和非 OpenTelemetry span 之间的父子关系,这使得 OpenTelemetry span 在 Elastic APM 代理中成为了一等公民。
其他语言
此时,我将停止在更多语言中复制完全相同的示例代码 — 我想你已经理解了这一点:在上面列出的每种语言中,我们的 Elastic APM 代理都能够桥接 OpenTelemetry 跟踪并在 Kibana 中将其显示为原生 span。我们还在 博客中介绍了如何在 Java 中使用相同的 API,你可以在相应的代理文档(上面链接)中看到其他语言的示例。
何时使用此功能以及何时使用纯 OpenTelemetry SDK
这完全取决于你。如果你只想在应用程序中使用纯 OpenTelemetry,并且你真的想避免任何与供应商相关的软件,那么请随意直接使用 OpenTelemetry SDK — 这是我们明确支持的用例。如果你选择这条路,此功能与你无关。
但是,我们的 Elastic APM 代理已经拥有非常庞大的用户群,并且它们提供了 OpenTelemetry 中没有的功能。其中一些功能包括 span 压缩、中央配置、推断 span、与多个 APM 服务器的分布式 尾部采样,以及更多功能。
如果你是许多现有 Elastic APM 代理用户之一,或者你计划使用 Elastic APM 代理是因为上述功能,那么桥接 OpenTelemetry span 使你仍然可以使用 OpenTelemetry API,而无需依赖任何与供应商相关的 API 使用。这样,你的开发团队可以使用 OpenTelemetry 来检测你的应用程序,你也可以使用任何已经由 OpenTelemetry 检测的第三方库,并且 Elastic APM 代理会很乐意将这些 span 作为其报告的跟踪的一部分进行报告。有了这个,你可以结合 OpenTelemetry 的供应商独立性,并仍然使用功能丰富的 Elastic APM 代理。
如果你希望将你的遥测库从 Elastic APM 代理更改为 OpenTelemetry(反之亦然),OpenTelemetry 桥接功能也是一个很好的工具,因为它允许你同时使用这两个库,并使用原子更改来切换它们。
下一步
在这篇博文中,我们讨论了如何使用 Elastic APM 代理桥接 OpenTelemetry span。当然,OpenTelemetry 不仅仅是跟踪。我们知道这一点,并且我们计划涵盖更多领域:目前,我们正在以非常类似的方式在 Elastic APM 代理中桥接 OpenTelemetry 指标。你可以在 此处 观看进展。