skip to content

A service writes its log to a file inside the container and the platform's captured log view is empty — why?

level: juniorimportance: must knowfreq 76%

answer

  1. the platform reads one channel
  2. write it, do not store it
  3. the contract is the two output streams
  4. a file inside has no reader
  5. not collected, not visible, not kept

basics

~20 s

A container platform's log contract is the process's standard output and error streams — the runtime captures those. A file written inside the container is outside that capture, so nothing collects it, and it is gone when the instance is replaced.

solid answer

~50 s

When a platform starts a container it attaches the first process's two output streams to pipes the runtime holds, reads everything written there, stamps it, and writes it to files the node manages. That captured copy is what the platform's log view shows and what a collector on the host ships onward. A write to a path inside the container is just an ordinary filesystem write into the container's own writable layer — no pipe is involved and nothing on the other side of the boundary is reading it. So the view is empty while the process runs, the collector ships nothing, and when the instance is replaced the file goes with it. The fix is to emit on the output streams and let the platform own transport; if a library only writes to files, point it at the process's own stream.

go deeper

for a junior

Recall the contract in one line: the platform captures what the process writes to standard output and standard error. A log file written inside the container is collected by nothing and disappears with the instance.

for a middle

Explain the path the bytes take — process stream, runtime pipe, node-side files, log view and collector — and say why an in-container file never enters it. Know that block buffering can still swallow the last lines.

for a senior

Show the diagnosis under pressure: empty log view plus a workload that clearly logs means a destination mismatch, not an outage. Be able to name what is lost, from when, and what you would change before the next incident.

for a principal

The judgment is where you put the boundary: making the output stream the only supported log destination across teams buys uniform collection, and costs you the libraries and vendored components that only write files. Decide who pays for those.

## What the platform actually captures When a container platform starts a workload it starts one process inside the boundary and connects that process's two output streams — **standard output** and **standard error** — to pipes the runtime itself holds open. Everything written there is read by the runtime, stamped with the time the runtime read it, and appended to files the node manages on the node's own disk. Those node-side files are what the platform's log view reads back, and what a collector running on the host ships onward. The workload configures nothing: **the contract is "write to the stream", and the platform owns everything after the write.** That is the whole of the default capture path, and it is deliberately narrow. It is the only thing a platform can offer identically to every workload, on every node, whatever the workload is written in: a process that can print has already satisfied it. Anything else — a file, a socket, a local agent of your own — is something you added, and the platform makes no promise about it. ## Why the file is invisible A write to a path inside the container is an ordinary filesystem write. The bytes land in the container's own writable layer (why that layer is throwaway is a storage subject of its own), and **nothing on the other side of the boundary is reading them**. The capture pipe is untouched, so three separate things are true at once: - the platform's log view shows an empty or near-empty stream for the workload; - the collector on the node ships nothing for it, because it ships what the runtime captured; - when the instance is replaced — a rollout, a rescheduling, a restart onto another node — the layer is discarded and the file goes with it. Teams usually meet those in that order, and meet the third one during the incident where the log was the only evidence. The file was readable the whole time, but only from inside that one running instance, and by the time anyone looks the instance is gone. ## Where a line can go, and what each choice costs | where the line is written | who can read it while the instance runs | survives replacement | |---|---|---| | the process's output streams | anyone with the platform's log view, and any collector on the node | yes, as the captured copy, until the node's rotation cap discards it | | a file inside the container | only someone who gets a view inside that specific instance | no | | a file on a path mounted from outside the container | whoever can read that path on the other side of the boundary | depends on what the path is backed by — a separate subject | The middle row is what this failure is made of. The problem is not that a file is a bad place to put bytes; it is that the file sits **outside the only channel anything is collecting**. ## What to do instead 1. Emit log lines on the output streams and let the platform own stamping, storage and shipping. This is why so many container-oriented services ship with no log-file setting at all — there is nothing useful for it to point at. 2. If a library can only write to a file, point its output at the process's own output stream; most accept a stream target rather than a path. Failing that, run a small forwarder alongside the process that reads the file and re-emits each line on the stream — and accept its cost: two copies of the data, another thing to supervise, and a window in which the forwarder is behind. 3. Do not try to fix it by choosing a conventional log directory. Nothing scans for one. There is no path the default capture is watching, and a name that looks standard buys nothing. ## The trap that survives the fix Writing to the stream is necessary, not sufficient. Two mechanisms still lose lines after the change: - **Buffering.** Many runtime libraries switch to block buffering when their output is a pipe rather than a terminal, so lines sit in the process's own memory in kilobyte-sized chunks instead of leaving immediately. A process killed mid-buffer loses everything unflushed — reliably including the last lines before a crash, which are the ones you wanted. Disable block buffering or flush per line for anything diagnostic. - **Back-pressure.** The pipe is finite. If whatever drains it stops draining, a write to the stream eventually blocks, and a process that logs on the request path stalls with it. It is rare, and worth recognising, because the symptom — a service that goes quiet and slow at the same moment — does not look like a logging problem. Neither is the file problem, but both hide behind the report "we moved to the stream and still lost the last minute".

  • The library in use can only write to a file path. What are the options?
    Point it at the process's own output stream — most stream-or-path implementations accept a stream. If it genuinely cannot, run a small forwarder alongside the process that tails the file and re-emits each line on the stream. That works, but you now keep two copies, supervise another component, and carry a window where the forwarder is behind.
  • The process writes to the stream, yet the captured view stays empty until it exits. Why?
    Its output is a pipe rather than a terminal, so the runtime library block-buffers: lines accumulate in process memory and only reach the pipe when a buffer fills or the process exits and flushes. Turn off block buffering or flush per line — otherwise a process that is killed loses exactly the lines before the kill.
  • Does the captured copy live forever once the runtime has it?
    No. The runtime writes it to node-side files under a size cap and a limit on how many are kept, and the oldest are deleted to bound disk use. It is durable enough to outlive the instance and be shipped, not durable as storage — the retained window on the node is minutes to hours for a noisy workload.

The platform is a microphone in front of the process, not a search of its desk: what you say into it is recorded, what you file in a drawer inside the room is not, and the room is cleared out when you leave.

saying these in an interview costs you the question

  • Thinks a node agent scans paths inside the container for log files
  • Believes a conventionally named log directory is picked up automatically
  • Says the file is safer than the stream because files are durable
  • Assumes the platform archives the container's filesystem when it stops
  • Reads the empty log view as a collector outage rather than a contract mismatch