Interesting timing. One of our programmers just mailed me his work on
this. His rewrites it to do syslog ONLY. I'm forwading it in case it
has any good ideas you want to borrow.
I haven't had a chance to test either the official syslogging or this
one, but intend to do so as soon as I can find a few moments free at my
desk. I actually have been VERY busy the past month or two, and wasn't
even aware of the syslog discussion going on the list until today.
On Thu, 16 Sep 1999, Philip Hazel wrote:
> I have done the work to allow Exim to log to syslog instead of, or as
> well as, to local files. I have taken a minimalist approach - no
> options, no messing with contents of log lines. The results can be
> found in a testing release:
>
> ftp://ftp.cus.cam.ac.uk/pub/software/programs/exim/Testing/exim-3.036.tar.gz
>
> Details of the syslog facility are in doc/NewStuff. Please could those
> who are interested in syslog try out the new facility and give me some
> feedback.
>
> Philip
>
> --
> Philip Hazel University of Cambridge Computing Service,
> ph10@??? Cambridge, England. Phone: +44 1223 334714.
>
>
>
> --
> ## List details at http://www.exim.org/mailman/listinfo/exim-users Exim details at http://www.exim.org/ ##
>
/*************************************************
* Exim - an Internet mail transport agent *
*************************************************/
/* Copyright (c) University of Cambridge 1995 - 1999 */
/* See the file NOTICE for conditions of use and distribution. */
/* Functions for writing log files. */
/* Changed to use only syslog by Peter Eisentraut
(peter@???) on 1999-08-27. */
#include "exim.h"
#define LOG_NAME_SIZE 256
/*************************************************
* Write message to log file *
*************************************************/
/* This now uses the syslog and makes everything much less cluttered.
The flags determine what priority the message will be written with,
and in the case of the panic log, whether the process should die afterwards.
The variable really_exim is TRUE only when exim is running in privileged state
(i.e. not with a changed configuration or with testing options such as -brw).
If it is not, don't try to write to the log (permission will probably be
denied) - just write to log_stderr instead.
Avoid actually writing to the logs when exim is called with -bv or -bt to
test an address, but take other actions, such as panicking.
If a message_id exists, we include it.
Arguments:
flags each bit indicates some independent action:
LOG_SENDER add raw sender to the message
LOG_RECIPIENTS add raw recipients list to message
LOG_MAIN write to main log
LOG_PROCESS write to process log
LOG_REJECT write to reject log
LOG_PANIC write to panic log
LOG_PANIC_DIE write to panic log and then crash
LOG_CONFIG add "Exim configuration error:\n "
LOG_CONFIG2 add "Exim configuration error for "
level write to main long only if log_level is >= this value
format a printf() format
... arguments for format
Returns: nothing
*/
void log_write(int level, int flags, char *format,...)
{
char *ptr;
BOOL testing = verify_only || address_test_mode || host_checking;
va_list ap;
char buffer[LOG_NAME_SIZE];
/* If debugging, show all log entries, but don't show headers. Do it all
in one go so that it doesn't get split when multi-processing. */
DEBUG(1) {
ptr = buffer;
sprintf(ptr, "LOG: %d%s%s%s%s\n ", level,
((flags & LOG_MAIN) != 0) ? " MAIN" : "",
((flags & LOG_PANIC) != 0) ? " PANIC" : "",
((flags & LOG_PROCESS) != 0) ? " PROCESS" : "",
((flags & LOG_REJECT) != 0) ? " REJECT" : "");
if ((flags & LOG_CONFIG) != 0)
strcat(ptr, "Exim configuration error\n ");
else if ((flags & LOG_CONFIG2) != 0)
strcat(ptr, "Exim configuration error for ");
while (*ptr)
ptr++;
va_start(ap, format);
if (!string_vformat(ptr, LOG_BUFFER_SIZE - (ptr - buffer) - 1, format, ap))
strcpy(ptr, "**** log string overflowed log buffer ****\n");
va_end(ap);
while (*ptr)
ptr++;
strcat(ptr, "\n");
fprintf(debug_file, "%s", buffer);
fflush(debug_file);
}
/* If no log file (i.e. main, panic, etc.) is specified, we are in a mess. */
if (flags == 0)
log_write(0, LOG_PANIC_DIE, "log_write called with no flags set");
/* Create the main message in the log buffer, including the message
id except for the process log and when called by a utility.
syslog already takes care of the time of day. */
ptr = buffer;
if (really_exim && (flags & LOG_PROCESS) == 0 && message_id[0] != 0)
sprintf(ptr, "%s ", message_id);
if ((flags & LOG_CONFIG) != 0)
strcat(ptr, "Exim configuration error\n ");
else if ((flags & LOG_CONFIG2) != 0)
strcat(ptr, "Exim configuration error for ");
while (*ptr)
ptr++;
va_start(ap, format);
if (!string_vformat(ptr, LOG_BUFFER_SIZE - (ptr - buffer) - 1, format, ap))
strcpy(ptr, "**** log string overflowed log buffer ****\n");
while (*ptr)
ptr++;
va_end(ap);
/* Add the raw, unrewritten, sender to the message if required. This is done
this way because it kind of fits with LOG_RECIPIENTS. */
if ((flags & LOG_SENDER) != 0 &&
ptr < buffer + LOG_BUFFER_SIZE - 8 - (int) strlen(raw_sender)) {
sprintf(ptr, " from <%s>", raw_sender);
while (*ptr)
ptr++;
}
/* Add list of recipients to the message if required; the raw list,
before rewriting, was saved in raw_recipients. */
if ((flags & LOG_RECIPIENTS) != 0 && ptr < buffer + LOG_BUFFER_SIZE - 6) {
int i;
sprintf(ptr, " for");
while (*ptr)
ptr++;
for (i = 0; i < recipients_count; i++) {
char *s = raw_recipients[i];
if (buffer + LOG_BUFFER_SIZE - ptr < (int) strlen(s) + 3)
break;
sprintf(ptr, " %s", s);
while (*ptr)
ptr++;
}
}
sprintf(ptr, "\n");
while (*ptr)
ptr++;
/* Handle loggable errors when running a utility, or when address testing.
Write to stderr unless debugging (when it will already have been written). */
if (!really_exim || testing) {
if (debug_level <= 0)
fprintf(stderr, "LOG: %s", buffer);
if ((flags & LOG_PANIC_DIE) == LOG_PANIC_DIE)
exit(EXIT_FAILURE);
return;
}
/* Handle the main log. This will be logged as "mail" facility wiht priority
of "info". */
if ((flags & LOG_MAIN) != 0 && log_level >= level) {
#ifndef NO_OPENLOG
openlog("exim", LOG_PID | LOG_CONS, LOG_MAIL);
#endif
syslog(LOG_INFO, buffer);
closelog();
}
/* Handle the log for rejected messages: log recipients and the headers if any,
but watch out for overflowing the buffer. Stick a separator between messages. */
if ((flags & LOG_REJECT) != 0) {
header_line *h;
if (recipients_count > 0) {
int i;
/* The first recipient */
string_format(ptr, LOG_BUFFER_SIZE - (ptr - buffer), "Recipients: %s\n",
recipients_list[0].address);
while (*ptr)
ptr++;
/* And up to 2 additional recipients */
for (i = 1; i < recipients_count && i < 3; i++) {
string_format(ptr, LOG_BUFFER_SIZE - (ptr - buffer), " %s\n",
recipients_list[i].address);
while (*ptr)
ptr++;
}
if (i < recipients_count) {
(void) string_format(ptr, LOG_BUFFER_SIZE - (ptr - buffer), " ...\n");
while (*ptr)
ptr++;
}
}
for (h = header_list; h != NULL; h = h->next) {
if (!string_format(ptr, LOG_BUFFER_SIZE - (ptr - buffer), "%c %s",
h->type, h->text))
break;
while (*ptr)
ptr++;
}
while (*ptr)
ptr++;
(void) string_format(ptr, LOG_BUFFER_SIZE - (ptr - buffer),
"----------------------------------------"
"--------------------------------------\n");
while (*ptr)
ptr++;
#ifndef NO_OPENLOG
openlog("exim", LOG_PID | LOG_CONS, LOG_MAIL);
#endif
syslog(LOG_INFO, buffer);
closelog();
}
/* Handle the process log file, where exim processes can be made to dump
details of what they are doing by sending them a USR1 signal. Note that
a message id is not automatically added above.
This will be logged with a priority of notice to distinguish it from
the main and reject logs. */
if ((flags & LOG_PROCESS) != 0) {
#ifndef NO_OPENLOG
openlog("exim", LOG_PID | LOG_CONS, LOG_MAIL);
#endif
syslog(LOG_NOTICE, buffer);
closelog();
}
/* Handle the panic log. This will be logged as priority "emerg" (a.k.a. "panic").
Also, try to write to log_stderr and/or debug_file. */
if ((flags & LOG_PANIC) != 0) {
if (log_stderr != NULL && log_stderr != debug_file)
fprintf(log_stderr, "%s", buffer);
#ifndef NO_OPENLOG
openlog("exim", LOG_PID | LOG_CONS, LOG_MAIL);
#endif
syslog(LOG_EMERG, buffer);
closelog();
/* Give up if the DIE flag is set, but get rid of a partial message or try
to close down an incoming SMTP call gracefully first. */
if ((flags & LOG_PANIC_DIE) != LOG_PANIC) {
if (accept_call_bombout) /* No return from accept_bomb_out() */
accept_bomb_out("Unexpected failure, please try later");
if (smtp_input)
smtp_closedown("Unexpected failure, please try later");
exit(EXIT_FAILURE);
}
}
}
/*************************************************
* Close any open log files *
*************************************************/
void log_close_all(void)
{
/* This is no longer used but is called by external functions. */
}
/* End of log.c */