Fastapi接入opentelemetry链路追踪

1,554 阅读2分钟

简介

以下简介为 chatgpt 生成

fastapi

FastAPI 是一个基于 Python 的现代、快速(高性能)的 Web 框架,用于构建 API。它兼具简洁性、易用性和高效性,是构建可伸缩、异步和高并发 API 的理想选择。

opentelemetry

Opentelemetry是一个用于监视和跟踪分布式系统的开源观测工具。它旨在提供一致的、可扩展的方式来收集和传输分布式跟踪数据、度量和日志以分析和优化系统性能。

本文涉及的技术栈

jaeger 快速搭建可以参考我的 helm 快速部署系列文章

环境准备

Poetry是一个用于Python项目管理和依赖项管理的工具。它旨在提供简单、一致且可靠的方式来创建、构建和发布Python项目。

使用 new 命令快速创建一个 fast 项目

poetry new fast

安装依赖

cd fast
poetry add opentelemetry-instrumentation-fastapi opentelemetry-instrumentation-redis opentelemetry-distro opentelemetry-exporter-otlp opentelemetry-exporter-otlp-proto-grpc "uvicorn[standard]"

代码开发

开发简单的 fastapi 代码,此处创建一个 startup hook 预设一个 redis key,方便后续使用,一个 / 路由,返回 redis 结果

from fastapi import FastAPI
from opentelemetry import trace
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import \
    OTLPSpanExporter
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
from opentelemetry.instrumentation.redis import RedisInstrumentor
from opentelemetry.sdk.resources import SERVICE_NAME, Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import SimpleSpanProcessor
from opentelemetry.sdk.trace.sampling import ParentBased, TraceIdRatioBased
from redis import Redis

# 设置 SERVICE_NAME, 用于在 jaeger 中显示
resource = Resource(attributes={SERVICE_NAME: "fast"})

# 设置 resource 和采样率, 1 为 全采样
provider = TracerProvider(sampler=ParentBased(TraceIdRatioBased(1)), resource=resource)
processor = SimpleSpanProcessor(
    OTLPSpanExporter(
        # 修改 JAEGER_HOST 为真实 jaeger 地址
        endpoint="http://{JAEJER_HOST}:4317/v1/traces",
    )
)
provider.add_span_processor(processor)

# 设置默认 provider
trace.set_tracer_provider(provider)

app = FastAPI()

redis = Redis(host="127.0.0.1")

# 增加 fastapi 指标
FastAPIInstrumentor().instrument_app(app)

# 增加 redis 指标
RedisInstrumentor().instrument()

redis_key = "hello"
redis_value = "world"


# fastapi 启动 hook,为 redis 预设一个值
@app.on_event("startup")
def startup():
    redis.set(redis_key, redis_value)


@app.get("/")
def home():
    result = redis.get(redis_key)
    return {"hello": result}

启动服务

# fast.main是文件main路径,app 是 fastapi 实例变量 --reload 方便开发中修改代码实时生效
uvicorn fast.main:app --port 5000 --reload
# windows 为 curl.exe
curl http://localhost:5000/

结果

image.png

image.png

这样就可以很方便查看链路调用情况了