@neutrino-io/logger
Structured JSON logger for Neutrino Cloudflare Workers services.
Package: @neutrino-io/logger
Lightweight structured logging for Cloudflare Workers services. Emits newline-delimited JSON to stdout/stderr, compatible with Cloudflare's log aggregation pipeline.
import { Logger, createLogger, initTrace, withTraceHeaders, requestLogger } from '@neutrino-io/logger'Log Levels
| Level | Method | Output stream |
|---|---|---|
"debug" | logger.debug() | stdout |
"info" | logger.info() | stdout |
"warn" | logger.warn() | stdout |
"error" | logger.error() | stderr |
Logger
Structured JSON logger class. Each instance is bound to a service name and optionally to a traceId and requestId for request-scoped logging.
class Logger {
constructor(service: string, traceId?: string, requestId?: string)
info(message: string, data?: Record<string, unknown>): void
warn(message: string, data?: Record<string, unknown>): void
error(message: string, data?: Record<string, unknown>): void
debug(message: string, data?: Record<string, unknown>): void
}Every call emits a LogEntry JSON object:
interface LogEntry {
timestamp: string // ISO 8601
level: LogLevel
service: string
traceId?: string
requestId?: string
message: string
[key: string]: unknown // spread from the data argument
}Example output:
{"timestamp":"2026-03-31T12:00:00.000Z","level":"info","service":"iam","traceId":"abc-123","requestId":"req-456","message":"→ request","method":"POST","path":"/api/nno/session"}createLogger(service)
Factory function — creates a Logger instance bound to the given service name. Use this for module-level loggers that are not yet bound to a request context.
function createLogger(service: string): Loggerimport { createLogger } from '@neutrino-io/logger'
const log = createLogger('my-service')
log.info('Service started')
log.error('Unhandled error', { error: err.message })For request-scoped logging with trace IDs, prefer constructing a Logger directly or using the requestLogger Hono middleware.
initTrace(request)
Extracts traceId and requestId from incoming request headers (x-trace-id, x-request-id). Generates new UUIDs for any missing values.
function initTrace(request: Request): { traceId: string; requestId: string }import { initTrace, Logger } from '@neutrino-io/logger'
export default {
async fetch(request: Request, env: Env) {
const { traceId, requestId } = initTrace(request)
const log = new Logger('my-worker', traceId, requestId)
log.info('Handling request')
}
}withTraceHeaders(headers, traceId, requestId)
Adds x-trace-id and x-request-id headers to an existing headers object. Returns a new Headers instance — does not mutate the input.
Use this when making outbound fetch calls to downstream services to propagate the trace context.
function withTraceHeaders(
headers: Headers | [string, string][] | Record<string, string> | undefined,
traceId: string,
requestId: string
): Headersimport { initTrace, withTraceHeaders } from '@neutrino-io/logger'
const { traceId, requestId } = initTrace(request)
const response = await fetch('https://registry.svc.nno.app/api/platforms', {
headers: withTraceHeaders(
{ 'Authorization': `Bearer ${token}` },
traceId,
requestId
)
})requestLogger(service) — Hono Middleware
Hono middleware that handles the full per-request logging lifecycle. On each request it:
- Calls
initTraceto extract or generatetraceIdandrequestId - Stores both on the Hono context (
c.get('traceId'),c.get('requestId')) - Creates a request-scoped
Loggerand stores it on the context (c.get('logger')) - Logs an incoming request line (
→ request) - Awaits
next(), then logs the outgoing response line (← response) with status and duration
import type { MiddlewareHandler } from 'hono'
function requestLogger(service: string): MiddlewareHandlerimport { Hono } from 'hono'
import { requestLogger } from '@neutrino-io/logger'
const app = new Hono()
app.use('*', requestLogger('iam'))
app.get('/health', (c) => {
const log = c.get('logger') as Logger
log.info('Health check')
return c.json({ ok: true })
})Context values set by this middleware:
| Key | Type | Description |
|---|---|---|
traceId | string | Distributed trace ID (from header or generated) |
requestId | string | Per-request ID (from header or generated) |
logger | Logger | Request-scoped logger bound to traceId and requestId |
Log output example:
{"timestamp":"2026-03-31T12:00:00.000Z","level":"info","service":"iam","traceId":"abc","requestId":"req-1","message":"→ request","method":"GET","path":"/health"}
{"timestamp":"2026-03-31T12:00:00.050Z","level":"info","service":"iam","traceId":"abc","requestId":"req-1","message":"← response","method":"GET","path":"/health","status":200,"duration":50}