diff --git a/apps/emqx_rule_engine/src/emqx_rule_engine_api.erl b/apps/emqx_rule_engine/src/emqx_rule_engine_api.erl index 95c028a1e..62e1553d2 100644 --- a/apps/emqx_rule_engine/src/emqx_rule_engine_api.erl +++ b/apps/emqx_rule_engine/src/emqx_rule_engine_api.erl @@ -423,7 +423,22 @@ param_path_id() -> %% Internal functions %%------------------------------------------------------------------------------ -err_msg(Msg) -> emqx_misc:readable_error_msg(Msg). +err_msg({RuleError, {_E, Reason, _S}}) -> + emqx_misc:readable_error_msg(encode_nested_error(RuleError, Reason)); +err_msg({Reason, _Details}) -> + emqx_misc:readable_error_msg(Reason); +err_msg(Msg) -> + emqx_misc:readable_error_msg(Msg). + +encode_nested_error(RuleError, Reason) when is_tuple(Reason) -> + encode_nested_error(RuleError, element(1, Reason)); +encode_nested_error(RuleError, Reason) -> + case emqx_json:safe_encode([{RuleError, Reason}]) of + {ok, Json} -> + Json; + _ -> + {RuleError, Reason} + end. format_rule_resp(Rules) when is_list(Rules) -> [format_rule_resp(R) || R <- Rules]; diff --git a/apps/emqx_rule_engine/test/emqx_rule_engine_api_SUITE.erl b/apps/emqx_rule_engine/test/emqx_rule_engine_api_SUITE.erl index 82a305009..d89bc2651 100644 --- a/apps/emqx_rule_engine/test/emqx_rule_engine_api_SUITE.erl +++ b/apps/emqx_rule_engine/test/emqx_rule_engine_api_SUITE.erl @@ -40,6 +40,9 @@ end_per_suite(_Config) -> init_per_testcase(_, Config) -> Config. +end_per_testcase(t_crud_rule_api, Config) -> + meck:unload(emqx_json), + end_per_testcase(common, Config); end_per_testcase(_, _Config) -> {200, #{data := Rules}} = emqx_rule_engine_api:'/rules'(get, #{query_string => #{}}), @@ -119,12 +122,54 @@ t_crud_rule_api(_Config) -> emqx_rule_engine_api:'/rules/:id'(get, #{bindings => #{id => RuleID}}) ), + {400, #{ + code := 'BAD_REQUEST', + message := SelectAndTransformJsonError + }} = + emqx_rule_engine_api:'/rule_test'( + post, + test_rule_params(<<"SELECT\n payload.msg\nFROM\n \"t/#\"">>, <<"{\"msg\": \"hel">>) + ), + ?assertMatch( + #{<<"select_and_transform_error">> := <<"decode_json_failed">>}, + emqx_json:decode(SelectAndTransformJsonError, [return_maps]) + ), + {400, #{ + code := 'BAD_REQUEST', + message := SelectAndTransformBadArgError + }} = + emqx_rule_engine_api:'/rule_test'( + post, + test_rule_params( + <<"SELECT\n payload.msg > 1\nFROM\n \"t/#\"">>, <<"{\"msg\": \"hello\"}">> + ) + ), + ?assertMatch( + #{<<"select_and_transform_error">> := <<"badarg">>}, + emqx_json:decode(SelectAndTransformBadArgError, [return_maps]) + ), + {400, #{ + code := 'BAD_REQUEST', + message := BadSqlMessage + }} = emqx_rule_engine_api:'/rule_test'( + post, + test_rule_params( + <<"BAD_SQL">>, <<"{\"msg\": \"hello\"}">> + ) + ), + ?assertMatch({match, _}, re:run(BadSqlMessage, "syntax error")), + meck:expect(emqx_json, safe_encode, 1, {error, foo}), ?assertMatch( {400, #{ code := 'BAD_REQUEST', - message := <<"{select_and_transform_error,{error,{decode_json_failed,", _/binary>> + message := <<"{select_and_transform_error,badarg}">> }}, - emqx_rule_engine_api:'/rule_test'(post, test_rule_params()) + emqx_rule_engine_api:'/rule_test'( + post, + test_rule_params( + <<"SELECT\n payload.msg > 1\nFROM\n \"t/#\"">>, <<"{\"msg\": \"hello\"}">> + ) + ) ), ok. @@ -221,19 +266,18 @@ t_reset_metrics_on_disable(_Config) -> ?assertMatch(#{passed := 0, matched := 0}, Metrics1), ok. -test_rule_params() -> +test_rule_params(Sql, Payload) -> #{ body => #{ <<"context">> => #{ <<"clientid">> => <<"c_emqx">>, <<"event_type">> => <<"message_publish">>, - <<"payload">> => <<"{\"msg\": \"hel">>, + <<"payload">> => Payload, <<"qos">> => 1, <<"topic">> => <<"t/a">>, <<"username">> => <<"u_emqx">> }, - <<"sql">> => - <<"SELECT\n payload.msg\nFROM\n \"t/#\"">> + <<"sql">> => Sql } }. diff --git a/changes/ce/feat-10059.en.md b/changes/ce/feat-10059.en.md new file mode 100644 index 000000000..2c4de015c --- /dev/null +++ b/changes/ce/feat-10059.en.md @@ -0,0 +1 @@ +Errors returned by rule engine API are formatted in a more human readable way rather than dumping the raw error including the stacktrace. diff --git a/changes/ce/feat-10059.zh.md b/changes/ce/feat-10059.zh.md new file mode 100644 index 000000000..99f8fe8ee --- /dev/null +++ b/changes/ce/feat-10059.zh.md @@ -0,0 +1 @@ +规则引擎 API 返回用户可读的错误信息而不是原始的栈追踪信息。