Files
zpan/server/middleware/logger.ts
T
saltbo d2f3a34f05 fix(server): log underlying cause chain for failed D1 queries
Drizzle wraps the real D1 error in DrizzleQueryError.cause; both the access
log and the origin-detect catch only logged .message, surfacing just
"Failed query: <sql>" with no reason. Add formatError() to flatten the cause
chain and use it at both sites so D1 failures are diagnosable.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 00:42:50 -04:00

54 lines
1.5 KiB
TypeScript

import type { Context } from 'hono'
import { createMiddleware } from 'hono/factory'
import { formatError } from '../lib/errors'
import type { Env } from './platform'
export const accessLog = createMiddleware<Env>(async (c, next) => {
const start = Date.now()
try {
await next()
} catch (error) {
writeAccessLog(c, start, 500, error)
throw error
}
writeAccessLog(c, start, c.res.status)
})
function writeAccessLog(c: Context<Env>, start: number, status: number, error?: unknown) {
const fields = accessLogFields(c, start, status, error)
console.log(fields.map(([key, value]) => `${key}=${JSON.stringify(value)}`).join(' '))
}
function accessLogFields(
c: Context<Env>,
start: number,
status: number,
error?: unknown,
): Array<[string, string | number]> {
const fields: Array<[string, string | number]> = [
['method', c.req.method],
['path', c.req.path],
['status', status],
['ms', Date.now() - start],
['uid', c.get('userId') ?? '-'],
]
if (c.req.path.startsWith('/dav/')) {
fields.push(
['range', c.req.header('Range') ?? '-'],
['ifRange', c.req.header('If-Range') ?? '-'],
['ifNoneMatch', c.req.header('If-None-Match') ?? '-'],
['ifModifiedSince', c.req.header('If-Modified-Since') ?? '-'],
['contentLength', c.req.header('Content-Length') ?? '-'],
['contentRange', c.res.headers.get('Content-Range') ?? '-'],
['userAgent', c.req.header('User-Agent') ?? '-'],
)
}
if (error !== undefined) {
fields.push(['error', formatError(error)])
}
return fields
}