Skip to content

Commit 2bc2f82

Browse files
edsiperxmcqueen
authored andcommitted
filter_lua: new 'time_as_table' property for timestamp handling (fluent#641 fluent#2519 fluent#2015)
Long time ago we got some reports that using timestamps as double/floats might lost precision when the values are converted back from Lua. Actually there is no exact way to have 100% precision in doubles in our use case 'C > Lua > C'. Community suggested that we might workaround this with another solution. This patch considering backward compatibility, implements a new configuration property called 'time_as_table', which passes the timestamp as a Lua table with the following keys ['sec'] => timestamp seconds ['nsec'] => timestamp nanoseconds for users looking for 100% timestamp precision and specifically when dealing with nanoseconds, this option ensures timestamp integrity. If the option is enabled the user just need to adjust the script to use the new format if they touch or use the timestamp value. By default the option 'time_as_table' is disabled and in the future we might consider to enable it by default. Signed-off-by: Eduardo Silva <eduardo@treasure-data.com> Signed-off-by: xmcqueen <bmcqueen@linkedin.com>
1 parent 75c1817 commit 2bc2f82

File tree

3 files changed

+55
-5
lines changed

3 files changed

+55
-5
lines changed

plugins/filter_lua/lua.c

+48-5
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,22 @@
3131

3232
#include "lua_config.h"
3333

34+
/* Push timestamp as a Lua table into the stack */
35+
static void lua_pushtimetable(lua_State *l, struct flb_time *tm)
36+
{
37+
lua_createtable(l, 0, 2);
38+
39+
/* seconds */
40+
lua_pushlstring(l, "sec", 3);
41+
lua_pushinteger(l, tm->tm.tv_sec);
42+
lua_settable(l, -3);
43+
44+
/* nanoseconds */
45+
lua_pushlstring(l, "nsec", 4);
46+
lua_pushinteger(l, tm->tm.tv_nsec);
47+
lua_settable(l, -3);
48+
}
49+
3450
static void lua_pushmsgpack(lua_State *l, msgpack_object *o)
3551
{
3652
int i;
@@ -439,8 +455,13 @@ static int cb_lua_filter(const void *data, size_t bytes,
439455
lua_pushstring(ctx->lua->state, tag);
440456

441457
/* Timestamp */
442-
ts = flb_time_to_double(&t);
443-
lua_pushnumber(ctx->lua->state, ts);
458+
if (ctx->time_as_table == FLB_TRUE) {
459+
lua_pushtimetable(ctx->lua->state, &t);
460+
}
461+
else {
462+
ts = flb_time_to_double(&t);
463+
lua_pushnumber(ctx->lua->state, ts);
464+
}
444465

445466
lua_pushmsgpack(ctx->lua->state, p);
446467
if (ctx->protected_mode) {
@@ -466,8 +487,28 @@ static int cb_lua_filter(const void *data, size_t bytes,
466487
lua_tomsgpack(ctx, &data_pck, 0);
467488
lua_pop(ctx->lua->state, 1);
468489

469-
l_timestamp = (double) lua_tonumber(ctx->lua->state, -1);
470-
lua_pop(ctx->lua->state, 1);
490+
/* Lua table */
491+
if (ctx->time_as_table == FLB_TRUE) {
492+
if (lua_type(ctx->lua->state, -1) == LUA_TTABLE) {
493+
/* Retrieve seconds */
494+
lua_getfield(ctx->lua->state, -1, "sec");
495+
t.tm.tv_sec = lua_tointeger(ctx->lua->state, -1);
496+
lua_pop(ctx->lua->state, 1);
497+
498+
/* Retrieve nanoseconds */
499+
lua_getfield(ctx->lua->state, -1, "nsec");
500+
t.tm.tv_nsec = lua_tointeger(ctx->lua->state, -1);
501+
lua_pop(ctx->lua->state, 2);
502+
}
503+
else {
504+
flb_plg_error(ctx->ins, "invalid lua timestamp type returned");
505+
t = t_orig;
506+
}
507+
}
508+
else {
509+
l_timestamp = (double) lua_tonumber(ctx->lua->state, -1);
510+
lua_pop(ctx->lua->state, 1);
511+
}
471512

472513
l_code = (int) lua_tointeger(ctx->lua->state, -1);
473514
lua_pop(ctx->lua->state, 1);
@@ -481,7 +522,9 @@ static int cb_lua_filter(const void *data, size_t bytes,
481522
}
482523
else if (l_code == 1 || l_code == 2) { /* Modified, pack new data */
483524
if (l_code == 1) {
484-
flb_time_from_double(&t, l_timestamp);
525+
if (ctx->time_as_table == FLB_FALSE) {
526+
flb_time_from_double(&t, l_timestamp);
527+
}
485528
}
486529
else if (l_code == 2) {
487530
/* Keep the timestamp */

plugins/filter_lua/lua_config.c

+6
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,12 @@ struct lua_filter *lua_config_create(struct flb_filter_instance *ins,
146146
lf->protected_mode = flb_utils_bool(tmp);
147147
}
148148

149+
lf->time_as_table = FLB_FALSE;
150+
tmp = flb_filter_get_property("time_as_table", ins);
151+
if (tmp) {
152+
lf->time_as_table = flb_utils_bool(tmp);
153+
}
154+
149155
return lf;
150156
}
151157

plugins/filter_lua/lua_config.h

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ struct lua_filter {
4040
flb_sds_t buffer; /* json dec buffer */
4141
int l2c_types_num; /* number of l2c_types */
4242
int protected_mode; /* exec lua function in protected mode */
43+
int time_as_table; /* timestamp as a Lua table */
4344
struct mk_list l2c_types; /* data types (lua -> C) */
4445
struct flb_luajit *lua; /* state context */
4546
struct flb_filter_instance *ins; /* filter instance */

0 commit comments

Comments
 (0)