Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ evlog provides built-in adapters for popular observability platforms. Use the `e
| Axiom | `evlog/axiom` | Send logs to Axiom for querying and dashboards |
| OTLP | `evlog/otlp` | OpenTelemetry Protocol for Grafana, Datadog, Honeycomb, etc. |
| PostHog | `evlog/posthog` | Send logs to PostHog as events for product analytics |
| Sentry | `evlog/sentry` | Send logs to Sentry Logs for structured logging and debugging |

**Using Axiom Adapter:**

Expand Down Expand Up @@ -260,6 +261,19 @@ export default defineNitroPlugin((nitroApp) => {

Set environment variable: `NUXT_POSTHOG_API_KEY` (and optionally `NUXT_POSTHOG_HOST` for EU or self-hosted instances).

**Using Sentry Adapter:**

```typescript
// server/plugins/evlog-drain.ts
import { createSentryDrain } from 'evlog/sentry'

export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('evlog:drain', createSentryDrain())
})
```

Set environment variable: `NUXT_SENTRY_DSN`.

**Multiple Destinations:**

```typescript
Expand Down
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,23 @@ Set environment variables:
NUXT_OTLP_ENDPOINT=http://localhost:4318
```

### Sentry

```typescript
// server/plugins/evlog-drain.ts
import { createSentryDrain } from 'evlog/sentry'

export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('evlog:drain', createSentryDrain())
})
```

Set environment variables:

```bash
NUXT_SENTRY_DSN=https://public@o0.ingest.sentry.io/123
```

### Multiple Destinations

Send logs to multiple services:
Expand Down
19 changes: 18 additions & 1 deletion apps/docs/content/3.adapters/1.overview.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Adapters Overview
description: Send your logs to external services with evlog adapters. Built-in support for Axiom, OTLP, and custom destinations.
description: Send your logs to external services with evlog adapters. Built-in support for Axiom, OTLP, Sentry, and custom destinations.
navigation:
title: Overview
icon: i-custom-plug
Expand All @@ -20,6 +20,11 @@ links:
to: /adapters/posthog
color: neutral
variant: subtle
- label: Sentry
icon: i-simple-icons-sentry
to: /adapters/sentry
color: neutral
variant: subtle
---

Adapters let you send logs to external observability platforms. evlog provides built-in adapters for popular services, and you can create custom adapters for any destination.
Expand Down Expand Up @@ -70,6 +75,15 @@ export default defineNitroPlugin((nitroApp) => {
Send logs to PostHog for product analytics and wide event querying.
:::

:::card
---
icon: i-simple-icons-sentry
title: Sentry
to: /adapters/sentry
---
Send structured logs to Sentry Logs for high-cardinality querying.
:::

:::card
---
icon: i-lucide-code
Expand Down Expand Up @@ -126,6 +140,9 @@ NUXT_OTLP_ENDPOINT=https://otlp.example.com

# PostHog
NUXT_POSTHOG_API_KEY=phc_xxx

# Sentry
NUXT_SENTRY_DSN=https://key@o0.ingest.sentry.io/123
```

```typescript [server/plugins/evlog-drain.ts]
Expand Down
187 changes: 187 additions & 0 deletions apps/docs/content/3.adapters/5.sentry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
---
title: Sentry Adapter
description: Send structured logs to Sentry Logs for high-cardinality querying and debugging. Zero-config setup with environment variables.
navigation:
title: Sentry
icon: i-simple-icons-sentry
links:
- label: Sentry Dashboard
icon: i-lucide-external-link
to: https://sentry.io
target: _blank
color: neutral
variant: subtle
- label: OTLP Adapter
icon: i-simple-icons-opentelemetry
to: /adapters/otlp
color: neutral
variant: subtle
---

[Sentry](https://sentry.io) is an error tracking and performance monitoring platform. The evlog Sentry adapter sends your wide events as **Sentry Structured Logs**, visible in **Explore > Logs** in the Sentry dashboard with high-cardinality searchable attributes.

## Installation

The Sentry adapter comes bundled with evlog:

```typescript [server/plugins/evlog-drain.ts]
import { createSentryDrain } from 'evlog/sentry'
```

## Quick Start

### 1. Get your Sentry DSN

1. Create a [Sentry account](https://sentry.io)
2. Create a new project (Node.js or JavaScript)
3. Find your DSN in **Settings > Projects > [Your Project] > Client Keys (DSN)**

### 2. Set environment variables

```bash [.env]
NUXT_SENTRY_DSN=https://your-public-key@o0.ingest.sentry.io/your-project-id
```

### 3. Create the drain plugin

```typescript [server/plugins/evlog-drain.ts]
import { createSentryDrain } from 'evlog/sentry'

export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('evlog:drain', createSentryDrain())
})
```

That's it! Your logs will now appear in **Explore > Logs** in Sentry.

## Configuration

The adapter reads configuration from multiple sources (highest priority first):

1. **Overrides** passed to `createSentryDrain()`
2. **Runtime config** at `runtimeConfig.evlog.sentry`
3. **Runtime config** at `runtimeConfig.sentry`
4. **Environment variables** (`NUXT_SENTRY_*` or `SENTRY_*`)

### Environment Variables

| Variable | Description |
|----------|-------------|
| `NUXT_SENTRY_DSN` | Sentry DSN (required) |
| `NUXT_SENTRY_ENVIRONMENT` | Environment name override |
| `NUXT_SENTRY_RELEASE` | Release version override |

You can also use `SENTRY_DSN`, `SENTRY_ENVIRONMENT`, and `SENTRY_RELEASE` as fallbacks.

### Runtime Config

Configure via `nuxt.config.ts` for type-safe configuration:

```typescript [nuxt.config.ts]
export default defineNuxtConfig({
modules: ['evlog/nuxt'],
evlog: {
sentry: {
dsn: '', // Set via NUXT_SENTRY_DSN
environment: 'production',
release: '1.0.0',
},
},
})
```

### Override Options

Pass options directly to override any configuration:

```typescript [server/plugins/evlog-drain.ts]
import { createSentryDrain } from 'evlog/sentry'

export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('evlog:drain', createSentryDrain({
dsn: 'https://key@o0.ingest.sentry.io/123',
tags: { team: 'backend' },
timeout: 10000, // 10 seconds
}))
})
```

### Full Configuration Reference

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `dsn` | `string` | - | Sentry DSN (required) |
| `environment` | `string` | Event environment | Environment name |
| `release` | `string` | Event version | Release version |
| `tags` | `Record<string, string>` | - | Additional attributes to attach |
| `timeout` | `number` | `5000` | Request timeout in milliseconds |

## Log Transformation

evlog wide events are converted to Sentry Logs using `toSentryLog()`:

- **Level mapping**: evlog levels map directly (`debug`, `info`, `warn`, `error`)
- **Severity numbers**: Follow the OpenTelemetry spec (`debug=5`, `info=9`, `warn=13`, `error=17`)
- **Body**: Derived from the event's `message`, `action`, or `path` fields (first available)
- **Attributes**: All wide event fields are sent as typed attributes (string, integer, double, boolean). Complex objects are serialized to JSON strings.
- **Sentry attributes**: `sentry.environment` and `sentry.release` are set automatically
- **Trace ID**: Uses `event.traceId` if available, otherwise generates a random one

## Querying Logs in Sentry

evlog sends wide events as structured logs. In the Sentry dashboard:

- **Explore > Logs**: View all evlog wide events with full attribute search
- **Filter by attributes**: `service:my-app`, `level:error`, or any wide event field
- **Trace correlation**: Logs are linked to traces via `trace_id` for cross-referencing

::callout{icon="i-lucide-info" color="info"}
Sentry Structured Logs support high-cardinality attributes, making them a great fit for evlog's wide events. Every field in your wide event becomes a searchable attribute in Sentry.
::

## Troubleshooting

### Missing DSN error

```
[evlog/sentry] Missing DSN. Set NUXT_SENTRY_DSN/SENTRY_DSN env var or pass to createSentryDrain()
```

Make sure your environment variable is set and the server was restarted after adding it.

### Invalid DSN

If the DSN is malformed (missing public key or project ID), the adapter will throw an error. Verify your DSN format:

```
https://<public-key>@<host>/<project-id>
```

### 401 Unauthorized

Your DSN may be revoked or invalid. Generate a new DSN in **Settings > Projects > Client Keys (DSN)**.

## Direct API Usage

For advanced use cases, you can use the lower-level functions:

```typescript [server/utils/sentry.ts]
import { sendToSentry, sendBatchToSentry } from 'evlog/sentry'

// Send a single event as a Sentry log
await sendToSentry(event, {
dsn: process.env.SENTRY_DSN!,
})

// Send multiple events in one request
await sendBatchToSentry(events, {
dsn: process.env.SENTRY_DSN!,
})
```

## Next Steps

- [Axiom Adapter](/adapters/axiom) - Send logs to Axiom for querying and dashboards
- [OTLP Adapter](/adapters/otlp) - Send logs via OpenTelemetry Protocol
- [PostHog Adapter](/adapters/posthog) - Send logs to PostHog
- [Custom Adapters](/adapters/custom) - Build your own adapter
1 change: 1 addition & 0 deletions apps/playground/nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export default defineNuxtConfig({
{ status: 400 }, // Keep errors
{ duration: 500 }, // Keep slow requests (>500ms)
{ path: '/api/test/critical/**' }, // Keep critical paths
{ path: '/api/test/drain' }, // Always keep drain test logs
],
},
},
Expand Down
6 changes: 4 additions & 2 deletions apps/playground/server/plugins/evlog-drain.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// import { createAxiomDrain } from 'evlog/axiom'
// import { createPostHogDrain } from 'evlog/posthog'
// import { createSentryDrain } from 'evlog/sentry'

export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('evlog:drain', (ctx) => {
Expand All @@ -12,11 +13,12 @@ export default defineNitroPlugin((nitroApp) => {
// const axiomDrain = createAxiomDrain({
// dataset: 'evlog',
// })

// axiomDrain(ctx)

// const posthogDrain = createPostHogDrain()

// posthogDrain(ctx)

// const sentryDrain = createSentryDrain()
// sentryDrain(ctx)
})
})
17 changes: 17 additions & 0 deletions packages/evlog/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,23 @@ Set environment variables:
NUXT_OTLP_ENDPOINT=http://localhost:4318
```

### Sentry

```typescript
// server/plugins/evlog-drain.ts
import { createSentryDrain } from 'evlog/sentry'

export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('evlog:drain', createSentryDrain())
})
```

Set environment variables:

```bash
NUXT_SENTRY_DSN=https://public@o0.ingest.sentry.io/123
```

### Multiple Destinations

Send logs to multiple services:
Expand Down
1 change: 1 addition & 0 deletions packages/evlog/build.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export default defineBuildConfig({
{ input: 'src/adapters/axiom', name: 'adapters/axiom' },
{ input: 'src/adapters/otlp', name: 'adapters/otlp' },
{ input: 'src/adapters/posthog', name: 'adapters/posthog' },
{ input: 'src/adapters/sentry', name: 'adapters/sentry' },
],
declaration: true,
clean: true,
Expand Down
7 changes: 7 additions & 0 deletions packages/evlog/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@
"./posthog": {
"types": "./dist/adapters/posthog.d.mts",
"import": "./dist/adapters/posthog.mjs"
},
"./sentry": {
"types": "./dist/adapters/sentry.d.mts",
"import": "./dist/adapters/sentry.mjs"
}
},
"main": "./dist/index.mjs",
Expand All @@ -76,6 +80,9 @@
],
"posthog": [
"./dist/adapters/posthog.d.mts"
],
"sentry": [
"./dist/adapters/sentry.d.mts"
]
}
},
Expand Down
Loading
Loading