master
c 101 lines 3.69 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "nd_log_limit.h"
4
5 void nd_log_limits_reset(void) {
6 usec_t now_ut = now_monotonic_usec();
7
8 for(size_t i = 0; i < _NDLS_MAX ;i++) {
9 spinlock_lock(&nd_log.sources[i].limits.spinlock);
10 nd_log.sources[i].limits.prevented = 0;
11 nd_log.sources[i].limits.counter = 0;
12 nd_log.sources[i].limits.started_monotonic_ut = now_ut;
13 nd_log.sources[i].limits.logs_per_period = nd_log.sources[i].limits.logs_per_period_backup;
14 spinlock_unlock(&nd_log.sources[i].limits.spinlock);
15 }
16 }
17
18 void nd_log_limits_unlimited(void) {
19 nd_log_limits_reset();
20 for(size_t i = 0; i < _NDLS_MAX ;i++) {
21 spinlock_lock(&nd_log.sources[i].limits.spinlock);
22 nd_log.sources[i].limits.logs_per_period = 0;
23 spinlock_unlock(&nd_log.sources[i].limits.spinlock);
24 }
25 }
26
27 bool nd_log_limit_reached(struct nd_log_source *source) {
28 if(source->limits.throttle_period == 0 || source->limits.logs_per_period == 0)
29 return false;
30
31 spinlock_lock(&source->limits.spinlock);
32
33 usec_t now_ut = now_monotonic_usec();
34 if(!source->limits.started_monotonic_ut)
35 source->limits.started_monotonic_ut = now_ut;
36
37 source->limits.counter++;
38
39 // Check if we need to reset the period
40 if(now_ut - source->limits.started_monotonic_ut > (usec_t)source->limits.throttle_period * USEC_PER_SEC) {
41 if(source->limits.prevented) {
42 BUFFER *wb = buffer_create(1024, NULL);
43 buffer_sprintf(wb,
44 "LOG FLOOD PROTECTION: resuming logging "
45 "(prevented %"PRIu32" logs in the last %"PRIu32" seconds).",
46 source->limits.prevented,
47 source->limits.throttle_period);
48
49 if(source->pending_msg)
50 freez((void *)source->pending_msg);
51
52 source->pending_msg = strdupz(buffer_tostring(wb));
53 source->pending_msgid = &log_flood_protection_msgid;
54 buffer_free(wb);
55 }
56
57 // restart the period accounting
58 source->limits.started_monotonic_ut = now_ut;
59 source->limits.counter = 1;
60 source->limits.prevented = 0;
61
62 spinlock_unlock(&source->limits.spinlock);
63 return false;
64 }
65
66 if(source->limits.counter > source->limits.logs_per_period) {
67 if(!source->limits.prevented) {
68 BUFFER *wb = buffer_create(1024, NULL);
69 buffer_sprintf(wb,
70 "LOG FLOOD PROTECTION: too many logs (%"PRIu32" logs in %"PRId64" seconds, threshold is set to %"PRIu32" logs "
71 "in %"PRIu32" seconds). Preventing more logs from process '%s' for %"PRId64" seconds.",
72 source->limits.counter,
73 (int64_t)((now_ut - source->limits.started_monotonic_ut) / USEC_PER_SEC),
74 source->limits.logs_per_period,
75 source->limits.throttle_period,
76 program_name,
77 (int64_t)(((source->limits.started_monotonic_ut + (source->limits.throttle_period * USEC_PER_SEC) - now_ut)) / USEC_PER_SEC)
78 );
79
80 if(source->pending_msg)
81 freez((void *)source->pending_msg);
82
83 source->pending_msg = strdupz(buffer_tostring(wb));
84 source->pending_msgid = &log_flood_protection_msgid;
85 buffer_free(wb);
86 }
87
88 source->limits.prevented++;
89 spinlock_unlock(&source->limits.spinlock);
90
91 // prevent logging this error
92 #ifdef NETDATA_INTERNAL_CHECKS
93 return false;
94 #else
95 return true;
96 #endif
97 }
98
99 spinlock_unlock(&source->limits.spinlock);
100 return false;
101 }