Mercurial > dovecot > core-2.2
changeset 20582:3e02c55136a6
lib: Added log throttling API.
author | Timo Sirainen <timo.sirainen@dovecot.fi> |
---|---|
date | Tue, 02 Aug 2016 23:14:23 +0300 |
parents | e8a810c9c96c |
children | c4cc24c77ad8 |
files | src/lib/Makefile.am src/lib/log-throttle.c src/lib/log-throttle.h src/lib/test-lib.c src/lib/test-lib.h src/lib/test-log-throttle.c |
diffstat | 6 files changed, 172 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib/Makefile.am Thu Aug 04 17:39:02 2016 +0300 +++ b/src/lib/Makefile.am Tue Aug 02 23:14:23 2016 +0300 @@ -91,6 +91,7 @@ json-tree.c \ lib.c \ lib-signals.c \ + log-throttle.c \ md4.c \ md5.c \ mempool.c \ @@ -229,6 +230,7 @@ lib.h \ lib-signals.h \ llist.h \ + log-throttle.h \ macros.h \ md4.h \ md5.h \ @@ -329,6 +331,7 @@ test-json-parser.c \ test-json-tree.c \ test-llist.c \ + test-log-throttle.c \ test-mempool-alloconly.c \ test-pkcs5.c \ test-net.c \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib/log-throttle.c Tue Aug 02 23:14:23 2016 +0300 @@ -0,0 +1,78 @@ +/* Copyright (c) 2016 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "ioloop.h" +#include "time-util.h" +#include "log-throttle.h" + +struct log_throttle { + struct log_throttle_settings set; + log_throttle_callback_t *callback; + void *context; + + struct timeval last_time; + unsigned int last_count; + + struct timeout *to_throttled; +}; + +#undef log_throttle_init +struct log_throttle * +log_throttle_init(const struct log_throttle_settings *set, + log_throttle_callback_t *callback, void *context) +{ + struct log_throttle *throttle; + + i_assert(set->throttle_at_max_per_interval > 0); + i_assert(set->unthrottle_at_max_per_interval > 0); + + throttle = i_new(struct log_throttle, 1); + throttle->set = *set; + if (throttle->set.interval_msecs == 0) + throttle->set.interval_msecs = 1000; + throttle->callback = callback; + throttle->context = context; + return throttle; +} + +void log_throttle_deinit(struct log_throttle **_throttle) +{ + struct log_throttle *throttle = *_throttle; + + *_throttle = NULL; + if (throttle->to_throttled != NULL) + timeout_remove(&throttle->to_throttled); + i_free(throttle); +} + +static void log_throttle_callback(struct log_throttle *throttle) +{ + if (throttle->last_count > 0) + throttle->callback(throttle->last_count, throttle->context); + if (throttle->last_count < throttle->set.unthrottle_at_max_per_interval) + timeout_remove(&throttle->to_throttled); + throttle->last_count = 0; +} + +bool log_throttle_accept(struct log_throttle *throttle) +{ + if (throttle->to_throttled != NULL) { + /* unthrottling and last_count resets are done only by + the callback */ + throttle->last_count++; + return FALSE; + } else if (timeval_diff_msecs(&ioloop_timeval, &throttle->last_time) >= + (int)throttle->set.interval_msecs) { + throttle->last_time = ioloop_timeval; + throttle->last_count = 1; + return TRUE; + } else if (++throttle->last_count <= throttle->set.throttle_at_max_per_interval) { + return TRUE; + } else { + throttle->last_count = 1; + throttle->to_throttled = + timeout_add(throttle->set.interval_msecs, + log_throttle_callback, throttle); + return FALSE; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib/log-throttle.h Tue Aug 02 23:14:23 2016 +0300 @@ -0,0 +1,32 @@ +#ifndef LOG_THROTTLE_H +#define LOG_THROTTLE_H + +struct log_throttle_settings { + /* Start throttling after we reach this many log events/interval. */ + unsigned int throttle_at_max_per_interval; + /* Throttling continues until there's only this many or below + log events/interval. */ + unsigned int unthrottle_at_max_per_interval; + /* Interval unit in milliseconds. The throttled-callback is also called + at this interval. Default (0) is 1000 milliseconds. */ + unsigned int interval_msecs; +}; + +typedef void +log_throttle_callback_t(unsigned int new_events_count, void *context); + +struct log_throttle * +log_throttle_init(const struct log_throttle_settings *set, + log_throttle_callback_t *callback, void *context); +#define log_throttle_init(set, callback, context) \ + log_throttle_init(set + \ + CALLBACK_TYPECHECK(callback, void (*)(unsigned int, typeof(context))), \ + (log_throttle_callback_t *)callback, context) +void log_throttle_deinit(struct log_throttle **throttle); + +/* Increase event count. Returns TRUE if the event should be logged, + FALSE if it's throttled. ioloop_timeval is used to determine the current + time. */ +bool log_throttle_accept(struct log_throttle *throttle); + +#endif
--- a/src/lib/test-lib.c Thu Aug 04 17:39:02 2016 +0300 +++ b/src/lib/test-lib.c Tue Aug 02 23:14:23 2016 +0300 @@ -36,6 +36,7 @@ test_json_parser, test_json_tree, test_llist, + test_log_throttle, test_mempool_alloconly, test_net, test_numpack,
--- a/src/lib/test-lib.h Thu Aug 04 17:39:02 2016 +0300 +++ b/src/lib/test-lib.h Tue Aug 02 23:14:23 2016 +0300 @@ -37,6 +37,7 @@ void test_json_parser(void); void test_json_tree(void); void test_llist(void); +void test_log_throttle(void); void test_mempool_alloconly(void); enum fatal_test_state fatal_mempool(int); void test_pkcs5_pbkdf2(void);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib/test-log-throttle.c Tue Aug 02 23:14:23 2016 +0300 @@ -0,0 +1,57 @@ +/* Copyright (c) 2016 Dovecot authors, see the included COPYING file */ + +#include "test-lib.h" +#include "ioloop.h" +#include "log-throttle.h" + +static unsigned int test_log_throttle_new_events_count; + +static void test_log_throttle_callback(unsigned int new_events_count, + struct ioloop *ioloop) +{ + test_log_throttle_new_events_count = new_events_count; + io_loop_stop(ioloop); +} + +void test_log_throttle(void) +{ + const struct log_throttle_settings set = { + .throttle_at_max_per_interval = 10, + .unthrottle_at_max_per_interval = 5, + .interval_msecs = 10, + }; + struct log_throttle *throttle; + struct ioloop *ioloop; + unsigned int i; + + test_begin("log throttle"); + + ioloop = io_loop_create(); + throttle = log_throttle_init(&set, test_log_throttle_callback, ioloop); + + /* throttle once and drop out just below */ + for (i = 0; i < 10; i++) + test_assert_idx(log_throttle_accept(throttle), i); + for (i = 0; i < 4; i++) + test_assert_idx(!log_throttle_accept(throttle), i); + + io_loop_run(ioloop); + test_assert(test_log_throttle_new_events_count == 4); + + /* throttle and continue just above */ + for (i = 0; i < 10; i++) + test_assert_idx(log_throttle_accept(throttle), i); + for (i = 0; i < 5; i++) + test_assert_idx(!log_throttle_accept(throttle), i); + + io_loop_run(ioloop); + test_assert(test_log_throttle_new_events_count == 5); + + /* we should be still throttled */ + test_assert(!log_throttle_accept(throttle)); + + log_throttle_deinit(&throttle); + io_loop_destroy(&ioloop); + + test_end(); +}