OpenTelemetry与Python联合使用入门指南
作者:社区 / 开发者
2023年5月22日
导航至
本文由Mercy Kibet撰写,她是一位热衷于学习和撰写关于新技术栈的全栈开发者。
在当今的数字世界中,软件应用程序变得越来越复杂和分布式,这使得在问题出现时诊断和排错变得更加困难。OpenTelemetry是一个强大的可观察性框架,可以帮助您和您的运维团队深入了解您的应用程序和基础设施,从而快速识别和解决问题。
OpenTelemetry已成为任何希望构建和维护高性能软件应用程序的组织的必要工具,它通过提供一种标准化的方式来收集、处理和导出遥测数据。
Python中的OpenTelemetry
OpenTelemetry是一个开源的可观察性框架,它从您的应用程序和基础设施中收集遥测数据。遥测数据包括指标、跟踪和日志。
OpenTelemetry是供应商无关的,这意味着您可以将其与多个监控和日志工具一起使用。它支持包括Python在内的多种编程语言。其灵活性和通用性使其成为一个强大的可观察性工具。
以下是在Python中使用OpenTelemetry的一般流程
-
仪器化:第一步是对代码进行仪器化以生成遥测数据。您可以使用OpenTelemetry SDK来完成此操作。
-
数据收集:一旦您对代码进行了仪器化,OpenTelemetry代理或SDK将从仪器化代码中收集遥测数据,例如跟踪、指标和日志。
-
数据处理:OpenTelemetry 收集器从代理或 SDK 接收遥测数据,并执行额外的数据处理,如过滤、聚合和丰富数据。然后,将处理后的数据发送到后端进行存储和分析。
-
数据导出:最后一步是将遥测数据导出到后端,如监控或日志系统,以进行可视化、分析和警报。OpenTelemetry 支持与各种后端集成,包括 Prometheus、Grafana 和 Jaeger 等流行的监控工具。
自动仪器化
自动仪器化 是 OpenTelemetry 框架的一种能力,能够对需要无需手动配置或代码更改的应用程序进行仪器化和收集遥测数据。您可以使用 Python 的仪器化库以及与 Fast API、Django 和 Flask 等流行框架的集成来实现这一点。
仪器化库使用代码修改、字节码注入和函数包装等技术。这使得库能够拦截应用程序代码并收集遥测数据,包括跟踪、指标和日志,而无需更改应用程序代码。
自动仪器化消除了手动配置和代码更改,并为在不同应用程序和框架之间收集遥测数据提供了一种一致和标准化的方式。
手动仪器化
与自动仪器化不同,手动仪器化 需要您修改应用程序代码以收集相关指标数据。当自动仪器化不可行或提供不足的覆盖范围时,您将使用手动仪器化。例如,如果应用程序使用由自动仪器化库不支持的定制协议或框架,则开发人员可能需要手动仪器化应用程序以收集遥测数据。
虽然手动仪器化需要更多的努力,但它可以提供对收集的遥测数据的更细粒度控制,并收集自动仪器化库无法覆盖的数据。
如何在 Python 中使用 OpenTelemetry
现在我们将向您展示如何使用 Python 中的 OpenTelemetry。我们将创建一个简单的 CRUD API,使用 Fast API。
先决条件
为了跟进,您需要安装和配置 Python 3.8+、Jaeger 和 Docker。
首先创建一个文件夹,切换到该文件夹,然后设置虚拟环境。然后激活虚拟环境。
mkdir opentelemetry-python
cd open telemetry-python
#creating a virtual environment
pip3 -m venv env
#activating virtual environment for mac and linux
source env/bin/activate
#activating for windows
env\Scripts\activate
接下来,安装 Fast API 和 Uvicorn,并将要求冻结到 requirements.txt 文件中。
pip install fastapi uvicorn[standard]
#freezing the dependencies
pip freeze > requirements.txt
然后创建一个简单的待办事项列表应用程序,您可以创建、读取、更新和删除(CRUD)待办事项。我们将使用列表或数组来存储我们的待办事项。基本上,端点将操作数组。以下是在 main.py 文件中包含所有端点的示例代码。
from fastapi import FastAPI
from pydantic import BaseModel
class Todo(BaseModel):
id: int
title: str
description: str
app = FastAPI()
todos: list[dict[str, str | int]] = [
{
"id": 1,
"title": "My first todo item",
"description": "This is what I'll do first before moving on"
},
{
"id": 2,
"title": "My second todo item",
"description": "This is what I'll do second before moving on"
}
]
@app.get("/", tags=["Root"])
def test_route() -> dict:
return {"hello": "world"}
@app.get("/todos", tags=["Todos"])
def get_todos() -> dict:
return {"data": todos}
@app.get("/todos/{id}", tags=["Todos"])
def get_todo_with_id(id: int) -> list[dict]:
return list(filter(lambda todo: todo['id'] == id, todos))
@app.post("/todos", tags=["Todos"])
def create_todo(todo: Todo):
todos.append(todo)
return {"data": todos}
@app.put("/todos/{id}", tags=["Todos"])
def update_todo(id: int, body: dict):
for todo in todos:
if (int(todo["id"])) == id:
todo["title"] = body["title"]
todo["description"] = body["description"]
return {
"data": f"Todo with id {id} has been updated"
}
return {
"data": f"This Todo with id {id} is not found!"
}
@app.delete("/todos/{id}", tags=["Todos"])
def delete_todo(id: int):
for todo in todos:
if int(todo["id"]) == id:
todos.remove(todo)
return {"data": "Todo deleted!"}
return {
"data": f"Todo with id {id} not found!"
}
运行您的应用程序,并导航到端点 localhost:8000/docs。由于 Fast API 随附 open API,您可以查询端点以确保它们按预期工作。
uvicorn main:app --reload
现在启动 Jaeger。为了确保它正在运行,请访问 localhost:16686。您正在使用 Jaeger 收集和可视化应用程序跟踪。
您需要仪器化您的代码,以将遥测数据推送到 Jaeger,以便在运行时了解应用程序正在做什么。这样,您的应用程序服务名称将出现在服务下拉菜单中。为此,请安装 OpenTelemetry 的 Python API 和 SDK。
在下一节中,我们将探索两种类型的仪器化:自动和手动。
Python 中的 OpenTelemetry 自动仪器化
由于您正在使用 Fast API,您可以利用 OpenTelemetry 的自动跟踪。首先,使用 PIP 安装 opentelemetry-distro。
pip install opentelemetry-distro
安装 opentelemetry-distro 可以让您访问 opentelemetry-bootstrap,您将使用它来安装 Fast API 库。要查看您可以安装的模块列表,请使用以下命令:
opentelemetry-bootstrap -a requirements
您应该会看到要安装的 Fast API 版本。在列表中找到它,然后使用 PIP 复制并安装。或者,您可以复制并添加到 requirements.txt 中,然后运行 pip install。
接下来,您需要将您的遥测数据(跟踪)导出到 Jaeger。为此,您需要安装默认导出器,因为 Jaeger 使用 OpenTelemetry 协议(OTLP)。
pip install opentelemetry-exporter-otlp-proto-grpc
最后,通过使用 opentelemetry-instrument 包装您的应用程序并声明一个服务名称,以便 Jaeger 可以识别它并收集其跟踪来运行您的应用程序。
opentelemetry-instrument --service_name my-app uvicorn main:app
或者,您可以将导出器设置为控制台,您的跟踪和指标将输出到终端的 JSON 格式。
opentelemetry-instrument --traces_exporter console --metrics_exporter console --service_name my_app uvicorn main:app
Python 中的 OpenTelemetry 手动仪器化
在这里,我们将修改代码以包含可观察性。如上所述,可观察性发生在您的应用程序的入站和出站流量边界,这意味着您对内部发生的确切情况访问有限。但通过手动仪器化,您可以创建可以窥视您的端点发生了什么的跨度。这样,您就可以轻松地排除错误。
由于您已经安装了所需的包,现在您可以导入它们并初始化提供程序。对于这个案例,您正在收集跟踪,因此您可以设置跟踪提供程序。
from opentelemetry import trace
from opentelemetry.exporter.jaeger.proto.grpc import JaegerExporter
from opentelemetry.sdk.resources import SERVICE_NAME, Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
resource = Resource(attributes={
SERVICE_NAME: "my-app"
})
jaeger_exporter = JaegerExporter()
provider = TracerProvider(resource=resource)
processor = BatchSpanProcessor(jaeger_exporter)
provider.add_span_processor(processor)
trace.set_tracer_provider(provider)
接下来,初始化一个用于创建跨度的追踪器。跨度表示一个属于更大分布式系统的工作单元。您可以使用上下文管理器或装饰器来创建一个,并使用它来跟踪请求在系统中通过多个服务时的路径。
tracer = trace.get_tracer(__name__)
您使用 get_tracer() 方法创建追踪器实例。接下来,您将使用上下文管理器创建跨度,如下所示,您将在上面创建的追踪器实例上调用 start_as_current_span() 方法并传递“get_todos_span”名称。
@app.get("/todos", tags=["Todos"])
def get_todos() -> dict:
with tracer.start_as_current_span("get_todos_span"):
return {"data": todos}
Alternatively, instead of using the context manager, you could use a decorator (like shown below) to start your span with the name "get_todos_span"
@tracer.start_as_current_span("get_todos_span"):
def get_todos() -> dict:
return {"data": todos}
有了这些步骤,您的 Fast API 应用程序应该会向 Jaeger 发送跟踪。您可以通过在您的网页浏览器中导航到 https://127.0.0.1:16686 来在 Jaeger UI 中查看跟踪。
结论
Python 中的 OpenTelemetry 是一个强大且灵活的可观察性框架,允许您从分布式系统中收集遥测数据,包括跟踪、指标和日志。它提供了一个强大且灵活的可观察性解决方案,您可以使用它来监控和调试任何复杂性的分布式系统。它对自动和手动仪器化的支持,以及它对多种语言和遥测数据类型的支持,使其成为任何寻求提高其分布式系统可观察性和可靠性的组织的宝贵工具。