In general, as everyone else said, keep the file open for performance (open is a relatively slow operation). However, you need to think about what's going to happen if you keep the file open and people either remove the log file or truncate it. And that depends on the flags used at open time. (I'm addressing Unix - similar considerations probably apply to Windows, but I'll accept correction by those more knowledgeable than me).
If someone sees the log file grow to, say, 1 MB and then removes it, the application will be none the wiser, and Unix will keep the log data safe until the log is closed by the application. What's more, the users will be confused because they probably created a new log file with the same name as the old and are puzzled about why the application 'stopped logging'. Of course, it didn't; it is just logging to the old file that no-one else can get at.
If someone notices that the log file growing to, say, 1 MB and then truncates it, the application will also be none the wiser. Depending on how the log file was opened, though, you might get weird results. If the file was not opened with O_APPEND (POSIX-speak), then the program will continue to write at its current offset in the log file, and the first 1 MB of the file will appear as a stream of zero bytes -- which is apt to confuse programs looking at the file.
How to avoid these problems?
- Open the log file with O_APPEND.
- Periodically use fstat() on the file descriptor and check whether st_nlink is zero.
If the link count goes to zero, somebody removed your log file. Time to close it, and reopen a new one. By comparison with stat() or open(), fstat() should be quick; it is basically copying information directly out of stuff that is already in memory, no name lookup needed. So, you should probably do that every time you are about to write.
Suggestions:
- Make sure there is a mechanism to tell the program to switch logs.
- Make sure you log the complete date and time in the messages.
I suffer from an application that puts out time and not date. Earlier today, I had a message file that had some entries from 17th August (one of the messages accidentally included the date in the message after the time), and then some entries from today, but I can only tell that because I created them. If I looked at the log file in a weeks time, I could not tell which day they were created (though I would know the time when they were created). That sort of thing is annoying.
You might also look at what systems such as Apache do - they have mechanisms for handling log files and there are tools for dealing with log rotation. Note: if the application does keep a single file open, does not use append mode, and does not plan for log rotation or size limits, then there's not much you can do about log files growing or having hunks of zeroes at the start -- other than restarting the application periodically.
Incidentally, the disk blocks that 'contain' the zeroes are not actually allocated on disk. You can really screw up people's backup strategies by creating files which are a few GB each, but all except the very last disk block contain just zeroes. Basically (error checking and file name generation omitted for conciseness):
int fd = open("/some/file", O_WRITE|O_CREATE, 0444);
lseek(fd, 1024L * 1024L * 1024L, 0);
write(fd, "hi", 2);
close(fd);
This occupies one disk block on the disk - but 1 GB (and change) on (uncompressed) backup and 1 GB (and change) when restored. Anti-social, but possible.