Hwaro::Logger::GuardedIO
Terminal stream that a vanished reader cannot turn into a failure.
Crystal ignores SIGPIPE, so once whoever was reading hwaro's stdout goes
away (a script that waited for hwaro serve: ready and closed the pipe,
a closed terminal) every later write raises IO::Error. Raised from a
log line, that aborted whatever was being logged — under hwaro serve
every save failed with "Build failed: … Broken pipe" before a single
page was rendered, for the rest of the session. Logging is never the
point of the work: the first failed write marks the stream gone and
every later one is dropped.
It is also the one lock on the stream. Render workers run on several
threads and warn concurrently; the terminal IO's buffer is not
thread-safe, so unlocked writes interleaved, duplicated and dropped
warning lines and even emitted NUL bytes. puts writes the line and
its newline as one locked write so lines never interleave either.
Constructors
Instance methods
Flushes buffered data, if any.
IO defines this is a no-op method, but including types may override.
Writes string to this IO, followed by a newline character
unless the string already ends with one.
io = IO::Memory.new
io.puts "hello\n"
io.puts "world"
io.to_s # => "hello\nworld\n"
Reads at most slice.size bytes from this IO into slice.
Returns the number of bytes read, which is 0 if and only if there is no
more data to read (so checking for 0 is the way to detect end of file).
io = IO::Memory.new "hello"
slice = Bytes.new(4)
io.read(slice) # => 4
slice # => Bytes[104, 101, 108, 108]
io.read(slice) # => 1
slice # => Bytes[111, 101, 108, 108]
io.read(slice) # => 0
Returns true if this IO is associated with a terminal device (tty), false otherwise.
IO returns false, but including types may override.
STDIN.tty? # => true
IO::Memory.new.tty? # => false