中文

Logging

Write per-invocation diagnostic logs for CLI applications.

Updated

func/log creates a separate diagnostic log for each CLI invocation. It preserves troubleshooting details without mixing internal output into the command’s normal stdout.

Register and write a log

Register Logger through LogModule.register(), then inject it wherever diagnostics are produced:

src/app.module.ts
import { Command, Handler, Module, createApp } from 'func'
import { Logger, LogModule } from 'func/log'

@Command('deploy')
export class DeployCommand {
  constructor(private readonly logger: Logger) {}

  @Handler()
  run() {
    this.logger.push('deploy started')
    this.logger.push({ target: 'production' })
  }
}

@Module({
  commands: [DeployCommand],
  imports: [LogModule.register()],
})
export class AppModule {}

const app = createApp(AppModule, { appName: 'ship' })

void app.bootstrap()

This application writes under ~/.ship/logs. The application name comes from createApp({ appName }); func forwards it to Log, which validates it when the Logger Provider initializes. Every invocation uses a different filename containing a timestamp, process ID, and random identifier.

Logger.push(...data) combines its arguments with Node.js console-formatting semantics and writes a timestamped line. ANSI control sequences are removed so the file always contains plain text.

Understand the file lifecycle

Constructing Logger does not immediately create a directory or file. The file is opened only after the first successful push, and it closes during invocation disposal.

Successful calls do not print the log location. If a call fails after writing at least one record, disposal reports the path on stderr:

Logs were written to "/Users/ada/.ship/logs/func-....log".

Logger.path exposes the resolved path for the current invocation even before the first push creates the file.

Limit size and retention

By default, one invocation may write up to 10 MiB and the directory retains the 10 most recent func log files. Both limits are configurable:

TypeScript
LogModule.register({
  maxBytes: 2 * 1024 * 1024,
  maxFiles: 20,
})
SettingBehavior
maxBytesMaximum bytes written by one invocation; must be positive.
maxFilesNumber of func log files retained; must be non-negative.
maxFiles: 0Disable file logging entirely.

After the size limit is reached, later records from that invocation are ignored and at most one warning is emitted. Failures while creating, writing, closing, or pruning log files never replace the original command result.

Retention cleanup only touches files matching the func log naming scheme; unrelated files in the same directory are left alone.

API reference

APIPurpose
LogModule.register(options?)Register the per-invocation Logger Provider.
Logger.push(...data)Append a timestamped diagnostic record.
Logger.pathRead the resolved log path for this invocation.
LogModuleOptionsConfigure maxBytes and maxFiles.
LOG_SYSTEM / LOG_RUNTIMEStable error-code enums for the logging feature.