☰
FastGPT 统一可观测性 SDK 实战:用 @fastgpt-sdk/otel 一站式接入 OpenTelemetry 日志、指标与链路追踪
2026/10/17 21:14:38 网站建设 项目流程

FastGPT 统一可观测性 SDK 实战:用 @fastgpt-sdk/otel 一站式接入 OpenTelemetry 日志、指标与链路追踪

【免费下载链接】FastGPTFastGPT is a knowledge-based platform built on the LLMs, offers a comprehensive suite of out-of-the-box capabilities such as data processing, RAG retrieval, and visual AI workflow orchestration, letting you easily develop and deploy complex question-answering systems without the need for extensive setup or configuration.项目地址: https://gitcode.com/GitHub_Trending/fa/FastGPT

本篇技术指南讲解 FastGPT 仓库中统一的可观测性 SDK——@fastgpt-sdk/otel(位于 sdk/otel/README.md)。该包的目标是把分散的@fastgpt-sdk/logger、@fastgpt-sdk/metrics与 tracing 能力收拢到单一入口,同时提供“统一入口”和“渐进迁移入口”两种用法。读完本文,你将掌握其环境变量体系、日志结构化输出与安全归一化规则、指标与采样的底层实现,以及如何像 FastGPT service 层那样用它接入 OpenTelemetry Collector / OTLP 后端。

一、定位:为什么需要一个统一的可观测性 SDK

从源码看,@fastgpt-sdk/otel是一个自包含(self-contained)包:

  • 内部自带 logger 实现、metrics 实现与 tracing 实现;
  • 不依赖@fastgpt-sdk/logger或@fastgpt-sdk/metrics,三者可独立工作;
  • 它的定位是“整理好的统一入口”,而不是“已经迁移完成的替换方案”——现有 logger 与 metrics 包仍然可以继续独立使用,后续再逐步迁移。

它对外提供四类能力:

能力说明统一入口渐进迁移入口
日志基于 LogTape 的 logger@fastgpt-sdk/otel@fastgpt-sdk/otel/logger
指标OpenTelemetry Metrics@fastgpt-sdk/otel@fastgpt-sdk/otel/metrics
链路追踪OpenTelemetry Tracing@fastgpt-sdk/otel@fastgpt-sdk/otel/tracing
初始化统一的configureOtel()/configureOtelFromEnv()@fastgpt-sdk/otel—

两种入口对应两种接入策略:新代码直接用统一入口;存量代码按模块逐个切换到子路径入口,实现渐进式迁移。包版本与导出结构可查看 sdk/otel/package.json(当前版本 0.1.2,exports中声明了.、./logger、./metrics、./tracing四个子路径,包以 ESM 方式构建,产物为dist/index.mjs等)。

二、快速开始

2.1 统一入口

最直接的用法是在应用启动时调用configureOtelFromEnv(),把日志、指标、追踪三者一次性从环境变量初始化:

import { configureOtelFromEnv, getLogger, getMeter, getTracer } from '@fastgpt-sdk/otel'; await configureOtelFromEnv({ defaultServiceName: 'fastgpt-client' }); const logger = getLogger(['system']); const meter = getMeter('fastgpt-client'); const tracer = getTracer('fastgpt-client');

其中defaultServiceName是兜底服务名:当环境变量没有显式指定时,日志的LOG_OTEL_SERVICE_NAME、指标的METRICS_OTEL_SERVICE_NAME、追踪的TRACING_OTEL_SERVICE_NAME以及标准 OTEL 的OTEL_SERVICE_NAME均会回退到它。

2.2 渐进迁移入口

如果只想逐步替换某个模块,可以按需导入子路径:

import { configureLoggerFromEnv, getLogger } from '@fastgpt-sdk/otel/logger'; import { configureMetricsFromEnv, getMeter } from '@fastgpt-sdk/otel/metrics'; import { configureTracingFromEnv, getTracer } from '@fastgpt-sdk/otel/tracing';

2.3 初始化与销毁的底层行为

configureOtel()/configureOtelFromEnv()的实现(见 src/client.ts 与 src/env.ts)本质上是并发执行三个子模块的初始化:

await Promise.all([ configureLogger(options.logger ?? {}), configureMetrics(options.metrics ?? {}), configureTracing(options.tracing ?? {}) ]);

三者互不阻塞、互不依赖,任何一个失败都会让整体初始化失败。对应的disposeOtel()也并行执行disposeLogger()、disposeMetrics()、disposeTracing(),分别完成 LogTape dispose、MeterProvider shutdown、TracerProvider shutdown,用于优雅退出。

值得注意的工程细节是:三个子模块的configure*都是幂等的。以 logger 为例(src/logger/client.ts),内部维护configured标志与configurePromise,重复调用不会重复创建 sink,并发调用则复用同一个 Promise——这保证了在模块多处初始化、或测试与生产代码混跑时不会出现双重注册。

三、日志(logger)能力深入

3.1 环境变量与默认值

logger 的初始化由configureLoggerFromEnv完成(src/logger/env.ts),支持的变量与默认值如下:

环境变量作用默认值
LOG_ENABLE_CONSOLE是否输出到控制台true
LOG_CONSOLE_LEVEL控制台最低日志级别trace
LOG_ENABLE_OTEL是否开启 OTel 日志导出false
LOG_OTEL_LEVELOTel 导出的最低日志级别warning
LOG_OTEL_SERVICE_NAME导出时的服务名defaultServiceName
LOG_OTEL_LOGGER_NAMELogger 名称同服务名
LOG_OTEL_URLOTLP HTTP logs 端点http://localhost:4318/v1/logs

日志级别取值集合为trace / debug / info / warning / error / fatal,非法值会静默回退到默认值(src/logger/env.ts)。布尔环境变量解析遵循1/true/yes/on为真、0/false/no/off为假的规则,见 src/env-utils.ts。

3.2 双 sink 架构:控制台 + OTel

sink 的组装在 src/logger/sinks.ts:

  • 控制台 sink:使用 LogTape 的getConsoleSink+getPrettyFormatter,输出人类可读的格式化日志,级别低于LOG_CONSOLE_LEVEL的记录被过滤;
  • OTel sink:通过getOpenTelemetrySink(src/logger/otel.ts)创建,内部使用OTLPLogExporter+BatchLogRecordProcessor批量上报,支持懒初始化——第一条日志到达时才初始化 exporter,初始化前的日志先进入pendingRecords缓冲队列,初始化完成后统一补发;若初始化失败(如端点不可达),则丢弃缓冲并只向控制台打印错误。

日志级别到 OTel SeverityNumber 的映射由mapLevelToSeverityNumber完成(src/logger/helpers.ts),trace→TRACE、debug→DEBUG、info→INFO、warning→WARN、error→ERROR、fatal→FATAL。

3.3 OTel 日志的结构化输出约定

这是 README 重点强调的设计(src/logger/otel.ts):

  • body承载业务数据:形如{ __log_message, ...properties }。__log_message是把 LogTape 的 message 模板与占位符拼接后的人读摘要,properties中剩余字段作为结构化上下文扁平放入 body;
  • attributes只保留日志元信息:仅保留category(即['system']、['http', 'request']这类分类数组),不再复制 properties,避免 body 与 attributes 内容重复;
  • 名为traceId/spanId的 properties 是保留字段,会被跳过(避免与链路上下文重复,见 src/logger/otel.ts)。

单元测试 sdk/otel/test/logger/otel.test.ts 用createMemoryLoggerProvider直接验证了这一点:带completionsBody等复杂对象属性时,body中完整保留结构化内容,而attributes严格等于{ category: ['test'] }。

3.4 安全归一化:JS 特有值不再出现[object Object]

在把 properties 写入 OTel body 之前,所有值都要经过normalizeLogValue(src/logger/otel.ts)安全归一化,规则包括:

输入类型归一化结果
Map展开为普通对象(key 字符串化)
Set转换为数组
BigInt转为字符串
Symbol转为字符串
Function[Function name]
DateISO 8601 字符串
Error{ name, message, stack, cause, errors }(含AggregateError的errors数组)
Uint8Array原样保留(或按bytesAsSummary输出[Uint8Array length=N]摘要)
class 实例普通对象化并附带__type: 构造函数名,必要时用util.inspect兜底
循环引用标记为[Circular]
超出深度/键数深度上限 8 层([MaxDepth]),单对象键数上限 128 个(__truncated: true)

对应测试见 sdk/otel/test/logger/otel.test.ts:Map被展开、Set变数组、bigint变字符串、class 实例带__type: 'CustomValue'、循环引用输出'[Circular]'。这一设计保证了即使业务属性里混入原生 JS 类型,也不会在序列化时抛异常或产出无意义的[object Object]。

3.5 敏感属性过滤与日志上下文

OTel sink 还支持sensitiveProperties过滤(src/logger/sinks.ts):当一条日志的 properties 中出现命中名单的键时,该记录不会被导出到 OTel。FastGPT service 层在初始化时传入了sensitiveProperties: ['fastgpt'](见 packages/service/common/logger/client.ts)。

此外,getLogger()返回的是带 Proxy 的 logger:当调用形式为logger.info(msg, { verbose: false, ...properties })时,verbose: false标记会被剥离、其余属性作为结构化上下文传入,避免把控制开关写进日志数据(src/logger/client.ts)。withContext()与withCategoryPrefix()也从@logtape/logtape直接转发,用于在异步上下文中注入requestId等关联字段。

四、指标(metrics)能力

4.1 环境变量

configureMetricsFromEnv(src/metrics/env.ts)支持的变量:

环境变量作用默认值
METRICS_ENABLE_OTEL是否开启 OTel 指标导出false(或OTEL_METRICS_EXPORTER=otlp时自动开启)
METRICS_OTEL_SERVICE_NAME指标服务名回退到OTEL_SERVICE_NAME/defaultServiceName
METRICS_OTEL_URLOTLP HTTP metrics 端点回退到OTEL_EXPORTER_OTLP_METRICS_ENDPOINT
METRICS_EXPORT_INTERVAL导出周期(毫秒)30000(同时兼容标准OTEL_METRIC_EXPORT_INTERVAL)
OTEL_METRICS_EXPORTER标准导出器选择,为otlp时自动启用—

底层实现(src/metrics/client.ts)使用MeterProvider+PeriodicExportingMetricReader,按exportIntervalMillis周期批量导出;URL 会自动规范化:不以/v1/metrics结尾时自动追加该路径。默认 meter 名为fastgpt,可通过defaultMeterName覆盖。

4.2 FastGPT service 层的指标实践

FastGPT service 层已经用该 SDK 埋了两个典型指标集:

  • 运行时指标(packages/service/common/metrics/runtime.ts):在fastgpt.runtimemeter 下注册了fastgpt.runtime.process.memory.{rss,heap_used,heap_total,external,array_buffers}、fastgpt.runtime.process.cpu.{user,system,utilization}、fastgpt.runtime.process.uptime等 ObservableGauge,CPU 利用率由两次采样间的 CPU 时间差与核数计算得到;
  • Redis 连接指标(packages/service/common/metrics/redis.ts):在fastgpt.redis.runtimemeter 下注册fastgpt.redis.connections.active/created/errors、fastgpt.redis.health.checks、fastgpt.redis.health.duration、fastgpt.redis.shutdown.duration,DAL 层只注入观测回调,不直接依赖 OTel,测试时可以注入内存 recorder 而不初始化 exporter。

service 层封装configureMetrics()(packages/service/common/metrics/client.ts)在初始化 OTel 后自动启动运行时指标采集,disposeMetrics()时同步停止。

五、链路追踪(tracing)能力

5.1 专属环境变量与标准 OTEL 回退

tracing 的环境变量解析在 src/tracing/env.ts,README 列出的专属变量与回退逻辑如下:

专属变量(优先级最高):

环境变量作用
TRACING_ENABLE_OTEL是否开启 tracing,true时启用
TRACING_OTEL_SERVICE_NAME追踪服务名
TRACING_OTEL_URLOTLP HTTP traces 端点
TRACING_OTEL_SAMPLE_RATIO采样率(0~1,越界会被 clamp)

标准 OTEL fallback(当专属变量缺失时按优先级读取):

标准变量作用
OTEL_SERVICE_NAME服务名兜底
OTEL_EXPORTER_OTLP_TRACES_ENDPOINTtraces 端点兜底
OTEL_EXPORTER_OTLP_ENDPOINT通用 OTLP 端点兜底(会自动追加/v1/traces)
OTEL_TRACES_EXPORTER值为otlp时自动启用 tracing
OTEL_TRACES_SAMPLER采样器选择,支持always_on、always_off、traceidratio及其parentbased_*变体
OTEL_TRACES_SAMPLER_ARG采样器参数(用于 ratio 型采样器)

采样率的解析规则(src/tracing/env.ts):always_off/parentbased_always_off映射为 0,always_on/parentbased_always_on映射为 1,traceidratio/parentbased_traceidratio读取OTEL_TRACES_SAMPLER_ARG,其余情况回退默认值。

5.2 采样与端点实现的底层细节

  • 默认采样率为 1(全量采样),经Math.max(0, Math.min(1, value))归一化;
  • 底层使用NodeTracerProvider,采样器为ParentBasedSampler({ root: new TraceIdRatioBasedSampler(ratio) })——即根 span 按比率采样,子 span 跟随父 span 决策,见 src/tracing/client.ts;
  • span 通过BatchSpanProcessor+OTLPTraceExporter批量导出,端点缺失时只注册 provider 不导出(span 仍可在进程内使用);
  • getCurrentSpanContext()可读取当前活跃 span 的traceId/spanId,用于把链路 ID 拼进日志,实现 trace 与 log 关联。

5.3 service 层的 tracing 封装

FastGPT service 层基于该 SDK 提供了三个生产级封装(packages/service/common/tracing/client.ts):

  • 默认采样策略:TRACING_OTEL_SAMPLE_RATIO未配置时,NODE_ENV === 'production'使用 0.01(1% 采样控制成本),非生产环境使用 1(全量采样);
  • withActiveSpan(name, callback):自动创建 span、注入 attributes、异常时setSpanError(记录 exception 并置 ERROR 状态)、finally中结束 span;
  • getTraceLogContext():返回{ traceId, spanId }供日志上下文关联。

实际调用链可参考两处:HTTP 入口在 packages/service/common/http/entry.ts 中用withContext({ requestId })包裹withActiveSpan({ name: 'http.request', tracerName: 'fastgpt.http' }),把 method、route、body size 写入 span attributes;工作流调度在 packages/service/core/workflow/dispatch/index.ts 与同文件第 1612 行对节点执行也包了withActiveSpan。这些是追踪能力在真实业务中的直接落地样本。

六、迁移思路与在 FastGPT 中的落地现状

README 给出了明确的三阶段迁移路径:

  1. 收拢初始化入口:先把 logger/metrics/tracing 的初始化从多个 SDK 入口收到@fastgpt-sdk/otel(或@fastgpt-sdk/otel/*子入口);
  2. 替换 import:把业务代码中的logger/metricsimport 逐步改成otel子路径;
  3. 补充 traces:最后按业务需要补充 span。

从仓库现状看,FastGPT 的 service 层已经完成了第一阶段,甚至进入了第二阶段:

  • @fastgpt-sdk/otel已通过workspace:*加入 service 依赖(packages/service/package.json);
  • logger 封装从@fastgpt-sdk/otel/logger导入(packages/service/common/logger/client.ts),metrics 封装从@fastgpt-sdk/otel/metrics导入,tracing 封装从@fastgpt-sdk/otel/tracing导入;
  • 测试与 Vitest 配置分别用paths/resolve.alias将三个子路径映射到sdk/otel/src下的入口文件(见 packages/service/test/tsconfig.json 与 packages/service/vitest.config.ts),说明子路径导出在开发与测试环境均可直接指向源码。

service 层环境变量的生产配置集中在 packages/service/env.ts,这些默认值可作为实际部署参考:

变量service 层默认值
LOG_ENABLE_CONSOLEtrue
LOG_CONSOLE_LEVELdebug
LOG_ENABLE_OTELfalse
LOG_OTEL_LEVELinfo
LOG_OTEL_SERVICE_NAMEfastgpt-client
LOG_OTEL_URL可选
METRICS_ENABLE_OTELfalse
METRICS_EXPORT_INTERVAL30000(毫秒)
METRICS_OTEL_SERVICE_NAMEfastgpt-client
METRICS_OTEL_URL可选
TRACING_ENABLE_OTELfalse
TRACING_OTEL_SERVICE_NAMEfastgpt-client
TRACING_OTEL_URL可选
TRACING_OTEL_SAMPLE_RATIO可选(0~1,未配置时按 NODE_ENV 决定:生产 0.01,否则 1)

七、小结

@fastgpt-sdk/otel是 FastGPT 可观测性体系的“统一收口层”:

  • 一键初始化:configureOtelFromEnv()并行初始化 logger / metrics / tracing,disposeOtel()并行优雅销毁;
  • 双入口设计:统一入口适合新代码,子路径入口适合存量代码渐进迁移,两者 API 完全一致;
  • 日志结构化:body 承载业务数据、attributes 只留元信息,配合 Map/Set/Error/循环引用等 JS 类型的深度安全归一化,保证导出数据可查询、可检索;
  • 标准兼容:专属*_OTEL_*变量与标准OTEL_*变量双轨并存,采样率、导出端点均有完备回退;
  • 已在生产路径落地:service 层的 HTTP 入口、工作流调度、运行时与 Redis 指标均基于该 SDK,可直接作为接入范本。

参考阅读:sdk/otel/README.md(包说明)、sdk/otel/src/index.ts(统一入口导出)、sdk/otel/test/logger/otel.test.ts(日志结构化行为测试)、packages/service/common/logger/client.ts(service 层日志封装)、packages/service/env.ts(生产环境变量默认值)。

【免费下载链接】FastGPTFastGPT is a knowledge-based platform built on the LLMs, offers a comprehensive suite of out-of-the-box capabilities such as data processing, RAG retrieval, and visual AI workflow orchestration, letting you easily develop and deploy complex question-answering systems without the need for extensive setup or configuration.项目地址: https://gitcode.com/GitHub_Trending/fa/FastGPT

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询