Frameworks
Astro
Wide events and structured errors in Astro server middleware.
Astro doesn't have a dedicated evlog integration. Instead, use the core evlog package with Astro's middleware to create request-scoped loggers manually.
Prompt
Set up evlog in my Astro app.
- Install evlog: pnpm add evlog
- Import initLogger and createRequestLogger from 'evlog'
- Call initLogger({ env: { service: 'my-app' } }) in Astro middleware
- Create a request logger with createRequestLogger({ method, path }) per request
- Use log.set() in API routes and middleware to accumulate context
- Call log.emit() before returning the response (no auto-emit lifecycle)
Docs: https://www.evlog.dev/frameworks/astro
Adapters: https://www.evlog.dev/adapters
This is a guide-level integration. It uses the generic
createRequestLogger API rather than a framework-specific module.Quick Start
1. Install
bun add evlog
2. Create a middleware
src/middleware.ts
import { defineMiddleware } from 'astro:middleware'
import { initLogger, createRequestLogger } from 'evlog'
initLogger({
env: { service: 'my-astro-app' },
})
export const onRequest = defineMiddleware(async ({ request, locals }, next) => {
const url = new URL(request.url)
const log = createRequestLogger({
method: request.method,
path: url.pathname,
})
locals.log = log
try {
const response = await next()
log.emit()
return response
} catch (error) {
log.error(error instanceof Error ? error : new Error(String(error)))
log.emit()
throw error
}
})
3. Type your locals
src/env.d.ts
/// <reference types="astro/client" />
import type { RequestLogger } from 'evlog'
declare namespace App {
interface Locals {
log: RequestLogger
}
}
Wide Events
Access the logger from Astro.locals in your pages and API routes:
src/pages/api/users/[id].ts
import type { APIRoute } from 'astro'
export const GET: APIRoute = async ({ params, locals }) => {
locals.log.set({ user: { id: params.id } })
const user = await db.findUser(params.id)
locals.log.set({ user: { name: user.name, plan: user.plan } })
return new Response(JSON.stringify(user), {
headers: { 'Content-Type': 'application/json' },
})
}
Terminal output
14:58:15 INFO [my-astro-app] GET /api/users/usr_123
├─ user: id=usr_123 name=Alice plan=pro
└─ requestId: 4a8ff3a8-...
Error Handling
Use createError for structured errors:
src/pages/api/checkout.ts
import type { APIRoute } from 'astro'
import { createError, parseError } from 'evlog'
export const POST: APIRoute = async ({ request, locals }) => {
const body = await request.json()
locals.log.set({ cart: { items: body.items } })
if (!body.paymentMethod) {
const error = createError({
status: 400,
message: 'Missing payment method',
why: 'No payment method was provided',
fix: 'Include a paymentMethod field in the request body',
})
locals.log.error(error)
const parsed = parseError(error)
return new Response(JSON.stringify(parsed), { status: parsed.status })
}
return new Response(JSON.stringify({ success: true }))
}
Configuration
See the Configuration reference for all available options (initLogger, middleware options, sampling, silent mode, etc.).
Drain
Configure drain in initLogger inside your middleware:
src/middleware.ts
import { initLogger, createRequestLogger } from 'evlog'
import { createAxiomDrain } from 'evlog/axiom'
import { createDrainPipeline } from 'evlog/pipeline'
import type { DrainContext } from 'evlog'
const pipeline = createDrainPipeline<DrainContext>({
batch: { size: 50, intervalMs: 5000 },
})
const drain = pipeline(createAxiomDrain())
initLogger({
env: { service: 'my-astro-app' },
drain,
})
See the Adapters docs for all available drain adapters.
Standalone
Use evlog in standalone TypeScript scripts, CLI tools, queues, cron jobs, and any TypeScript process.
Custom Integration
Build your own evlog framework integration using the toolkit API with createMiddlewareLogger, header extraction, AsyncLocalStorage, and the full drain/enrich/keep pipeline.