When to Use
- CI test output capture: After a test container exits, retrieve stdout to parse test results and extract pass/fail counts for reporting.
- Crash investigation: Retrieve the error logs from a crashed container immediately after
container/inspect reveals an unexpected exit code.
- Structured log extraction: Pull JSON-formatted log output from a container and pass it to a Function node for parsing, enrichment, and forwarding to a log aggregator.
- Failure alerting: After a health-check workflow detects a container issue, retrieve logs and include the last 50 lines in a Slack alert notification.
- Pre-removal archival: Capture and store all container output to S3 or a database before calling
container/remove to preserve an audit trail.
Logs are retrieved from the Docker daemon's log buffer, not from files inside the container. For very high-volume containers, consider using a tail parameter in the Docker API to limit the response size. This node returns the full log buffer by default.
Configuration
Connection Fields
| Field | Type | Default | Description |
dockerHost | string | unix:///var/run/docker.sock | Docker socket path or TCP endpoint |
connectionType | string | unixsocket | unixsocket | tcp | tcptls |
tlsCertPath | string | — | TLS certificate directory. Required for tcptls. optional |
timeoutSeconds | int | 30 | Operation timeout. Increase for containers with large log buffers. optional |
Operation Fields
| Field | Type | Required | Description |
resource | string | required | Must be container |
operation | string | required | Must be logs |
ContainerId | string | required | Container ID (full or short) or container name |
Sample Configuration
{
"resource": "container",
"operation": "logs",
"ContainerId": "batch-job-20240101",
"connection": {
"dockerHost": "unix:///var/run/docker.sock",
"connectionType": "unixsocket",
"timeoutSeconds": 60
}
}
Validation Errors
| Error Code | Trigger | Resolution |
MISSING_INPUT | ContainerId is empty | Provide the container name or ID. |
NOT_FOUND | Container does not exist | Container may have already been removed. Always collect logs before calling container/remove. |
DOCKER_API_ERROR | Daemon error retrieving logs | Check daemon logs. May occur if the container's log driver does not support log retrieval (e.g. none log driver). |
CONFIG_ERROR | Connection settings invalid | Verify dockerHost and connectionType values. |
Output
Success Port
| Field | Type | Description |
logs | string | Combined stdout and stderr output |
stdout | string | Standard output only |
stderr | string | Standard error only |
status | string | success |
resource | string | container |
operation | string | logs |
Error Port
On failure, the error port receives errorCode, message, resource, and operation. If logs retrieval is part of a cleanup sequence, ensure the error port continues the workflow rather than halting (e.g. proceed to container removal even if logs are unavailable).
Sample Output
{
"logs": "[2024-01-01T08:00:05Z] INFO Starting batch processor\n[2024-01-01T08:00:06Z] INFO Processing 1,542 records\n[2024-01-01T08:02:31Z] INFO Batch complete. Processed: 1542, Errors: 0\n[2024-01-01T08:02:31Z] INFO Output written to /app/output/results.json",
"stdout": "[2024-01-01T08:00:05Z] INFO Starting batch processor\n[2024-01-01T08:00:06Z] INFO Processing 1,542 records\n[2024-01-01T08:02:31Z] INFO Batch complete. Processed: 1542, Errors: 0\n[2024-01-01T08:02:31Z] INFO Output written to /app/output/results.json",
"stderr": "",
"status": "success",
"resource": "container",
"operation": "logs"
}
Expression Reference
| Expression | Returns |
{{ $output.logs }} | Full combined log output string |
{{ $output.stdout }} | Standard output stream only |
{{ $output.stderr }} | Standard error stream only |
{{ $output.stderr.length > 0 }} | Boolean — true if there is any stderr output |
{{ $output.logs.split('\n').length }} | Number of log lines |
{{ $output.logs.includes('ERROR') }} | Boolean — true if any error lines appear in combined logs |
{{ $output.logs.split('\n').slice(-10).join('\n') }} | Last 10 lines of combined log output |
Node Policies & GuardRails
| Policy | Detail |
| Collect logs before remove | Always place container/logs before container/remove in cleanup workflows. Post-removal log retrieval is not possible. |
| Do not log sensitive output | Container logs may contain credential values printed at startup. Avoid writing raw logs output to workflow execution history without redaction. |
| Handle large log buffers | Long-running containers may produce megabytes of logs. Increase timeoutSeconds and consider adding a Function node to trim logs to the last N lines before forwarding. |
| No remote TCP without TLS | Use tcptls for remote Docker hosts. |
| Read-only operation | container/logs is non-destructive. It does not affect container state and can be called on running or stopped containers. |
Examples
Example 1: Retrieve and parse CI test results
// Node 1: container/logs
{ "resource": "container", "operation": "logs", "ContainerId": "test-runner-{{ $trigger.buildId }}" }
// Node 2: Function node — parse test output
const lines = $input.stdout.split('\n');
const passed = lines.filter(l => l.includes('✓') || l.includes('PASS')).length;
const failed = lines.filter(l => l.includes('✗') || l.includes('FAIL')).length;
return { passed, failed, totalTests: passed + failed, raw: $input.stdout };
Example 2: Send last 50 lines of logs to Slack on container failure
// Node 1: container/logs (after inspect reveals exit code != 0)
{ "resource": "container", "operation": "logs", "ContainerId": "{{ $trigger.containerName }}" }
// Node 2: Function node — trim to last 50 lines
const lastLines = $input.logs.split('\n').slice(-50).join('\n');
return { excerpt: lastLines };
// Node 3: Slack node
// message: "Container {{ $trigger.containerName }} crashed.\n```{{ $nodes.trimLogs.output.excerpt }}```"
Example 3: Archive logs to S3 before container removal
// Node 1: container/logs
{ "resource": "container", "operation": "logs", "ContainerId": "job-{{ $trigger.jobId }}" }
// Node 2: S3 node — put object
{
"bucket": "bizfirst-container-logs",
"key": "jobs/{{ $trigger.jobId }}/{{ $now | date('YYYY-MM-DD') }}/stdout.log",
"body": "{{ $output.logs }}"
}
// Node 3: container/remove (logs safely archived)