분산 추적 구현하기
분산 추적 구현하기
때로는 여러 서비스에 걸쳐 요청을 추적해야 할 때가 있어요.
LangSmith는 분산 추적을 기본으로 지원하며, 컨텍스트 전파 헤더(langsmith-trace와 메타데이터/태그용 옵션 baggage)를 사용해 서비스 간에 트레이스 내의 런을 연결해요.
클라이언트-서버 설정 예시:
- 트레이스가 클라이언트에서 시작
- 서버에서 계속
신뢰할 수 있는 서비스의 분산 추적 헤더만 수락하세요.
langsmith-trace와baggage헤더는 신뢰되는 추적 컨텍스트로 사용돼요. 신뢰할 수 없는 제3자나 공개 인터넷에서 직접 요청을 받는 서비스에는TracingMiddleware를 추가하지 마세요(또는 인바운드 요청 헤더를 추적parent로 전달하지 마세요). 분산 추적은 내부 서비스 간 호출로 제한하고, 게이트웨이나 프록시에서 신뢰할 수 없는 인바운드 요청의 이러한 헤더를 제거하세요. 외부 호출자의baggage를 신뢰하면 그들이 런이 어떻게 기록되는지에 영향을 줄 수 있어요.
출처: 문서
본문
Python의 분산 추적
# client.py
from langsmith.run_helpers import get_current_run_tree, traceable
import httpx
@traceable
async def my_client_function():
headers = {}
async with httpx.AsyncClient(base_url="...") as client:
if run_tree := get_current_run_tree():
# add langsmith-id to headers
headers.update(run_tree.to_headers())
return await client.post("/my-route", headers=headers)
그런 다음 서버(또는 다른 서비스)는 헤더를 적절히 처리해 트레이스를 계속할 수 있어요. asgi 앱 Starlette이나 FastAPI를 사용한다면 LangSmith의 TracingMiddleware로 분산 트레이스를 연결할 수 있어요.
TracingMiddleware클래스는langsmith==0.1.133에서 추가됐어요.
FastAPI 사용 예시:
from langsmith import traceable
from langsmith.middleware import TracingMiddleware
from fastapi import FastAPI, Request
app = FastAPI() # Or Flask, Django, or any other framework
app.add_middleware(TracingMiddleware)
@traceable
async def some_function():
...
@app.post("/my-route")
async def fake_route(request: Request):
return await some_function()
또는 Starlette:
from starlette.applications import Starlette
from starlette.middleware import Middleware
from langsmith.middleware import TracingMiddleware
routes = ...
middleware = [
Middleware(TracingMiddleware),
]
app = Starlette(..., middleware=middleware)
다른 서버 프레임워크를 사용한다면 langsmith_extra를 통해 헤더를 전달해 분산 트레이스를 "수신"할 수 있어요:
# server.py
import langsmith as ls
from fastapi import FastAPI, Request
@ls.traceable
async def my_application():
...
app = FastAPI() # Or Flask, Django, or any other framework
@app.post("/my-route")
async def fake_route(request: Request):
# request.headers: {"langsmith-trace": "..."}
# as well as optional metadata/tags in `baggage`
with ls.tracing_context(parent=request.headers):
return await my_application()
위 예시는 tracing_context 컨텍스트 매니저를 사용해요. @traceable로 래핑된 메서드의 langsmith_extra 파라미터에서 상위 런 컨텍스트를 직접 지정할 수도 있어요.
# ... same as above
@app.post("/my-route")
async def fake_route(request: Request):
# request.headers: {"langsmith-trace": "..."}
my_application(langsmith_extra={"parent": request.headers})
TypeScript의 분산 추적
TypeScript의 분산 추적에는
langsmith>=0.1.31이 필요해요.
먼저 클라이언트에서 현재 런 트리를 가져와 langsmith-trace 및 baggage 헤더 값으로 변환해 서버에 전달할 수 있어요:
// client.mts
import { getCurrentRunTree, traceable } from "langsmith/traceable";
const client = traceable(
async () => {
const runTree = getCurrentRunTree();
return await fetch("...", {
method: "POST",
headers: runTree.toHeaders(),
}).then((a) => a.text());
},
{ name: "client" }
);
await client();
그런 다음 서버는 헤더를 런 트리로 다시 변환하고, 이를 사용해 추적을 계속해요.
새로 만든 런 트리를 traceable 함수에 전달하려면 withRunTree 헬퍼를 사용해 traceable 호출 내에서 런 트리가 전파되도록 할 수 있어요.
Express.JS:
// server.mts
import { RunTree } from "langsmith";
import { traceable, withRunTree } from "langsmith/traceable";
import express from "express";
import bodyParser from "body-parser";
const server = traceable(
(text: string) => `Hello from the server! Received "${text}"`,
{ name: "server" }
);
const app = express();
app.use(bodyParser.text());
app.post("/", async (req, res) => {
const runTree = RunTree.fromHeaders(req.headers);
const result = await withRunTree(runTree, () => server(req.body));
res.send(result);
});
Hono:
// server.mts
import { RunTree } from "langsmith";
import { traceable, withRunTree } from "langsmith/traceable";
import { Hono } from "hono";
const server = traceable(
(text: string) => `Hello from the server! Received "${text}"`,
{ name: "server" }
);
const app = new Hono();
app.post("/", async (c) => {
const body = await c.req.text();
const runTree = RunTree.fromHeaders(c.req.raw.headers);
const result = await withRunTree(runTree, () => server(body));
return c.body(result);
});