diff --git a/AGENTS.md b/AGENTS.md index b9200da..305c8fd 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -137,7 +137,7 @@ logger.error('DB write failed: {err}', { err }) - Categories are hierarchical arrays — they show up as dot-paths in JSON output (`"logger":"feature.subsystem"`) and let you filter by prefix when shipping logs. - The `{name}` placeholders in the message string are filled from the second-arg properties object. Don't string-concatenate or template-literal — that defeats structured logging. - Format is `pretty` (icons + ANSI) on TTY, `json` (one-line JSON) when piped — perfect for Loki/Datadog/CloudWatch ingestion. Override with `LOG_FORMAT`. -- Drizzle SQL queries are logged at `debug` under category `['db']` when `LOG_DB=true`, via `@logtape/drizzle-orm`'s `DrizzleLogger` adapter (constructed in `src/server/db/index.ts`). +- Drizzle SQL queries are logged at `info` under category `['db']` when `LOG_DB=true`, via `@logtape/drizzle-orm`'s `DrizzleLogger` adapter (constructed in `src/server/db/index.ts`). The `info` level is intentional: flipping `LOG_DB=true` alone is enough — no need to also lower `LOG_LEVEL`. - `src/server/api/interceptors.ts` calls `getLogger(['api']).error(...)` from `logError`. CLI subcommands lazy-import the logger inside `run()` — they are still required to be side-effect-free at module top (citty eager-loads for `--help`). - Bun-specific: `process.env.NODE_ENV` is **inlined at build time** by `bun build --minify` — do NOT branch on it for logger config (use `process.stdout.isTTY` or `LOG_FORMAT` instead). pino is unusable here because its worker-thread transports crash inside the `/$bunfs/` virtual filesystem of compiled binaries; LogTape has zero workers and zero dynamic require, so it ships cleanly into the single binary. diff --git a/src/server/db/index.ts b/src/server/db/index.ts index 1aafc6c..692405e 100644 --- a/src/server/db/index.ts +++ b/src/server/db/index.ts @@ -7,5 +7,5 @@ import { getLogger } from '@/server/logger' export const db = drizzle({ connection: env.DATABASE_URL, schema, - logger: env.LOG_DB ? new DrizzleLogger(getLogger(['db'])) : false, + logger: env.LOG_DB ? new DrizzleLogger(getLogger(['db']), 'info') : false, }) diff --git a/src/server/logger.ts b/src/server/logger.ts index ac18696..349eacb 100644 --- a/src/server/logger.ts +++ b/src/server/logger.ts @@ -1,19 +1,19 @@ -import { configureSync, getConsoleSink, getJsonLinesFormatter, getLogger, type LogLevel } from '@logtape/logtape' +import { configureSync, getConfig, getConsoleSink, getJsonLinesFormatter } from '@logtape/logtape' import { prettyFormatter } from '@logtape/pretty' import { env } from '@/env' -const format = env.LOG_FORMAT ?? (process.stdout.isTTY ? 'pretty' : 'json') +if (getConfig() === null) { + const format = env.LOG_FORMAT ?? (process.stdout.isTTY ? 'pretty' : 'json') -configureSync({ - reset: true, - sinks: { - console: getConsoleSink({ formatter: format === 'pretty' ? prettyFormatter : getJsonLinesFormatter() }), - }, - loggers: [ - { category: [], lowestLevel: env.LOG_LEVEL, sinks: ['console'] }, - { category: ['logtape', 'meta'], lowestLevel: 'warning', sinks: ['console'] }, - ], -}) + configureSync({ + sinks: { + console: getConsoleSink({ formatter: format === 'pretty' ? prettyFormatter : getJsonLinesFormatter() }), + }, + loggers: [ + { category: [], lowestLevel: env.LOG_LEVEL, sinks: ['console'] }, + { category: ['logtape', 'meta'], lowestLevel: 'warning', sinks: ['console'], parentSinks: 'override' }, + ], + }) +} -export type { LogLevel } -export { getLogger } +export { getLogger } from '@logtape/logtape'