Toast
Contributor

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:

  • Logger interface → packages/core/src/logger.ts
  • createLogger()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:

FieldMeaning
requestIdrequest correlation
siteIdtenant scope
userIdauthenticated actor
errerror object
duration_mstiming 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

EnvironmentOutput
Developmentpretty-printed logs
ProductionJSON to stdout

Use LOG_LEVEL to control verbosity.

On this page