Logger Rules
Apply to all logging in klex. No exceptions.
Types
- Root logger —
tslog Logger<ILogObj>. Created once per process. Owns config: level, format, masking, transports.
- Module logger — restricted type alias. No wrapping, no adapters.
export type ModuleLogger = Pick<
Logger<ILogObj>,
'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal'
>;
Rules
One root logger per process. Create in main.ts before all other modules.
Configure global level, formatting, masking, and transports only in the logging module (logger.ts). Never inside modules.
Pass root logger into module factories as logging. Factory creates one named child logger and injects it into the implementation class.
export function createAdminApi(deps: AdminApiDependencies): AdminApi {
return new AdminApiModule({
logger: deps.logging.child({
name: 'admin-api',
bindings: { module: 'admin-api' },
}),
});
}
Modules store the injected child logger and call it directly. Constructor stores deps — no async init.
Do not wrap logger methods in custom adapter methods. Use the actual tslog logger through ModuleLogger so source locations point to the real call site.
No global logger imports inside modules. All logger deps explicit via constructor.
Create child loggers only for stable scopes (modules, long-lived components). Not per log call.
Structured fields for searchable data. Messages stable.
logger.info({ port, host }, 'AdminAPI listening');
- Pass
Error objects directly. Use consistent field name.
logger.error({ error, context }, 'Request failed');
Use async logging context for request/session/trace/user IDs. Do not manually pass through every method.
Never log credentials, auth headers, tokens, prompts, or model responses. Configure global masking as second line of defence.
Modules borrow their logger. Never change global level, attach transports, flush, or dispose.
Create root logger before all other modules. Dispose after all stopped.
Pretty output for local dev. JSON for deployed environments.
Prefer JSON on stdout with external collector. In-process transports only where runtime requires.
1---2name: logger3description: Rules for using tslog v5 in klex. Use when creating, modifying, or reviewing logging code, module factories, or logger configuration.4---56# Logger Rules78Apply to all logging in klex. No exceptions.910## Types1112- **Root logger** — `tslog` `Logger<ILogObj>`. Created once per process. Owns config: level, format, masking, transports.13- **Module logger** — restricted type alias. No wrapping, no adapters.1415```ts16export type ModuleLogger = Pick<17 Logger<ILogObj>,18 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal'19>;20```2122## Rules23241. **One root logger per process.** Create in `main.ts` before all other modules.25262. **Configure global level, formatting, masking, and transports only in the logging module** (`logger.ts`). Never inside modules.27283. **Pass root logger into module factories as `logging`.** Factory creates one named child logger and injects it into the implementation class.2930```ts31export function createAdminApi(deps: AdminApiDependencies): AdminApi {32 return new AdminApiModule({33 logger: deps.logging.child({34 name: 'admin-api',35 bindings: { module: 'admin-api' },36 }),37 });38}39```40414. **Modules store the injected child logger and call it directly.** Constructor stores deps — no async init.42435. **Do not wrap logger methods in custom adapter methods.** Use the actual `tslog` logger through `ModuleLogger` so source locations point to the real call site.44456. **No global logger imports inside modules.** All logger deps explicit via constructor.46477. **Create child loggers only for stable scopes** (modules, long-lived components). Not per log call.48498. **Structured fields for searchable data. Messages stable.**5051```ts52logger.info({ port, host }, 'AdminAPI listening');53```54559. **Pass `Error` objects directly.** Use consistent field name.5657```ts58logger.error({ error, context }, 'Request failed');59```606110. **Use async logging context for request/session/trace/user IDs.** Do not manually pass through every method.626311. **Never log credentials, auth headers, tokens, prompts, or model responses.** Configure global masking as second line of defence.646512. **Modules borrow their logger.** Never change global level, attach transports, flush, or dispose.666713. **Create root logger before all other modules. Dispose after all stopped.**686914. **Pretty output for local dev. JSON for deployed environments.**707115. **Prefer JSON on stdout with external collector.** In-process transports only where runtime requires.