diff --git a/lib/filterx/expr-variable.c b/lib/filterx/expr-variable.c index 2eede2f4e..c38539c19 100644 --- a/lib/filterx/expr-variable.c +++ b/lib/filterx/expr-variable.c @@ -104,7 +104,7 @@ _update_repr(FilterXExpr *s, FilterXObject *new_repr) FilterXVariable *variable = filterx_scope_lookup_variable(scope, self->handle); g_assert(variable != NULL); - filterx_variable_set_value(variable, new_repr); + filterx_variable_set_value(variable, new_repr, FALSE); } static gboolean @@ -130,7 +130,7 @@ _assign(FilterXExpr *s, FilterXObject *new_value) /* this only clones mutable objects */ new_value = filterx_object_clone(new_value); - filterx_variable_set_value(variable, new_value); + filterx_variable_set_value(variable, new_value, TRUE); filterx_object_unref(new_value); return TRUE; } diff --git a/lib/filterx/filterx-scope.c b/lib/filterx/filterx-scope.c index d742ae199..95c3658c1 100644 --- a/lib/filterx/filterx-scope.c +++ b/lib/filterx/filterx-scope.c @@ -130,9 +130,7 @@ _register_variable(FilterXScope *self, * it was a new value */ filterx_variable_set_generation(v_slot, self->generation); - filterx_variable_set_value(v_slot, initial_value); - /* consider this to be unset just as an initial registration is */ - filterx_variable_unassign(v_slot); + filterx_variable_set_value(v_slot, initial_value, FALSE); } return v_slot; } diff --git a/lib/filterx/filterx-variable.h b/lib/filterx/filterx-variable.h index 447774c1c..b31afe52c 100644 --- a/lib/filterx/filterx-variable.h +++ b/lib/filterx/filterx-variable.h @@ -115,17 +115,17 @@ filterx_variable_get_value(FilterXVariable *v) } static inline void -filterx_variable_set_value(FilterXVariable *v, FilterXObject *new_value) +filterx_variable_set_value(FilterXVariable *v, FilterXObject *new_value, gboolean assignment) { filterx_object_unref(v->value); v->value = filterx_object_ref(new_value); - v->assigned = TRUE; + v->assigned = assignment; } static inline void filterx_variable_unset_value(FilterXVariable *v) { - filterx_variable_set_value(v, NULL); + filterx_variable_set_value(v, NULL, TRUE); } static inline gboolean diff --git a/lib/filterx/func-vars.c b/lib/filterx/func-vars.c index 6c24ceed5..d412998db 100644 --- a/lib/filterx/func-vars.c +++ b/lib/filterx/func-vars.c @@ -118,7 +118,7 @@ _load_from_dict(FilterXObject *key, FilterXObject *value, gpointer user_data) variable = filterx_scope_register_variable(scope, variable_type, handle, NULL); FilterXObject *cloned_value = filterx_object_clone(value); - filterx_variable_set_value(variable, cloned_value); + filterx_variable_set_value(variable, cloned_value, TRUE); filterx_object_unref(cloned_value); if (!variable) diff --git a/tests/light/functional_tests/filterx/test_filterx_scope.py b/tests/light/functional_tests/filterx/test_filterx_scope.py index d62b97207..9f9e9c0b3 100644 --- a/tests/light/functional_tests/filterx/test_filterx_scope.py +++ b/tests/light/functional_tests/filterx/test_filterx_scope.py @@ -30,10 +30,10 @@ def render_filterx_exprs(expressions): return '\n'.join(f"filterx {{ {expr} }};" for expr in expressions) -def create_config(config, init_exprs, true_exprs=(), false_exprs=(), final_exprs=(), 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'") - file_final = config.create_file_destination(file_name="dest-final.log", template="'$MSG\n'") +def create_config(config, init_exprs, true_exprs=(), false_exprs=(), final_exprs=(), msg="foobar", template='"$MSG\n"'): + file_final = config.create_file_destination(file_name="dest-final.log", template=template) + file_true = config.create_file_destination(file_name="dest-true.log", template=template) + file_false = config.create_file_destination(file_name="dest-false.log", template=template) preamble = f""" @version: {config.get_version()} @@ -182,6 +182,40 @@ def test_message_tied_variables_do_not_propagate_to_parallel_branches(config, sy assert file_false.read_log() == "kecske\n" +def test_message_tied_variables_are_not_considered_changed_just_by_unmarshaling(config, syslog_ng): + (file_true, file_false, file_final) = create_config( + config, init_exprs=[ + """ + # pull up the value from the message into a filterx variable + ${values.json}; + # cause an unmarshal into JSON + ${values.json}.emb_key1; + # $foo is set to the unmarshalled version of ${values.json} + $foo = ${values.json}; + """, + ], init_log_exprs=[ + # trigger a sync + """ + rewrite { + }; + """, + ], + # ${values.json} should retain to have spaces in them, since it was not actually changed, just unmarshalled + # ${foo} is reformatted from the unmarshalled value + # + # NOTE the extra spaces in the assertion below on the $foo part + template="'${values.json} -- $foo\n'" + ) + + syslog_ng.start(config) + + assert file_true.get_stats()["processed"] == 1 + assert "processed" not in file_false.get_stats() + (values_json, foo) = file_true.read_log().strip().split(' -- ') + assert values_json == """{"emb_key1": "emb_key1 value", "emb_key2": "emb_key2 value"}""" + assert foo == """{"emb_key1":"emb_key1 value","emb_key2":"emb_key2 value"}""" + + def test_floating_variables_are_dropped_at_the_end_of_the_scope(config, syslog_ng): (file_true, file_false, _) = create_config( config, [