Skip to content

die and stream-file output silently goes to stdout — blocked on let-go *out* semantics #1

Description

@mparrett

A few places rely on (binding [*out* …] …) to redirect output, but the rebinding is currently a no-op, so output lands on the wrong stream:

  • Error reports go to stdout, not stderr. die (cli.lg:6, imgstore.lg:17, container.lg:26) does (binding [*out* *err*] (println …)), but println ignores the *out* rebinding and writes to stdout.
  • Container log streaming goes to lgcr's own stdout. stream-file (container.lg:1060) does (binding [*out* sink] (print chunk)), and it's called with *out*/*err* sinks for stdout.log/stderr.log at container.lg:1344-1345. print ignores the sink binding the same way.

Reproduce on current let-go (no lgcr needed):

$ lg -e '(binding [*out* *err*] (println "x"))'  # "x" -> stdout, stderr empty
$ lg -e '(let [f (open "/tmp/s" :write)] (binding [*out* f] (print "y")) (close! f))'
$ cat /tmp/s                                      # empty — "y" went to stdout, not the file

Root cause is upstream: let-go's top-level print fns (print/pr/prn/println) write straight to os.Stdout and don't consult *out*, so (binding [*out* x] (println …)) has no effect. The lgcr code is written correctly per Clojure semantics — the runtime just doesn't honor it yet. Tracked in nooga/let-go#79, which has a proposed fix and a working implementation.

No lgcr code change is needed: once the let-go fix lands and the pin bumps to a release that includes it, die and stream-file start behaving as written. Add a regression test at that point so a later let-go change can't silently re-break error routing.

Filing mainly as a tracking link from the affected project; will close on the pin bump.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions