From a5a8aa3b6de810ccdb2cc646972ab5bfdff3f152 Mon Sep 17 00:00:00 2001 From: EMQ-YangM Date: Tue, 4 Jan 2022 22:48:39 -0800 Subject: [PATCH] feat(rule_metrics): add more metrics to the rule engine --- .../src/emqx_rule_metrics.erl | 97 +++++++++++++++---- .../src/emqx_rule_runtime.erl | 24 +++-- .../test/emqx_rule_metrics_SUITE.erl | 7 ++ 3 files changed, 101 insertions(+), 27 deletions(-) diff --git a/apps/emqx_rule_engine/src/emqx_rule_metrics.erl b/apps/emqx_rule_engine/src/emqx_rule_metrics.erl index bc2b04c07..53bfd9bb5 100644 --- a/apps/emqx_rule_engine/src/emqx_rule_metrics.erl +++ b/apps/emqx_rule_engine/src/emqx_rule_metrics.erl @@ -25,16 +25,20 @@ , stop/0 ]). --export([ get_rules_matched/1 - , get_actions_taken/1 +-export([ get_actions_taken/1 , get_actions_success/1 , get_actions_error/1 , get_actions_exception/1 , get_actions_retry/1 + , get_rules_matched/1 + , get_rules_failed/1 + , get_rules_passed/1 + , get_rules_exception/1 + , get_rules_no_result/1 + ]). --export([ inc_rules_matched/1 - , inc_rules_matched/2 +-export([ inc_rules_matched/2 , inc_actions_taken/1 , inc_actions_taken/2 , inc_actions_success/1 @@ -45,6 +49,11 @@ , inc_actions_exception/2 , inc_actions_retry/1 , inc_actions_retry/2 + , inc_rules_matched/1 + , inc_rules_failed/1 + , inc_rules_passed/1 + , inc_rules_exception/1 + , inc_rules_no_result/1 ]). -export([ inc/2 @@ -145,6 +154,10 @@ get_overall_rule_speed() -> get_rule_metrics(Id) -> #{max := Max, current := Current, last5m := Last5M} = get_rule_speed(Id), #{matched => get_rules_matched(Id), + failed => get_rules_failed(Id), + passed => get_rules_passed(Id), + exception => get_rules_exception(Id), + no_result => get_rules_no_result(Id), speed => Current, speed_max => Max, speed_last5m => Last5M @@ -181,11 +194,6 @@ inc(Id, Metric, Val) -> inc_overall(Metric, Val) -> emqx_metrics:inc(Metric, Val). -inc_rules_matched(Id) -> - inc_rules_matched(Id, 1). -inc_rules_matched(Id, Val) -> - inc(Id, 'rules.matched', Val). - inc_actions_taken(Id) -> inc_actions_taken(Id, 1). inc_actions_taken(Id, Val) -> @@ -211,8 +219,32 @@ inc_actions_retry(Id) -> inc_actions_retry(Id, Val) -> inc(Id, 'actions.retry', Val). -get_rules_matched(Id) -> - get(Id, 'rules.matched'). +inc_rules_matched(Id) -> + inc_rules_matched(Id, 1). +inc_rules_matched(Id, Val) -> + inc(Id, 'rules.matched', Val). + +inc_rules_failed(Id) -> + inc_rules_failed(Id, 1). +inc_rules_failed(Id, Val) -> + inc(Id, 'rules.failed', Val). + +inc_rules_passed(Id) -> + inc_rules_passed(Id, 1). +inc_rules_passed(Id, Val) -> + inc(Id, 'rules.passed', Val). + +inc_rules_exception(Id) -> + inc_rules_exception(Id, 1). +inc_rules_exception(Id, Val) -> + inc(Id, 'rules.failed', Val), + inc(Id, 'rules.exception', Val). + +inc_rules_no_result(Id) -> + inc_rules_no_result(Id, 1). +inc_rules_no_result(Id, Val) -> + inc(Id, 'rules.failed', Val), + inc(Id, 'rules.no_result', Val). get_actions_taken(Id) -> get(Id, 'actions.taken'). @@ -229,6 +261,21 @@ get_actions_exception(Id) -> get_actions_retry(Id) -> get(Id, 'actions.retry'). +get_rules_matched(Id) -> + get(Id, 'rules.matched'). + +get_rules_failed(Id) -> + get(Id, 'rules.failed'). + +get_rules_passed(Id) -> + get(Id, 'rules.passed'). + +get_rules_exception(Id) -> + get(Id, 'rules.exception'). + +get_rules_no_result(Id) -> + get(Id, 'rules.no_result'). + start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). @@ -420,21 +467,29 @@ precision(Float, N) -> %% Metrics Definitions %%------------------------------------------------------------------------------ -max_counters_size() -> 7. +max_counters_size() -> 11. -metrics_idx('rules.matched') -> 1; -metrics_idx('actions.success') -> 2; -metrics_idx('actions.error') -> 3; -metrics_idx('actions.taken') -> 4; -metrics_idx('actions.exception') -> 5; -metrics_idx('actions.retry') -> 6; -metrics_idx(_) -> 7. +metrics_idx('actions.success') -> 1; +metrics_idx('actions.error') -> 2; +metrics_idx('actions.taken') -> 3; +metrics_idx('actions.exception') -> 4; +metrics_idx('actions.retry') -> 5; +metrics_idx('rules.matched') -> 6; +metrics_idx('rules.failed') -> 7; +metrics_idx('rules.passed') -> 8; +metrics_idx('rules.exception') -> 9; +metrics_idx('rules.no_result') -> 10; +metrics_idx(_) -> 11. overall_metrics() -> - [ 'rules.matched' - , 'actions.success' + [ 'actions.success' , 'actions.error' , 'actions.taken' , 'actions.exception' , 'actions.retry' + , 'rules.matched' + , 'rules.failed' + , 'rules.passed' + , 'rules.exception' + , 'rules.no_result' ]. diff --git a/apps/emqx_rule_engine/src/emqx_rule_runtime.erl b/apps/emqx_rule_engine/src/emqx_rule_runtime.erl index f9e210ab3..25addb817 100644 --- a/apps/emqx_rule_engine/src/emqx_rule_runtime.erl +++ b/apps/emqx_rule_engine/src/emqx_rule_runtime.erl @@ -51,6 +51,7 @@ apply_rules([], _Input) -> apply_rules([#rule{enabled = false}|More], Input) -> apply_rules(More, Input); apply_rules([Rule = #rule{id = RuleID}|More], Input) -> + ok = emqx_rule_metrics:inc_rules_matched(RuleID), try apply_rule_discard_result(Rule, Input) catch %% ignore the errors if select or match failed @@ -89,15 +90,21 @@ do_apply_rule(#rule{id = RuleId, on_action_failed = OnFailed, actions = Actions}, Input) -> {Selected, Collection} = ?RAISE(select_and_collect(Fields, Input), + emqx_rule_metrics:inc_rules_exception(RuleId), {select_and_collect_error, {_EXCLASS_,_EXCPTION_,_ST_}}), ColumnsAndSelected = maps:merge(Input, Selected), case ?RAISE(match_conditions(Conditions, ColumnsAndSelected), + emqx_rule_metrics:inc_rules_exception(RuleId), {match_conditions_error, {_EXCLASS_,_EXCPTION_,_ST_}}) of true -> - ok = emqx_rule_metrics:inc(RuleId, 'rules.matched'), - Collection2 = filter_collection(Input, InCase, DoEach, Collection), + Collection2 = filter_collection(RuleId, Input, InCase, DoEach, Collection), + case Collection2 of + [] -> emqx_rule_metrics:inc_rules_no_result(RuleId); + _ -> emqx_rule_metrics:inc_rules_passed(RuleId) + end, {ok, [take_actions(Actions, Coll, Input, OnFailed) || Coll <- Collection2]}; false -> + ok = emqx_rule_metrics:inc_rules_no_result(RuleId), {error, nomatch} end; @@ -107,14 +114,17 @@ do_apply_rule(#rule{id = RuleId, conditions = Conditions, on_action_failed = OnFailed, actions = Actions}, Input) -> - Selected = ?RAISE(select_and_transform(Fields, Input), + Selected = ?RAISE(select_and_transform(Fields, Input), + emqx_rule_metrics:inc_rules_exception(RuleId), {select_and_transform_error, {_EXCLASS_,_EXCPTION_,_ST_}}), case ?RAISE(match_conditions(Conditions, maps:merge(Input, Selected)), + emqx_rule_metrics:inc_rules_exception(RuleId), {match_conditions_error, {_EXCLASS_,_EXCPTION_,_ST_}}) of true -> - ok = emqx_rule_metrics:inc(RuleId, 'rules.matched'), + ok = emqx_rule_metrics:inc_rules_passed(RuleId), {ok, take_actions(Actions, Selected, Input, OnFailed)}; false -> + ok = emqx_rule_metrics:inc_rules_no_result(RuleId), {error, nomatch} end. @@ -166,16 +176,18 @@ select_and_collect([Field|More], Input, {Output, LastKV}) -> {nested_put(Key, Val, Output), LastKV}). %% Filter each item got from FOREACH --dialyzer({nowarn_function, filter_collection/4}). -filter_collection(Input, InCase, DoEach, {CollKey, CollVal}) -> +-dialyzer({nowarn_function, filter_collection/5}). +filter_collection(RuleId, Input, InCase, DoEach, {CollKey, CollVal}) -> lists:filtermap( fun(Item) -> InputAndItem = maps:merge(Input, #{CollKey => Item}), case ?RAISE(match_conditions(InCase, InputAndItem), + emqx_rule_metrics:inc_rules_exception(RuleId), {match_incase_error, {_EXCLASS_,_EXCPTION_,_ST_}}) of true when DoEach == [] -> {true, InputAndItem}; true -> {true, ?RAISE(select_and_transform(DoEach, InputAndItem), + emqx_rule_metrics:inc_rules_exception(RuleId), {doeach_error, {_EXCLASS_,_EXCPTION_,_ST_}})}; false -> false end diff --git a/apps/emqx_rule_engine/test/emqx_rule_metrics_SUITE.erl b/apps/emqx_rule_engine/test/emqx_rule_metrics_SUITE.erl index e7c543c91..81c95bf23 100644 --- a/apps/emqx_rule_engine/test/emqx_rule_metrics_SUITE.erl +++ b/apps/emqx_rule_engine/test/emqx_rule_metrics_SUITE.erl @@ -92,9 +92,16 @@ t_rule(_) -> ok = emqx_rule_metrics:create_rule_metrics(<<"rule:1">>), ok = emqx_rule_metrics:create_rule_metrics(<<"rule2">>), ok = emqx_rule_metrics:inc(<<"rule:1">>, 'rules.matched'), + ok = emqx_rule_metrics:inc(<<"rule:1">>, 'rules.passed'), + ok = emqx_rule_metrics:inc(<<"rule:1">>, 'rules.exception'), + ok = emqx_rule_metrics:inc(<<"rule:1">>, 'rules.no_result'), ok = emqx_rule_metrics:inc(<<"rule2">>, 'rules.matched'), ok = emqx_rule_metrics:inc(<<"rule2">>, 'rules.matched'), ?assertEqual(1, emqx_rule_metrics:get(<<"rule:1">>, 'rules.matched')), + ?assertEqual(1, emqx_rule_metrics:get(<<"rule:1">>, 'rules.passed')), + ?assertEqual(1, emqx_rule_metrics:get(<<"rule:1">>, 'rules.exception')), + ?assertEqual(1, emqx_rule_metrics:get(<<"rule:1">>, 'rules.no_result')), + ?assertEqual(2, emqx_rule_metrics:get(<<"rule:1">>, 'rules.failed')), ?assertEqual(2, emqx_rule_metrics:get(<<"rule2">>, 'rules.matched')), ?assertEqual(0, emqx_rule_metrics:get(<<"rule3">>, 'rules.matched')), ?assertEqual(3, emqx_rule_metrics:get_overall('rules.matched')),