From 5762a11cec35c2aacba039ee2c2894133b591c55 Mon Sep 17 00:00:00 2001 From: Attila Szakacs Date: Wed, 5 Jun 2024 20:07:51 +0200 Subject: [PATCH 1/4] filterx: add filterx_variable_get_name() Signed-off-by: Attila Szakacs --- lib/filterx/filterx-scope.c | 6 ++++++ lib/filterx/filterx-scope.h | 1 + 2 files changed, 7 insertions(+) diff --git a/lib/filterx/filterx-scope.c b/lib/filterx/filterx-scope.c index 21c5b760e4..a7c47c3fbd 100644 --- a/lib/filterx/filterx-scope.c +++ b/lib/filterx/filterx-scope.c @@ -59,6 +59,12 @@ filterx_variable_get_nv_handle(FilterXVariable *v) return v->handle & ~FILTERX_HANDLE_FLOATING_BIT; } +const gchar * +filterx_variable_get_name(FilterXVariable *v, gssize *len) +{ + return log_msg_get_handle_name(filterx_variable_get_nv_handle(v), len); +} + FilterXObject * filterx_variable_get_value(FilterXVariable *v) { diff --git a/lib/filterx/filterx-scope.h b/lib/filterx/filterx-scope.h index c7edfcda44..211946d4a5 100644 --- a/lib/filterx/filterx-scope.h +++ b/lib/filterx/filterx-scope.h @@ -37,6 +37,7 @@ typedef enum gboolean filterx_variable_is_floating(FilterXVariable *v); gboolean filterx_variable_handle_is_floating(FilterXVariableHandle handle); +const gchar *filterx_variable_get_name(FilterXVariable *v, gssize *len); FilterXObject *filterx_variable_get_value(FilterXVariable *v); void filterx_variable_set_value(FilterXVariable *v, FilterXObject *new_value); void filterx_variable_unset_value(FilterXVariable *v); From f7697421cc586a435978811fda5a74d3444ef5d0 Mon Sep 17 00:00:00 2001 From: Attila Szakacs Date: Wed, 5 Jun 2024 20:08:04 +0200 Subject: [PATCH 2/4] filterx: add filterx_scope_foreach_variable() Signed-off-by: Attila Szakacs --- lib/filterx/filterx-scope.c | 18 ++++++++++++++++++ lib/filterx/filterx-scope.h | 3 +++ 2 files changed, 21 insertions(+) diff --git a/lib/filterx/filterx-scope.c b/lib/filterx/filterx-scope.c index a7c47c3fbd..597349237d 100644 --- a/lib/filterx/filterx-scope.c +++ b/lib/filterx/filterx-scope.c @@ -239,6 +239,24 @@ filterx_scope_register_declared_variable(FilterXScope *self, return v; } +gboolean +filterx_scope_foreach_variable(FilterXScope *self, FilterXScopeForeachFunc func, gpointer user_data) +{ + for (gsize i = 0; i < self->variables->len; i++) + { + FilterXVariable *variable = &g_array_index(self->variables, FilterXVariable, i); + + if (filterx_variable_handle_is_floating(variable->handle) && + !variable->declared && variable->generation != self->generation) + continue; + + if (!func(variable, user_data)) + return FALSE; + } + + return TRUE; +} + /* * 1) sync objects to message * 2) drop undeclared objects diff --git a/lib/filterx/filterx-scope.h b/lib/filterx/filterx-scope.h index 211946d4a5..fcf346d62d 100644 --- a/lib/filterx/filterx-scope.h +++ b/lib/filterx/filterx-scope.h @@ -56,6 +56,8 @@ gboolean filterx_variable_is_set(FilterXVariable *v); */ typedef struct _FilterXScope FilterXScope; +typedef gboolean (*FilterXScopeForeachFunc)(FilterXVariable *variable, gpointer user_data); + void filterx_scope_set_dirty(FilterXScope *self); gboolean filterx_scope_is_dirty(FilterXScope *self); void filterx_scope_sync(FilterXScope *self, LogMessage *msg); @@ -68,6 +70,7 @@ FilterXVariable *filterx_scope_register_variable(FilterXScope *self, FilterXVariable *filterx_scope_register_declared_variable(FilterXScope *self, FilterXVariableHandle handle, FilterXObject *initial_value); +gboolean filterx_scope_foreach_variable(FilterXScope *self, FilterXScopeForeachFunc func, gpointer user_data); /* copy on write */ void filterx_scope_write_protect(FilterXScope *self); From 23f39497baae10403e253cb9d1b8ebb57bda329f Mon Sep 17 00:00:00 2001 From: Attila Szakacs Date: Wed, 5 Jun 2024 20:09:09 +0200 Subject: [PATCH 3/4] filterx: add vars() function This function gathers all filterx variables to a json object. Similar to the python vars() function without arguments. https://docs.python.org/3/library/functions.html#vars Signed-off-by: Attila Szakacs --- lib/filterx/CMakeLists.txt | 2 ++ lib/filterx/Makefile.am | 2 ++ lib/filterx/filterx-globals.c | 2 ++ lib/filterx/func-vars.c | 66 +++++++++++++++++++++++++++++++++++ lib/filterx/func-vars.h | 31 ++++++++++++++++ 5 files changed, 103 insertions(+) create mode 100644 lib/filterx/func-vars.c create mode 100644 lib/filterx/func-vars.h diff --git a/lib/filterx/CMakeLists.txt b/lib/filterx/CMakeLists.txt index 92d112c69a..e28abdeb80 100644 --- a/lib/filterx/CMakeLists.txt +++ b/lib/filterx/CMakeLists.txt @@ -38,6 +38,7 @@ set(FILTERX_HEADERS filterx/filterx-private.h filterx/func-istype.h filterx/func-len.h + filterx/func-vars.h filterx/expr-plus.h PARENT_SCOPE ) @@ -82,6 +83,7 @@ set(FILTERX_SOURCES filterx/expr-regexp.c filterx/func-istype.c filterx/func-len.c + filterx/func-vars.c filterx/expr-plus.c filterx/filterx-private.c PARENT_SCOPE diff --git a/lib/filterx/Makefile.am b/lib/filterx/Makefile.am index 69b2172795..62acf92637 100644 --- a/lib/filterx/Makefile.am +++ b/lib/filterx/Makefile.am @@ -40,6 +40,7 @@ filterxinclude_HEADERS = \ lib/filterx/expr-regexp.h \ lib/filterx/func-istype.h \ lib/filterx/func-len.h \ + lib/filterx/func-vars.h \ lib/filterx/filterx-private.h @@ -84,6 +85,7 @@ filterx_sources = \ lib/filterx/expr-regexp.c \ lib/filterx/func-istype.c \ lib/filterx/func-len.c \ + lib/filterx/func-vars.c \ lib/filterx/filterx-private.c \ lib/filterx/filterx-grammar.y diff --git a/lib/filterx/filterx-globals.c b/lib/filterx/filterx-globals.c index a9837b4bbe..4db93b4bb2 100644 --- a/lib/filterx/filterx-globals.c +++ b/lib/filterx/filterx-globals.c @@ -32,6 +32,7 @@ #include "filterx/object-dict-interface.h" #include "filterx/func-istype.h" #include "filterx/func-len.h" +#include "filterx/func-vars.h" static GHashTable *filterx_builtin_simple_functions = NULL; static GHashTable *filterx_builtin_function_ctors = NULL; @@ -81,6 +82,7 @@ _simple_init(void) g_assert(filterx_builtin_simple_function_register("int", filterx_typecast_integer)); g_assert(filterx_builtin_simple_function_register("double", filterx_typecast_double)); g_assert(filterx_builtin_simple_function_register("len", filterx_simple_function_len)); + g_assert(filterx_builtin_simple_function_register("vars", filterx_simple_function_vars)); } diff --git a/lib/filterx/func-vars.c b/lib/filterx/func-vars.c new file mode 100644 index 0000000000..f4e1fe11af --- /dev/null +++ b/lib/filterx/func-vars.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2024 Attila Szakacs + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As an additional exemption you are allowed to compile & link against the + * OpenSSL libraries as published by the OpenSSL project. See the file + * COPYING for details. + * + */ + +#include "func-vars.h" +#include "filterx-eval.h" +#include "object-json.h" +#include "object-string.h" + +static gboolean +_add_to_dict(FilterXVariable *variable, gpointer user_data) +{ + FilterXObject *vars = (FilterXObject *) user_data; + + gssize name_len; + const gchar *name_str = filterx_variable_get_name(variable, &name_len); + FilterXObject *name = filterx_string_new(name_str, name_len); + + FilterXObject *value = filterx_variable_get_value(variable); + FilterXObject *cloned_value = filterx_object_clone(value); + filterx_object_unref(value); + + gboolean success = filterx_object_set_subscript(vars, name, &cloned_value); + + filterx_object_unref(cloned_value); + filterx_object_unref(name); + return success; +} + +FilterXObject * +filterx_simple_function_vars(GPtrArray *args) +{ + if (args && args->len != 0) + { + msg_error("filterx: vars() function does not take any arguments"); + return NULL; + } + + FilterXEvalContext *context = filterx_eval_get_context(); + FilterXObject *vars = filterx_json_object_new_empty(); + + if (filterx_scope_foreach_variable(context->scope, _add_to_dict, vars)) + return vars; + + filterx_object_unref(vars); + return NULL; +} diff --git a/lib/filterx/func-vars.h b/lib/filterx/func-vars.h new file mode 100644 index 0000000000..000a947249 --- /dev/null +++ b/lib/filterx/func-vars.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2024 Attila Szakacs + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As an additional exemption you are allowed to compile & link against the + * OpenSSL libraries as published by the OpenSSL project. See the file + * COPYING for details. + * + */ + +#ifndef FILTERX_FUNC_VARS_H_INCLUDED +#define FILTERX_FUNC_VARS_H_INCLUDED + +#include "filterx/expr-function.h" + +FilterXObject *filterx_simple_function_vars(GPtrArray *args); + +#endif From 2be477b7440614fd747025ba3e216db544a34ae5 Mon Sep 17 00:00:00 2001 From: Attila Szakacs Date: Wed, 5 Jun 2024 20:18:08 +0200 Subject: [PATCH 4/4] filterx: add E2E test for vars() Signed-off-by: Attila Szakacs --- .../functional_tests/filterx/test_filterx.py | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/tests/light/functional_tests/filterx/test_filterx.py b/tests/light/functional_tests/filterx/test_filterx.py index 79d458f99a..bcbe857320 100644 --- a/tests/light/functional_tests/filterx/test_filterx.py +++ b/tests/light/functional_tests/filterx/test_filterx.py @@ -27,7 +27,7 @@ from src.syslog_ng_config.renderer import render_statement -def create_config(config, filterx_expr, msg="foobar"): +def create_config(config, filterx_expr_1, filterx_expr_2=None, msg="foobar"): file_true = config.create_file_destination(file_name="dest-true.log", template="'$MSG\n'") file_false = config.create_file_destination(file_name="dest-false.log", template="'$MSG\n'") @@ -68,7 +68,8 @@ def create_config(config, filterx_expr, msg="foobar"): log {{ source(genmsg); if {{ - filterx {{ {filterx_expr} \n}}; + filterx {{ {filterx_expr_1} \n}}; + {"filterx { " + filterx_expr_2 + " };" if filterx_expr_2 is not None else ""} destination(dest_true); }} else {{ destination(dest_false); @@ -1487,3 +1488,24 @@ def test_parse_csv_dialect(config, syslog_ng): assert file_true.get_stats()["processed"] == 1 assert "processed" not in file_false.get_stats() assert file_true.read_log() == '["PTHREAD \\"support initialized"]\n' + + +def test_vars(config, syslog_ng): + (file_true, file_false) = create_config( + config, + filterx_expr_1=r""" + $logmsg_variable = "foo"; + scope_local_variable = "bar"; + declare pipeline_level_variable = "baz"; + """, + filterx_expr_2=r""" + log = otel_logrecord({"body": "foobar", "attributes": {"attribute": 42}}); + js_array = json_array([1, 2, 3, [4, 5, 6]]); + $MSG = vars(); + """, + ) + syslog_ng.start(config) + + assert file_true.get_stats()["processed"] == 1 + assert "processed" not in file_false.get_stats() + assert file_true.read_log() == '{"logmsg_variable":"foo","pipeline_level_variable":"baz","log":{"body":"foobar","attributes":{"attribute":42}},"js_array":[1,2,3,[4,5,6]]}\n'