/*++ /* NAME /* msg_rate_delay 3 /* SUMMARY /* diagnostic interface /* SYNOPSIS /* #include /* /* void msg_rate_delay(stamp, delay, log_fn, fmt, ...) /* time_t *stamp; /* int delay; /* void (*log_fn)(const char *fmt, ...); /* const char *fmt; /* DESCRIPTION /* msg_rate_delay() produces log output at a reduced rate: no /* more than one message per 'delay' seconds. It discards log /* output that would violate the output rate policy. /* /* This is typically used to log errors accessing a cache with /* high-frequency access but low-value information, to avoid /* spamming the logfile with the same kind of message. /* /* Arguments: /* .IP stamp /* Time stamp of last log output; specify a zero time stamp /* on the first call. This is an input-output parameter. /* This parameter is ignored when verbose logging is enabled /* or when the delay value is zero. /* .IP delay /* The minimum time between log outputs; specify zero to log /* all output for debugging purposes. This parameter is ignored /* when verbose logging is enabled. /* .IP log_fn /* The function that produces log output. Typically, this will /* be msg_info() or msg_warn(). /* .IP fmt /* Format string as used with msg(3) routines. /* SEE ALSO /* msg(3) diagnostics interface /* DIAGNOSTICS /* Fatal errors: memory allocation problem. /* LICENSE /* .ad /* .fi /* The Secure Mailer license must be distributed with this software. /* AUTHOR(S) /* Wietse Venema /* IBM T.J. Watson Research /* P.O. Box 704 /* Yorktown Heights, NY 10598, USA /*--*/ /* System library. */ #include #include /* Utility library. */ #include #include #include /* SLMs. */ #define STR(x) vstring_str(x) /* msg_rate_delay - rate-limit message logging */ void msg_rate_delay(time_t *stamp, int delay, void (*log_fn) (const char *,...), const char *fmt,...) { const char *myname = "msg_rate_delay"; static time_t saved_event_time; time_t now; VSTRING *buf; va_list ap; /* * Sanity check. */ if (delay < 0) msg_panic("%s: bad message rate delay: %d", myname, delay); /* * This function may be called frequently. Avoid an unnecessary syscall * if possible. Deal with the possibility that a program does not use the * events(3) engine, so that event_time() always produces the same * result. */ if (msg_verbose == 0 && delay > 0) { if (saved_event_time == 0) now = saved_event_time = event_time(); else if ((now = event_time()) == saved_event_time) now = time((time_t *) 0); /* * Don't log if time is too early. */ if (*stamp + delay > now) return; *stamp = now; } /* * OK to log. This is a low-rate event, so we can afford some overhead. */ buf = vstring_alloc(100); va_start(ap, fmt); vstring_vsprintf(buf, fmt, ap); va_end(ap); log_fn("%s", STR(buf)); vstring_free(buf); } #ifdef TEST /* * Proof-of-concept test program: log messages but skip messages during a * two-second gap. */ #include int main(int argc, char **argv) { int n; time_t stamp = 0; for (n = 0; n < 6; n++) { msg_rate_delay(&stamp, 2, msg_info, "text here %d", n); sleep(1); } return (0); } #endif