Skip to content

Logging

Observability is fundamental to operating a multi-provider API gateway. GodeX uses LogTape as its logging engine, wrapped behind a thin Logger contract that supports lazy attribute evaluation -- attributes are only serialised when the log level is active, preventing unnecessary object allocation on hot paths. The system is fully configurable via the logging section of godex.yaml, supporting console output with pretty formatting, rotating file output with JSON-lines format, and per-sink level overrides.

At a Glance

AspectDetail
Engine@logtape/logtape with @logtape/pretty and @logtape/file
ContractLogger interface at src/logger/contract.ts
Levelstrace, debug, info, warn, error
SinksConsole (pretty), File (rotating JSON-lines)
Lazy attrs`LogAttr = Record
Noop fallbackNoopLogger when all sinks disabled

Logger Architecture

Logger Contract

The Logger interface at src/logger/contract.ts:6-14 defines the shape consumed throughout the codebase:

typescript
interface Logger {
  readonly level: LogLevel;
  child(bindings: Record<string, unknown>): Logger;
  trace(event: string, attr?: LogAttr): void;
  debug(event: string, attr?: LogAttr): void;
  info(event: string, attr?: LogAttr): void;
  warn(event: string, attr?: LogAttr): void;
  error(event: string, attr?: LogAttr): void;
}

The LogAttr type at line 4 accepts either a plain object or a lazy getter function. The getter form is preferred on hot paths:

typescript
// Eager -- object created regardless of log level
logger.info("event", { data: expensiveCall() });

// Lazy -- function called only when level is active
logger.info("event", () => ({ data: expensiveCall() }));

Logger Creation

createLogger at src/logger/logger.ts:8-14 decides between a real LogTape-backed logger and the no-op fallback:

ConditionResult
configureLogging returns truewrapLogTape(getLogTapeLogger([]), level)
No sinks configuredcreateNoopLogger(level)

LogTape Configuration

configureLogging at src/logger/configure.ts:7-26 calls LogTape's configureSync with two logger categories:

CategoryLowest LevelPurpose
[] (root)Computed from sinksAll application log events
["logtape", "meta"]warningSuppress LogTape internal noise

The computed lowestLevel is the minimum level across all active sinks, ensuring no sink misses events it should receive.

Sink Types

Console Sink

Configured when console.enabled is not explicitly false. Uses the pretty formatter from @logtape/pretty at src/logger/sinks.ts:29-45.

SettingDefaultDescription
formatterpretty (date-time, properties)Human-readable output
levelInherits logging.levelPer-sink override

File Sink

Activated when file.enabled is true. Uses a rotating file sink from @logtape/file with JSON-lines formatting at src/logger/sinks.ts:47-62.

SettingDefaultDescription
dirRequiredDirectory for log files
filenameRequiredLog file name
max_size10 (MB)Max file size before rotation
max_files5Number of rotated files to keep
formatterJSON-lines (flattened)Machine-parseable output
levelInherits logging.levelPer-sink override

Level Mapping

GodeX uses five log levels. The mapping to LogTape's internal levels is handled by toLogTapeLevel at src/logger/levels.ts:7-13:

GodeX LevelLogTape Level
tracetrace
debugdebug
infoinfo
warnwarning
errorerror

minLogTapeLevel at line 19 computes the most verbose level from a set of sink levels, ensuring the root logger captures everything the most permissive sink needs.

NoopLogger

When all sinks are disabled, createNoopLogger at src/logger/noop-logger.ts:3-14 returns a logger whose methods are all no-ops. This avoids LogTape overhead when logging is intentionally turned off (e.g., in lightweight tests).

File Path Expansion

expandHomeDir at src/logger/paths.ts:4-9 resolves ~/ prefixes in file paths using process.env.HOME or Node's homedir(), allowing configs like:

yaml
logging:
  file:
    enabled: true
    dir: ~/logs/godex
    filename: godex.log

Configuration Example

yaml
logging:
  level: info
  console:
    enabled: true
    level: debug       # console sees debug and above
  file:
    enabled: true
    dir: /var/log/godex
    filename: godex.log
    max_size: 20       # 20 MB per file
    max_files: 10      # keep 10 rotated files
    level: info        # file sees info and above

Cross-References

References