Skip to content

DSC support: Capture logs from containers; retry on startup - #870

Open
mpobrien wants to merge 2 commits into
mongodb-js:mainfrom
mpobrien:mdb-runner-dsc-logging
Open

DSC support: Capture logs from containers; retry on startup#870
mpobrien wants to merge 2 commits into
mongodb-js:mainfrom
mpobrien:mdb-runner-dsc-logging

Conversation

@mpobrien

@mpobrien mpobrien commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

The log-create flow may need to retry if the SLS containers are still coming up, so this supports retries/retryInterval with sensible defaults.
To help debugging, an additional logDir param will also allow capturing the docker container output from SLS.

Copilot AI lite review requested due to automatic review settings September 1, 2026 19:09

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds support for capturing Docker Compose container logs to disk when mongodb-runner starts a disaggregated storage backend, so those logs are preserved independently of Docker’s log rotation and (optionally) the parent process lifetime.

Changes:

  • Forward MongoClusterOptions.logDir into DockerComposeProject.start() for disaggregated storage projects.
  • Add logDir support to DockerComposeProject to continuously stream docker compose logs --follow to a file while the project is up.
  • Add a fallback dumpLogs() snapshot on teardown if the log follower is not running, and include log settings in serialization.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
packages/mongodb-runner/src/mongocluster.ts Pass logDir into Docker Compose project startup for disaggregated storage.
packages/mongodb-runner/src/docker-compose.ts Implement continuous log streaming to file, fallback snapshot dumping, and serialization for log capture.
Suppressed comments (4)

packages/mongodb-runner/src/docker-compose.ts:104

  • startLogFollower() awaits the spawn event, but a failed spawn emits error and never emits spawn, which can deadlock startup and also keep the log file descriptor open indefinitely. Racing spawn against error makes the failure explicit and ensures the finally block can run.
        env: { ...process.env, ...env },
        detached: true,
      },
    );
    await once(proc, 'spawn');
    proc.unref();

packages/mongodb-runner/src/docker-compose.ts:178

  • dumpLogs() includes this.projectName verbatim in the output filename. As with startLogFollower(), this can contain path separators (via options.projectName / COMPOSE_PROJECT_NAME) and write outside the intended directory. Sanitize it before building the filename.
    const outFile = path.join(
      logDir,
      `docker-compose-${this.projectName}-${new Date()
        .toISOString()
        .replace(/[^-_a-zA-Z0-9.]/g, '')}.log`,
    );

packages/mongodb-runner/src/docker-compose.ts:196

  • Like the other docker spawns, dumpLogs() awaits the spawn event without handling the error event. If docker can't be spawned, this can hang and leak the opened file descriptor until process exit. Race spawn vs error so the finally block reliably closes the fd.
      const proc = spawn(
        'docker',
        dockerComposeArgs(this.composeFile, this.projectName, [
          'logs',
          '--no-color',
          '--timestamps',
        ]),
        {
          stdio: ['ignore', fd, fd],
          env: { ...process.env, ...this.env },
        },
      );
      await once(proc, 'spawn');
      const [code] = await once(proc, 'exit');
      debug('dumped docker compose logs', { outFile, code });

packages/mongodb-runner/src/docker-compose.ts:223

  • close() uses this.logDir !== undefined, which will treat an empty string as enabled and then attempt to dump logs to '' (throwing). This should match the truthy check used in MongoServer.start() so an empty string behaves like "unset".
    // If the log follower died (or was never started) while the project kept
    // running, fall back to a one-off snapshot before teardown destroys the
    // container logs.
    if (this.logDir !== undefined && !this.isLogFollowerRunning()) {
      try {
        await this.dumpLogs(this.logDir);

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines 43 to 47
const proc = spawn(
'docker',
['compose', '-f', composeFile, '-p', projectName, ...args],
dockerComposeArgs(composeFile, projectName, args),
{
stdio: ['inherit', 'pipe', 'pipe'],
Comment on lines +83 to +86
await fs.mkdir(logDir, { recursive: true });
const logFile = path.join(logDir, `docker-compose-${projectName}.log`);
const fd = openSync(logFile, 'a');
try {
Comment on lines +145 to +157
let logFollowerPid: number | undefined;
if (options.logDir !== undefined) {
try {
({ pid: logFollowerPid } = await startLogFollower(
composeFile,
projectName,
options.env,
options.logDir,
));
} catch (err) {
debug('failed to start docker compose log follower', err);
}
}
Comment on lines 553 to 556
cluster.dockerComposeProject = await DockerComposeProject.start(
disaggregatedStorage.composeFile,
{ env: disaggregatedStorage.env },
{ env: disaggregatedStorage.env, logDir: options.logDir },
);
@mpobrien mpobrien changed the title option to capture logs from containers into file DSC support: Capture logs from containers; retry on startup Sep 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants