3 * Copyright (C) 2010 Julien Ammous
4 * Copyright (C) 2010 Florian Forster
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; only version 2.1 of the License is
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 * Florian Forster <octo at collectd.org>
25 /* <lua5.1/luaconf.h> defines a macro using "sprintf". Although not used here,
26 * GCC will complain about the macro definition. */
27 #define DONT_POISON_SPRINTF_YET
32 #include "configfile.h"
33 #include "utils_cache.h"
35 /* Include the Lua API header files. */
39 #include "utils_lua.h"
41 #if defined(COLLECT_DEBUG) && COLLECT_DEBUG && defined(__GNUC__) && __GNUC__
43 # pragma GCC poison sprintf
46 typedef struct lua_script_s {
50 struct lua_script_s *next;
53 struct clua_read_function_s
56 char *lua_function_name;
59 typedef struct clua_read_function_s clua_read_function_t;
61 struct lua_c_functions_s
66 typedef struct lua_c_functions_s lua_c_functions_t;
68 static char base_path[PATH_MAX + 1] = "";
69 static lua_script_t *scripts = NULL;
71 static int clua_store_callback (lua_State *l, int idx) /* {{{ */
73 static int callback_num = 0;
76 /* XXX FIXME: Not thread-safe! */
77 callback_id = callback_num++;
80 idx += lua_gettop (l) + 1;
82 lua_getfield (l, LUA_REGISTRYINDEX, "collectd_callbacks"); /* +1 = 1 */
83 if (!lua_istable (l, /* idx = */ -1))
85 lua_pop (l, /* nelems = */ 1); /* -1 = 0 */
86 lua_newtable (l); /* +1 = 1 */
87 lua_pushvalue (l, -1); /* +1 = 2 */
88 lua_setfield (l, LUA_REGISTRYINDEX, "collectd_callbacks"); /* -1 = 1 */
91 /* The table is now on top of the stack */
92 lua_pushinteger (l, (lua_Integer) callback_id); /* +1 = 2 */
94 /* Copy the function pointer */
95 lua_pushvalue (l, idx); /* +1 = 3 */
96 /* Lookup function if it's a string */
97 if (lua_isstring (l, /* idx = */ -1))
98 lua_gettable (l, LUA_GLOBALSINDEX); /* +-0 = 3 */
100 if (!lua_isfunction (l, /* idx = */ -1))
102 lua_pop (l, /* nelems = */ 3); /* -3 = 0 */
106 lua_settable (l, /* idx = */ -3); /* -2 = 1 */
107 lua_pop (l, /* nelems = */ 1); /* -1 = 0 */
108 return (callback_id);
109 } /* }}} int clua_store_callback */
111 static int clua_load_callback (lua_State *l, int callback_id) /* {{{ */
113 lua_getfield (l, LUA_REGISTRYINDEX, "collectd_callbacks"); /* +1 */
114 if (!lua_istable (l, /* idx = */ -1))
116 lua_pop (l, /* nelems = */ 1); /* -1 */
120 lua_pushinteger (l, (lua_Integer) callback_id); /* + 1 */
121 lua_gettable (l, /* idx = */ -2); /* +-0 */
123 if (!lua_isfunction (l, -1))
125 lua_pop (l, /* nelems = */ 2); /* -2 */
130 lua_remove (l, /* idx = */ -2); /* -1 */
132 } /* }}} int clua_load_callback */
134 static int clua_read (user_data_t *ud) /* {{{ */
136 clua_read_function_t *rf = ud->data;
139 status = clua_load_callback (rf->lua_state, rf->callback_id);
142 ERROR ("lua plugin: Unable to load callback \"%s\" (id %i).",
143 rf->lua_function_name, rf->callback_id);
148 lua_call (rf->lua_state, /* nargs = */ 0, /* nresults = */ 1); /* +1 */
150 if (lua_isnumber (rf->lua_state, /* idx = */ -1))
152 status = (int) lua_tointeger (rf->lua_state, /* idx = */ -1);
156 ERROR ("lua plugin: Read function \"%s\" (id %i) did not return a numeric status.",
157 rf->lua_function_name, rf->callback_id);
160 /* pop return value and function */
161 lua_settop (rf->lua_state, /* idx = */ -2); /* -2 */
164 } /* }}} int clua_read */
166 /* Cleans up the stack, pushes the return value as a number onto the stack and
167 * returns the number of values returned (1). */
168 #define RETURN_LUA(l,status) do { \
169 lua_State *_l_state = (l); \
170 lua_settop (_l_state, 0); \
171 lua_pushnumber (_l_state, (lua_Number) (status)); \
178 static int lua_cb_log (lua_State *l) /* {{{ */
180 int nargs = lua_gettop (l); /* number of arguments */
186 WARNING ("lua plugin: collectd_log() called with an invalid number of arguments (%i).",
191 if (!lua_isnumber (l, 1))
193 WARNING ("lua plugin: The first argument to collectd_log() must be a number.");
197 if (!lua_isstring (l, 2))
199 WARNING ("lua plugin: The second argument to collectd_log() must be a string.");
203 severity = (int) lua_tonumber (l, /* stack pos = */ 1);
204 if ((severity != LOG_ERR)
205 && (severity != LOG_WARNING)
206 && (severity != LOG_NOTICE)
207 && (severity != LOG_INFO)
208 && (severity != LOG_DEBUG))
211 msg = lua_tostring (l, 2);
214 ERROR ("lua plugin: lua_tostring failed.");
218 plugin_log (severity, "%s", msg);
221 } /* }}} int lua_cb_log */
223 static int lua_cb_dispatch_values (lua_State *l) /* {{{ */
226 int nargs = lua_gettop (l); /* number of arguments */
227 char identifier[6 * DATA_MAX_NAME_LEN];
231 WARNING ("lua plugin: collectd_dispatch_values() called "
232 "with an invalid number of arguments (%i).", nargs);
236 if (!lua_istable (l, 1))
238 WARNING ("lua plugin: The first argument to collectd_dispatch_values() "
239 "must be a \"value list\" (i.e. a table).");
243 vl = luaC_tovaluelist (l, /* idx = */ -1);
246 WARNING ("lua plugin: ltoc_value_list failed.");
250 FORMAT_VL (identifier, sizeof (identifier), vl);
252 DEBUG ("lua plugin: collectd_dispatch_values: Received value list \"%s\", time %.3f, interval %.3f.",
253 identifier, CDTIME_T_TO_DOUBLE (vl->time), CDTIME_T_TO_DOUBLE (vl->interval));
258 } /* }}} lua_cb_dispatch_values */
260 static int lua_cb_register_read (lua_State *l) /* {{{ */
262 int nargs = lua_gettop (l); /* number of arguments */
263 clua_read_function_t *rf;
266 char function_name[DATA_MAX_NAME_LEN] = "";
270 WARNING ("lua plugin: collectd_register_read() called with an invalid "
271 "number of arguments (%i).", nargs);
275 if (lua_isstring (l, /* stack pos = */ 1))
277 const char *tmp = lua_tostring (l, /* idx = */ 1);
278 ssnprintf (function_name, sizeof (function_name), "lua/%s", tmp);
281 callback_id = clua_store_callback (l, /* idx = */ 1);
284 ERROR ("lua plugin: Storing callback function failed.");
288 if (function_name[0] == 0)
289 ssnprintf (function_name, sizeof (function_name), "lua/callback_%i", callback_id);
291 rf = malloc (sizeof (*rf));
294 ERROR ("lua plugin: malloc failed.");
299 user_data_t ud = { rf, /* free func */ NULL /* FIXME */ };
301 memset (rf, 0, sizeof (*rf));
303 rf->callback_id = callback_id;
304 rf->lua_function_name = strdup (function_name);
306 plugin_register_complex_read (/* group = */ "lua",
307 /* name = */ function_name,
308 /* callback = */ clua_read,
309 /* interval = */ NULL,
310 /* user_data = */ &ud);
313 DEBUG ("lua plugin: Successful call to lua_cb_register_read().");
316 } /* }}} int lua_cb_register_read */
318 static lua_c_functions_t lua_c_functions[] =
320 { "collectd_log", lua_cb_log },
321 { "collectd_dispatch_values", lua_cb_dispatch_values },
322 { "collectd_register_read", lua_cb_register_read }
325 static void lua_script_free (lua_script_t *script) /* {{{ */
334 if (script->lua_state != NULL)
336 lua_close (script->lua_state);
337 script->lua_state = NULL;
340 sfree (script->script_path);
343 lua_script_free (next);
344 } /* }}} void lua_script_free */
346 static int lua_script_init (lua_script_t *script) /* {{{ */
350 memset (script, 0, sizeof (*script));
351 script->script_path = NULL;
354 /* initialize the lua context */
355 script->lua_state = lua_open();
356 if (script->lua_state == NULL)
358 ERROR ("lua plugin: lua_open failed.");
362 /* Open up all the standard Lua libraries. */
363 luaL_openlibs (script->lua_state);
365 /* Register all the functions we implement in C */
366 for (i = 0; i < STATIC_ARRAY_SIZE (lua_c_functions); i++)
367 lua_register (script->lua_state,
368 lua_c_functions[i].name, lua_c_functions[i].func);
371 } /* }}} int lua_script_init */
373 static int lua_script_load (const char *script_path) /* {{{ */
375 lua_script_t *script;
378 script = malloc (sizeof (*script));
381 ERROR ("lua plugin: malloc failed.");
385 status = lua_script_init (script);
388 lua_script_free (script);
392 script->script_path = strdup (script_path);
393 if (script->script_path == NULL)
395 ERROR ("lua plugin: strdup failed.");
396 lua_script_free (script);
400 status = luaL_loadfile (script->lua_state, script->script_path);
403 ERROR ("lua plugin: luaL_loadfile failed with status %i", status);
404 lua_script_free (script);
408 status = lua_pcall (script->lua_state,
410 /* nresults = */ LUA_MULTRET,
416 errmsg = lua_tostring (script->lua_state, /* stack pos = */ -1);
419 ERROR ("lua plugin: lua_pcall failed with status %i. "
420 "In addition, no error message could be retrieved from the stack.",
423 ERROR ("lua plugin: Executing script \"%s\" failed:\n%s",
424 script->script_path, errmsg);
426 lua_script_free (script);
430 /* Append this script to the global list of scripts. */
440 while (last->next != NULL)
447 } /* }}} int lua_script_load */
449 static int lua_config_base_path (const oconfig_item_t *ci) /* {{{ */
454 status = cf_util_get_string_buffer (ci, base_path, sizeof (base_path));
458 len = strlen (base_path);
459 while ((len > 0) && (base_path[len - 1] == '/'))
465 DEBUG ("lua plugin: base_path = \"%s\";", base_path);
468 } /* }}} int lua_config_base_path */
470 static int lua_config_script (const oconfig_item_t *ci) /* {{{ */
472 char rel_path[PATH_MAX + 1];
473 char abs_path[PATH_MAX + 1];
476 status = cf_util_get_string_buffer (ci, rel_path, sizeof (rel_path));
480 if (base_path[0] == 0)
481 sstrncpy (abs_path, rel_path, sizeof (abs_path));
483 ssnprintf (abs_path, sizeof (abs_path), "%s/%s", base_path, rel_path);
485 DEBUG ("lua plugin: abs_path = \"%s\";", abs_path);
487 status = lua_script_load (abs_path);
491 INFO("lua plugin: File \"%s\" loaded succesfully", abs_path);
494 } /* }}} int lua_config_script */
499 * Script "script1.lua"
500 * Script "script2.lua"
503 static int lua_config (oconfig_item_t *ci) /* {{{ */
507 for (i = 0; i < ci->children_num; i++)
509 oconfig_item_t *child = ci->children + i;
511 if (strcasecmp ("BasePath", child->key) == 0) {
512 lua_config_base_path(child);
514 else if (strcasecmp ("Script", child->key) == 0){
515 lua_config_script(child);
519 WARNING ("network plugin: Option `%s' is not allowed here.",
525 } /* }}} int lua_config */
527 static int lua_shutdown (void) /* {{{ */
529 lua_script_free (scripts);
533 } /* }}} int lua_shutdown */
535 void module_register()
537 plugin_register_complex_config("lua", lua_config);
538 plugin_register_shutdown("lua", lua_shutdown);
541 /* vim: set sw=2 sts=2 et fdm=marker : */