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
msg_rate_delay(time_t * stamp,int delay,void (* log_fn)(const char *,...),const char * fmt,...)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
main(int argc,char ** argv)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