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
|
--[[
Copyright (c) 2011-2015, Vsevolod Stakhov <vsevolod@highsecure.ru>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
]]--
if confighelp then
rspamd_config:add_example(nil, 'maps_stats',
"Stores maps statistics in Redis", [[
maps_stats {
# one iteration step per 2 minutes
interval = 2m;
# how many elements to store in Redis
count = 1k;
# common prefix for elements
prefix = 'rm_';
}
]])
end
local redis_params
local lua_util = require "lua_util"
local rspamd_logger = require "rspamd_logger"
local lua_redis = require "lua_redis"
local N = "maps_stats"
local settings = {
interval = 120, -- one iteration step per 2 minutes
count = 1000, -- how many elements to store in Redis
prefix = 'rm_', -- common prefix for elements
}
local function process_map(map, ev_base, _)
if map:get_nelts() > 0 and map:get_uri() ~= 'static' then
local key = settings.prefix .. map:get_uri()
local function redis_zrange_cb(err, data)
if err then
rspamd_logger.errx(rspamd_config, 'cannot delete extra elements in %s: %s',
key, err)
elseif data then
rspamd_logger.infox(rspamd_config, 'cleared %s elements from %s',
data, key)
end
end
local function redis_card_cb(err, data)
if err then
rspamd_logger.errx(rspamd_config, 'cannot get number of elements in %s: %s',
key, err)
elseif data then
if settings.count > 0 and tonumber(data) > settings.count then
lua_redis.rspamd_redis_make_request_taskless(ev_base,
rspamd_config,
redis_params, -- connect params
key, -- hash key
true, -- is write
redis_zrange_cb, --callback
'ZREMRANGEBYRANK', -- command
{key, '0', tostring(-(settings.count) - 1)} -- arguments
)
end
end
end
local ret, conn, _ = lua_redis.rspamd_redis_make_request_taskless(ev_base,
rspamd_config,
redis_params, -- connect params
key, -- hash key
true, -- is write
redis_card_cb, --callback
'ZCARD', -- command
{key} -- arguments
)
if ret and conn then
local stats = map:get_stats(true)
for k,s in pairs(stats) do
if s > 0 then
conn:add_cmd('ZINCRBY', {key, tostring(s), k})
end
end
end
end
end
if not lua_util.check_experimental(N) then
return
end
local opts = rspamd_config:get_all_opt(N)
if opts then
for k,v in pairs(opts) do
settings[k] = v
end
end
redis_params = lua_redis.parse_redis_server(N, opts)
-- XXX, this is a poor approach as not all maps are defined here...
local tmaps = rspamd_config:get_maps()
for _,m in ipairs(tmaps) do
if m:get_uri() ~= 'static' then
lua_redis.register_prefix(settings.prefix .. m:get_uri(), N,
'Maps stats data', {
type = 'zlist',
persistent = true,
})
end
end
if redis_params then
rspamd_config:add_on_load(function (_, ev_base, worker)
local maps = rspamd_config:get_maps()
for _,m in ipairs(maps) do
rspamd_config:add_periodic(ev_base,
settings['interval'],
function ()
process_map(m, ev_base, worker)
return true
end, true)
end
end)
end
|