Skip to content

Commit 08cab7b

Browse files
authored
fix(nuxt): sync runtime evlog to nitro & noop logger when off (#261)
1 parent 7ab2243 commit 08cab7b

5 files changed

Lines changed: 55 additions & 5 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'evlog': patch
3+
---
4+
5+
Fix Nuxt `evlog` options not reaching the Nitro plugin in dev: the Nuxt module now mirrors standalone Nitro by setting `process.env.__EVLOG_CONFIG` during `nitro:config`. When `enabled` is `false`, the Nitro plugins still attach a no-op request logger so `useLogger(event)` does not throw.

AGENTS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,8 @@ export default defineConfig({
234234

235235
The Nuxt module uses `addVitePlugin()` to add strip + source location plugins internally. Auto-imports and client init are NOT delegated (Nuxt handles those natively). This is purely additive — no breaking change.
236236

237+
On `nitro:config`, the module serializes `runtimeConfig.evlog` into **`process.env.__EVLOG_CONFIG`** (same bridge as standalone Nitro). The Nitro plugin resolves config with **env first**, then `useRuntimeConfig().evlog`. That env injection is required because dev workers often cannot resolve the virtual Nitro runtime-config module reliably. **Do not** set `__EVLOG_CONFIG` yourself in a Nuxt app unless you mean to override the entire `evlog` block from `nuxt.config`.
238+
237239
## Framework Integration
238240

239241
> **Creating a new framework integration?** Follow the skill at `.agents/skills/create-framework-integration/SKILL.md`. It covers all touchpoints: source code, build config, package exports, tests, example app, and all documentation updates.

packages/evlog/src/nitro-v3/plugin.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,10 +142,28 @@ export default definePlugin(async (nitroApp) => {
142142
_suppressDrainWarning: true,
143143
})
144144

145-
if (!isEnabled()) return
146-
147145
const hooks = nitroApp.hooks as unknown as Hooks
148146

147+
// When globally disabled, createRequestLogger returns a no-op logger — still
148+
// attach it so handlers can call useLogger without throwing.
149+
if (!isEnabled()) {
150+
hooks.hook('request', (event) => {
151+
const { pathname } = parseURL(event.req.url)
152+
const ctx = getContext(event)
153+
let requestIdOverride: string | undefined
154+
if (globalThis.navigator?.userAgent === 'Cloudflare-Workers') {
155+
const cfRay = event.req.headers.get('cf-ray')
156+
if (cfRay) requestIdOverride = cfRay
157+
}
158+
ctx.log = createRequestLogger({
159+
method: event.req.method,
160+
path: pathname,
161+
requestId: requestIdOverride || ctx.requestId as string | undefined || crypto.randomUUID(),
162+
}, { _deferDrain: true })
163+
})
164+
return
165+
}
166+
149167
hooks.hook('request', (event) => {
150168
const { pathname } = parseURL(event.req.url)
151169
const ctx = getContext(event)

packages/evlog/src/nitro/plugin.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,24 @@ export default defineNitroPlugin(async (nitroApp) => {
117117
_suppressDrainWarning: true,
118118
})
119119

120-
if (!isEnabled()) return
120+
// When globally disabled, createRequestLogger returns a no-op logger — still
121+
// attach it so handlers can call useLogger(event) without throwing.
122+
if (!isEnabled()) {
123+
nitroApp.hooks.hook('request', (event) => {
124+
const e = event as ServerEvent
125+
let requestIdOverride: string | undefined
126+
if (globalThis.navigator?.userAgent === 'Cloudflare-Workers') {
127+
const cfRay = getSafeHeaders(e)?.['cf-ray']
128+
if (cfRay) requestIdOverride = cfRay
129+
}
130+
e.context.log = createRequestLogger({
131+
method: e.method,
132+
path: e.path,
133+
requestId: requestIdOverride || e.context.requestId || crypto.randomUUID(),
134+
}, { _deferDrain: true })
135+
})
136+
return
137+
}
121138

122139
nitroApp.hooks.hook('request', (event) => {
123140
const e = event as ServerEvent

packages/evlog/src/nuxt/module.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -267,14 +267,22 @@ export default defineNuxtModule<ModuleOptions>({
267267
const transportEndpoint = options.transport?.endpoint ?? '/api/_evlog/ingest'
268268
const transportCredentials = options.transport?.credentials ?? 'same-origin'
269269

270+
nuxt.options.runtimeConfig.evlog = options
271+
270272
// Register custom error handler for proper EvlogError serialization
271273
// Only set if not already configured to avoid overwriting user's custom handler
274+
// Mirror standalone Nitro modules: serialize evlog options into __EVLOG_CONFIG so
275+
// resolveEvlogConfigForNitroPlugin() picks them up in dev (Nitro worker threads
276+
// often cannot resolve useRuntimeConfig().evlog via dynamic import reliably).
272277
// @ts-expect-error nitro:config hook exists but is not in NuxtHooks type
273278
nuxt.hook('nitro:config', (nitroConfig: NitroConfig) => {
274279
nitroConfig.errorHandler = nitroConfig.errorHandler || resolver.resolve('../nitro/errorHandler')
275-
})
276280

277-
nuxt.options.runtimeConfig.evlog = options
281+
const evlogForNitro = nuxt.options.runtimeConfig.evlog ?? options
282+
if (evlogForNitro !== undefined && typeof evlogForNitro === 'object') {
283+
process.env.__EVLOG_CONFIG = JSON.stringify(evlogForNitro)
284+
}
285+
})
278286
nuxt.options.runtimeConfig.public.evlog = {
279287
enabled: options.enabled ?? true,
280288
console: options.console,

0 commit comments

Comments
 (0)