From 1f01405b15c1a3350902af17ea5ce60e34b3a53c Mon Sep 17 00:00:00 2001 From: Sean LeCheminant Date: Thu, 5 Feb 2026 10:50:36 -0600 Subject: [PATCH 1/9] feat: inset Add feature to allow nesting evlog data into another property --- .../1.getting-started/2.installation.md | 36 +++++++++++++++++++ bun.lock | 1 + packages/evlog/src/logger.ts | 15 ++++++-- packages/evlog/src/nitro/plugin.ts | 11 +++--- packages/evlog/src/nuxt/module.ts | 23 +++++++++++- packages/evlog/src/types.ts | 9 +++++ 6 files changed, 87 insertions(+), 8 deletions(-) diff --git a/apps/docs/content/1.getting-started/2.installation.md b/apps/docs/content/1.getting-started/2.installation.md index 12a4326..ef1a3e9 100644 --- a/apps/docs/content/1.getting-started/2.installation.md +++ b/apps/docs/content/1.getting-started/2.installation.md @@ -46,6 +46,8 @@ export default defineNuxtConfig({ include: ['/api/**'], // Optional: exclude specific routes from logging exclude: ['/api/_nuxt_icon/**'], + // Optional: nested property name for wide events + inset: 'evlog' }, }) ``` @@ -60,6 +62,7 @@ export default defineNuxtConfig({ | `exclude` | `string[]` | `undefined` | Route patterns to exclude from logging. Supports glob (`/api/_nuxt_icon/**`). Exclusions take precedence over inclusions | | `routes` | `Record` | `undefined` | Route-specific service configuration. Allows setting different service names for different routes using glob patterns | | `pretty` | `boolean` | `true` in dev | Pretty print with tree formatting | +| `inset` | `string` | `'evlog'` | Nested property name for wide events | | `sampling.rates` | `object` | `undefined` | Head sampling rates per log level (0-100%). See [Sampling](#sampling) | | `sampling.keep` | `array` | `undefined` | Tail sampling conditions to force-keep logs. See [Sampling](#sampling) | | `transport.enabled` | `boolean` | `false` | Enable sending client logs to the server. See [Client Transport](#client-transport) | @@ -116,6 +119,39 @@ All logs from matching routes will automatically include the configured service You can also override the service name per handler using `useLogger(event, 'service-name')`. See [Quick Start - Service Identification](/getting-started/quick-start#service-identification) for details. +### Nesting log data + +By default, evlog will log the object at root level when logging without ```pretty``` enabled (see [Configuration Options](/getting-started/installation#configuration-options)); however, for services like Cloudflare Observability, you may wish to nest the data inside an arbitrary property name. This can help organize your data and make it easier to query and analyze. + +::callout{icon="i-lucide-info" color="warning"} +**Note:** Nesting can have adverse effects if your logging system expects root-level json data, such as requestIds, or tracing ids. +:: + +```typescript [nuxt.config.ts] +export default defineNuxtConfig({ + modules: ['evlog/nuxt'], + evlog: { + inset: "data", + }, +}); +``` + +In this example, your logs will then be nested under the `data` property: + +```json [Observability Logs] +{ + "$data": { + "timestamp": "2026-02-05T06:48:18.122Z", + "level": "info", + "message": "This is an info log", + "method": "GET", + ... + }, + "$metadata": {...}, + "$workers": {...} +} +``` + ### Sampling At scale, logging everything can become expensive. evlog supports two sampling strategies: diff --git a/bun.lock b/bun.lock index ba7d399..76dae0e 100644 --- a/bun.lock +++ b/bun.lock @@ -1,5 +1,6 @@ { "lockfileVersion": 1, + "configVersion": 0, "workspaces": { "": { "name": "evlog-monorepo", diff --git a/packages/evlog/src/logger.ts b/packages/evlog/src/logger.ts index 4e997d2..c1d4827 100644 --- a/packages/evlog/src/logger.ts +++ b/packages/evlog/src/logger.ts @@ -1,5 +1,5 @@ import { defu } from 'defu' -import type { EnvironmentContext, Log, LogLevel, LoggerConfig, RequestLogger, RequestLoggerOptions, SamplingConfig, TailSamplingContext, WideEvent } from './types' +import type { EnvironmentContext, InsetWideEvent, Log, LogLevel, LoggerConfig, RequestLogger, RequestLoggerOptions, SamplingConfig, TailSamplingContext, WideEvent } from './types' import { colors, detectEnvironment, formatDuration, getConsoleMethod, getLevelColor, isDev, matchesPattern } from './utils' let globalEnv: EnvironmentContext = { @@ -10,6 +10,7 @@ let globalEnv: EnvironmentContext = { let globalPretty = isDev() let globalSampling: SamplingConfig = {} let globalStringify = true +let globalInset: string | undefined = undefined /** * Initialize the logger with configuration. @@ -29,6 +30,7 @@ export function initLogger(config: LoggerConfig = {}): void { globalPretty = config.pretty ?? isDev() globalSampling = config.sampling ?? {} globalStringify = config.stringify ?? true + globalInset = config.inset ?? undefined } /** @@ -75,12 +77,19 @@ export function shouldKeep(ctx: TailSamplingContext): boolean { }) } -function emitWideEvent(level: LogLevel, event: Record, skipSamplingCheck = false): WideEvent | null { +function emitWideEvent(level: LogLevel, event: Record, skipSamplingCheck = false): WideEvent | InsetWideEvent | null { if (!skipSamplingCheck && !shouldSample(level)) { return null } - const formatted: WideEvent = { + const formatted: InsetWideEvent | WideEvent = !globalPretty && globalInset && globalInset !== undefined ? { + [`$${globalInset}`]: { + timestamp: new Date().toISOString(), + level, + ...globalEnv, + ...event, + } + } : { timestamp: new Date().toISOString(), level, ...globalEnv, diff --git a/packages/evlog/src/nitro/plugin.ts b/packages/evlog/src/nitro/plugin.ts index 18d61a2..cf15774 100644 --- a/packages/evlog/src/nitro/plugin.ts +++ b/packages/evlog/src/nitro/plugin.ts @@ -12,6 +12,7 @@ interface EvlogConfig { exclude?: string[] routes?: Record sampling?: SamplingConfig + inset?: string } function shouldLog(path: string, include?: string[], exclude?: string[]): boolean { @@ -119,11 +120,12 @@ function callDrainHook(nitroApp: NitroApp, emittedEvent: WideEvent | null, event // Use waitUntil if available (Cloudflare Workers, Vercel Edge) // This ensures drains complete before the runtime terminates - const waitUntil = event.context.cloudflare?.context?.waitUntil - ?? event.context.waitUntil + const cfContext = event.context.cloudflare?.context - if (typeof waitUntil === 'function') { - waitUntil(drainPromise) + if (cfContext && typeof cfContext.waitUntil === 'function') { + cfContext.waitUntil(drainPromise) + } else if (event.context.waitUntil && typeof event.context.waitUntil === 'function') { + event.context.waitUntil(drainPromise) } } @@ -135,6 +137,7 @@ export default defineNitroPlugin((nitroApp) => { env: evlogConfig?.env, pretty: evlogConfig?.pretty, sampling: evlogConfig?.sampling, + inset: evlogConfig?.inset, }) nitroApp.hooks.hook('request', (event) => { diff --git a/packages/evlog/src/nuxt/module.ts b/packages/evlog/src/nuxt/module.ts index 2534d32..744d62a 100644 --- a/packages/evlog/src/nuxt/module.ts +++ b/packages/evlog/src/nuxt/module.ts @@ -134,7 +134,28 @@ export interface ModuleOptions { headers?: Record /** Request timeout in milliseconds. Default: 5000 */ timeout?: number - } + }, + /** + * Nest logs inside a specific property instead of the root of the log object. + * + * @default undefined + * Logs will be root level objects + * + * @example + * ```ts + * inset: "evlog" + * + * // Resulting Logs + * // { + * // $evlog: { + * // level: 'info', + * // message: 'Hello World', + * // timestamp: '2023-03-01T12:00:00.000Z', + * // } + * // } + * ``` + */ + inset?: string } export default defineNuxtModule({ diff --git a/packages/evlog/src/types.ts b/packages/evlog/src/types.ts index 1036dc9..af4c0f0 100644 --- a/packages/evlog/src/types.ts +++ b/packages/evlog/src/types.ts @@ -213,6 +213,8 @@ export interface LoggerConfig { * @default true */ stringify?: boolean + /** Nested property name for wide events */ + inset?: string; } /** @@ -228,6 +230,13 @@ export interface BaseWideEvent { region?: string } +/** + * Wide event inside a nested propery from global config: inset + */ +export type InsetWideEvent = { + [key: string]: BaseWideEvent & Record +} + /** * Wide event with arbitrary additional fields */ From 066522520e85a2b884c8a0881289248681525770 Mon Sep 17 00:00:00 2001 From: Sean LeCheminant Date: Thu, 5 Feb 2026 14:19:37 -0600 Subject: [PATCH 2/9] Added missing export --- packages/evlog/src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/evlog/src/index.ts b/packages/evlog/src/index.ts index d20be58..d471dcb 100644 --- a/packages/evlog/src/index.ts +++ b/packages/evlog/src/index.ts @@ -23,4 +23,5 @@ export type { TailSamplingContext, TransportConfig, WideEvent, + InsetWideEvent } from './types' From 37dc309b776db83ba84fc1c572810edb57ae13c5 Mon Sep 17 00:00:00 2001 From: Sean LeCheminant Date: Thu, 5 Feb 2026 14:19:53 -0600 Subject: [PATCH 3/9] Complete Skills / Docs with inset --- AGENTS.md | 1 + README.md | 26 ++++++++ skills/evlog/SKILL.md | 26 ++++++++ skills/evlog/references/code-review.md | 6 ++ skills/evlog/references/wide-events.md | 85 ++++++++++++++++++++++++++ 5 files changed, 144 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 29f95bf..336ac16 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -163,6 +163,7 @@ export default defineNuxtConfig({ | `env.environment` | `string` | Auto-detected | Environment name | | `include` | `string[]` | `undefined` | Route patterns to log (glob). If not set, all routes are logged | | `pretty` | `boolean` | `true` in dev | Pretty print logs with tree formatting | +| `inset` | `string` | `undefined` | Next evlog data inside a property when pretty is disabled | | `sampling.rates` | `object` | `undefined` | Head sampling rates per log level (0-100%). Error defaults to 100% | | `sampling.keep` | `array` | `undefined` | Tail sampling conditions to force-keep logs (see below) | | `transport.enabled` | `boolean` | `false` | Enable sending client logs to the server | diff --git a/README.md b/README.md index 959b4c2..912af3e 100644 --- a/README.md +++ b/README.md @@ -487,6 +487,7 @@ initLogger({ pretty?: boolean // Pretty print (default: true in dev) stringify?: boolean // JSON.stringify output (default: true, false for Workers) include?: string[] // Route patterns to log (glob), e.g. ['/api/**'] + inset?: string // Nest all log data inside this property sampling?: { rates?: { // Head sampling (random per level) info?: number // 0-100, default 100 @@ -561,6 +562,29 @@ export default defineNitroPlugin((nitroApp) => { }) ``` +### Inset - Nesting Logs + +By default, ```pretty``` is disabled, soevlog will log the object at root level when logging in production; however, for services like Cloudflare Observability, you may wish to nest the data inside an arbitrary property name. This can help organize your data and make it easier to query and analyze. + +> **Note**: Nesting can have adverse effects if your logging system expects root-level json data, such as requestIds, or tracing ids. + + +In this example, your logs will then be nested under the `data` property: + +```json [Observability Logs] +{ + "$data": { + "timestamp": "2026-02-05T06:48:18.122Z", + "level": "info", + "message": "This is an info log", + "method": "GET", + ... + }, + "$metadata": {...}, + "$workers": {...} +} +``` + ### Pretty Output Format In development, evlog uses a compact tree format: @@ -678,6 +702,8 @@ try { } ``` + + ## Framework Support evlog works with any framework powered by [Nitro](https://nitro.unjs.io/): diff --git a/skills/evlog/SKILL.md b/skills/evlog/SKILL.md index c5a737a..1dc65a9 100644 --- a/skills/evlog/SKILL.md +++ b/skills/evlog/SKILL.md @@ -205,6 +205,8 @@ export default defineNuxtConfig({ }, // Optional: only log specific routes (supports glob patterns) include: ['/api/**'], + // Optional: nest log data under a property (e.g., for Cloudflare Observability) + inset: 'evlog', // Optional: send client logs to server (default: false) transport: { enabled: true, @@ -340,6 +342,29 @@ nitroApp.hooks.hook('evlog:drain', async (ctx) => { }) ``` +## Inset (Nested Log Data) + +`inset` nests the wide event inside a `$`-prefixed property. Only applies when `pretty: false` (production JSON). + +- Use when the platform injects root-level metadata (e.g., Cloudflare Observability adds `$metadata`, `$workers`) +- Do NOT use with Axiom, Datadog, Grafana — they expect flat root-level JSON + +```typescript +// inset: 'evlog' → wraps under $evlog +{ "$evlog": { "level": "info", "service": "api", "user": { "id": "123" }, ... } } + +// Without inset (default) → flat root +{ "level": "info", "service": "api", "user": { "id": "123" }, ... } +``` + +```typescript +// ❌ Don't use with flat-log consumers +evlog: { inset: 'data' } // Axiom/Datadog expect root-level fields + +// ✅ Use when platform adds root-level metadata +evlog: { inset: 'evlog' } // Cloudflare Observability +``` + ## Log Draining & Adapters evlog provides built-in adapters to send logs to external observability platforms. @@ -468,6 +493,7 @@ When reviewing code, check for: 8. **Client-side logging** → Use `log` API for debugging in Vue components 9. **Client log centralization** → Enable `transport.enabled: true` to send client logs to server 10. **Missing log draining** → Set up adapters (`evlog/axiom`, `evlog/otlp`) for production log export +11. **Inset misconfiguration** → Only enable `inset` when the platform adds root-level metadata (e.g., Cloudflare Observability). Do not use with systems expecting flat root-level JSON (Axiom, Datadog, Grafana). ## Loading Reference Files diff --git a/skills/evlog/references/code-review.md b/skills/evlog/references/code-review.md index 61ca5a4..b3df4cb 100644 --- a/skills/evlog/references/code-review.md +++ b/skills/evlog/references/code-review.md @@ -273,6 +273,11 @@ export default defineEventHandler(async (event) => { - [ ] Business context is domain-specific and useful for debugging - [ ] No sensitive data in logs (passwords, tokens, full card numbers) +### Configuration + +- [ ] `inset` is only enabled when the platform adds root-level metadata (e.g., Cloudflare Workers Observability) +- [ ] `inset` is not used with systems expecting flat root-level JSON (Axiom, Datadog, Grafana) + ## Anti-Pattern Summary | Anti-Pattern | Fix | @@ -283,6 +288,7 @@ export default defineEventHandler(async (event) => { | No logging in request handlers | Add `useLogger(event)` (Nuxt/Nitro) or `createRequestLogger()` (standalone) | | Flat log data | Grouped objects: `{ user: {...}, cart: {...} }` | | Abbreviated field names | Descriptive names: `userId` not `uid` | +| `inset` with flat-log consumers | Only use `inset` for platforms that add root-level metadata (e.g., Cloudflare) | ## Suggested Review Comments diff --git a/skills/evlog/references/wide-events.md b/skills/evlog/references/wide-events.md index 890d076..66e87d7 100644 --- a/skills/evlog/references/wide-events.md +++ b/skills/evlog/references/wide-events.md @@ -390,3 +390,88 @@ log.set({ pm: 'card', }) ``` + +## Inset: Nested Wide Events + +By default, wide events are emitted as flat root-level JSON. The `inset` option wraps the entire wide event inside a named property (prefixed with `$`), which is useful when your observability platform injects its own metadata at the root level. + +### Default Output (no inset) + +```json +{ + "timestamp": "2026-01-24T10:23:45.235Z", + "level": "info", + "service": "api", + "method": "POST", + "path": "/checkout", + "duration": "234ms", + "user": { "id": "user_123", "plan": "premium" }, + "cart": { "items": 3, "total": 9999 } +} +``` + +### With Inset (`inset: 'evlog'`) + +```json +{ + "$evlog": { + "timestamp": "2026-01-24T10:23:45.235Z", + "level": "info", + "service": "api", + "method": "POST", + "path": "/checkout", + "duration": "234ms", + "user": { "id": "user_123", "plan": "premium" }, + "cart": { "items": 3, "total": 9999 } + } +} +``` + +### Cloudflare Workers Observability Example + +Cloudflare injects `$metadata` and `$workers` at the root level. With inset, your data stays cleanly separated: + +```json +{ + "$evlog": { + "timestamp": "2026-02-05T06:48:18.122Z", + "level": "info", + "service": "edge-api", + "method": "POST", + "path": "/api/checkout", + "duration": "456ms", + "user": { "id": "user_789", "plan": "enterprise" }, + "cart": { "items": 5, "total": 24999 }, + "checkout": { "step": "payment", "paymentMethod": "card" }, + "fraud": { "score": 12, "riskLevel": "low", "passed": true } + }, + "$metadata": { "..." }, + "$workers": { "..." } +} +``` + +This makes it easy to query all your application data under a single namespace (e.g., `$evlog.user.plan` or `$evlog.cart.total`) without collision with platform fields. + +### Configuration + +```typescript +// Nuxt +export default defineNuxtConfig({ + modules: ['evlog/nuxt'], + evlog: { + inset: 'evlog', // → logs nested under $evlog + }, +}) + +// Standalone +initLogger({ + env: { service: 'my-worker' }, + inset: 'data', // → logs nested under $data +}) +``` + +### Important Considerations + +- **Pretty mode is unaffected.** Inset only applies to JSON output (`pretty: false`). Development pretty-print remains unchanged. +- **Property prefix.** The value is prefixed with `$` automatically: `inset: 'evlog'` → `$evlog`. +- **Platform compatibility.** Do not enable inset if your logging system expects fields like `level`, `requestId`, or `timestamp` at the root level (e.g., Axiom, Datadog, Grafana). Only use when the platform adds its own root-level metadata. From ee9a87dc45b42949b1ea1b0bf99449c289b7b182 Mon Sep 17 00:00:00 2001 From: Sean LeCheminant Date: Thu, 5 Feb 2026 15:17:42 -0600 Subject: [PATCH 4/9] OOPS: revert polluted change --- packages/evlog/src/nitro/plugin.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/evlog/src/nitro/plugin.ts b/packages/evlog/src/nitro/plugin.ts index cf15774..7aa7b99 100644 --- a/packages/evlog/src/nitro/plugin.ts +++ b/packages/evlog/src/nitro/plugin.ts @@ -120,12 +120,11 @@ function callDrainHook(nitroApp: NitroApp, emittedEvent: WideEvent | null, event // Use waitUntil if available (Cloudflare Workers, Vercel Edge) // This ensures drains complete before the runtime terminates - const cfContext = event.context.cloudflare?.context + const waitUntil = event.context.cloudflare?.context?.waitUntil + ?? event.context.waitUntil - if (cfContext && typeof cfContext.waitUntil === 'function') { - cfContext.waitUntil(drainPromise) - } else if (event.context.waitUntil && typeof event.context.waitUntil === 'function') { - event.context.waitUntil(drainPromise) + if (typeof waitUntil === 'function') { + waitUntil(drainPromise) } } From 7352df7b56a0cb421793576eb107c65a46281efb Mon Sep 17 00:00:00 2001 From: Sean LeCheminant Date: Mon, 9 Feb 2026 18:42:17 -0600 Subject: [PATCH 5/9] fix: types for RequestLogger.emit() from added inset feature. --- packages/evlog/src/logger.ts | 2 +- packages/evlog/src/types.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/evlog/src/logger.ts b/packages/evlog/src/logger.ts index bf6d6b2..648012f 100644 --- a/packages/evlog/src/logger.ts +++ b/packages/evlog/src/logger.ts @@ -266,7 +266,7 @@ export function createRequestLogger(options: RequestLoggerOptions = {}): Request context = deepDefaults(errorData, context) as Record }, - emit(overrides?: Record & { _forceKeep?: boolean }): WideEvent | null { + emit(overrides?: Record & { _forceKeep?: boolean }): WideEvent | InsetWideEvent | null { const durationMs = Date.now() - startTime const duration = formatDuration(durationMs) const level: LogLevel = hasError ? 'error' : 'info' diff --git a/packages/evlog/src/types.ts b/packages/evlog/src/types.ts index c727c0a..4b0fc6d 100644 --- a/packages/evlog/src/types.ts +++ b/packages/evlog/src/types.ts @@ -303,7 +303,7 @@ export interface RequestLogger { * Emit the final wide event with all accumulated context. * Returns the emitted WideEvent, or null if the log was sampled out. */ - emit: (overrides?: Record) => WideEvent | null + emit: (overrides?: Record) => WideEvent | InsetWideEvent | null /** * Get the current accumulated context From 46452547afc9ddde6cc32de27ba79d63acea1faf Mon Sep 17 00:00:00 2001 From: Sean LeCheminant Date: Mon, 9 Feb 2026 19:04:00 -0600 Subject: [PATCH 6/9] test: inset logic tests --- packages/evlog/test/logger.test.ts | 37 ++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/packages/evlog/test/logger.test.ts b/packages/evlog/test/logger.test.ts index a7d085d..680bb80 100644 --- a/packages/evlog/test/logger.test.ts +++ b/packages/evlog/test/logger.test.ts @@ -729,3 +729,40 @@ describe('tail sampling', () => { expect(errorSpy).toHaveBeenCalledTimes(0) }) }) + +describe('inset configuration', () => { + let infoSpy: ReturnType + + beforeEach(() => { + infoSpy = vi.spyOn(console, 'info').mockImplementation(() => {}) + }) + + afterEach(() => { + vi.restoreAllMocks() + }) + + it('wraps wide event in $ property when pretty is false', () => { + initLogger({ inset: 'evlog', pretty: false }) + + log.info({ action: 'test' }) + + expect(infoSpy).toHaveBeenCalled() + const [[output]] = infoSpy.mock.calls + const parsed = JSON.parse(output) + expect(parsed).toHaveProperty('$evlog') + expect(parsed.$evlog).toHaveProperty('level', 'info') + expect(parsed.$evlog).toHaveProperty('action', 'test') + }) + + it('pretty mode outputs correctly even when inset is configured', () => { + const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {}) + initLogger({ inset: 'evlog', pretty: true }) + + log.info({ action: 'test' }) + + expect(logSpy).toHaveBeenCalled() + const allOutput = logSpy.mock.calls.map(c => c[0]).join('\n') + expect(allOutput).toContain('INFO') + expect(allOutput).toMatch(/action:.*test/) + }) +}) From 238f8665edd5ad3539e91d9ef7f715ca5d991b18 Mon Sep 17 00:00:00 2001 From: Sean LeCheminant Date: Mon, 9 Feb 2026 19:11:32 -0600 Subject: [PATCH 7/9] docs: fix incorrect default value --- apps/docs/content/1.getting-started/2.installation.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/docs/content/1.getting-started/2.installation.md b/apps/docs/content/1.getting-started/2.installation.md index c9e0156..bde3955 100644 --- a/apps/docs/content/1.getting-started/2.installation.md +++ b/apps/docs/content/1.getting-started/2.installation.md @@ -62,7 +62,7 @@ export default defineNuxtConfig({ | `exclude` | `string[]` | `undefined` | Route patterns to exclude from logging. Supports glob (`/api/_nuxt_icon/**`). Exclusions take precedence over inclusions | | `routes` | `Record` | `undefined` | Route-specific service configuration. Allows setting different service names for different routes using glob patterns | | `pretty` | `boolean` | `true` in dev | Pretty print with tree formatting | -| `inset` | `string` | `'evlog'` | Nested property name for wide events | +| `inset` | `string` | `undefined` | Nested property name for wide events | | `sampling.rates` | `object` | `undefined` | Head sampling rates per log level (0-100%). See [Sampling](#sampling) | | `sampling.keep` | `array` | `undefined` | Tail sampling conditions to force-keep logs. See [Sampling](#sampling) | | `transport.enabled` | `boolean` | `false` | Enable sending client logs to the server. See [Client Transport](#client-transport) | @@ -514,4 +514,4 @@ evlog requires TypeScript 5.0 or higher for optimal type inference. ## Next Steps -- [Quick Start](/getting-started/quick-start) - Learn the core concepts and start using evlog +- [Quick Start](/getting-started/quick-start) - Learn the core concepts and start using evlog \ No newline at end of file From dedefb832825b819067c341e9a411b93d71464e6 Mon Sep 17 00:00:00 2001 From: Sean LeCheminant Date: Mon, 9 Feb 2026 19:20:21 -0600 Subject: [PATCH 8/9] cleanup typos, consistencies --- AGENTS.md | 2 +- README.md | 2 -- apps/docs/content/1.getting-started/2.installation.md | 4 ++-- packages/evlog/src/types.ts | 2 +- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index a96a741..aff3609 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -165,7 +165,7 @@ export default defineNuxtConfig({ | `env.environment` | `string` | Auto-detected | Environment name | | `include` | `string[]` | `undefined` | Route patterns to log (glob). If not set, all routes are logged | | `pretty` | `boolean` | `true` in dev | Pretty print logs with tree formatting | -| `inset` | `string` | `undefined` | Next evlog data inside a property when pretty is disabled | +| `inset` | `string` | `undefined` | Nest evlog data inside a property when pretty is disabled | | `sampling.rates` | `object` | `undefined` | Head sampling rates per log level (0-100%). Error defaults to 100% | | `sampling.keep` | `array` | `undefined` | Tail sampling conditions to force-keep logs (see below) | | `transport.enabled` | `boolean` | `false` | Enable sending client logs to the server | diff --git a/README.md b/README.md index 266a603..53e972f 100644 --- a/README.md +++ b/README.md @@ -809,8 +809,6 @@ try { } ``` - - ## Framework Support evlog works with any framework powered by [Nitro](https://nitro.unjs.io/): diff --git a/apps/docs/content/1.getting-started/2.installation.md b/apps/docs/content/1.getting-started/2.installation.md index bde3955..08de45a 100644 --- a/apps/docs/content/1.getting-started/2.installation.md +++ b/apps/docs/content/1.getting-started/2.installation.md @@ -121,7 +121,7 @@ You can also override the service name per handler using `useLogger(event, 'serv ### Nesting log data -By default, evlog will log the object at root level when logging without ```pretty``` enabled (see [Configuration Options](/getting-started/installation#configuration-options)); however, for services like Cloudflare Observability, you may wish to nest the data inside an arbitrary property name. This can help organize your data and make it easier to query and analyze. +By default, evlog will log the object at root level when logging without `pretty` enabled (see [Configuration Options](/getting-started/installation#configuration-options)); however, for services like Cloudflare Observability, you may wish to nest the data inside an arbitrary property name. This can help organize your data and make it easier to query and analyze. ::callout{icon="i-lucide-info" color="warning"} **Note:** Nesting can have adverse effects if your logging system expects root-level json data, such as requestIds, or tracing ids. @@ -514,4 +514,4 @@ evlog requires TypeScript 5.0 or higher for optimal type inference. ## Next Steps -- [Quick Start](/getting-started/quick-start) - Learn the core concepts and start using evlog \ No newline at end of file +- [Quick Start](/getting-started/quick-start) - Learn the core concepts and start using evlog diff --git a/packages/evlog/src/types.ts b/packages/evlog/src/types.ts index 4b0fc6d..8b2273c 100644 --- a/packages/evlog/src/types.ts +++ b/packages/evlog/src/types.ts @@ -266,7 +266,7 @@ export interface BaseWideEvent { } /** - * Wide event inside a nested propery from global config: inset + * Wide event inside a nested property from global config: inset */ export type InsetWideEvent = { [key: string]: BaseWideEvent & Record From 7e58e236f588fbfb6235f7d882638674f9680314 Mon Sep 17 00:00:00 2001 From: Sean LeCheminant <32964349+saltytostitos@users.noreply.github.com> Date: Mon, 9 Feb 2026 19:41:47 -0600 Subject: [PATCH 9/9] Apply suggestion from @Copilot :) Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- packages/evlog/src/logger.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/evlog/src/logger.ts b/packages/evlog/src/logger.ts index 648012f..639b079 100644 --- a/packages/evlog/src/logger.ts +++ b/packages/evlog/src/logger.ts @@ -100,7 +100,7 @@ function emitWideEvent(level: LogLevel, event: Record, skipSamp return null } - const formatted: InsetWideEvent | WideEvent = !globalPretty && globalInset && globalInset !== undefined ? { + const formatted: InsetWideEvent | WideEvent = !globalPretty && globalInset ? { [`$${globalInset}`]: { timestamp: new Date().toISOString(), level,