Search code examples
fileluahammerspoon

Data not appearing in log file after write operation


I have the following code:

time = os.date("*t")
data = io.open("test.txt", "a")

function applicationWatcher(appName, eventType, appObject)
    if (eventType == hs.application.watcher.launched) then
        data:write("" .. appName .. " launched at ".. ("%02d:%02d:%02d:%02d:%02d:%02d"):format(time.day, time.month, time.year, time.hour, time.min, time.sec))
    end
end

local appWatcher = hs.application.watcher.new(applicationWatcher)
appWatcher:start()

This code sees when you launch an application on macOS. I want the program to log the time, date and the application's name in a file so that I can see which apps I've launched, and when.

Nothing appears to get logged into my text file. Why?


Solution

  • File I/O is buffered. This means that data is not always written to the file immediately, but rather saved in memory until the buffer is full, so that data may be written in bulk.

    The simple fix is to simply use file:flush to immediately push data from the buffer into the file.

    data:write('name and timestamp')
    data:flush()
    

    The more advanced solution is to use file:setvbuf to set your appropriate mode, and buffer size:

    file:setvbuf (mode [, size])

    Sets the buffering mode for an output file. There are three available modes:

    • "no": no buffering; the result of any output operation appears immediately.
    • "full": full buffering; output operation is performed only when the buffer is full or when you explicitly flush the file (see io.flush).
    • "line": line buffering; output is buffered until a newline is output or there is any input from some special files (such as a terminal device).

    For the last two cases, size specifies the size of the buffer, in bytes. The default is an appropriate size.

    What you probably want is 'line' buffering, since you should add a newline character ('\n') to the end of your string anyway, otherwise your logfile is going to be very hard to read.

    local data = io.open("test.txt", "a")
    data:setvbuf('line')