Deno 2.2 版本引入了原生的 OpenTelemetry 支持,使得在 Deno 应用中集成分布式追踪变得异常简单。本文将介绍如何使用 Deno 2.2 和 Hono 框架构建一个简单的微服务系统,并通过 OpenTelemetry 实现服务的可观测性。
项目概述
我们构建了一个包含两个服务的简单系统:
- API 网关服务 (
gateway.ts
):负责接收客户端请求,并将其路由到相应的服务。
- 天气服务 (
weather.ts
):提供天气信息查询功能。
此外,我们还实现了一个中间件 (TraceRoute.ts
) 和一个模拟的第三方 API 调用 (thirdApi.ts
),用于演示如何在服务中进行追踪。
代码实现
API 网关服务 (gateway.ts
)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| import { Hono } from "@hono/hono"; import { TraceRoute } from "./TraceRoute.ts";
const app = new Hono().basePath("/api");
app.use(TraceRoute());
app .get("/", (c) => { return c.text("Hello from the Trees!"); }) .get("/weather/batch-get", async (c) => { const cities = c.req.queries("city") as string[]; const result = ( await Promise.all( cities.map(async (city: string) => { const resp = await fetch(`http://localhost:8001/weather/${city}`); return await resp.text(); }) ) ).join("\n"); return c.text(result); }) .get("/weather/:city", (c) => { return fetch(`http://localhost:8001/weather/${c.req.param("city")}`); });
Deno.serve(app.fetch);
|
天气服务 (weather.ts
)
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import { Hono } from "@hono/hono"; import { TraceRoute } from "./TraceRoute.ts"; import { getWeather } from "./thirdApi.ts";
const app = new Hono();
app.use(TraceRoute());
app.get("/weather/:city", (c) => { const city = c.req.param("city"); return c.text(getWeather(city)); });
Deno.serve({ port: 8001 }, app.fetch);
|
追踪中间件 (TraceRoute.ts
)
1 2 3 4 5 6 7 8 9 10 11
| import type { MiddlewareHandler } from "@hono/hono/types"; import { trace } from "@opentelemetry/api";
export const TraceRoute = (): MiddlewareHandler => { return async function (c, next) { const span = trace.getActiveSpan(); span?.setAttribute("http.route", c.req.path); span?.updateName(`${c.req.method} ${c.req.path}`); await next(); }; };
|
第三方 API 调用 (thirdApi.ts
)
1 2 3 4 5 6 7 8 9 10 11 12
| import { trace } from "@opentelemetry/api";
export function getWeather(city: string) { return trace .getTracer("weather-api") .startActiveSpan("getWeatherFunction", (span) => { span.setAttribute("city", city); span.end(); console.log(`Fetch weather from ${city}`); return `${city} is sunny, 20℃.`; }); }
|
运行服务
要运行这两个服务,可以使用以下命令:
1
| OTEL_SERVICE_NAME=gateway OTEL_DENO=true OTEL_DENO_CONSOLE=capture deno run --unstable-otel -A --watch gateway.ts
|
1
| OTEL_SERVICE_NAME=weather-api OTEL_DENO=true OTEL_DENO_CONSOLE=capture deno run --unstable-otel -A --watch weather.ts
|
然后,可以使用 curl
命令测试服务:
1
| curl http://localhost:8000/api/weather/batch-get?city=beijing&city=shanghai
|
可视化追踪数据
为了查看追踪和指标信息,我们在本地启动了一套 LGTM 服务:
1 2 3 4 5 6
| docker run --name lgtm -p 3000:3000 -p 4317:4317 -p 4318:4318 --rm -ti \ -v "$PWD"/lgtm/grafana:/data/grafana \ -v "$PWD"/lgtm/prometheus:/data/prometheus \ -v "$PWD"/lgtm/loki:/data/loki \ -e GF_PATHS_DATA=/data/grafana \ docker.io/grafana/otel-lgtm:0.8.1
|
通过访问 http://localhost:3000
,可以在 Grafana 中查看服务的追踪和指标信息。
总结
Deno 2.2 的原生 OpenTelemetry 支持使得在 Deno 应用中实现可观测性变得非常简单。通过本文的示例,我们展示了如何在微服务系统中集成 OpenTelemetry,并通过 LGTM 服务可视化追踪数据。希望这篇文章能帮助你更好地理解和应用 Deno 和 OpenTelemetry。
更多详细信息和完整代码,请访问 GitHub 仓库。