---
title: "AI SDK Integration"
description: "Capture token usage, tool calls, model info, and streaming metrics from the Vercel AI SDK into wide events. Wrap your model, get the rest free."
canonical_url: "https://www.evlog.dev/use-cases/ai-sdk/overview"
---
# AI SDK Integration

> Capture token usage, tool calls, model info, and streaming metrics from the Vercel AI SDK into wide events. Wrap your model, get the rest free.

`evlog/ai` gives you full AI observability by wrapping your model with middleware. Token usage, tool calls, streaming performance, cache hits, reasoning tokens, and cost estimation, all captured into the wide event automatically.

<prompt :actions="["copy","cursor","claude"]" description="Add AI observability with evlog" icon="i-simple-icons-vercel">

Add AI observability to my app with evlog.

- Install the AI SDK: pnpm add ai
- Import createAILogger from 'evlog/ai'
- Create an AI logger with createAILogger(log) where log is your request logger
- Wrap your model with ai.wrap('anthropic/claude-sonnet-4.6') and pass it to generateText, streamText, etc.
- Token usage, tool calls, streaming metrics, and errors are captured automatically into the wide event
- For deeper observability (tool execution timing, total generation wall time), add createEvlogIntegration(ai) to telemetry.integrations
- For embedding calls, use ai.captureEmbed({ usage, model, dimensions, count }) after embed() or embedMany()
- For cost estimation, pass a cost map: createAILogger(log, { cost: { 'claude-sonnet-4.6': { input: 3, output: 15 } } })
- Works with all frameworks: Nuxt, Express, Hono, Fastify, NestJS, Elysia, standalone

Docs: [https://www.evlog.dev/use-cases/ai-sdk/overview](https://www.evlog.dev/use-cases/ai-sdk/overview)
Adapters: [https://www.evlog.dev/integrate/adapters/overview](https://www.evlog.dev/integrate/adapters/overview)

</prompt>

## Install

Add the AI SDK as a dependency:

<code-group>

```bash [pnpm]
pnpm add ai
```

```bash [bun]
bun add ai
```

```bash [yarn]
yarn add ai
```

```bash [npm]
npm install ai
```

</code-group>

## Quick Start

<ai-sdk-wide-event>



</ai-sdk-wide-event>

Two lines to add, one param to change:

<code-group>

```typescript [Before]
export default defineEventHandler(async (event) => {
  const result = streamText({
    model: 'anthropic/claude-sonnet-4.6',
    messages,
  })
  return result.toTextStreamResponse()
})
```

```typescript [After]
import { useLogger } from 'evlog'
import { createAILogger } from 'evlog/ai'

export default defineEventHandler(async (event) => {
  const log = useLogger(event)
  const ai = createAILogger(log)

  const result = streamText({
    model: ai.wrap('anthropic/claude-sonnet-4.6'),
    messages,
  })
  return result.toTextStreamResponse()
})
```

</code-group>

Your wide event now includes:

```json [Wide Event]
{
  "method": "POST",
  "path": "/api/chat",
  "status": 200,
  "duration": "4.5s",
  "durationMs": 4512,
  "ai": {
    "calls": 1,
    "model": "claude-sonnet-4.6",
    "provider": "anthropic",
    "inputTokens": 3312,
    "outputTokens": 814,
    "totalTokens": 4126,
    "reasoningTokens": 225,
    "finishReason": "stop",
    "msToFirstChunk": 234,
    "msToFinish": 4500,
    "tokensPerSecond": 180
  }
}
```

## How It Works

`createAILogger(log, options?)` returns an `AILogger` with the following methods:

<table>
<thead>
  <tr>
    <th>
      Method
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        wrap(model)
      </code>
    </td>
    
    <td>
      Wraps a language model with middleware. Accepts a model string (e.g. <code>
        'anthropic/claude-sonnet-4.6'
      </code>
      
      ) or a <code>
        LanguageModelV3
      </code>
      
       / <code>
        LanguageModelV4
      </code>
      
       object. Works with <code>
        generateText
      </code>
      
      , <code>
        streamText
      </code>
      
      , and <code>
        ToolLoopAgent
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        captureEmbed(result)
      </code>
    </td>
    
    <td>
      Manually captures token usage, model info, and dimensions from <code>
        embed()
      </code>
      
       or <code>
        embedMany()
      </code>
      
       results.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        getMetadata()
      </code>
    </td>
    
    <td>
      Returns a snapshot of the current execution metadata. See <a href="https://www.evlog.dev/use-cases/ai-sdk/metadata">
        Access Metadata
      </a>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        getEstimatedCost()
      </code>
    </td>
    
    <td>
      Returns the current estimated cost in dollars when a <code>
        cost
      </code>
      
       map is configured.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        onUpdate(callback)
      </code>
    </td>
    
    <td>
      Subscribe to metadata updates. Fires on every step, embed, error, and integration finish.
    </td>
  </tr>
</tbody>
</table>

The middleware intercepts calls at the provider level. It does not touch your callbacks, prompts, or responses. Captured data flows through the normal evlog pipeline (sampling, enrichers, drains) and lands in Axiom, Better Stack, or wherever you drain to.

## Where to next

<card-group>
<card icon="i-lucide-code" title="Usage Patterns" to="https://www.evlog.dev/use-cases/ai-sdk/usage">

`streamText`, `generateText`, multi-step agents, RAG, multiple models: every common pattern, ready to copy.

</card>

<card icon="i-lucide-sliders" title="Options" to="https://www.evlog.dev/use-cases/ai-sdk/options">

Capture tool inputs (with redaction and truncation), enable cost estimation, and handle errors.

</card>

<card icon="i-lucide-database" title="Access Metadata" to="https://www.evlog.dev/use-cases/ai-sdk/metadata">

Read the captured `ai` data inside your handler: persist it, bill against it, or stream it to the client.

</card>

<card icon="i-lucide-activity" title="Deeper Telemetry" to="https://www.evlog.dev/use-cases/ai-sdk/telemetry">

Add tool execution timing and total wall time with `createEvlogIntegration`. Compose with other middlewares.

</card>
</card-group>

## Works With All Frameworks

`evlog/ai` works with any framework that evlog supports:

<framework-tabs>

```typescript [Nuxt]
import { useLogger } from 'evlog'
import { createAILogger } from 'evlog/ai'

const log = useLogger(event)
const ai = createAILogger(log)
```

```typescript [Next.js]
import { withEvlog, useLogger } from '@/lib/evlog'
import { createAILogger } from 'evlog/ai'

export const POST = withEvlog(async () => {
  const log = useLogger()
  const ai = createAILogger(log)
  // ...
})
```

```typescript [Express]src/index.ts
import { createAILogger } from 'evlog/ai'

app.post('/api/chat', (req, res) => {
  const ai = createAILogger(req.log)
  // ...
})
```

```typescript [Hono]src/index.ts
import { createAILogger } from 'evlog/ai'

app.post('/api/chat', (c) => {
  const ai = createAILogger(c.get('log'))
  // ...
})
```

```typescript [Fastify]src/index.ts
import { createAILogger } from 'evlog/ai'

app.post('/api/chat', async (request) => {
  const ai = createAILogger(request.log)
  // ...
})
```

```typescript [NestJS]src/app.module.ts
import { useLogger } from 'evlog/nestjs'
import { createAILogger } from 'evlog/ai'

const log = useLogger()
const ai = createAILogger(log)
```

```typescript [Standalone]
import { createLogger } from 'evlog'
import { createAILogger } from 'evlog/ai'

const log = createLogger()
const ai = createAILogger(log)
// ...
log.emit()
```

</framework-tabs>

---

- [Usage Patterns](https://www.evlog.dev/use-cases/ai-sdk/usage)
- [Options](https://www.evlog.dev/use-cases/ai-sdk/options)
- [Access Metadata](https://www.evlog.dev/use-cases/ai-sdk/metadata)
- [Deeper Telemetry](https://www.evlog.dev/use-cases/ai-sdk/telemetry)


## Sitemap

See the full [sitemap](https://www.evlog.dev/sitemap.md) for all pages.
