class

Hwaro::Logger::GuardedIO

Inherits IO < Reference < Object

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

new(io : IO)
Source

Instance methods

flush

Flushes buffered data, if any.

IO defines this is a no-op method, but including types may override.

Source
puts(string : String) : Nil

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"
Source
read(slice : Bytes) : Int32

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
Source
tty?

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
Source
write(slice : Bytes) : Nil

Writes the contents of slice into this IO.

io = IO::Memory.new
slice = Bytes.new(4) { |i| ('a'.ord + i).to_u8 }
io.write(slice)
io.to_s # => "abcd"
Source