The Problem
When you open a file for writing, the default settings truncate (erase) the contents of the file. This is not always what you want. With log files, for example, you only want to add a new line of text to the end of the file. You never want to erase data from a log file. Perhaps a cron job will "rotate" the file (rename it) at the end of the week or month; but that's a separate issue.
The Solution
Sample code to append a line of text to a log file:
my $logfile = "/var/log/mylogfile";
my $date = localtime();
my $logmsg = "$date user $ENV{USER} ran this program";
open LOGFILE, ">>$logfile" or die "cannot open logfile $logfile for append: $!";
print LOGFILE $logmsg, "\n";
close LOGFILE;
This will create the log file (if it doesn't exist), and then write the log message to the end of the file.
Why include a "die" command on the open line? Because it's possible for the open statement to fail completely. If that happens, you want to know it. You need a clear error message to help you debug the problem. This open can fail if the directory is not accessable by the user running your program. Or maybe the log file exists, but the user does not have write permission to it. Or the file does not exist, and the user does not have write access to the directory (required to create new files). You can't predict what's going to happen in the future, and you don't care. You just want a clear error message if it ever happens.
Keep it Closed, Most of the Time
Note that the file remains closed most of the time. We open it only long enough to write the message, then close it again. This is the best way to write to log files. If your application leaves the log file open too long when not in use, you will encounter weird problems. For example, if there are two or more instances of the program running at the same time (such as if it's a command that multiple people have access to), then you can get data corruption / data loss issues.
Multiple Access
Imagine that 2 programs open the log file around the same time. They both move their internal file position pointer to the end of the file. One application eventually writes its log line to the file. Then, a second later, the other application writes its log line in the same exact spot! The data which the first application wrote is gone forever. We now have data loss.
This is a sort of "race condition" that can occur in applications used simultaneously by many people. To truely fix this kind of issue, you should open-and-lock the file for exclusive use. There are two styles of exclusive locking:
Which one should you use? It depends on your application. If you can afford to wait indefinitely for the file to open on a heavily loaded server with lots of users coming and going, then wait is the best choice for you. It's certainly the easiest.
If you are an event-driven application and must respond to the user quickly and in a timely manner, you can't afford to be sitting around waiting for a log file to be freed up for you. Then, nowait is a better choice. If the file is "busy", you simply queue up another event to remind yourself to try again later. Be sure to store all the appropriate data in that event record; for example, store the timestamp that should be written to the log file. Don't just write the current timestamp after a successful open. Because a substantial amount of time could pass between the moment when the log event occurred, and when it was actually recorded. You don't want an inaccurate timestamp written to your log file.
File Locking in Perl
You'll have to use a low-level open command to lock files upon open in Perl:
use Fcntl qw(:DEFAULT);
...
if (sysopen(LOGFILE, $logfile, O_EXCL|O_NONBLOCK|O_CREAT|O_WRONLY)) {
...write to file...
}
This directly calls the low-level system call "open", which supports many more flags than Perl's open() function. The constants O_EXCL and so forth are defined in the Fcntl.pm module that comes with Perl. We use the "|" symbol to combine them because they are really single bit-values being logical-OR'd together into a single integer number.
Meaning of the flags:
Daemons
When writing daemons (background programs that basically run forever), you have to be especially careful when accessing common files. This is one of the reasons that the Syslog facility in Unix was created. Daemons should log their messages using the syslog facility whenever possible. Don't reinvent the wheel unless you have a really good reason to do so.
Here's a web page with good information on file access and locking.
Don't miss the latest perl tips and tricks!
Subscribe to our low-volume mailing list:
Privacy Policy
| Copyright © 2006 Fastech Learning LLC, all rights reserved. |
| Phone toll free 1-866-464-6688, Phoenix Metro area 480-895-6688 |
| Problem with this web site? please let us know |