> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sedata-ai.tech/llms.txt
> Use this file to discover all available pages before exploring further.

# TelemetryManager

> Lower-level class behind instrumentServer. Owns the OpenTelemetry SDK.

```ts theme={null}
class TelemetryManager implements ObservabilityInstance
```

`TelemetryManager` is the implementation behind the
[`ObservabilityInstance`](/api-reference/types/observability-instance) you get
back from `instrumentServer`. Most users never construct one directly —
`instrumentServer` does it for you. Reach for it when you want more control:
multiple managers per process, advanced testing, or non-MCP instrumentation.

## Constructor

```ts theme={null}
new TelemetryManager(config: TelemetryConfig)
```

Validates the config, builds the OpenTelemetry `NodeSDK`, attaches resource
detectors, and starts the SDK.

## Public properties

<ResponseField name="tracer" type="Tracer">
  The OpenTelemetry tracer scoped to your `serverName` / `serverVersion`.
</ResponseField>

<ResponseField name="meter" type="Meter">
  The OpenTelemetry meter scoped to your `serverName` / `serverVersion`.
</ResponseField>

## Methods

### `startActiveSpan(name, attributes, fn)`

Open an active span. Adds `mcp.session.id` to the attributes automatically.

```ts theme={null}
manager.startActiveSpan('cache.lookup', { 'cache.key': 'user:42' }, (span) => {
  // ...
  span.end()
})
```

### `createSpan(name, attributes)`

Create a span without making it active. Useful when you need a manually
managed span.

```ts theme={null}
const span = manager.createSpan('background.task', {})
// later
span.end()
```

### `getHistogram(name, options)`

Returns a recorder function `(value, attributes?) => void`. Reuse the same
recorder across calls to avoid re-creating the instrument:

```ts theme={null}
const recordDuration = manager.getHistogram('cache.lookup.duration', {
  description: 'Cache lookup duration',
  unit: 'ms',
})

recordDuration(12, { 'cache.hit': true })
```

### `getIncrementCounter(name, options)`

Returns an increment function `(value, attributes?) => void`:

```ts theme={null}
const incRetry = manager.getIncrementCounter('upstream.retry.count', {
  description: 'Upstream retries',
})

incRetry(1, { upstream: 'github' })
```

### `getArgumentAttributes(params, prefix?)`

Flattens an object of tool arguments into a flat attribute map for use in span
attributes. Honors `enableArgumentCollection` — returns `{}` when off.

```ts theme={null}
manager.getArgumentAttributes({ city: 'sf', units: 'metric' })
// → { 'mcp.request.argument.city': 'sf', 'mcp.request.argument.units': 'metric' }
```

### `processTelemetryAttributes(data)`

Runs `data` through every configured `dataProcessor` in order.

```ts theme={null}
const cleaned = manager.processTelemetryAttributes({ 'user.email': 'jane@acme.com' })
```

### `shutdown(): Promise<void>`

Records the session-duration histogram and shuts down the underlying
`NodeSDK`. Always call this on graceful exit.

## Example: standalone use

```ts theme={null}
import { TelemetryManager } from '@sedata-ai/mcp'

const manager = new TelemetryManager({
  serverName: 'background-worker',
  serverVersion: '1.0.0',
  exporterEndpoint: 'https://otel.sedata-ai.tech/v1',
  exporterAuth: { type: 'bearer', token: process.env.SEDATA_TOKEN! },
})

manager.startActiveSpan('worker.run', { 'worker.id': '42' }, async (span) => {
  await doWork()
  span.end()
})

await manager.shutdown()
```

## See also

<CardGroup cols={2}>
  <Card title="instrumentServer" icon="plug" href="/api-reference/instrument-server">
    Higher-level entry point most users want.
  </Card>

  <Card title="Custom instrumentation" icon="code" href="/metrics-and-traces/custom-instrumentation">
    Patterns for using the tracer and meter directly.
  </Card>
</CardGroup>
