[comp.lang.c] Request code for log-file mechanism

marco@westc.uucp (Marco Nijdam) (10/17/90)

Dear netters,

We are writing an application that must keep a log-file of the
actions that where taken. It is possible that more than one
process writes to a log file at the same time. It would therefore
be very convenient that the processes can not write to the
same log-file, or even better, that the logging mechanism is
intelligent enough to allow several processes to log things
in the same file, without causing file corruption. Due to the
nature of the application, the logging mechanism must be very
reliable. Furthermore, the application will be running on multiple
platforms, including Sun and VAX,, so a portable routine it
preferred. The application is written in C.

I am sure that such a logging mechanism has been written before
hundreds of times. So I do not want to invent the wheel all over
again. The problem is to find it.

Therefore, can anyone give us a lead where I can obtain a routine
or library in C that implements the above described logging function,
preferably in public domain, or commercial. Or if someone has such a
thing lying around, can you send it to me. It must however be royalty
free and include source code, so we can maintain it.
Also, if you have something that implements only part of our wishes,
we are interested.

Please reply by email.

M.D. Nijdam

-- Marco Nijdam, marco@westc.nl  OR  mcsun!hp4nl!westc!marco
-- West Consulting bv, Phoenixstraat 49, 2611 AL  Delft, The Netherlands
--                     P.O. Box 3318,    2601 DH  Delft
-- Tel: +31-15-123190, Fax: +31-15-147889

mjr@hussar.dco.dec.com (Marcus J. Ranum) (10/18/90)

In article <1990Oct17.094623.2381@westc.uucp> marco@westc.uucp (Marco Nijdam) writes:
>We are writing an application that must keep a log-file of the
>actions that where taken. It is possible that more than one
>process writes to a log file at the same time.

	Depending on how time-critical the logging function is, you might
want to either use a log server (like syslog(), which is already written
and comes with most bsd Unixes) - otherwise, you can roll your own by
just keeping the file open, attempting to lock it, seeking to the eof,
writing, and releasing the lock. Something like:

/*
don't take this as gospel! for the purpose of example, error checks are
omitted. besides, where do you log failures to write to your log ?
*/
#include	<stdio.h>
#include	<sys/file.h>

log(fd,txt)
int	fd;
char	*txt;
{
	int	rv;
	int	ln = strlen(txt);

	while(flock(fd,LOCK_EX))
		sleep(1);

	(void)lseek(fd,0L,SEEK_END);

	rv = (write(fd,txt,ln) == ln);

	(void)flock(fd,LOCK_UN);
	return(rv);
}

ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (10/18/90)

In article <1990Oct17.094623.2381@westc.uucp> marco@westc.uucp (Marco Nijdam) writes:
>We are writing an application that must keep a log-file of the
>actions that where taken. It is possible that more than one
>process writes to a log file at the same time.

Not only that, they wanted it *portable*.

You're in luck.  ANSI C comes pretty close to what you want.

    Open the log file:

	FILE *log = fopen(LogFileTitle, "a");

    Ensure that the buffer is big enough for the longest message:

	size_t MaxLogLineLength = {whatever};
	char *log_buffer = malloc(MaxLogLineLength+1);

    After having checked everything, set up the buffer:

	setvbuf(log, log_buffer, _IOLBF, MaxLogLineLength+1);

    Now, to write a record to the log file:

	fprintf(log, "{format}\n, {arguments});

What's going on here?  The "a" argument of fopen() says "the file position
indicator is positioned at the end of the file before EACH write".  Making
the buffer big enough for the longest line and selecting line buffering
ensures that each time you write a line using fprintf(), the whole line
will be buffered and then sent out.

You really need to check the fine print, but this *should* work reasonably
well.  That is, after all, why "a" is defined the way it is.  For anything
more reliable, you will have to rely on file locking.

-- 
Fear most of all to be in error.	-- Kierkegaard, quoting Socrates.

scs@adam.mit.edu (Steve Summit) (10/23/90)

In article <1990Oct17.094623.2381@westc.uucp> marco@westc.uucp (Marco Nijdam) writes:
>We are writing an application that must keep a log-file of the
>actions that where taken. It is possible that more than one
>process writes to a log file at the same time.

In article <4006@goanna.cs.rmit.oz.au> ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) writes:
>Not only that, they wanted it *portable*.
>You're in luck.  ANSI C comes pretty close to what you want.
[Suggests using fopen "a" mode and setvbuf() to select line
buffering, with a large buffer.]
>What's going on here?  The "a" argument of fopen() says "the file position
>indicator is positioned at the end of the file before EACH write".  Making
>the buffer big enough for the longest line and selecting line buffering
>ensures that each time you write a line using fprintf(), the whole line
>will be buffered and then sent out.
>
>You really need to check the fine print, but this *should* work reasonably
>well.  That is, after all, why "a" is defined the way it is.  For anything
>more reliable, you will have to rely on file locking.

I was going to suggest a similar approach, as an approximate
solution, but I'm afraid that the "fine print" does not ensure
that this will work.  First of all, there is no guarantee that
buffered output is written with a single call to the underlying
operating system (write(2) or the equivalent for Unix).
(Actually, section 4.9.3 comes closer than I would have thought,
saying that line-buffered "characters are intended to be
transmitted to... the host environment as a block," although
that's "when a new-line character is encountered.")  Secondly,
there is no guarantee that the underlying operating system's
low-level write mechanism is atomic.  (Unix's tends to be, at
least for "reasonably" sized requests.)

As Richard mentions, file locking is the more reliable approach,
though obviously less portable.  (In practice, his suggested
mechanism will probably work fine, at least on a Unix system.
Beware of older Unix systems, for which fopen "a" mode indicated
a seek to the end at open time, with no special attention
thereafter, whereas this application requires the equivalent of
open(2)'s O_APPEND mode, indicating a seek to the end upon each
write.)

                                            Steve Summit
                                            scs@adam.mit.edu