Unbuffered output with Logger (newbie question)

E

Eric LIn

I'm trying to use Ruby's built-in Logger facility, and I'm not able to
make it output log messages in real-time. Instead, log messages are
only outputted when I call Logger#close.

The Logger is created with a line like this:

log = Logger.new(File.open('test.log', File::WRONLY | File::APPEND
| File::CREAT))

Then I log things using lines like:

log.info('hello')

tail -f test.log shows nothing.

It's only when I call "l.close" that all the log messages get written
out.

My suspicion is I'm not instantiating File correctly. Perhaps there
is an option for unbuffered output?

Any help appreciated.

Eric
 
D

Dave Bass

Eric said:
My suspicion is I'm not instantiating File correctly. Perhaps there
is an option for unbuffered output?

File is a subclass of IO, and IO has a flush method, which File
inherits. So you can do file.flush after each write to bypass Ruby's
buffering.

Pickaxe p. 509 says:

"io.flush -- Flushes any buffered data within io to the underlying
operating system (note that this is Ruby internal buffering only; the OS
may buffer the data as well)."

So you could try flushing the log file after each log.info call. I
suspect this means subclassing Logger or modifying something within
Logger; maybe someone more experienced could suggest how to do this.

You're still at the mercy of the OS's buffering, which is additional to
Ruby's.
 
R

Robert Klemme

File is a subclass of IO, and IO has a flush method, which File
inherits. So you can do file.flush after each write to bypass Ruby's
buffering.

Pickaxe p. 509 says:

"io.flush -- Flushes any buffered data within io to the underlying
operating system (note that this is Ruby internal buffering only; the OS
may buffer the data as well)."

So you could try flushing the log file after each log.info call. I
suspect this means subclassing Logger or modifying something within
Logger; maybe someone more experienced could suggest how to do this.

There is a much better option: create the File with File::SYNC. You
should check on your platform if io.sync returns true afterwards. If
not, you should try io.sync=true. That way all writes go directly to
the file.
You're still at the mercy of the OS's buffering, which is additional to
Ruby's.

But this does not matter that much because if you read the log file and
the block was not yet written to disk you see the contents nevertheless.
OS buffering is only an issue if the OS crashes which is unlikely.

Kind regards

robert
 
E

Eric LIn

There is a much better option: create the File with File::SYNC.  You
should check on your platform if io.sync returns true afterwards.  If
not, you should try io.sync=true.  That way all writes go directly to
the file.
        robert

Hi Robert,

It appears File::SYNC doesn't exist (at least not in my copy of
Ruby). However, setting IO#sync to true explicitly does work.

Thanks,
Eric
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,128
Latest member
ElwoodPhil
Top