diff options
Diffstat (limited to 'src/plugins/lua/maps_stats.lua')
-rw-r--r-- | src/plugins/lua/maps_stats.lua | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/src/plugins/lua/maps_stats.lua b/src/plugins/lua/maps_stats.lua new file mode 100644 index 0000000..d418810 --- /dev/null +++ b/src/plugins/lua/maps_stats.lua @@ -0,0 +1,133 @@ +--[[ +Copyright (c) 2022, Vsevolod Stakhov <vsevolod@rspamd.com> + +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
\ No newline at end of file |