Mastra
Add Harbor as an exporter in Mastra's observability config.
Mastra runs its own observability pipeline rather than emitting OpenTelemetry directly, so
Harbor joins it as an exporter. There is no tracer provider to register and no Harbor
client to construct.
Install
npm install harbor-ai-sdk @mastra/otel-exporter@mastra/otel-exporter converts Mastra's spans to the OpenTelemetry GenAI conventions
Harbor ingests. It is an optional peer dependency, so it is only needed for this integration.
Set up
import { Mastra } from '@mastra/core/mastra'
import { SpanType } from '@mastra/core/observability'
import {
MastraStorageExporter,
Observability,
SensitiveDataFilter,
} from '@mastra/observability'
import { HarborExporter } from 'harbor-ai-sdk/mastra'
import { agent } from './agents/agent'
export const mastra = new Mastra({
agents: { agent },
observability: new Observability({
configs: {
harbor: {
serviceName: 'support-agent',
exporters: [new MastraStorageExporter(), new HarborExporter()],
excludeSpanTypes: [SpanType.MODEL_CHUNK],
spanOutputProcessors: [new SensitiveDataFilter()],
},
},
}),
})That is the whole integration. HarborExporter reads HARBOR_API_KEY and HARBOR_BASE_URL
from the environment, and takes the same options explicitly if you load configuration some
other way.
What you get
Agent runs, model calls and tool calls arrive as one nested trace, carrying model, provider, token usage, messages, tool definitions and tool arguments. Mastra's own identifiers map onto Harbor's concepts without any work on your side:
| Mastra | Harbor |
|---|---|
threadId | session — reuse it and turns stitch into one conversation |
resourceId | user.id |
| agent name | gen_ai.agent.name |
Choices worth making
Keep MastraStorageExporter if you want traces in Mastra Studio as well as Harbor. It is
what fills Studio's own trace view, and it is independent of Harbor.
Set excludeSpanTypes. Mastra emits one span per streamed chunk. Those spans carry
nothing Harbor reads and roughly double the span count of a short turn, so dropping
SpanType.MODEL_CHUNK costs nothing and saves a lot of volume.
SensitiveDataFilter redacts sensitive fields before export. Mastra applies one
automatically if you do not, but naming it keeps the behaviour visible.
The config key — harbor above — is a label, not a keyword: the first entry is the default
regardless of its name. Additional backends belong in the same config's exporters array.
A second config is for routing between environments and requires a configSelector.
Mastra puts the provider's entire HTTP response and its response headers in span metadata. Harbor keeps both out of a trace's metadata for size and safety, but they still arrive as raw span attributes — worth excluding at the source if response headers are sensitive in your environment.