FaasJS
Home
  • Guide
  • Documents
  • Templates
  • Changelog
  • Ecosystem

    • Docker Images
  • Github
  • Contributing
  • Sponsor
  • Security
Home
  • Guide
  • Documents
  • Templates
  • Changelog
  • Ecosystem

    • Docker Images
  • Github
  • Contributing
  • Sponsor
  • Security
  • Curated Stack Guide
  • Application Slices Guide
  • Project Config Guide
  • File Conventions
  • Code Comments Guide
  • defineApi Guide
  • Jobs Guide
  • Testing Guide
  • React Guide
  • React Data Fetching Guide
  • React Testing Guide
  • Ant Design Guide
  • Node Utils Guide
  • Logger Guide
  • Utils Guide
  • PG Query Builder and Raw SQL Guide
  • PG Table Types Guide
  • PG Schema and Migrations Guide
  • PG Testing Guide
  • CLI and Tooling Guide
  • CRUD Patterns Guide
  • faas.yaml Configuration Specification
  • Getting Started Guide
  • HTTP Plugin Guide
  • HTTP Protocol Specification
  • JSON Guide
  • Middleware Guide
  • Naming Convention
  • Plugin Specification
  • Plugins Guide
  • Routing Mapping Specification
  • Validation Guide
  • YAML Guide

Logger Guide

Use this guide when working with Logger instances, log levels, timing, and transport configuration in FaasJS apps.

Applicable Scenarios

  • Logging in middleware, plugins, or background jobs
  • Adding request, lifecycle, or failure logging to a FaasJS server
  • Creating standalone scripts that need a shared logger
  • Timing slow operations
  • Adjusting log verbosity for debugging

Default Workflow

  1. Reuse the injected logger when FaasJS already gives you one.
  2. Create new Logger('label') only for standalone scripts, adapters, or infrastructure code.
  3. Use debug for details, info for normal milestones, warn for degraded paths, and error for failures.
  4. Keep labels short and stable so related logs stay easy to scan.
  5. Use time() and timeEnd() around slow steps.
  6. Change verbosity, color mode, truncation, and transport behavior with environment variables before changing log call sites.

Rules

1. Prefer the injected logger when the framework provides one

  • In FaasJS runtime code, logger is often already part of the callback context.
  • Reuse that logger so labels, timing, and transport behavior stay consistent with the runtime.
  • Do not create a second logger inside the same request or job handler unless you have a very specific reason.

Middleware example:

import { useMiddleware } from '@faasjs/core'

export default useMiddleware((request, response, { logger }) => {
  logger.info('%s %s', request.method, request.url)

  response.end('ok')
})

Job handler example:

import { defineJob } from '@faasjs/jobs'

export default defineJob({
  async handler({ logger }) {
    logger.info('run cleanup')
  },
})

2. Create a labeled logger for standalone code

  • Use new Logger('label') in scripts, CLIs, build tools, or custom adapters.
  • A good label explains where the log came from without becoming noisy.
  • Prefer labels like seed, typegen, server, or sync:users.
import { Logger } from '@faasjs/node-utils'

const logger = new Logger('seed')

logger.info('start importing users')
logger.info('loaded config %o', { region: 'cn', dryRun: false })

3. Choose levels by intent

  • debug: internal steps, params, cache hits, and other noisy diagnostics
  • info: expected lifecycle messages such as startup, shutdown, and successful jobs
  • warn: recoverable problems, fallbacks, skipped work, or unusual states
  • error: failures that need attention
  • Pass an Error object directly to logger.error(error) when you have one

Prefer this:

try {
  await syncUsers()
  logger.info('sync completed')
} catch (error) {
  logger.error(error)
}

Over manually stringifying the error first.

4. Use format strings instead of building large strings by hand

  • Logger supports format-style messages, which keeps logs compact and readable.
  • Reach for %s for text, %d for numbers, %j for JSON, and %o for inspected objects.
  • This is usually clearer than manual concatenation or eager JSON.stringify().
logger.debug('user=%s retries=%d payload=%j', user.id, retries, payload)

5. Time slow operations with time() and timeEnd()

  • Use timers for network calls, database work, file IO, or startup hooks.
  • Keep the timer key stable and make sure timeEnd() uses the same key.
  • If the key is missing, FaasJS logs a warning, so mismatches are easy to spot.
logger.time('load-user', 'info')

const user = await loadUser(id)

logger.timeEnd('load-user', 'loaded user %s', user.id)

6. Tune output with environment variables

  • Logger defaults are FaasLog=info, FaasLogSize=1000, auto-detected terminal colors, and shared transport forwarding outside Vitest.
  • FaasLog=debug|info|warn|error sets the minimum level.
  • FaasLogMode=plain disables ANSI colors.
  • FaasLogMode=pretty forces colorized terminal output.
  • Without FaasLogMode, color output follows FORCE_COLOR, NO_COLOR, TERM, and whether stdout is a TTY.
  • FaasLogSize=2000 changes the truncation threshold for long debug/info logs. Warnings and errors are not truncated.
  • FaasLogTransport=true|false enables or disables shared transport forwarding. In Vitest, forwarding is disabled unless FaasLogTransport=true.

Examples:

FaasLog=info npx vp test
FaasLog=debug FaasLogMode=plain node ./scripts/sync-users.ts

7. Use transport only when you really need log shipping

  • Logger forwards messages to the shared transport by default.
  • Reach for getTransport() when you want to batch logs into another system.
  • Transport handlers receive batches of formatted log messages on the configured interval.
  • If a flush happens with no registered handlers, buffered messages are discarded and transport disables itself until a handler is registered or config is applied.
  • If you register transport handlers, flush them during shutdown so buffered logs are not lost.
import { getTransport } from '@faasjs/node-utils'

const transport = getTransport()

transport.register('shipper', async (messages) => {
  for (const message of messages) {
    await sendToRemote(message)
  }
})

process.on('SIGINT', async () => {
  await transport.stop()
  process.exit(0)
})

8. Do not log secrets or full sensitive payloads

  • Avoid logging tokens, cookies, session content, passwords, or raw request bodies by default.
  • Be extra careful with debug logs because they often survive in CI logs and incident reports.
  • If you must log request context, prefer IDs, counts, and safe summaries.

Review Checklist

  • injected loggers are reused where available
  • labels are short, stable, and meaningful
  • debug is used for noisy diagnostics instead of info
  • caught errors are logged with logger.error(error) when possible
  • slow steps use time() and timeEnd() with matching keys
  • environment variables are used to change verbosity, color mode, truncation, and transport forwarding
  • secrets and sensitive payloads are not logged
  • transport handlers call stop() during shutdown when transport is enabled