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