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