Summary
Invocations of the docker executable do not log their standard output or standard error in production. Two independent gaps cause this: (1) the production Mongo path constructs the Docker engine with a NullLogger, so all docker stdout/stderr is silently discarded; and (2) even when a real ILogger is supplied, successful runs log only the combined output at Debug level, so at default log levels docker output is invisible. The requirement is that invocations of the docker executable log BOTH standard output and standard error, on success and on failure.
Docker is invoked via DockerCommandRunner.RunAsync -> ProcessRunner.RunAndLogAsync -> ProcessRunner.RunProcessAsync.
Root Cause
1. NullLogger in the production Mongo path
Phantom.Workspaces.Data.MongoDB\MongoDbConnectionBroker.cs (line ~35) constructs the engine with the PARAMETERLESS constructor:
_containerEngine = containerEngine ?? new WindowsDockerDesktopEngine();
Phantom.Workspaces.Containers\WindowsDockerDesktopEngine.cs (lines ~11-14): the parameterless ctor wires a NullLogger:
public WindowsDockerDesktopEngine()
: this(new DockerCommandRunner(NullLogger<DockerCommandRunner>.Instance))
{
}
So EVERY docker command run by the broker (info, container inspect, create, start, stop, rm) logs to NullLogger -> all stdout/stderr is silently discarded. Phantom.Workspaces.Data.MongoDB.Tests\MongoDbTestDatabaseFixture.cs (line ~23) does the same:
private readonly ContainerEngine _containerEngine = new WindowsDockerDesktopEngine();
2. Success output only at Debug, combined stream only
Even when a real ILogger is supplied, Phantom.Workspaces.Data.Core\ProcessRunner.cs RunAndLogAsync (lines ~158-200) logs the COMBINED stdout+stderr blob only at LogDebug on success (exit 0), at LogWarning on non-zero exit, and LogError on timeout:
if (result.ExitCode != 0)
{
logger.LogWarning(
"Process '{Command}' exited with code {ExitCode}{Description}.\nOutput:\n{Output}",
...
result.StandardOutAndError);
}
else if (!string.IsNullOrWhiteSpace(result.StandardOutAndError))
{
logger.LogDebug(
"Process '{Command}' completed successfully{Description}.\nOutput:\n{Output}",
...
result.StandardOutAndError);
}
On a normal successful run at default log levels, docker output is invisible. stdout and stderr are captured SEPARATELY into ProcessResult (ProcessRunner.cs lines ~146-150), but only the combined StandardOutAndError blob is ever logged:
return new ProcessResult(
process.ExitCode,
string.Join(Environment.NewLine, stdoutLines),
string.Join(Environment.NewLine, stderrLines),
string.Join(Environment.NewLine, combinedLines));
3. Failure exception surfaces only stderr
WindowsDockerDesktopEngine.RunAndEnsureSuccessAsync (lines ~135-151) throws on failure but includes only result.StandardError in the exception message; stdout on failure is not surfaced there. (It IS in the Warning log, but only when a real logger is wired -- which it is not in the broker path.)
throw new InvalidOperationException(
$"Docker command failed: docker {string.Join(' ', arguments)}{Environment.NewLine}" +
$"{result.StandardError}".TrimEnd());
Impact
When the Mongo container fails to create/start (image pull failure, port conflict, mount error, Atlas Local startup error), docker's actual stdout/stderr -- the only useful diagnostic -- is thrown away because the broker uses NullLogger. Users and maintainers diagnosing container issues (e.g. related to the slow/flaky container-connect tests and first-run image pulls) get no docker output at all.
Affected Files
| File |
Role |
Phantom.Workspaces.Data.MongoDB\MongoDbConnectionBroker.cs |
Line ~35 uses parameterless WindowsDockerDesktopEngine() -> NullLogger; must pass a real logger |
Phantom.Workspaces.Containers\WindowsDockerDesktopEngine.cs |
Parameterless ctor (line ~11) wires NullLogger; ctor selection |
Phantom.Workspaces.Containers\DockerCommandRunner.cs |
Routes all docker commands through ProcessRunner.RunAndLogAsync with its ILogger |
Phantom.Workspaces.Data.Core\ProcessRunner.cs |
RunAndLogAsync logs combined output only at Debug on success (lines ~181-197); should log stdout+stderr at a visible level |
Phantom.Workspaces.Data.MongoDB.Tests\MongoDbTestDatabaseFixture.cs |
Line ~23 also uses parameterless ctor |
Design / Fix
Make docker invocations always log stdout AND stderr through a real logger.
Recommended
-
Wire a real logger into the broker's engine. Give MongoDbConnectionBroker access to an ILoggerFactory/ILogger<DockerCommandRunner> (constructor param, defaulting to something non-null) and construct new WindowsDockerDesktopEngine(logger) (the ILogger<DockerCommandRunner> ctor at WindowsDockerDesktopEngine.cs line ~16) instead of the parameterless ctor. Do the same for MongoDbTestDatabaseFixture (use a test logger). Avoid the NullLogger default silently swallowing output in production -- the parameterless ctor should be reserved for tests, or removed/guarded.
-
Log stdout and stderr on every invocation, not just failures. In ProcessRunner.RunAndLogAsync, raise the success log level for external-command output above Debug (e.g. Information, or a caller-selectable level), and/or log stdout and stderr as distinct fields rather than only the combined blob, so both streams are always visible. Consider adding an option so callers (docker) opt into always-log-at-Information. The exact level is a design decision, but the requirement is that docker stdout AND stderr are logged on both success and failure.
Considered / Background
Current behavior (Debug-only combined output, NullLogger in broker) -- rejected because docker output is invisible exactly when it is needed (container create/start failures).
Expected Tests
Existing tests: Phantom.Workspaces.Data.Core.Tests\ProcessRunnerTests.cs (namespace Phantom.Workspaces.Data.Tests) already has a FakeLogger : ILogger capturing (LogLevel Level, string Message) and tests such as RunAndLogAsync_ProcessSucceeds_LogsStdoutAtDebugLevel (which currently asserts Debug and will need updating). Phantom.Workspaces.Containers.Tests\WindowsDockerDesktopEngineTests.cs uses a fake RecordingDockerCommandRunner. New tests should match these classes and styles.
| Test Name |
Class |
What It Verifies |
ProcessRunner_RunAndLogAsync_OnSuccess_LogsStandardOutputAndStandardError |
ProcessRunnerTests |
A FakeLogger receives both stdout and stderr content at a non-Debug (visible) level on exit 0 |
ProcessRunner_RunAndLogAsync_OnFailure_LogsStandardOutputAndStandardError |
ProcessRunnerTests |
Both stdout and stderr are logged on non-zero exit |
MongoDbConnectionBroker_UsesLoggingDockerEngine_DoesNotUseNullLogger |
MongoDbConnectionBrokerTests (broker/engine test) |
The production path constructs an engine whose command runner is wired with a real, non-null logger, so docker output is no longer silently discarded |
Note: existing RunAndLogAsync_ProcessSucceeds_LogsStdoutAtDebugLevel / RunAndLogAsync_ProcessSucceeds_LogsStderrAtDebugLevel / RunAndLogAsync_NoLogCall_WhenExitCodeIsZero will need to be updated to reflect the new visible success-log level.
Summary
Invocations of the
dockerexecutable do not log their standard output or standard error in production. Two independent gaps cause this: (1) the production Mongo path constructs the Docker engine with aNullLogger, so all docker stdout/stderr is silently discarded; and (2) even when a realILoggeris supplied, successful runs log only the combined output atDebuglevel, so at default log levels docker output is invisible. The requirement is that invocations of thedockerexecutable log BOTH standard output and standard error, on success and on failure.Docker is invoked via
DockerCommandRunner.RunAsync->ProcessRunner.RunAndLogAsync->ProcessRunner.RunProcessAsync.Root Cause
1. NullLogger in the production Mongo path
Phantom.Workspaces.Data.MongoDB\MongoDbConnectionBroker.cs(line ~35) constructs the engine with the PARAMETERLESS constructor:Phantom.Workspaces.Containers\WindowsDockerDesktopEngine.cs(lines ~11-14): the parameterless ctor wires aNullLogger:So EVERY docker command run by the broker (
info,container inspect,create,start,stop,rm) logs toNullLogger-> all stdout/stderr is silently discarded.Phantom.Workspaces.Data.MongoDB.Tests\MongoDbTestDatabaseFixture.cs(line ~23) does the same:2. Success output only at Debug, combined stream only
Even when a real
ILoggeris supplied,Phantom.Workspaces.Data.Core\ProcessRunner.csRunAndLogAsync(lines ~158-200) logs the COMBINED stdout+stderr blob only atLogDebugon success (exit 0), atLogWarningon non-zero exit, andLogErroron timeout:On a normal successful run at default log levels, docker output is invisible. stdout and stderr are captured SEPARATELY into
ProcessResult(ProcessRunner.cslines ~146-150), but only the combinedStandardOutAndErrorblob is ever logged:3. Failure exception surfaces only stderr
WindowsDockerDesktopEngine.RunAndEnsureSuccessAsync(lines ~135-151) throws on failure but includes onlyresult.StandardErrorin the exception message; stdout on failure is not surfaced there. (It IS in the Warning log, but only when a real logger is wired -- which it is not in the broker path.)Impact
When the Mongo container fails to create/start (image pull failure, port conflict, mount error, Atlas Local startup error), docker's actual stdout/stderr -- the only useful diagnostic -- is thrown away because the broker uses
NullLogger. Users and maintainers diagnosing container issues (e.g. related to the slow/flaky container-connect tests and first-run image pulls) get no docker output at all.Affected Files
Phantom.Workspaces.Data.MongoDB\MongoDbConnectionBroker.csWindowsDockerDesktopEngine()-> NullLogger; must pass a real loggerPhantom.Workspaces.Containers\WindowsDockerDesktopEngine.csNullLogger; ctor selectionPhantom.Workspaces.Containers\DockerCommandRunner.csProcessRunner.RunAndLogAsyncwith itsILoggerPhantom.Workspaces.Data.Core\ProcessRunner.csRunAndLogAsynclogs combined output only at Debug on success (lines ~181-197); should log stdout+stderr at a visible levelPhantom.Workspaces.Data.MongoDB.Tests\MongoDbTestDatabaseFixture.csDesign / Fix
Make docker invocations always log stdout AND stderr through a real logger.
Recommended
Wire a real logger into the broker's engine. Give
MongoDbConnectionBrokeraccess to anILoggerFactory/ILogger<DockerCommandRunner>(constructor param, defaulting to something non-null) and constructnew WindowsDockerDesktopEngine(logger)(theILogger<DockerCommandRunner>ctor atWindowsDockerDesktopEngine.csline ~16) instead of the parameterless ctor. Do the same forMongoDbTestDatabaseFixture(use a test logger). Avoid theNullLoggerdefault silently swallowing output in production -- the parameterless ctor should be reserved for tests, or removed/guarded.Log stdout and stderr on every invocation, not just failures. In
ProcessRunner.RunAndLogAsync, raise the success log level for external-command output aboveDebug(e.g.Information, or a caller-selectable level), and/or log stdout and stderr as distinct fields rather than only the combined blob, so both streams are always visible. Consider adding an option so callers (docker) opt into always-log-at-Information. The exact level is a design decision, but the requirement is that docker stdout AND stderr are logged on both success and failure.Considered / Background
Current behavior (Debug-only combined output,
NullLoggerin broker) -- rejected because docker output is invisible exactly when it is needed (container create/start failures).Expected Tests
Existing tests:
Phantom.Workspaces.Data.Core.Tests\ProcessRunnerTests.cs(namespacePhantom.Workspaces.Data.Tests) already has aFakeLogger : ILoggercapturing(LogLevel Level, string Message)and tests such asRunAndLogAsync_ProcessSucceeds_LogsStdoutAtDebugLevel(which currently assertsDebugand will need updating).Phantom.Workspaces.Containers.Tests\WindowsDockerDesktopEngineTests.csuses a fakeRecordingDockerCommandRunner. New tests should match these classes and styles.ProcessRunner_RunAndLogAsync_OnSuccess_LogsStandardOutputAndStandardErrorProcessRunnerTestsFakeLoggerreceives both stdout and stderr content at a non-Debug (visible) level on exit 0ProcessRunner_RunAndLogAsync_OnFailure_LogsStandardOutputAndStandardErrorProcessRunnerTestsMongoDbConnectionBroker_UsesLoggingDockerEngine_DoesNotUseNullLoggerMongoDbConnectionBrokerTests(broker/engine test)Note: existing
RunAndLogAsync_ProcessSucceeds_LogsStdoutAtDebugLevel/RunAndLogAsync_ProcessSucceeds_LogsStderrAtDebugLevel/RunAndLogAsync_NoLogCall_WhenExitCodeIsZerowill need to be updated to reflect the new visible success-log level.