1/*++ 2/* NAME 3/* msg_rate_delay 3 4/* SUMMARY 5/* diagnostic interface 6/* SYNOPSIS 7/* #include <msg.h> 8/* 9/* void msg_rate_delay(stamp, delay, log_fn, fmt, ...) 10/* time_t *stamp; 11/* int delay; 12/* void (*log_fn)(const char *fmt, ...); 13/* const char *fmt; 14/* DESCRIPTION 15/* msg_rate_delay() produces log output at a reduced rate: no 16/* more than one message per 'delay' seconds. It discards log 17/* output that would violate the output rate policy. 18/* 19/* This is typically used to log errors accessing a cache with 20/* high-frequency access but low-value information, to avoid 21/* spamming the logfile with the same kind of message. 22/* 23/* Arguments: 24/* .IP stamp 25/* Time stamp of last log output; specify a zero time stamp 26/* on the first call. This is an input-output parameter. 27/* This parameter is ignored when verbose logging is enabled 28/* or when the delay value is zero. 29/* .IP delay 30/* The minimum time between log outputs; specify zero to log 31/* all output for debugging purposes. This parameter is ignored 32/* when verbose logging is enabled. 33/* .IP log_fn 34/* The function that produces log output. Typically, this will 35/* be msg_info() or msg_warn(). 36/* .IP fmt 37/* Format string as used with msg(3) routines. 38/* SEE ALSO 39/* msg(3) diagnostics interface 40/* DIAGNOSTICS 41/* Fatal errors: memory allocation problem. 42/* LICENSE 43/* .ad 44/* .fi 45/* The Secure Mailer license must be distributed with this software. 46/* AUTHOR(S) 47/* Wietse Venema 48/* IBM T.J. Watson Research 49/* P.O. Box 704 50/* Yorktown Heights, NY 10598, USA 51/*--*/ 52 53 54/* System library. */ 55 56#include <sys_defs.h> 57#include <time.h> 58 59/* Utility library. */ 60 61#include <msg.h> 62#include <vstring.h> 63#include <events.h> 64 65/* SLMs. */ 66 67#define STR(x) vstring_str(x) 68 69/* msg_rate_delay - rate-limit message logging */ 70 71void msg_rate_delay(time_t *stamp, int delay, 72 void (*log_fn) (const char *,...), 73 const char *fmt,...) 74{ 75 const char *myname = "msg_rate_delay"; 76 static time_t saved_event_time; 77 time_t now; 78 VSTRING *buf; 79 va_list ap; 80 81 /* 82 * Sanity check. 83 */ 84 if (delay < 0) 85 msg_panic("%s: bad message rate delay: %d", myname, delay); 86 87 /* 88 * This function may be called frequently. Avoid an unnecessary syscall 89 * if possible. Deal with the possibility that a program does not use the 90 * events(3) engine, so that event_time() always produces the same 91 * result. 92 */ 93 if (msg_verbose == 0 && delay > 0) { 94 if (saved_event_time == 0) 95 now = saved_event_time = event_time(); 96 else if ((now = event_time()) == saved_event_time) 97 now = time((time_t *) 0); 98 99 /* 100 * Don't log if time is too early. 101 */ 102 if (*stamp + delay > now) 103 return; 104 *stamp = now; 105 } 106 107 /* 108 * OK to log. This is a low-rate event, so we can afford some overhead. 109 */ 110 buf = vstring_alloc(100); 111 va_start(ap, fmt); 112 vstring_vsprintf(buf, fmt, ap); 113 va_end(ap); 114 log_fn("%s", STR(buf)); 115 vstring_free(buf); 116} 117 118#ifdef TEST 119 120 /* 121 * Proof-of-concept test program: log messages but skip messages during a 122 * two-second gap. 123 */ 124#include <unistd.h> 125 126int main(int argc, char **argv) 127{ 128 int n; 129 time_t stamp = 0; 130 131 for (n = 0; n < 6; n++) { 132 msg_rate_delay(&stamp, 2, msg_info, "text here %d", n); 133 sleep(1); 134 } 135 return (0); 136} 137 138#endif 139