summaryrefslogtreecommitdiffstats
path: root/src/util/msg_rate_delay.c
blob: e21b0214a8e857d6216e1c90144f770901ebf5b6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/*++
/* NAME
/*	msg_rate_delay 3
/* SUMMARY
/*	diagnostic interface
/* SYNOPSIS
/*	#include <msg.h>
/*
/*	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 <sys_defs.h>
#include <time.h>

/* Utility library. */

#include <msg.h>
#include <vstring.h>
#include <events.h>

/* 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 <unistd.h>

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