In Selenoid (unmaintained), how does following a session under /logs/ differ from downloading its saved .log file?
answer
- one path, two different answers
- the suffix on the request decides
- watching is not the same as downloading
- the browser's own container is the source
- the file arrives as the container leaves
basics
~20 sOne path serves two unrelated channels. Where an output directory is configured, a remainder that is empty or ends in .log is answered as a file from it; anything else opens a websocket that follows the running browser container's output.
solid answer
~50 sSelenoid, unmaintained by its own README, dispatches `/logs/` on the shape of what follows the prefix. With an output directory configured, an empty remainder or one ending in `.log` takes the **archive** branch: a listing, a download, or a `DELETE`, served out of `-log-output-dir`. Anything else, typically a session identifier, takes the **live** branch: a websocket that follows the browser's container output for as long as the session runs. Their prerequisites differ. Live following needs neither the output directory nor a log capability, but it does need a container-backed session, so it is unavailable when Selenoid runs browser drivers as bare processes. The saved file needs both. And in container mode the file does not exist during the session at all: its contents are copied out of the container at session close, just before the container is removed.
code
bash · 10 lines# Selenoid is UNMAINTAINED per its own README; read as a model of the mechanism.
# Archive branch - remainder is empty or ends in .log
curl "$SELENOID/logs/?json" # JSON array of file names
curl -O "$SELENOID/logs/$SESSION_ID.log" # download a saved file
curl -X DELETE "$SELENOID/logs/$SESSION_ID.log" # remove it; not found if already gone
# Live branch - remainder is anything else, so this upgrades to a websocket
# and follows the running browser container's output until you disconnect.
# ws://<selenoid>/logs/$SESSION_IDgo deeper
Know that watching a session's output as it runs and downloading its log afterwards are different requests, and that the name you would download by only becomes valid once the session has finished.
Be ready to say what selects between the two behaviours on the same path, and which of them needs the server to have been configured with an output directory.
Be ready to diagnose from symptoms: a listing that shows unfetchable entries, a live follow that reports a live session as missing, a file that never appears mid-run. Each maps to one branch condition.
Decide which channel your triage actually depends on, and design for the fact that one of them exists only while a person is watching and the other only after the session has ended.
`/logs/` on a session-container grid looks like one feature and is two. Which branch a request lands in explains several baffling results: a download that returns nothing while the test is clearly producing output, a listing that advertises files the same path refuses to serve, and a live stream that works on one deployment and not another. ## The dispatch rule Aerokube's Selenoid, unmaintained by its own README and read here as an open model of a mechanism hosted services implement privately, strips the `/logs/` prefix and looks at what is left: - If a log output directory is configured **and** the remainder is empty or ends in `.log`, the request is handled as a file operation against that directory. - Otherwise the request is handed to a websocket handler that follows a live session. The test is purely syntactic. Nothing looks up whether a session exists before choosing the branch, and nothing looks at the HTTP method until the branch is already chosen. ## The archive branch Inside the file branch there are three behaviours: - `DELETE /logs/<name>.log` removes the file, answering not-found when it is already gone. - `GET /logs/?json` returns the directory as a JSON array of names. - Any other `GET` is served by an ordinary static file server rooted at the output directory, which gives you both the plain listing for `/logs/` and the download for `/logs/<name>.log`. There is a real asymmetry in that list. The listing enumerates **every** file in the directory, but only names ending in `.log` reach the file branch. A build that also writes per-session metadata as JSON into the same directory therefore produces entries visible in the listing but unfetchable through this path: a request for one fails the suffix test and is handed to the websocket handler, which has no idea what to do with it. ## The live branch The other branch opens a websocket and follows the browser's own container output, standard output and standard error together, streaming it until the client disconnects or the session ends. This is what a grid user interface renders in a terminal panel while a test runs. Its prerequisites are different from the archive branch's in both directions: | | live follow | saved file | |---|---|---| | needs an output directory | no | yes | | needs a per-session log capability | no | yes, unless capture is global | | needs a container-backed session | yes | no | | downloadable while the session runs | yes | not under its final name | | carries timestamps | no | yes, in container mode | The container requirement surprises people. When Selenoid runs browser drivers as local processes rather than containers, a session has no container to follow, and the live branch reports it as not found though the session is plainly running. ## Why the saved file is late In container mode the saved log is not streamed as the test proceeds. At session close, and before the browser's container is removed, the server reads that container's accumulated output through the container runtime and copies it into a file in one pass, with timestamps attached. Only then is the file renamed from the random temporary name it was allocated at session start to its final name, which is either the session identifier or whatever the session asked for. Two consequences follow, and both are worth saying out loud in an interview: 1. In container mode there is nothing to download mid-session. A harness that polls for the file while the test runs will poll forever. 2. The final name appears only at the end. The temporary name is a poor handle rather than none: it is random, the session-creation reply never carries it, and only the directory listing reveals it. When Selenoid instead drives bare processes, the shape inverts: the file is created at session start and the driver process writes into it live. That temporary-named file is on disk while the session runs and its name ends in the log extension, so the listing shows it and the archive branch serves it half-written. It is still renamed at close, so the name you would ask for still only becomes valid at the end. ## Reading the same failure two ways Consider a port-logistics container-tracking suite whose shipment-status view intermittently never finishes loading. The two channels answer different questions about it: - The live follow answers "what is the browser saying right now, while it is stuck" — which is the question you have during a reproduction attempt, with a human watching. - The saved file answers "what did the browser say, in order, with timestamps" — which is the question you have the next morning, with nobody watching. A triage design with only the live channel cannot answer the second question, and one with only the archive channel cannot answer the first. They are complements, not alternatives, and the single `/logs/` prefix makes them look like one feature. ## What to verify on an unfamiliar deployment - Fetch the bare listing. If it does not answer as a directory, no output directory is configured and the archive branch does not exist here. - Try a live follow against a known-running session. If it reports the session as not found while the session is demonstrably alive, the deployment is not container-backed.
- Why does a harness that waits for a session's log file while the test runs never succeed in container mode?Because the file is produced at session close. During the session the server holds only a random temporary name, which the session-creation reply never carries, and in container mode nothing is written to it; the browser's output is copied out of its container in one pass at the end. The name the harness is waiting for comes into existence only after the session is deleted.
- A deployment shows the log file in its listing but returns nothing useful when you request it by name. What would you check first?The extension. The download branch is selected by the name ending in a log extension, and the listing enumerates every file in the directory regardless of its name. A metadata file, or a log the session named without the expected extension, is visible in the listing but is routed to the live-follow handler when requested by name.
saying these in an interview costs you the question
- Expects a session's log to be downloadable under its final name mid-run
- Thinks live following needs the same flag as saving does
- Assumes everything the listing shows can be fetched from the same path
- Thinks the live stream is what writes the saved file
- Assumes live following works without a container-backed session