OpenTelemetry 与 Python 结合使用入门

导航至

这篇文章由 Mercy Kibet 撰写,她是一位全栈开发人员,热衷于学习和撰写关于新兴和有趣的科技堆栈的文章。

在当今的数字世界中,软件应用程序正变得越来越复杂和分布式,这使得在问题出现时诊断和排除故障比以往任何时候都更具挑战性。OpenTelemetry 是一个强大的可观测性框架,它将帮助您和您的运营团队获得对应用程序和基础设施的可见性,从而使您能够快速识别和解决问题。

OpenTelemetry 通过提供收集、处理和导出遥测数据的标准化方法,已成为任何希望构建和维护高性能软件应用程序的组织必不可少的工具。这篇文章将向您介绍如何将 OpenTelemetry 与 Python 结合使用。

Python 中的 OpenTelemetry

OpenTelemetry 是一个开源的可观测性框架,用于从您的应用程序和基础设施收集遥测数据。遥测数据包括指标、跟踪和日志。

OpenTelemetry 是供应商无关的,这意味着您可以将其与多种监控和日志记录工具一起使用。它支持不同的编程语言,包括 Python。其多功能性和灵活性使其成为一个强大的可观测性工具。

以下是 OpenTelemetry 在 Python 中工作的一般流程

  • Instrumentation(检测):第一步是检测代码以生成遥测数据。您可以使用 OpenTelemetry SDK 来完成此操作。

  • 数据收集:一旦您检测了代码,OpenTelemetry 代理或 SDK 将从检测后的代码中收集遥测数据,例如跟踪、指标和日志。

  • 数据处理:OpenTelemetry 收集器从代理或 SDK 接收遥测数据,并对数据执行额外的处理,例如过滤、聚合和丰富。然后,将处理后的数据发送到后端以进行存储和分析。

  • 数据导出:最后一步是将遥测数据导出到后端,例如监控或日志记录系统,以进行可视化、分析和警报。OpenTelemetry 支持与各种后端集成,包括流行的监控工具,如 Prometheus、Grafana 和 Jaeger 等。

自动检测

自动检测 是 OpenTelemetry 框架的功能,它无需手动配置或代码更改即可检测应用程序并从中收集遥测数据。您可以使用 Python 的检测库以及与流行的框架(如 Fast API、Django 和 Flask)的集成来完成此操作。

检测库使用代码修改、字节码注入和函数包装等技术。这使得库能够拦截应用程序代码并收集遥测数据,包括跟踪、指标和日志,而无需更改应用程序代码。

自动检测消除了手动配置和代码更改,并且它提供了一种一致且标准化的方法来跨不同的应用程序和框架收集遥测数据。

手动检测

与自动检测不同,手动检测 需要您修改应用程序的代码以收集相关的指标数据。当自动检测不可行或提供的覆盖范围不足时,您将使用手动检测。例如,如果应用程序使用自定义协议或自动检测库不支持的框架,开发人员可能需要手动检测应用程序以收集遥测数据。

虽然手动检测需要付出更多努力,但它可以提供对收集的遥测数据更精细的控制,并收集自动检测库未涵盖的数据。

如何在 Python 中使用 OpenTelemetry

现在我们将向您展示如何在 Python 中使用 OpenTelemetry。我们将使用 Fast API 创建一个简单的 CRUD 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 附带了开放 API,您可以查询您的端点以确保它们按预期工作。

uvicorn main:app --reload

现在启动 Jaeger。为了确保它正在运行,请访问 localhost:16686。您正在使用 Jaeger 来收集和可视化应用程序跟踪。

opentelemetry-python

您需要检测您的代码以将遥测数据推送回 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,您将使用它来创建一个 span。span 表示一个工作单元,它是更大的分布式系统的一部分。您可以使用上下文管理器或装饰器来创建一个,并且可以使用它来跟踪请求在系统中多个服务中流动的路径。

tracer = trace.get_tracer(__name__)

您可以使用 get_tracer() 方法创建一个 tracer 实例。接下来,您将使用上下文管理器创建一个 span,如下所示,您将在其中调用您上面创建的 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。您可以通过在 Web 浏览器中导航到 http://localhost:16686 来查看 Jaeger UI 中的跟踪。

结论

OpenTelemetryPython 中是一个强大而灵活的可观测性框架,它允许您从分布式系统收集遥测数据,包括跟踪、指标和日志。它提供了一个强大而灵活的可观测性解决方案,您可以使用它来监控和调试任何复杂程度的分布式系统。它对自动和手动检测的支持,以及对多种语言和遥测数据类型的支持,使其成为任何寻求提高其分布式系统的可观测性和可靠性的组织的宝贵工具。