summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@rambler-co.ru>2009-03-30 17:57:59 +0400
committerVsevolod Stakhov <vsevolod@rambler-co.ru>2009-03-30 17:57:59 +0400
commitdd2fbb7a5b7e1c0d844900147486ad7ffd98c1e4 (patch)
treeab8bfcf6c21bd8a47f49b9f9331378e6454e90cf /src
parentc72912310c575a5ba7e7e50a5fdd425f3a4e4dbc (diff)
downloadrspamd-dd2fbb7a5b7e1c0d844900147486ad7ffd98c1e4.tar.gz
rspamd-dd2fbb7a5b7e1c0d844900147486ad7ffd98c1e4.zip
* Add message handling functions to lua API
* Add ability to add lua code in config with .lua and .endlua * Add consolidation functions support that are written in perl or lua
Diffstat (limited to 'src')
-rw-r--r--src/cfg_file.l10
-rw-r--r--src/cfg_file.y10
-rw-r--r--src/filter.c6
-rw-r--r--src/filter.h4
-rw-r--r--src/lua-rspamd.h5
-rw-r--r--src/lua.c322
-rw-r--r--src/main.c9
-rw-r--r--src/perl.c70
-rw-r--r--src/perl.h9
9 files changed, 406 insertions, 39 deletions
diff --git a/src/cfg_file.l b/src/cfg_file.l
index be1e780f3..3224b4fde 100644
--- a/src/cfg_file.l
+++ b/src/cfg_file.l
@@ -1,5 +1,6 @@
%x incl
%x module
+%x lua
%{
@@ -7,6 +8,11 @@
#include "config.h"
#include "cfg_file.h"
#include "cfg_yacc.h"
+#ifdef WITH_LUA
+#include "lua.h"
+#else
+#define add_luabuf(x) yyerror ("lua support diabled"); YYERROR
+#endif
#define MAX_INCLUDE_DEPTH 10
YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH];
@@ -23,6 +29,7 @@ extern struct config_file *cfg;
[ \t]*#.* /* ignore comments */;
.include BEGIN(incl);
.module BEGIN(module);
+.lua BEGIN(lua);
composites return COMPOSITES;
tempdir return TEMPDIR;
pidfile return PIDFILE;
@@ -150,6 +157,9 @@ yes|YES|no|NO|[yY]|[nN] yylval.flag=parse_flag(yytext); return FLAG;
<module>\$[a-zA-Z_][a-zA-Z0-9_]+ yylval.string=strdup(yytext + 1); return VARIABLE;
<module>\".+[^\\]\" yylval.string=strdup(yytext + 1); yylval.string[strlen(yylval.string) - 1] = '\0'; unescape_quotes(yylval.string); return QUOTEDSTRING;
+<lua>^.endlua$ BEGIN(INITIAL);
+<lua>.* add_luabuf(yytext);
+
%%
/*
* vi:ts=4
diff --git a/src/cfg_file.y b/src/cfg_file.y
index 5cd98e9fc..b62b6b5b4 100644
--- a/src/cfg_file.y
+++ b/src/cfg_file.y
@@ -8,6 +8,11 @@
#include "expressions.h"
#include "classifiers/classifiers.h"
#include "tokenizers/tokenizers.h"
+#ifdef WITH_LUA
+#include "lua-rspamd.h"
+#else
+#include "perl.h"
+#endif
#define YYDEBUG 1
@@ -323,6 +328,11 @@ metricfunction:
cur_metric = memory_pool_alloc0 (cfg->cfg_pool, sizeof (struct metric));
}
cur_metric->func_name = memory_pool_strdup (cfg->cfg_pool, $3);
+#ifdef WITH_LUA
+ cur_metric->func = lua_consolidation_func;
+#else
+ cur_metric->func = perl_consolidation_func;
+#endif
}
;
diff --git a/src/filter.c b/src/filter.c
index a1679d499..d06987b97 100644
--- a/src/filter.c
+++ b/src/filter.c
@@ -123,7 +123,7 @@ consolidation_callback (gpointer key, gpointer value, gpointer arg)
}
double
-factor_consolidation_func (struct worker_task *task, const char *metric_name)
+factor_consolidation_func (struct worker_task *task, const char *metric_name, const char *unused)
{
struct metric_result *metric_res;
double res = 0.;
@@ -220,10 +220,10 @@ metric_process_callback (gpointer key, gpointer value, void *data)
struct metric_result *metric_res = (struct metric_result *)value;
if (metric_res->metric->func != NULL) {
- metric_res->score = metric_res->metric->func (task, metric_res->metric->name);
+ metric_res->score = metric_res->metric->func (task, metric_res->metric->name, metric_res->metric->func_name);
}
else {
- metric_res->score = factor_consolidation_func (task, metric_res->metric->name);
+ metric_res->score = factor_consolidation_func (task, metric_res->metric->name, NULL);
}
msg_debug ("process_metric_callback: got result %.2f from consolidation function for metric %s",
metric_res->score, metric_res->metric->name);
diff --git a/src/filter.h b/src/filter.h
index 02fc60c63..4e51bf2a7 100644
--- a/src/filter.h
+++ b/src/filter.h
@@ -10,7 +10,7 @@
struct worker_task;
-typedef double (*metric_cons_func)(struct worker_task *task, const char *metric_name);
+typedef double (*metric_cons_func)(struct worker_task *task, const char *metric_name, const char *func_name);
typedef void (*filter_func)(struct worker_task *task);
enum filter_type { C_FILTER, PERL_FILTER };
@@ -88,6 +88,6 @@ void make_composites (struct worker_task *task);
* @param metric_name name of metric
* @return result metric weight
*/
-double factor_consolidation_func (struct worker_task *task, const char *metric_name);
+double factor_consolidation_func (struct worker_task *task, const char *metric_name, const char *unused);
#endif
diff --git a/src/lua-rspamd.h b/src/lua-rspamd.h
index a99a121a3..0d0b2a693 100644
--- a/src/lua-rspamd.h
+++ b/src/lua-rspamd.h
@@ -2,9 +2,6 @@
#define RSPAMD_LUA_H
#include "config.h"
-#include <lua.h>
-#include <lauxlib.h>
-#include <lualib.h>
struct uri;
struct worker_task;
@@ -17,5 +14,7 @@ int lua_call_mime_filter (const char *function, struct worker_task *task);
int lua_call_message_filter (const char *function, struct worker_task *task);
int lua_call_url_filter (const char *function, struct worker_task *task);
int lua_call_chain_filter (const char *function, struct worker_task *task, int *marks, unsigned int number);
+double lua_consolidation_func (struct worker_task *task, const char *metric_name, const char *function_name);
+void add_luabuf (const char *line);
#endif
diff --git a/src/lua.c b/src/lua.c
index 1df52310a..edc64bc91 100644
--- a/src/lua.c
+++ b/src/lua.c
@@ -25,26 +25,122 @@
#include "config.h"
#include "url.h"
#include "main.h"
+#include "message.h"
#include "lua-rspamd.h"
#include "cfg_file.h"
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+
/* Lua module init function */
#define MODULE_INIT_FUNC "module_init"
-lua_State *L = NULL;
+/* Interface definitions */
+#define LUA_FUNCTION_DEF(class, name) static int lua_##class##_##name(lua_State *L)
+#define LUA_INTERFACE_DEF(class, name) { #name, lua_##class##_##name }
+
+#define LUA_GMIME_BRIDGE_GET(class, name, mime_class) \
+static int \
+lua_##class##_##name(lua_State *L) \
+{ \
+ GMime##mime_class *obj = lua_check_##class(L); \
+ if (obj != NULL) { \
+ lua_pushstring (L, g_mime_##class##_##name(obj)); \
+ } \
+ else { \
+ lua_pushnil (L); \
+ } \
+ return 1; \
+}
+
+#define LUA_GMIME_BRIDGE_SET(class, name, mime_class) \
+static int \
+lua_##class##_##name(lua_State *L) \
+{ \
+ const char *str; \
+ GMime##mime_class *obj = lua_check_##class(L); \
+ if (obj != NULL) { \
+ str = luaL_checkstring (L, 2); \
+ g_mime_##class##_##name(obj, str); \
+ } \
+ else { \
+ lua_pushnil (L); \
+ } \
+ return 1; \
+}
-static int lua_task_get_message (lua_State *L);
-static int lua_task_insert_result (lua_State *L);
-static int lua_task_get_urls (lua_State *L);
+lua_State *L = NULL;
/* Task methods */
+LUA_FUNCTION_DEF(task, get_message);
+LUA_FUNCTION_DEF(task, insert_result);
+LUA_FUNCTION_DEF(task, get_urls);
+
static const struct luaL_reg tasklib_m[] = {
- {"get_message", lua_task_get_message},
- {"insert_result", lua_task_insert_result},
- {"get_urls", lua_task_get_urls},
+ LUA_INTERFACE_DEF(task, get_message),
+ LUA_INTERFACE_DEF(task, insert_result),
+ LUA_INTERFACE_DEF(task, get_urls),
{NULL, NULL},
};
+/* Message methods */
+LUA_FUNCTION_DEF(message, get_subject);
+LUA_FUNCTION_DEF(message, set_subject);
+LUA_FUNCTION_DEF(message, get_message_id);
+LUA_FUNCTION_DEF(message, set_message_id);
+LUA_FUNCTION_DEF(message, get_sender);
+LUA_FUNCTION_DEF(message, set_sender);
+LUA_FUNCTION_DEF(message, get_reply_to);
+LUA_FUNCTION_DEF(message, set_reply_to);
+LUA_FUNCTION_DEF(message, get_header);
+LUA_FUNCTION_DEF(message, set_header);
+
+static const struct luaL_reg msglib_m[] = {
+ LUA_INTERFACE_DEF(message, get_subject),
+ LUA_INTERFACE_DEF(message, set_subject),
+ LUA_INTERFACE_DEF(message, get_message_id),
+ LUA_INTERFACE_DEF(message, set_message_id),
+ LUA_INTERFACE_DEF(message, get_sender),
+ LUA_INTERFACE_DEF(message, set_sender),
+ LUA_INTERFACE_DEF(message, get_reply_to),
+ LUA_INTERFACE_DEF(message, set_reply_to),
+ LUA_INTERFACE_DEF(message, get_header),
+ LUA_INTERFACE_DEF(message, set_header),
+ {NULL, NULL}
+};
+
+void
+lua_newclass (lua_State *L, const char *classname, const struct luaL_reg *func)
+{
+ luaL_newmetatable (L, classname); /* mt */
+ /* create __index table to place methods */
+ lua_pushstring (L, "__index"); /* mt,"__index" */
+ lua_newtable (L); /* mt,"__index",it */
+ /* put class name into class metatable */
+ lua_pushstring (L, "class"); /* mt,"__index",it,"class" */
+ lua_pushstring (L, classname); /* mt,"__index",it,"class",classname */
+ lua_rawset (L, -3); /* mt,"__index",it */
+ /* pass all methods that start with _ to the metatable, and all others
+ * to the index table */
+ for (; func->name; func++) { /* mt,"__index",it */
+ lua_pushstring (L, func->name);
+ lua_pushcfunction (L, func->func);
+ lua_rawset (L, func->name[0] == '_' ? -5: -3);
+ }
+ lua_rawset (L, -3); /* mt */
+ lua_pop (L, 1);
+}
+
+void lua_setclass (lua_State *L, const char *classname, int objidx)
+{
+ luaL_getmetatable (L, classname);
+ if (objidx < 0) {
+ objidx--;
+ }
+ lua_setmetatable (L, objidx);
+}
+
static struct worker_task *
lua_check_task (lua_State *L)
{
@@ -53,12 +149,25 @@ lua_check_task (lua_State *L)
return (struct worker_task *)ud;
}
+static GMimeMessage *
+lua_check_message (lua_State *L)
+{
+ void *ud = luaL_checkudata (L, 1, "Rspamd.message");
+ luaL_argcheck (L, ud != NULL, 1, "'message' expected");
+ return (GMimeMessage *)ud;
+}
+/*** Task interface ***/
static int
lua_task_get_message (lua_State *L)
{
+ GMimeMessage **pmsg;
struct worker_task *task = lua_check_task (L);
+
if (task != NULL) {
/* XXX write handler for message object */
+ pmsg = lua_newuserdata (L, sizeof (GMimeMessage *));
+ lua_setclass (L, "Rspamd.message", -1);
+ *pmsg = task->message;
}
return 1;
}
@@ -93,47 +202,135 @@ lua_task_get_urls (lua_State *L)
return 1;
}
+/*** Message interface ***/
+
+LUA_GMIME_BRIDGE_GET(message, get_subject, Message)
+LUA_GMIME_BRIDGE_SET(message, set_subject, Message)
+LUA_GMIME_BRIDGE_GET(message, get_message_id, Message)
+LUA_GMIME_BRIDGE_SET(message, set_message_id, Message)
+LUA_GMIME_BRIDGE_GET(message, get_sender, Message)
+LUA_GMIME_BRIDGE_SET(message, set_sender, Message)
+LUA_GMIME_BRIDGE_GET(message, get_reply_to, Message)
+LUA_GMIME_BRIDGE_SET(message, set_reply_to, Message)
+
+static int
+lua_message_get_header (lua_State *L)
+{
+ const char *headern;
+ GMimeMessage *obj = lua_check_message (L);
+ GList *res = NULL, *cur;
+
+ if (obj != NULL) {
+ headern = luaL_checkstring (L, 2);
+ if (headern) {
+ res = message_get_header (NULL, obj, headern);
+ if (res) {
+ cur = res;
+ while (cur) {
+ lua_pushstring (L, (const char *)cur->data);
+ g_free (cur->data);
+ cur = g_list_next (cur);
+ }
+ g_free (res);
+ }
+ else {
+ lua_pushnil (L);
+ }
+ }
+ else {
+ lua_pushnil (L);
+ }
+ }
+ else {
+ lua_pushnil (L);
+ }
+
+ return 1;
+}
+
+static int
+lua_message_set_header (lua_State *L)
+{
+ const char *headern, *headerv;
+ GMimeMessage *obj = lua_check_message (L);
+
+ if (obj != NULL) {
+ headern = luaL_checkstring (L, 2);
+ headerv = luaL_checkstring (L, 3);
+ if (headern && headerv) {
+ message_set_header (obj, headern, headerv);
+ }
+ else {
+ lua_pushnil (L);
+ }
+ }
+ else {
+ lua_pushnil (L);
+ }
+
+ return 1;
+}
+
+/*** Init functions ***/
static int
luaopen_task (lua_State *L)
{
- luaL_newmetatable(L, "Rspamd.task");
+ lua_newclass (L, "Rspamd.task", tasklib_m);
- lua_pushstring(L, "__index");
- lua_pushvalue(L, -2); /* pushes the metatable */
- lua_settable(L, -3); /* metatable.__index = metatable */
+ luaL_openlib (L, "task", tasklib_m, 0);
- luaL_openlib(L, NULL, tasklib_m, 0);
+ return 1;
+}
+
+static int
+luaopen_message (lua_State *L)
+{
+ lua_newclass (L, "Rspamd.message", msglib_m);
+
+ luaL_openlib (L, "message", msglib_m, 0);
return 1;
}
+static void
+init_lua ()
+{
+ if (L == NULL) {
+ L = lua_open ();
+ luaL_openlibs (L);
+
+ luaopen_task (L);
+ luaopen_message (L);
+ }
+}
+
void
init_lua_filters (struct config_file *cfg)
{
struct perl_module *module;
char *init_func;
size_t funclen;
-
- L = lua_open ();
- luaL_openlibs (L);
+ struct config_file **pcfg;
+ init_lua ();
LIST_FOREACH (module, &cfg->perl_modules, next) {
if (module->path) {
luaL_loadfile (L, module->path);
/* Call module init function */
- funclen = strlen (module->path) + sizeof ("::") + sizeof (MODULE_INIT_FUNC) - 1;
+ funclen = strlen (module->path) + sizeof (":") + sizeof (MODULE_INIT_FUNC) - 1;
init_func = g_malloc (funclen);
- snprintf (init_func, funclen, "%s::%s", module->path, MODULE_INIT_FUNC);
+ snprintf (init_func, funclen, "%s:%s", module->path, MODULE_INIT_FUNC);
lua_getglobal (L, init_func);
- lua_pushlightuserdata (L, cfg);
+ pcfg = lua_newuserdata (L, sizeof (struct config_file *));
+ lua_setclass (L, "Rspamd.config", -1);
+ *pcfg = cfg;
/* do the call (1 arguments, 1 result) */
if (lua_pcall (L, 1, 1, 0) != 0) {
msg_info ("lua_init_filters: call to %s failed", init_func);
}
}
}
- luaopen_task (L);
}
@@ -141,9 +338,12 @@ int
lua_call_header_filter (const char *function, struct worker_task *task)
{
int result;
+ struct worker_task **ptask;
lua_getglobal (L, function);
- lua_pushlightuserdata (L, task);
+ ptask = lua_newuserdata (L, sizeof (struct worker_task *));
+ lua_setclass (L, "Rspamd.task", -1);
+ *ptask = task;
if (lua_pcall (L, 1, 1, 0) != 0) {
msg_info ("lua_init_filters: call to %s failed", function);
@@ -162,9 +362,12 @@ int
lua_call_mime_filter (const char *function, struct worker_task *task)
{
int result;
+ struct worker_task **ptask;
lua_getglobal (L, function);
- lua_pushlightuserdata (L, task);
+ ptask = lua_newuserdata (L, sizeof (struct worker_task *));
+ lua_setclass (L, "Rspamd.task", -1);
+ *ptask = task;
if (lua_pcall (L, 1, 1, 0) != 0) {
msg_info ("lua_init_filters: call to %s failed", function);
@@ -183,9 +386,12 @@ int
lua_call_message_filter (const char *function, struct worker_task *task)
{
int result;
+ struct worker_task **ptask;
lua_getglobal (L, function);
- lua_pushlightuserdata (L, task);
+ ptask = lua_newuserdata (L, sizeof (struct worker_task *));
+ lua_setclass (L, "Rspamd.task", -1);
+ *ptask = task;
if (lua_pcall (L, 1, 1, 0) != 0) {
msg_info ("lua_init_filters: call to %s failed", function);
@@ -204,9 +410,12 @@ int
lua_call_url_filter (const char *function, struct worker_task *task)
{
int result;
+ struct worker_task **ptask;
lua_getglobal (L, function);
- lua_pushlightuserdata (L, task);
+ ptask = lua_newuserdata (L, sizeof (struct worker_task *));
+ lua_setclass (L, "Rspamd.task", -1);
+ *ptask = task;
if (lua_pcall (L, 1, 1, 0) != 0) {
msg_info ("lua_init_filters: call to %s failed", function);
@@ -244,3 +453,70 @@ lua_call_chain_filter (const char *function, struct worker_task *task, int *mark
return result;
}
+/*
+ * LUA custom consolidation function
+ */
+struct consolidation_callback_data {
+ struct worker_task *task;
+ double score;
+ const char *func;
+};
+
+static void
+lua_consolidation_callback (gpointer key, gpointer value, gpointer arg)
+{
+ double res;
+ struct symbol *s = (struct symbol *)value;
+ struct consolidation_callback_data *data = (struct consolidation_callback_data *)arg;
+
+ lua_getglobal (L, data->func);
+
+ lua_pushstring (L, (const char *)key);
+ lua_pushnumber (L, s->score);
+ if (lua_pcall (L, 2, 1, 0) != 0) {
+ msg_info ("lua_consolidation_callback: call to %s failed", data->func);
+ }
+
+ /* retrieve result */
+ if (!lua_isnumber (L, -1)) {
+ msg_info ("lua_consolidation_callback: function %s must return a number", data->func);
+ }
+ res = lua_tonumber (L, -1);
+ lua_pop (L, 1); /* pop returned value */
+ data->score += res;
+}
+
+double
+lua_consolidation_func (struct worker_task *task, const char *metric_name, const char *function_name)
+{
+ struct metric_result *metric_res;
+ double res = 0.;
+ struct consolidation_callback_data data = { task, 0, function_name };
+
+ if (function_name == NULL) {
+ return 0;
+ }
+
+ metric_res = g_hash_table_lookup (task->results, metric_name);
+ if (metric_res == NULL) {
+ return res;
+ }
+
+ g_hash_table_foreach (metric_res->symbols, lua_consolidation_callback, &data);
+
+ return data.score;
+}
+
+void
+add_luabuf (const char *line)
+{
+ int error;
+ init_lua ();
+
+ error = luaL_loadbuffer(L, line, strlen(line), "config") ||
+ lua_pcall(L, 0, 0, 0);
+ if (error) {
+ yyerror ("lua error: %s", lua_tostring(L, -1));
+ lua_pop(L, 1); /* pop error message from the stack */
+ }
+}
diff --git a/src/main.c b/src/main.c
index 7e78fce9a..348e7a1ea 100644
--- a/src/main.c
+++ b/src/main.c
@@ -29,7 +29,16 @@
#include "lmtp.h"
#ifndef WITHOUT_PERL
+
+#include <EXTERN.h> /* from the Perl distribution */
+#include <perl.h> /* from the Perl distribution */
+
+# ifndef PERL_IMPLICIT_CONTEXT
+# undef dTHXa
+# define dTHXa(a)
+# endif
#include "perl.h"
+
#elif defined(WITH_LUA)
#include "lua-rspamd.h"
#endif
diff --git a/src/perl.c b/src/perl.c
index 08a101285..f39ac7df0 100644
--- a/src/perl.c
+++ b/src/perl.c
@@ -28,6 +28,14 @@
#include "perl.h"
#include "cfg_file.h"
+#include <EXTERN.h> /* from the Perl distribution */
+#include <perl.h> /* from the Perl distribution */
+
+#ifndef PERL_IMPLICIT_CONTEXT
+#undef dTHXa
+#define dTHXa(a)
+#endif
+
/* Perl module init function */
#define MODULE_INIT_FUNC "module_init"
@@ -254,7 +262,8 @@ perl_call_chain_filter (const char *function, struct worker_task *task, int *mar
return result;
}
-void perl_call_memcached_callback (memcached_ctx_t *ctx, memc_error_t error, void *data)
+void
+perl_call_memcached_callback (memcached_ctx_t *ctx, memc_error_t error, void *data)
{
struct {
SV *callback;
@@ -287,3 +296,62 @@ void perl_call_memcached_callback (memcached_ctx_t *ctx, memc_error_t error, voi
LEAVE;
}
+
+/*
+ * Perl custom consolidation function
+ */
+struct consolidation_callback_data {
+ struct worker_task *task;
+ double score;
+ const char *func;
+};
+
+static void
+perl_consolidation_callback (gpointer key, gpointer value, gpointer arg)
+{
+ double res;
+ struct symbol *s = (struct symbol *)value;
+ struct consolidation_callback_data *data = (struct consolidation_callback_data *)arg;
+
+ dTHXa (perl_interpreter);
+ PERL_SET_CONTEXT (perl_interpreter);
+
+ dSP;
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK (SP);
+
+ XPUSHs (sv_2mortal (newSVpv ((const char *)key, 0)));
+ XPUSHs (sv_2mortal (newSVnv (s->score)));
+ PUTBACK;
+
+ call_pv (data->func, G_SCALAR);
+
+ SPAGAIN;
+
+ res = POPi;
+
+ data->score += res;
+}
+
+double
+perl_consolidation_func (struct worker_task *task, const char *metric_name, const char *function_name)
+{
+ struct metric_result *metric_res;
+ double res = 0.;
+ struct consolidation_callback_data data = { task, 0, function_name };
+
+ if (function_name == NULL) {
+ return 0;
+ }
+
+ metric_res = g_hash_table_lookup (task->results, metric_name);
+ if (metric_res == NULL) {
+ return res;
+ }
+
+ g_hash_table_foreach (metric_res->symbols, perl_consolidation_callback, &data);
+
+ return data.score;
+}
diff --git a/src/perl.h b/src/perl.h
index af97b6f46..9b1f8af63 100644
--- a/src/perl.h
+++ b/src/perl.h
@@ -5,13 +5,6 @@
#include "config.h"
#include "memcached.h"
-#include <EXTERN.h> /* from the Perl distribution */
-#include <perl.h> /* from the Perl distribution */
-
-#ifndef PERL_IMPLICIT_CONTEXT
-#undef dTHXa
-#define dTHXa(a)
-#endif
struct uri;
struct worker_task;
@@ -27,4 +20,6 @@ int perl_call_chain_filter (const char *function, struct worker_task *task, int
void perl_call_memcached_callback (memcached_ctx_t *ctx, memc_error_t error, void *data);
+double perl_consolidation_func (struct worker_task *task, const char *metric_name, const char *function_name);
+
#endif