You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

maps_stats.lua 3.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. --[[
  2. Copyright (c) 2022, Vsevolod Stakhov <vsevolod@rspamd.com>
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ]]--
  13. if confighelp then
  14. rspamd_config:add_example(nil, 'maps_stats',
  15. "Stores maps statistics in Redis", [[
  16. maps_stats {
  17. # one iteration step per 2 minutes
  18. interval = 2m;
  19. # how many elements to store in Redis
  20. count = 1k;
  21. # common prefix for elements
  22. prefix = 'rm_';
  23. }
  24. ]])
  25. end
  26. local redis_params
  27. local lua_util = require "lua_util"
  28. local rspamd_logger = require "rspamd_logger"
  29. local lua_redis = require "lua_redis"
  30. local N = "maps_stats"
  31. local settings = {
  32. interval = 120, -- one iteration step per 2 minutes
  33. count = 1000, -- how many elements to store in Redis
  34. prefix = 'rm_', -- common prefix for elements
  35. }
  36. local function process_map(map, ev_base, _)
  37. if map:get_nelts() > 0 and map:get_uri() ~= 'static' then
  38. local key = settings.prefix .. map:get_uri()
  39. local function redis_zrange_cb(err, data)
  40. if err then
  41. rspamd_logger.errx(rspamd_config, 'cannot delete extra elements in %s: %s',
  42. key, err)
  43. elseif data then
  44. rspamd_logger.infox(rspamd_config, 'cleared %s elements from %s',
  45. data, key)
  46. end
  47. end
  48. local function redis_card_cb(err, data)
  49. if err then
  50. rspamd_logger.errx(rspamd_config, 'cannot get number of elements in %s: %s',
  51. key, err)
  52. elseif data then
  53. if settings.count > 0 and tonumber(data) > settings.count then
  54. lua_redis.rspamd_redis_make_request_taskless(ev_base,
  55. rspamd_config,
  56. redis_params, -- connect params
  57. key, -- hash key
  58. true, -- is write
  59. redis_zrange_cb, --callback
  60. 'ZREMRANGEBYRANK', -- command
  61. {key, '0', tostring(-(settings.count) - 1)} -- arguments
  62. )
  63. end
  64. end
  65. end
  66. local ret, conn, _ = lua_redis.rspamd_redis_make_request_taskless(ev_base,
  67. rspamd_config,
  68. redis_params, -- connect params
  69. key, -- hash key
  70. true, -- is write
  71. redis_card_cb, --callback
  72. 'ZCARD', -- command
  73. {key} -- arguments
  74. )
  75. if ret and conn then
  76. local stats = map:get_stats(true)
  77. for k,s in pairs(stats) do
  78. if s > 0 then
  79. conn:add_cmd('ZINCRBY', {key, tostring(s), k})
  80. end
  81. end
  82. end
  83. end
  84. end
  85. if not lua_util.check_experimental(N) then
  86. return
  87. end
  88. local opts = rspamd_config:get_all_opt(N)
  89. if opts then
  90. for k,v in pairs(opts) do
  91. settings[k] = v
  92. end
  93. end
  94. redis_params = lua_redis.parse_redis_server(N, opts)
  95. -- XXX, this is a poor approach as not all maps are defined here...
  96. local tmaps = rspamd_config:get_maps()
  97. for _,m in ipairs(tmaps) do
  98. if m:get_uri() ~= 'static' then
  99. lua_redis.register_prefix(settings.prefix .. m:get_uri(), N,
  100. 'Maps stats data', {
  101. type = 'zlist',
  102. persistent = true,
  103. })
  104. end
  105. end
  106. if redis_params then
  107. rspamd_config:add_on_load(function (_, ev_base, worker)
  108. local maps = rspamd_config:get_maps()
  109. for _,m in ipairs(maps) do
  110. rspamd_config:add_periodic(ev_base,
  111. settings['interval'],
  112. function ()
  113. process_map(m, ev_base, worker)
  114. return true
  115. end, true)
  116. end
  117. end)
  118. end