Logging
Structured logging conventions for the API and contributor code.
Toast uses structured logging with Pino.
The logger contract and default factory now live in @toast/core:
Loggerinterface →packages/core/src/logger.tscreateLogger()→packages/core/src/logger.factory.ts
The API composition root creates the logger at startup and passes it down through dependency injection.
Basic pattern
Application code should receive a Logger through dependencies rather than importing a singleton.
export function createSomethingService(deps: { logger: Logger }) {
return {
async doWork() {
deps.logger.info({ resource: 'something' }, 'Starting work');
},
};
}Use structured fields, not string interpolation:
logger.info({ userId, contentId, action: 'publish' }, 'Content published');Logger setup
The composition root creates the logger from validated config:
import { createLogger } from '@toast/core';
const logger = createLogger(config.logger);Standard fields
Include these when relevant:
| Field | Meaning |
|---|---|
requestId | request correlation |
siteId | tenant scope |
userId | authenticated actor |
err | error object |
duration_ms | timing information |
Sensitive data
Never log:
- passwords
- tokens or API keys
- full session credentials
- full payment data
Prefer redacted or partial values if context is needed.
// Bad
logger.info({ password, token }, 'Login attempt');
// Better
logger.info({ emailDomain: email.split('@')[1] }, 'Login attempt');Request logging
HTTP requests are logged by middleware. Route and service code should add extra logs only when they provide debugging value beyond the standard request record.
Environment behavior
| Environment | Output |
|---|---|
| Development | pretty-printed logs |
| Production | JSON to stdout |
Use LOG_LEVEL to control verbosity.