Skip to content

Commit 9cdba0e

Browse files
authored
feat: add Sentry adapter (#51)
1 parent dd32666 commit 9cdba0e

13 files changed

Lines changed: 927 additions & 3 deletions

File tree

AGENTS.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ evlog provides built-in adapters for popular observability platforms. Use the `e
220220
| Axiom | `evlog/axiom` | Send logs to Axiom for querying and dashboards |
221221
| OTLP | `evlog/otlp` | OpenTelemetry Protocol for Grafana, Datadog, Honeycomb, etc. |
222222
| PostHog | `evlog/posthog` | Send logs to PostHog as events for product analytics |
223+
| Sentry | `evlog/sentry` | Send logs to Sentry Logs for structured logging and debugging |
223224

224225
**Using Axiom Adapter:**
225226

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

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

264+
**Using Sentry Adapter:**
265+
266+
```typescript
267+
// server/plugins/evlog-drain.ts
268+
import { createSentryDrain } from 'evlog/sentry'
269+
270+
export default defineNitroPlugin((nitroApp) => {
271+
nitroApp.hooks.hook('evlog:drain', createSentryDrain())
272+
})
273+
```
274+
275+
Set environment variable: `NUXT_SENTRY_DSN`.
276+
263277
**Multiple Destinations:**
264278

265279
```typescript

README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,23 @@ Set environment variables:
431431
NUXT_OTLP_ENDPOINT=http://localhost:4318
432432
```
433433

434+
### Sentry
435+
436+
```typescript
437+
// server/plugins/evlog-drain.ts
438+
import { createSentryDrain } from 'evlog/sentry'
439+
440+
export default defineNitroPlugin((nitroApp) => {
441+
nitroApp.hooks.hook('evlog:drain', createSentryDrain())
442+
})
443+
```
444+
445+
Set environment variables:
446+
447+
```bash
448+
NUXT_SENTRY_DSN=https://public@o0.ingest.sentry.io/123
449+
```
450+
434451
### Multiple Destinations
435452

436453
Send logs to multiple services:

apps/docs/content/3.adapters/1.overview.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
title: Adapters Overview
3-
description: Send your logs to external services with evlog adapters. Built-in support for Axiom, OTLP, and custom destinations.
3+
description: Send your logs to external services with evlog adapters. Built-in support for Axiom, OTLP, Sentry, and custom destinations.
44
navigation:
55
title: Overview
66
icon: i-custom-plug
@@ -20,6 +20,11 @@ links:
2020
to: /adapters/posthog
2121
color: neutral
2222
variant: subtle
23+
- label: Sentry
24+
icon: i-simple-icons-sentry
25+
to: /adapters/sentry
26+
color: neutral
27+
variant: subtle
2328
---
2429

2530
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.
@@ -70,6 +75,15 @@ export default defineNitroPlugin((nitroApp) => {
7075
Send logs to PostHog for product analytics and wide event querying.
7176
:::
7277

78+
:::card
79+
---
80+
icon: i-simple-icons-sentry
81+
title: Sentry
82+
to: /adapters/sentry
83+
---
84+
Send structured logs to Sentry Logs for high-cardinality querying.
85+
:::
86+
7387
:::card
7488
---
7589
icon: i-lucide-code
@@ -126,6 +140,9 @@ NUXT_OTLP_ENDPOINT=https://otlp.example.com
126140

127141
# PostHog
128142
NUXT_POSTHOG_API_KEY=phc_xxx
143+
144+
# Sentry
145+
NUXT_SENTRY_DSN=https://key@o0.ingest.sentry.io/123
129146
```
130147

131148
```typescript [server/plugins/evlog-drain.ts]
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
---
2+
title: Sentry Adapter
3+
description: Send structured logs to Sentry Logs for high-cardinality querying and debugging. Zero-config setup with environment variables.
4+
navigation:
5+
title: Sentry
6+
icon: i-simple-icons-sentry
7+
links:
8+
- label: Sentry Dashboard
9+
icon: i-lucide-external-link
10+
to: https://sentry.io
11+
target: _blank
12+
color: neutral
13+
variant: subtle
14+
- label: OTLP Adapter
15+
icon: i-simple-icons-opentelemetry
16+
to: /adapters/otlp
17+
color: neutral
18+
variant: subtle
19+
---
20+
21+
[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.
22+
23+
## Installation
24+
25+
The Sentry adapter comes bundled with evlog:
26+
27+
```typescript [server/plugins/evlog-drain.ts]
28+
import { createSentryDrain } from 'evlog/sentry'
29+
```
30+
31+
## Quick Start
32+
33+
### 1. Get your Sentry DSN
34+
35+
1. Create a [Sentry account](https://sentry.io)
36+
2. Create a new project (Node.js or JavaScript)
37+
3. Find your DSN in **Settings > Projects > [Your Project] > Client Keys (DSN)**
38+
39+
### 2. Set environment variables
40+
41+
```bash [.env]
42+
NUXT_SENTRY_DSN=https://your-public-key@o0.ingest.sentry.io/your-project-id
43+
```
44+
45+
### 3. Create the drain plugin
46+
47+
```typescript [server/plugins/evlog-drain.ts]
48+
import { createSentryDrain } from 'evlog/sentry'
49+
50+
export default defineNitroPlugin((nitroApp) => {
51+
nitroApp.hooks.hook('evlog:drain', createSentryDrain())
52+
})
53+
```
54+
55+
That's it! Your logs will now appear in **Explore > Logs** in Sentry.
56+
57+
## Configuration
58+
59+
The adapter reads configuration from multiple sources (highest priority first):
60+
61+
1. **Overrides** passed to `createSentryDrain()`
62+
2. **Runtime config** at `runtimeConfig.evlog.sentry`
63+
3. **Runtime config** at `runtimeConfig.sentry`
64+
4. **Environment variables** (`NUXT_SENTRY_*` or `SENTRY_*`)
65+
66+
### Environment Variables
67+
68+
| Variable | Description |
69+
|----------|-------------|
70+
| `NUXT_SENTRY_DSN` | Sentry DSN (required) |
71+
| `NUXT_SENTRY_ENVIRONMENT` | Environment name override |
72+
| `NUXT_SENTRY_RELEASE` | Release version override |
73+
74+
You can also use `SENTRY_DSN`, `SENTRY_ENVIRONMENT`, and `SENTRY_RELEASE` as fallbacks.
75+
76+
### Runtime Config
77+
78+
Configure via `nuxt.config.ts` for type-safe configuration:
79+
80+
```typescript [nuxt.config.ts]
81+
export default defineNuxtConfig({
82+
modules: ['evlog/nuxt'],
83+
evlog: {
84+
sentry: {
85+
dsn: '', // Set via NUXT_SENTRY_DSN
86+
environment: 'production',
87+
release: '1.0.0',
88+
},
89+
},
90+
})
91+
```
92+
93+
### Override Options
94+
95+
Pass options directly to override any configuration:
96+
97+
```typescript [server/plugins/evlog-drain.ts]
98+
import { createSentryDrain } from 'evlog/sentry'
99+
100+
export default defineNitroPlugin((nitroApp) => {
101+
nitroApp.hooks.hook('evlog:drain', createSentryDrain({
102+
dsn: 'https://key@o0.ingest.sentry.io/123',
103+
tags: { team: 'backend' },
104+
timeout: 10000, // 10 seconds
105+
}))
106+
})
107+
```
108+
109+
### Full Configuration Reference
110+
111+
| Option | Type | Default | Description |
112+
|--------|------|---------|-------------|
113+
| `dsn` | `string` | - | Sentry DSN (required) |
114+
| `environment` | `string` | Event environment | Environment name |
115+
| `release` | `string` | Event version | Release version |
116+
| `tags` | `Record<string, string>` | - | Additional attributes to attach |
117+
| `timeout` | `number` | `5000` | Request timeout in milliseconds |
118+
119+
## Log Transformation
120+
121+
evlog wide events are converted to Sentry Logs using `toSentryLog()`:
122+
123+
- **Level mapping**: evlog levels map directly (`debug`, `info`, `warn`, `error`)
124+
- **Severity numbers**: Follow the OpenTelemetry spec (`debug=5`, `info=9`, `warn=13`, `error=17`)
125+
- **Body**: Derived from the event's `message`, `action`, or `path` fields (first available)
126+
- **Attributes**: All wide event fields are sent as typed attributes (string, integer, double, boolean). Complex objects are serialized to JSON strings.
127+
- **Sentry attributes**: `sentry.environment` and `sentry.release` are set automatically
128+
- **Trace ID**: Uses `event.traceId` if available, otherwise generates a random one
129+
130+
## Querying Logs in Sentry
131+
132+
evlog sends wide events as structured logs. In the Sentry dashboard:
133+
134+
- **Explore > Logs**: View all evlog wide events with full attribute search
135+
- **Filter by attributes**: `service:my-app`, `level:error`, or any wide event field
136+
- **Trace correlation**: Logs are linked to traces via `trace_id` for cross-referencing
137+
138+
::callout{icon="i-lucide-info" color="info"}
139+
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.
140+
::
141+
142+
## Troubleshooting
143+
144+
### Missing DSN error
145+
146+
```
147+
[evlog/sentry] Missing DSN. Set NUXT_SENTRY_DSN/SENTRY_DSN env var or pass to createSentryDrain()
148+
```
149+
150+
Make sure your environment variable is set and the server was restarted after adding it.
151+
152+
### Invalid DSN
153+
154+
If the DSN is malformed (missing public key or project ID), the adapter will throw an error. Verify your DSN format:
155+
156+
```
157+
https://<public-key>@<host>/<project-id>
158+
```
159+
160+
### 401 Unauthorized
161+
162+
Your DSN may be revoked or invalid. Generate a new DSN in **Settings > Projects > Client Keys (DSN)**.
163+
164+
## Direct API Usage
165+
166+
For advanced use cases, you can use the lower-level functions:
167+
168+
```typescript [server/utils/sentry.ts]
169+
import { sendToSentry, sendBatchToSentry } from 'evlog/sentry'
170+
171+
// Send a single event as a Sentry log
172+
await sendToSentry(event, {
173+
dsn: process.env.SENTRY_DSN!,
174+
})
175+
176+
// Send multiple events in one request
177+
await sendBatchToSentry(events, {
178+
dsn: process.env.SENTRY_DSN!,
179+
})
180+
```
181+
182+
## Next Steps
183+
184+
- [Axiom Adapter](/adapters/axiom) - Send logs to Axiom for querying and dashboards
185+
- [OTLP Adapter](/adapters/otlp) - Send logs via OpenTelemetry Protocol
186+
- [PostHog Adapter](/adapters/posthog) - Send logs to PostHog
187+
- [Custom Adapters](/adapters/custom) - Build your own adapter

apps/playground/nuxt.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export default defineNuxtConfig({
2828
{ status: 400 }, // Keep errors
2929
{ duration: 500 }, // Keep slow requests (>500ms)
3030
{ path: '/api/test/critical/**' }, // Keep critical paths
31+
{ path: '/api/test/drain' }, // Always keep drain test logs
3132
],
3233
},
3334
},

apps/playground/server/plugins/evlog-drain.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// import { createAxiomDrain } from 'evlog/axiom'
22
// import { createPostHogDrain } from 'evlog/posthog'
3+
// import { createSentryDrain } from 'evlog/sentry'
34

45
export default defineNitroPlugin((nitroApp) => {
56
nitroApp.hooks.hook('evlog:drain', (ctx) => {
@@ -12,11 +13,12 @@ export default defineNitroPlugin((nitroApp) => {
1213
// const axiomDrain = createAxiomDrain({
1314
// dataset: 'evlog',
1415
// })
15-
1616
// axiomDrain(ctx)
1717

1818
// const posthogDrain = createPostHogDrain()
19-
2019
// posthogDrain(ctx)
20+
21+
// const sentryDrain = createSentryDrain()
22+
// sentryDrain(ctx)
2123
})
2224
})

packages/evlog/README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,23 @@ Set environment variables:
431431
NUXT_OTLP_ENDPOINT=http://localhost:4318
432432
```
433433

434+
### Sentry
435+
436+
```typescript
437+
// server/plugins/evlog-drain.ts
438+
import { createSentryDrain } from 'evlog/sentry'
439+
440+
export default defineNitroPlugin((nitroApp) => {
441+
nitroApp.hooks.hook('evlog:drain', createSentryDrain())
442+
})
443+
```
444+
445+
Set environment variables:
446+
447+
```bash
448+
NUXT_SENTRY_DSN=https://public@o0.ingest.sentry.io/123
449+
```
450+
434451
### Multiple Destinations
435452

436453
Send logs to multiple services:

packages/evlog/build.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export default defineBuildConfig({
1919
{ input: 'src/adapters/axiom', name: 'adapters/axiom' },
2020
{ input: 'src/adapters/otlp', name: 'adapters/otlp' },
2121
{ input: 'src/adapters/posthog', name: 'adapters/posthog' },
22+
{ input: 'src/adapters/sentry', name: 'adapters/sentry' },
2223
],
2324
declaration: true,
2425
clean: true,

packages/evlog/package.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@
5050
"./posthog": {
5151
"types": "./dist/adapters/posthog.d.mts",
5252
"import": "./dist/adapters/posthog.mjs"
53+
},
54+
"./sentry": {
55+
"types": "./dist/adapters/sentry.d.mts",
56+
"import": "./dist/adapters/sentry.mjs"
5357
}
5458
},
5559
"main": "./dist/index.mjs",
@@ -76,6 +80,9 @@
7680
],
7781
"posthog": [
7882
"./dist/adapters/posthog.d.mts"
83+
],
84+
"sentry": [
85+
"./dist/adapters/sentry.d.mts"
7986
]
8087
}
8188
},

0 commit comments

Comments
 (0)