Mastra Observability:用 @mastra/observability 构建 Agent 全链路可观测体系
【免费下载链接】mastraMastra is the modern TypeScript framework for AI-powered applications and agents.项目地址: https://gitcode.com/GitHub_Trending/ma/mastra
本指南以 Mastra 仓库中 observability/mastra 包为主线,完整讲解@mastra/observability的安装、配置与工作原理:如何在 Mastra 应用中接入分层 Trace、自动提取指标、将结构化日志与活动 Trace 关联,并通过采样、敏感数据过滤、基数控制等手段在生产环境中掌控观测成本与安全边界。读完本文,你将能够独立配置一个多实例、多导出目标的 Agent 观测栈,并把 trace、日志、指标、评分与反馈信号打通到 Studio、Mastra Platform 或任意第三方后端。
一、@mastra/observability 是什么
@mastra/observability是 Mastra 的核心可观测性包(见 package.json),它负责对 Mastra 应用中的Agent 运行、模型生成(model generation)、工具与 MCP 调用、处理器(processor)执行、工作流运行(workflow run)与工作流步骤(workflow step)进行全链路插桩。该包以分层 Trace(hierarchical traces)为核心,并自动提取指标、把结构化日志与当前活动的 Trace 相关联。
从源码结构看(见 src 目录),该包由几个相互协作的模块组成:
default.ts/registry.ts/instances/:对外入口Observability类、实例注册表以及BaseObservabilityInstance/DefaultObservabilityInstance等实例实现;bus/:统一的可观测性事件总线(ObservabilityBus),负责把 tracing、log、metric、score、feedback 事件路由给注册的 exporter 与 bridge;exporters/:MastraStorageExporter、MastraPlatformExporter、ConsoleExporter、TestExporter等导出器;span_processors/:输出端处理器,其中SensitiveDataFilter默认启用,负责脱敏;metrics/:指标自动提取(duration、token、cost)与基数过滤(CardinalityFilter);client/:客户端可观测性代理(W3C trace context 注入与 OTLP/JSON 载荷接收);spans//context//model-tracing.ts:Span 模型、日志与指标上下文、模型调用追踪。
该包以@mastra/core的observability类型体系为基础实现(peer 依赖为@mastra/core >=1.16.0-0 <2.0.0-0与zod ^3.25.0 || ^4.0.0,Node 版本要求>=22.13.0)。
二、安装与最小接入
在项目中使用pnpm或npm安装:
npm install @mastra/observability安装后即可在 Mastra 实例上挂载观测配置,这是文档给出的最小用法:
import { Mastra } from '@mastra/core'; import { Observability, MastraStorageExporter, MastraPlatformExporter } from '@mastra/observability'; export const mastra = new Mastra({ observability: new Observability({ configs: { default: { serviceName: 'my-app', exporters: [new MastraStorageExporter(), new MastraPlatformExporter()], }, }, }), });这段配置的含义是:注册一个名为default的观测实例,服务名my-app,同时把观测事件导出到 Mastra 存储(供 Studio 查询)与 Mastra Platform。MastraStorageExporter在 mastra-storage.ts 中实现,负责把事件批量写入配置的ObservabilityStorage;MastraPlatformExporter在 mastra-platform.ts 中实现,负责把事件发布到 Mastra Platform 的 collector。
三、核心配置项逐项拆解
在 config.ts 中,每个观测实例(ObservabilityInstanceConfig)支持以下字段:
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
serviceName | string | 必填 | 服务名,用于区分不同服务的 trace |
sampling | SamplingStrategy | { type: 'always' } | 采样策略,控制是否采集 trace |
exporters | ObservabilityExporter[] | [] | 自定义导出器,至少配置一个 exporter 或 bridge |
bridge | ObservabilityBridge | 无 | 可观测性桥(如 OpenTelemetry 桥),用于上下文提取 |
spanOutputProcessors | SpanOutputProcessor[] | [] | 自定义 Span 输出处理器 |
includeInternalSpans | boolean | false | 是否导出 Mastra 内部 Span(如 MODEL_CHUNK) |
excludeSpanTypes | SpanType[] | 无 | 从导出中剔除的 Span 类型,可降低按 Span 计费的成本 |
spanFilter | (span) => boolean | 无 | 细粒度过滤函数,返回false则丢弃该 Span |
requestContextKeys | string[] | [] | 从 RequestContext 自动提取到 Span 元数据的键,支持点号嵌套 |
serializationOptions | SerializationOptions | 无 | 控制 input/output/attributes 的截断与序列化 |
cardinality | CardinalityConfig | 无 | 指标标签基数保护配置 |
logging | { enabled, level } | 双写开启,级别warn | 控制观测日志(loggerVNext)的过滤级别与是否双写 |
示例:排除噪声 Span、只保留成功工具调用
import { SpanType } from '@mastra/core/observability'; const config = { configs: { default: { serviceName: 'my-app', // 不计费的链路内 Span,全部剔除,减少平台成本 excludeSpanTypes: [SpanType.MODEL_CHUNK, SpanType.MODEL_STEP], spanFilter: span => { // 丢弃失败的模型生成块 if (span.type === SpanType.MODEL_CHUNK && span.attributes?.success === false) return false; return true; }, exporters: [new MastraStorageExporter()], }, }, };从源码看,getSpanForExport(instances/base.ts)的执行顺序是:先检查isValid与内部 Span 过滤,再检查excludeSpanTypes,随后依次运行spanOutputProcessors,最后应用spanFilter——因此用户过滤器拿到的是最终将要导出的 Span 数据,可按类型、属性、实体、元数据任意组合过滤。
3.1 注册表级配置:default、configs 与 configSelector
ObservabilityRegistryConfig(config.ts)在实例之上再做一层组织:
default: { enabled: true }:旧式快捷开关,已标记@deprecated,默认会注册一个serviceName: 'mastra'、使用MastraStorageExporter + MastraPlatformExporter的实例;configs:命名实例的映射表,值可以是普通配置对象,也可以是预实例化的ObservabilityInstance;configSelector:当存在多个config 时必须提供,用于在运行时根据ConfigSelectorOptions选择实例;sensitiveDataFilter:控制是否自动给每个实例套上SensitiveDataFilter(true默认开启 /false关闭 / 传对象自定义选项)。
Zod 校验规则(config.ts)明确约束了这三种模式不能混用:default开启时不能再给configs,多个 configs 必须有configSelector,有configSelector就必须有 configs 或 default。
3.2 多实例与配置选择器
多实例场景适合“不同服务、不同导出目标”的部署,例如同一进程内同时运行网关服务与 Agent 服务:
import { Mastra } from '@mastra/core'; import { Observability, MastraStorageExporter } from '@mastra/observability'; import { LangfuseExporter } from '@mastra/langfuse'; const mastra = new Mastra({ observability: new Observability({ configs: { gateway: { serviceName: 'api-gateway', exporters: [new MastraStorageExporter()], }, agents: { serviceName: 'my-agents', exporters: [new MastraStorageExporter(), new LangfuseExporter({ publicKey: '...', secretKey: '...' })], }, }, configSelector: ({ operation, entityType }) => entityType === 'agent' || operation?.includes('agent') ? 'agents' : 'gateway', }), });每个配置的观测实例拥有独立的 serviceName、exporter、采样策略与 Span 处理器,这一点在包文档中有明确说明,也与BaseObservabilityInstance的构造逻辑(instances/base.ts)一致:每个实例单独初始化CardinalityFilter、ObservabilityBus,并注册自己的 exporter 与 bridge。
四、导出器:从存储到第三方平台的完整清单
4.1 MastraStorageExporter(Studio 数据源)
MastraStorageExporter把 trace、log、metric、score、feedback 事件缓冲后批量写入ObservabilityStorage(即 Mastra 配置的存储后端),Studio 便可以从存储中查询这些 trace。其关键行为参数(mastra-storage.ts):
| 参数 | 默认值 | 说明 |
|---|---|---|
maxBatchSize | 1000 | 触发批量刷新的 Span 数量阈值 |
maxBufferSize | 10000 | 缓冲区上限,超出后紧急刷新 |
maxBatchWaitMs | 5000 | 时间触发阈值,缓冲非空时最迟等待毫秒数 |
maxRetries | 4 | 失败重试次数 |
retryDelayMs | 500 | 指数退避的基础延迟(retryDelayMs * 2^(n-1)) |
strategy | 'auto' | 存储写入策略(realtime/ 缓冲等),auto时按存储适配器偏好选择 |
写入时按信号类型分别调用batchCreateSpans、batchCreateLogs、batchCreateMetrics、batchCreateScores、batchCreateFeedback(见 mastra-storage.ts)。Span 的 update/end 事件会检查对应 Span 是否已创建,未创建则延迟到下一批(flushSpanUpdates,mastra-storage.ts),从而保证事件顺序正确。
4.2 MastraPlatformExporter(Mastra 云平台)
MastraPlatformExporter把信号发布到 Mastra Platform 的 collector 路由(/spans/publish、/logs/publish、/metrics/publish、/scores/publish、/feedback/publish,见 mastra-platform.ts)。它默认过滤掉MODEL_CHUNKSpan(DEFAULT_PLATFORM_SPAN_FILTER),并实现了配额暂停协议:当 collector 返回402或x-mastra-observability: disabled时,停止发送并按照x-mastra-observability-retry-after头(默认 300 秒)周期性探测恢复。
4.3 其他可用导出器
仓库的 observability 目录下还有多个配套包,例如 Arize、Braintrust、Langfuse、LangSmith、Sentry 等(参见 observability 下的arize、braintrust、langfuse、langsmith、sentry等子目录)。包文档特别指出,额外的包提供了面向这些服务以及 OpenTelemetry 兼容后端的导出器。
4.4 导出器如何收到事件:ObservabilityBus
所有导出器都通过中央可观测性总线接收事件。ObservabilityBus(bus/observability-bus.ts)将事件按类型路由到实现了对应方法(onTracingEvent、onLogEvent、onMetricEvent、onScoreEvent、onFeedbackEvent)的处理器,未实现该方法的处理器会被静默跳过。事件在扇出前会经过deepClean(对 log/metric/score/feedback 的整包做深度清洗,tracing 事件在 Span 构造时已清洗),保证JSON.stringify安全。flush()采用两阶段流程:先排空在途 handler Promise,再调用各 exporter 与 bridge 的flush()排空其 SDK 内部缓冲(如 OTEL BatchSpanProcessor),这对 Inngest 等持久化执行引擎尤其重要——步骤完成后进程可能被中断,调用flush()能确保数据送达外部系统。
五、敏感数据过滤:默认开启的安全底线
SensitiveDataFilter(span_processors/sensitive-data-filter.ts)是一个默认启用的 Span 输出处理器,在 Span 到达 exporter之前统一脱敏。它覆盖 attributes、metadata、input、output、errorInfo、requestContext 六个字段,并且对 JSON 字符串做解析后再脱敏。
匹配规则:字段名大小写不敏感,并归一化分隔符——api-key、api_key、Api Key都会归一化为apikey再精确匹配,因此promptTokens不会被误伤成token。默认敏感字段包括:
password、token、secret、key、apikey、auth、authorization、bearer、bearertoken、jwt、credential、clientsecret、privatekey、refresh、ssn
脱敏有三种风格(redactionStyle):
| 风格 | 行为 | 示例 |
|---|---|---|
full(默认) | 一律替换为固定令牌 | sk-abc…→[REDACTED] |
partial | 保留首尾各 3 个字符,中间省略;长度 ≤6 时整体脱敏 | sk-abc123xyz→sk-…xyz |
indexed | 同一 trace 内同一值映射到稳定令牌[LABEL_N],可在不暴露原文的前提下做关联分析 | sk-abc→[APIKEY_1] |
indexed模式的状态按 trace 作用域管理,使用 SHA-256 摘要做键(不保留原始值),最多跟踪最近 1000 个 trace、每个 trace 最多 1000 个唯一值,超出后退化为完整脱敏令牌。
在 default.ts 中可以确认自动应用逻辑:sensitiveDataFilter默认为true;若用户自己的spanOutputProcessors里已包含SensitiveDataFilter则跳过自动追加,避免双重脱敏;自动追加的过滤器排在其他处理器之后运行,确保上游处理器引入的敏感数据仍会被脱敏;预实例化的ObservabilityInstance不会被修改,只会打印警告。
自定义脱敏示例:
import { Observability } from '@mastra/observability'; const observability = new Observability({ configs: { default: { serviceName: 'my-app', exporters: [new MastraStorageExporter()], }, }, // 关闭默认敏感数据过滤(不推荐,仅示例) sensitiveDataFilter: false, });需要完全关闭时设sensitiveDataFilter: false;需要定制时传入选项对象:
const observability = new Observability({ configs: { default: { serviceName: 'my-app', exporters: [new MastraStorageExporter()], }, }, sensitiveDataFilter: { sensitiveFields: ['password', 'token', 'secret', 'key', 'apikey', 'jwt', 'api_key_custom'], redactionToken: '***', redactionStyle: 'indexed', }, });六、采样策略:控制采集成本与数据量
采样策略在 config.ts 中定义,支持四种类型:
// 1. 全量采集(默认) { type: 'always' } // 2. 完全不采集 { type: 'never' } // 3. 按比例随机采样(probability 必须在 [0,1]) { type: 'ratio', probability: 0.1 } // 4. 应用自定义采样逻辑 { type: 'custom', sampler: ({ requestContext, metadata }) => { // 例如:只采样登录/支付相关请求 return metadata?.businessCritical === true; }, }shouldSample的实现(instances/base.ts)对ratio使用Math.random() < probability,概率越界会告警并退化为不采样;custom直接调用用户提供的sampler函数,可接收requestContext与metadata。
需要特别强调的是trace 级采样:startSpan(instances/base.ts)只在根 Span 上执行采样判定,子 Span 直接继承父 Span 的采样结果(父是NoOpSpan则子也是NoOpSpan)。这保证了“要么整条 trace 都被采集,要么都不被采集”,避免出现只有子 Span、没有根 Span 的断裂链路。
七、自动提取的指标与结构化日志
7.1 指标:从 Span 生命周期自动派生
包文档说明:指标从 Span 生命周期事件自动派生,涵盖duration(耗时)、status(状态)、模型 token 数、缓存 token 数。对应实现是 metrics/auto-extract.ts:
emitDurationMetrics:根据startTime与endTime计算耗时,并带上status: 'ok' | 'error'标签;emitTokenMetrics:仅对MODEL_GENERATION类型 Span 读取usage字段,派发 token 指标;- 成本估算由 metrics/estimator.ts 结合 metrics/pricing-data.jsonl 的定价数据完成,模型 ID 解析逻辑见 model-id.ts。
值得注意的细节:指标发射独立于导出过滤。即使用户通过excludeSpanTypes剔除了AGENT_RUN、TOOL_CALL等 Span 以降低按 Span 计费的成本,duration/token/cost 指标依然会生成(见 instances/base.ts 中emitSpanEnded的处理)。当内部MODEL_GENERATIONSpan 被过滤时,其 usage 会“回滚”累加到最近的可见祖先 Span 的internalUsage属性上(captureModelUsageRollup/applyUsageRollup),让成本归属到用户可见的 Span。
7.2 指标基数保护
metrics 标签会经过基数过滤(cardinality filtering),防止 user ID、trace ID 等无界值压垮指标后端。CardinalityFilter(metrics/cardinality.ts)默认阻止一组标签键(DEFAULT_BLOCKED_LABELS,如trace_id等),并默认拦截符合 UUID v4 形态的值(正则见 cardinality.ts)。可通过cardinality配置覆盖:
configs: { default: { serviceName: 'my-app', exporters: [new MastraStorageExporter()], cardinality: { blockedLabels: ['trace_id', 'user_id', 'conversation_id'], blockUUIDs: true, }, }, }该过滤器同样作用于用户自定义指标(MetricsContext中的标签会先经过CardinalityFilter.filterLabels再发射)。
7.3 结构化日志与 trace 关联
包文档指出:结构化日志会继承 trace ID、span ID、tags 与实体元数据。LoggerContextImpl(context/logger.ts)由getLoggerContext(instances/base.ts)创建:当logging.enabled === false时返回 no-op logger;否则把当前 Span 的traceId、可导出的spanId(resolveExportedSpanId会跳过内部/被排除的 Span)、correlation context 与 metadata 一并注入。日志级别按logging.level过滤(默认warn),并支持logging.enabled关闭向观测存储的双写。
这样,在 Studio 中点击某条 trace,即可看到与之关联的所有日志,无需手动拼接 traceId 去检索。
八、Span 模型与生命周期
Span 的生命周期由startSpan统一管理,BaseObservabilityInstance会在创建后自动接线(wireSpanLifecycle,instances/base.ts):
span.end(options):包装原始end,捕获 usage 回滚数据,调用原始结束逻辑,随后发出SPAN_ENDED事件并触发自动指标提取;span.update(options):包装原始update,随后发出SPAN_UPDATED事件;- 事件型 Span(
span.isEvent)不经过生命周期接线,直接在创建时发出结束事件。
根 Span 的 metadata 会自动注入environment(来自 Mastra 实例环境,前提是用户未显式设置),RequestContext 中配置的requestContextKeys(支持点号嵌套,如headers.x-request-id)也会被提取进根 Span metadata,子 Span 通过继承父 metadata 自动获得这些上下文。这对跨服务的链路贯穿很有用:例如在网关层把x-request-id写入 RequestContext,所有下游 Agent trace 都会自动带上该请求 ID。
九、分数(Score)与反馈(Feedback)
除 trace/log/metric 外,Observability还提供addScore与addFeedbackAPI(default.ts)。可以通过correlationContext(自动继承当前 Span 的 trace/span ID)快速打分,也可以通过traceId/spanId对历史 trace 打分。后者会先从观测存储中重建 trace(getRecordedTrace),并以重试调度(累计约 5.85 秒)规避 exporter 异步刷新的竞态——Span 刚结束时马上打分,可能遇到数据尚未落库而丢失,该重试机制覆盖了默认刷新间隔并留有余量(见 default.ts)。分数与反馈事件同样经由ObservabilityBus路由到所有注册的 exporter,可被存储或平台消费。
十、生命周期管理:flush 与 shutdown
flush():强制排空缓冲事件并刷新 exporter/bridge 的 SDK 内部缓冲,适合 Serverless 环境在运行时实例终止前调用,或持久化执行引擎(如 Inngest)在 durable step 之外调用;shutdown():先关闭总线(排空剩余事件、清理订阅者),再并行关闭所有 exporter、Span 输出处理器与 bridge(instances/base.ts)。
Observability注册表层面同样暴露flush()与shutdown(),分别对所有已注册实例生效。
十一、相关测试与延伸阅读
该包带有丰富的测试覆盖,是理解行为细节的绝佳入口:
- config.test.ts:验证采样策略、序列化、日志配置等 Zod 校验逻辑;
- trace-level-sampling.test.ts:验证 trace 级采样继承行为;
- span-filtering.test.ts:验证
excludeSpanTypes与spanFilter的过滤语义; - senstive-data-filter.test.ts:验证三种脱敏风格与字段归一化;
- mastra-storage.test.ts 与 mastra-platform.test.ts:验证两个核心导出器的缓冲、重试与配额协议;
- auto-extract.test.ts 与 cardinality.test.ts:验证指标自动提取与基数过滤;
- observability-bus.test.ts:验证事件路由与两阶段 flush;
- processor-tracing.test.ts 与 model-tracing.test.ts:验证处理器与模型调用的插桩链路。
__snapshots__/目录下的 trace 快照(如agent-tool-call-trace.json、workflow-branching-trace.json)展示了真实生成的 trace 结构,是理解分层 Span 数据形态的第一手资料。
结语
@mastra/observability把 Agent 应用的观测从“打日志”升级为“一套体系”:分层 trace 刻画每次 Agent/工作流/工具/模型调用的完整脉络,指标与日志自动挂靠到活动 trace,采样、脱敏、基数过滤与 Span 级过滤四道闸门共同守住成本与安全,而事件总线让存储、平台与第三方后端可以同时、无侵入地消费同一份观测数据。在生产环境中,建议至少配置MastraStorageExporter(供 Studio 本地查询)并按需叠加平台或第三方 exporter,同时保留默认的SensitiveDataFilter,再根据业务重要性选择 ratio 或 custom 采样,即可获得一套既完整又受控的 Agent 可观测栈。
【免费下载链接】mastraMastra is the modern TypeScript framework for AI-powered applications and agents.项目地址: https://gitcode.com/GitHub_Trending/ma/mastra
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考