refactor(rule trace): templates rendered trace to increase code reuse

* The code for passing the trace context to a sub process has been
  improved to increase code reuse. This code is used when the action
  templates are rendered in a sub process.
* A macro has also been added for the error term that is thrown when the
  action shall be stopped after the templates has been rendered. This is
  also done to reduce code duplication and to reduce the risk of
  introducing bugs due to typos.
* Fix incorrect type spec

Thanks to @zmstone for suggesting these improvements in comments to a PR
(https://github.com/emqx/emqx/pull/12916).
This commit is contained in:
Kjell Winblad 2024-04-25 11:39:20 +02:00
parent 0dbaef4316
commit ef9884cf47
9 changed files with 140 additions and 146 deletions

View File

@ -38,4 +38,10 @@
-define(SHARD, ?COMMON_SHARD). -define(SHARD, ?COMMON_SHARD).
-define(MAX_SIZE, 30). -define(MAX_SIZE, 30).
-define(EMQX_TRACE_STOP_ACTION(REASON),
{unrecoverable_error, {action_stopped_after_template_rendering, REASON}}
).
-define(EMQX_TRACE_STOP_ACTION_MATCH, ?EMQX_TRACE_STOP_ACTION(_)).
-endif. -endif.

View File

@ -29,7 +29,9 @@
unsubscribe/2, unsubscribe/2,
log/3, log/3,
log/4, log/4,
rendered_action_template/2 rendered_action_template/2,
make_rendered_action_template_trace_context/1,
rendered_action_template_with_ctx/2
]). ]).
-export([ -export([
@ -70,6 +72,12 @@
-export_type([ruleid/0]). -export_type([ruleid/0]).
-type ruleid() :: binary(). -type ruleid() :: binary().
-export_type([rendered_action_template_ctx/0]).
-opaque rendered_action_template_ctx() :: #{
trace_ctx := map(),
action_id := any()
}.
publish(#message{topic = <<"$SYS/", _/binary>>}) -> publish(#message{topic = <<"$SYS/", _/binary>>}) ->
ignore; ignore;
publish(#message{from = From, topic = Topic, payload = Payload}) when publish(#message{from = From, topic = Topic, payload = Payload}) when
@ -107,15 +115,56 @@ rendered_action_template(<<"action:", _/binary>> = ActionID, RenderResult) ->
) )
), ),
MsgBin = unicode:characters_to_binary(StopMsg), MsgBin = unicode:characters_to_binary(StopMsg),
error({unrecoverable_error, {action_stopped_after_template_rendering, MsgBin}}); error(?EMQX_TRACE_STOP_ACTION(MsgBin));
_ -> _ ->
ok ok
end, end,
TraceResult; TraceResult;
rendered_action_template(_ActionID, _RenderResult) -> rendered_action_template(_ActionID, _RenderResult) ->
%% We do nothing if we don't get a valid Action ID %% We do nothing if we don't get a valid Action ID. This can happen when
%% called from connectors that are used for actions as well as authz and
%% authn.
ok. ok.
%% The following two functions are used for connectors that don't do the
%% rendering in the main process (the one that called on_*query). In this case
%% we need to pass the trace context to the sub process that do the rendering
%% so that the result of the rendering can be traced correctly. It is also
%% important to ensure that the error that can be thrown from
%% rendered_action_template_with_ctx is handled in the appropriate way in the
%% sub process.
-spec make_rendered_action_template_trace_context(any()) -> rendered_action_template_ctx().
make_rendered_action_template_trace_context(ActionID) ->
MetaData =
case logger:get_process_metadata() of
undefined -> #{};
M -> M
end,
#{trace_ctx => MetaData, action_id => ActionID}.
-spec rendered_action_template_with_ctx(rendered_action_template_ctx(), Result :: term()) -> term().
rendered_action_template_with_ctx(
#{
trace_ctx := LogMetaData,
action_id := ActionID
},
RenderResult
) ->
OldMetaData =
case logger:get_process_metadata() of
undefined -> #{};
M -> M
end,
try
logger:set_process_metadata(LogMetaData),
emqx_trace:rendered_action_template(
ActionID,
RenderResult
)
after
logger:set_process_metadata(OldMetaData)
end.
log(List, Msg, Meta) -> log(List, Msg, Meta) ->
log(debug, List, Msg, Meta). log(debug, List, Msg, Meta).

View File

@ -9,6 +9,7 @@
-include_lib("emqx_resource/include/emqx_resource.hrl"). -include_lib("emqx_resource/include/emqx_resource.hrl").
-include_lib("typerefl/include/types.hrl"). -include_lib("typerefl/include/types.hrl").
-include_lib("emqx/include/logger.hrl"). -include_lib("emqx/include/logger.hrl").
-include_lib("emqx/include/emqx_trace.hrl").
-include_lib("snabbkaffe/include/snabbkaffe.hrl"). -include_lib("snabbkaffe/include/snabbkaffe.hrl").
-include_lib("hocon/include/hoconsc.hrl"). -include_lib("hocon/include/hoconsc.hrl").
@ -246,16 +247,15 @@ do_query(
table := Table, table := Table,
templates := Templates templates := Templates
} = ChannelState, } = ChannelState,
LogMetaData = logger:get_process_metadata(), TraceRenderedCTX =
TraceRenderedFuncContext = #{trace_ctx => LogMetaData, action_id => ChannelId}, emqx_trace:make_rendered_action_template_trace_context(ChannelId),
TraceRenderedFunc = {fun trace_render_result/2, TraceRenderedFuncContext},
Result = Result =
case ensuare_dynamo_keys(Query, ChannelState) of case ensuare_dynamo_keys(Query, ChannelState) of
true -> true ->
ecpool:pick_and_do( ecpool:pick_and_do(
PoolName, PoolName,
{emqx_bridge_dynamo_connector_client, query, [ {emqx_bridge_dynamo_connector_client, query, [
Table, QueryTuple, Templates, TraceRenderedFunc Table, QueryTuple, Templates, TraceRenderedCTX
]}, ]},
no_handover no_handover
); );
@ -264,7 +264,7 @@ do_query(
end, end,
case Result of case Result of
{error, {unrecoverable_error, {action_stopped_after_template_rendering, _}}} = Error -> {error, ?EMQX_TRACE_STOP_ACTION(_)} = Error ->
Error; Error;
{error, Reason} -> {error, Reason} ->
?tp( ?tp(
@ -298,22 +298,6 @@ do_query(
Result Result
end. end.
trace_render_result(RenderResult, #{trace_ctx := LogMetaData, action_id := ActionID}) ->
OldMetaData =
case logger:get_process_metadata() of
undefined -> #{};
M -> M
end,
try
logger:set_process_metadata(LogMetaData),
emqx_trace:rendered_action_template(
ActionID,
RenderResult
)
after
logger:set_process_metadata(OldMetaData)
end.
get_channel_id([{ChannelId, _Req} | _]) -> get_channel_id([{ChannelId, _Req} | _]) ->
ChannelId; ChannelId;
get_channel_id({ChannelId, _Req}) -> get_channel_id({ChannelId, _Req}) ->

View File

@ -40,8 +40,8 @@ is_connected(Pid, Timeout) ->
{false, Error} {false, Error}
end. end.
query(Pid, Table, Query, Templates, TraceRenderedFunc) -> query(Pid, Table, Query, Templates, TraceRenderedCTX) ->
gen_server:call(Pid, {query, Table, Query, Templates, TraceRenderedFunc}, infinity). gen_server:call(Pid, {query, Table, Query, Templates, TraceRenderedCTX}, infinity).
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
%% @doc %% @doc
@ -77,8 +77,8 @@ handle_call(is_connected, _From, State) ->
{false, Error} {false, Error}
end, end,
{reply, IsConnected, State}; {reply, IsConnected, State};
handle_call({query, Table, Query, Templates, TraceRenderedFunc}, _From, State) -> handle_call({query, Table, Query, Templates, TraceRenderedCTX}, _From, State) ->
Result = do_query(Table, Query, Templates, TraceRenderedFunc), Result = do_query(Table, Query, Templates, TraceRenderedCTX),
{reply, Result, State}; {reply, Result, State};
handle_call(_Request, _From, State) -> handle_call(_Request, _From, State) ->
{reply, ok, State}. {reply, ok, State}.
@ -102,10 +102,13 @@ code_change(_OldVsn, State, _Extra) ->
%%%=================================================================== %%%===================================================================
%%% Internal functions %%% Internal functions
%%%=================================================================== %%%===================================================================
do_query(Table, Query0, Templates, {TraceRenderedFun, TraceRenderedCTX}) -> do_query(Table, Query0, Templates, TraceRenderedCTX) ->
try try
Query = apply_template(Query0, Templates), Query = apply_template(Query0, Templates),
TraceRenderedFun(#{table => Table, query => Query}, TraceRenderedCTX), emqx_trace:rendered_action_template_with_ctx(TraceRenderedCTX, #{
table => Table,
query => {fun trace_format_query/1, Query}
}),
execute(Query, Table) execute(Query, Table)
catch catch
error:{unrecoverable_error, Reason} -> error:{unrecoverable_error, Reason} ->
@ -114,6 +117,14 @@ do_query(Table, Query0, Templates, {TraceRenderedFun, TraceRenderedCTX}) ->
{error, {unrecoverable_error, {invalid_request, Reason}}} {error, {unrecoverable_error, {invalid_request, Reason}}}
end. end.
trace_format_query({Type, Data}) ->
#{type => Type, data => Data};
trace_format_query([_ | _] = Batch) ->
BatchData = [trace_format_query(Q) || Q <- Batch],
#{type => batch, data => BatchData};
trace_format_query(Query) ->
Query.
%% some simple query commands for authn/authz or test %% some simple query commands for authn/authz or test
execute({insert_item, Msg}, Table) -> execute({insert_item, Msg}, Table) ->
Item = convert_to_item(Msg), Item = convert_to_item(Msg),

View File

@ -301,29 +301,11 @@ on_query_async(ResourceId, {_ChannelId, Msg}, _Callback, #{}) ->
}). }).
with_egress_client(ActionID, ResourceId, Fun, Args) -> with_egress_client(ActionID, ResourceId, Fun, Args) ->
LogMetaData = logger:get_process_metadata(), TraceRenderedCTX = emqx_trace:make_rendered_action_template_trace_context(ActionID),
TraceRenderedFuncContext = #{trace_ctx => LogMetaData, action_id => ActionID},
TraceRenderedFunc = {fun trace_render_result/2, TraceRenderedFuncContext},
ecpool:pick_and_do( ecpool:pick_and_do(
ResourceId, {emqx_bridge_mqtt_egress, Fun, [TraceRenderedFunc | Args]}, no_handover ResourceId, {emqx_bridge_mqtt_egress, Fun, [TraceRenderedCTX | Args]}, no_handover
). ).
trace_render_result(RenderResult, #{trace_ctx := LogMetaData, action_id := ActionID}) ->
OldMetaData =
case logger:get_process_metadata() of
undefined -> #{};
M -> M
end,
try
logger:set_process_metadata(LogMetaData),
emqx_trace:rendered_action_template(
ActionID,
RenderResult
)
after
logger:set_process_metadata(OldMetaData)
end.
on_async_result(Callback, Result) -> on_async_result(Callback, Result) ->
apply_callback_function(Callback, handle_send_result(Result)). apply_callback_function(Callback, handle_send_result(Result)).
@ -343,9 +325,7 @@ handle_send_result({ok, #{reason_code := ?RC_NO_MATCHING_SUBSCRIBERS}}) ->
handle_send_result({ok, Reply}) -> handle_send_result({ok, Reply}) ->
{error, classify_reply(Reply)}; {error, classify_reply(Reply)};
handle_send_result({error, Reason}) -> handle_send_result({error, Reason}) ->
{error, classify_error(Reason)}; {error, classify_error(Reason)}.
handle_send_result({unrecoverable_error, Reason}) ->
{error, {unrecoverable_error, Reason}}.
classify_reply(Reply = #{reason_code := _}) -> classify_reply(Reply = #{reason_code := _}) ->
{unrecoverable_error, Reply}. {unrecoverable_error, Reply}.
@ -360,6 +340,8 @@ classify_error({shutdown, _} = Reason) ->
{recoverable_error, Reason}; {recoverable_error, Reason};
classify_error(shutdown = Reason) -> classify_error(shutdown = Reason) ->
{recoverable_error, Reason}; {recoverable_error, Reason};
classify_error({unrecoverable_error, _Reason} = Error) ->
Error;
classify_error(Reason) -> classify_error(Reason) ->
{unrecoverable_error, Reason}. {unrecoverable_error, Reason}.

View File

@ -29,9 +29,6 @@
-type message() :: emqx_types:message() | map(). -type message() :: emqx_types:message() | map().
-type callback() :: {function(), [_Arg]} | {module(), atom(), [_Arg]}. -type callback() :: {function(), [_Arg]} | {module(), atom(), [_Arg]}.
-type remote_message() :: #mqtt_msg{}. -type remote_message() :: #mqtt_msg{}.
-type trace_rendered_func() :: {
fun((RenderResult :: any(), CTX :: map()) -> any()), TraceCTX :: map()
}.
-type egress() :: #{ -type egress() :: #{
local => #{ local => #{
@ -45,37 +42,40 @@
config(#{remote := RC = #{}} = Conf) -> config(#{remote := RC = #{}} = Conf) ->
Conf#{remote => emqx_bridge_mqtt_msg:parse(RC)}. Conf#{remote => emqx_bridge_mqtt_msg:parse(RC)}.
-spec send(pid(), trace_rendered_func(), message(), egress()) -> ok. -spec send(pid(), emqx_trace:rendered_action_template_ctx(), message(), egress()) ->
send(Pid, TraceRenderedFunc, MsgIn, Egress) -> ok | {error, {unrecoverable_error, term()}}.
send(Pid, TraceRenderedCTX, MsgIn, Egress) ->
try try
emqtt:publish(Pid, export_msg(MsgIn, Egress, TraceRenderedFunc)) emqtt:publish(Pid, export_msg(MsgIn, Egress, TraceRenderedCTX))
catch catch
error:{unrecoverable_error, Reason} -> error:{unrecoverable_error, Reason} ->
{unrecoverable_error, Reason} {error, {unrecoverable_error, Reason}}
end. end.
-spec send_async(pid(), trace_rendered_func(), message(), callback(), egress()) -> -spec send_async(pid(), emqx_trace:rendered_action_template_ctx(), message(), callback(), egress()) ->
ok | {ok, pid()}. {ok, pid()} | {error, {unrecoverable_error, term()}}.
send_async(Pid, TraceRenderedFunc, MsgIn, Callback, Egress) -> send_async(Pid, TraceRenderedCTX, MsgIn, Callback, Egress) ->
try try
ok = emqtt:publish_async( ok = emqtt:publish_async(
Pid, export_msg(MsgIn, Egress, TraceRenderedFunc), _Timeout = infinity, Callback Pid, export_msg(MsgIn, Egress, TraceRenderedCTX), _Timeout = infinity, Callback
), ),
{ok, Pid} {ok, Pid}
catch catch
error:{unrecoverable_error, Reason} -> error:{unrecoverable_error, Reason} ->
{unrecoverable_error, Reason} {error, {unrecoverable_error, Reason}}
end. end.
export_msg(Msg, #{remote := Remote}, TraceRenderedFunc) -> export_msg(Msg, #{remote := Remote}, TraceRenderedCTX) ->
to_remote_msg(Msg, Remote, TraceRenderedFunc). to_remote_msg(Msg, Remote, TraceRenderedCTX).
-spec to_remote_msg(message(), emqx_bridge_mqtt_msg:msgvars(), trace_rendered_func()) -> -spec to_remote_msg(
message(), emqx_bridge_mqtt_msg:msgvars(), emqx_trace:rendered_action_template_ctx()
) ->
remote_message(). remote_message().
to_remote_msg(#message{flags = Flags} = Msg, Vars, TraceRenderedFunc) -> to_remote_msg(#message{flags = Flags} = Msg, Vars, TraceRenderedCTX) ->
{EventMsg, _} = emqx_rule_events:eventmsg_publish(Msg), {EventMsg, _} = emqx_rule_events:eventmsg_publish(Msg),
to_remote_msg(EventMsg#{retain => maps:get(retain, Flags, false)}, Vars, TraceRenderedFunc); to_remote_msg(EventMsg#{retain => maps:get(retain, Flags, false)}, Vars, TraceRenderedCTX);
to_remote_msg(Msg = #{}, Remote, {TraceRenderedFun, TraceRenderedCTX}) -> to_remote_msg(Msg = #{}, Remote, TraceRenderedCTX) ->
#{ #{
topic := Topic, topic := Topic,
payload := Payload, payload := Payload,
@ -83,16 +83,13 @@ to_remote_msg(Msg = #{}, Remote, {TraceRenderedFun, TraceRenderedCTX}) ->
retain := Retain retain := Retain
} = emqx_bridge_mqtt_msg:render(Msg, Remote), } = emqx_bridge_mqtt_msg:render(Msg, Remote),
PubProps = maps:get(pub_props, Msg, #{}), PubProps = maps:get(pub_props, Msg, #{}),
TraceRenderedFun( emqx_trace:rendered_action_template_with_ctx(TraceRenderedCTX, #{
#{ qos => QoS,
qos => QoS, retain => Retain,
retain => Retain, topic => Topic,
topic => Topic, props => PubProps,
props => PubProps, payload => Payload
payload => Payload }),
},
TraceRenderedCTX
),
#mqtt_msg{ #mqtt_msg{
qos = QoS, qos = QoS,
retain = Retain, retain = Retain,

View File

@ -9,6 +9,7 @@
-include_lib("emqx_resource/include/emqx_resource.hrl"). -include_lib("emqx_resource/include/emqx_resource.hrl").
-include_lib("typerefl/include/types.hrl"). -include_lib("typerefl/include/types.hrl").
-include_lib("emqx/include/logger.hrl"). -include_lib("emqx/include/logger.hrl").
-include_lib("emqx/include/emqx_trace.hrl").
-include_lib("hocon/include/hoconsc.hrl"). -include_lib("hocon/include/hoconsc.hrl").
-include_lib("snabbkaffe/include/snabbkaffe.hrl"). -include_lib("snabbkaffe/include/snabbkaffe.hrl").
@ -214,12 +215,10 @@ on_query(ResourceID, {ChannelId, Data} = MsgReq, State) ->
#{channels := Channels} = State, #{channels := Channels} = State,
case maps:find(ChannelId, Channels) of case maps:find(ChannelId, Channels) of
{ok, #{param := ProcParam, rabbitmq := RabbitMQ}} -> {ok, #{param := ProcParam, rabbitmq := RabbitMQ}} ->
LogMetaData = logger:get_process_metadata(), TraceRenderedCTX = emqx_trace:make_rendered_action_template_trace_context(ChannelId),
TraceRenderedFuncContext = #{trace_ctx => LogMetaData, action_id => ChannelId},
TraceRenderedFunc = {fun trace_render_result/2, TraceRenderedFuncContext},
Res = ecpool:pick_and_do( Res = ecpool:pick_and_do(
ResourceID, ResourceID,
{?MODULE, publish_messages, [RabbitMQ, ProcParam, [MsgReq], TraceRenderedFunc]}, {?MODULE, publish_messages, [RabbitMQ, ProcParam, [MsgReq], TraceRenderedCTX]},
no_handover no_handover
), ),
handle_result(Res); handle_result(Res);
@ -237,12 +236,10 @@ on_batch_query(ResourceID, [{ChannelId, _Data} | _] = Batch, State) ->
#{channels := Channels} = State, #{channels := Channels} = State,
case maps:find(ChannelId, Channels) of case maps:find(ChannelId, Channels) of
{ok, #{param := ProcParam, rabbitmq := RabbitMQ}} -> {ok, #{param := ProcParam, rabbitmq := RabbitMQ}} ->
LogMetaData = logger:get_process_metadata(), TraceRenderedCTX = emqx_trace:make_rendered_action_template_trace_context(ChannelId),
TraceRenderedFuncContext = #{trace_ctx => LogMetaData, action_id => ChannelId},
TraceRenderedFunc = {fun trace_render_result/2, TraceRenderedFuncContext},
Res = ecpool:pick_and_do( Res = ecpool:pick_and_do(
ResourceID, ResourceID,
{?MODULE, publish_messages, [RabbitMQ, ProcParam, Batch, TraceRenderedFunc]}, {?MODULE, publish_messages, [RabbitMQ, ProcParam, Batch, TraceRenderedCTX]},
no_handover no_handover
), ),
handle_result(Res); handle_result(Res);
@ -250,22 +247,6 @@ on_batch_query(ResourceID, [{ChannelId, _Data} | _] = Batch, State) ->
{error, {unrecoverable_error, {invalid_message_tag, ChannelId}}} {error, {unrecoverable_error, {invalid_message_tag, ChannelId}}}
end. end.
trace_render_result(RenderResult, #{trace_ctx := LogMetaData, action_id := ActionID}) ->
OldMetaData =
case logger:get_process_metadata() of
undefined -> #{};
M -> M
end,
try
logger:set_process_metadata(LogMetaData),
emqx_trace:rendered_action_template(
ActionID,
RenderResult
)
after
logger:set_process_metadata(OldMetaData)
end.
publish_messages( publish_messages(
Conn, Conn,
RabbitMQ, RabbitMQ,
@ -278,7 +259,7 @@ publish_messages(
publish_confirmation_timeout := PublishConfirmationTimeout publish_confirmation_timeout := PublishConfirmationTimeout
}, },
Messages, Messages,
TraceRenderedFunc TraceRenderedCTX
) -> ) ->
try try
publish_messages( publish_messages(
@ -291,10 +272,10 @@ publish_messages(
Messages, Messages,
WaitForPublishConfirmations, WaitForPublishConfirmations,
PublishConfirmationTimeout, PublishConfirmationTimeout,
TraceRenderedFunc TraceRenderedCTX
) )
catch catch
error:{unrecoverable_error, {action_stopped_after_template_rendering, _}} = Reason -> error:?EMQX_TRACE_STOP_ACTION_MATCH = Reason ->
{error, Reason}; {error, Reason};
%% if send a message to a non-existent exchange, RabbitMQ client will crash %% if send a message to a non-existent exchange, RabbitMQ client will crash
%% {shutdown,{server_initiated_close,404,<<"NOT_FOUND - no exchange 'xyz' in vhost '/'">>} %% {shutdown,{server_initiated_close,404,<<"NOT_FOUND - no exchange 'xyz' in vhost '/'">>}
@ -314,7 +295,7 @@ publish_messages(
Messages, Messages,
WaitForPublishConfirmations, WaitForPublishConfirmations,
PublishConfirmationTimeout, PublishConfirmationTimeout,
{TraceRenderedFun, TraceRenderedFuncCTX} TraceRenderedCTX
) -> ) ->
case maps:find(Conn, RabbitMQ) of case maps:find(Conn, RabbitMQ) of
{ok, Channel} -> {ok, Channel} ->
@ -330,20 +311,17 @@ publish_messages(
format_data(PayloadTmpl, M) format_data(PayloadTmpl, M)
|| {_, M} <- Messages || {_, M} <- Messages
], ],
TraceRenderedFun( emqx_trace:rendered_action_template_with_ctx(TraceRenderedCTX, #{
#{ messages => FormattedMsgs,
messages => FormattedMsgs, properties => #{
properties => #{ headers => [],
headers => [], delivery_mode => DeliveryMode
delivery_mode => DeliveryMode
},
method => #{
exchange => Exchange,
routing_key => RoutingKey
}
}, },
TraceRenderedFuncCTX method => #{
), exchange => Exchange,
routing_key => RoutingKey
}
}),
lists:foreach( lists:foreach(
fun(Msg) -> fun(Msg) ->
amqp_channel:cast( amqp_channel:cast(

View File

@ -10,6 +10,7 @@
-include_lib("hocon/include/hoconsc.hrl"). -include_lib("hocon/include/hoconsc.hrl").
-include_lib("emqx/include/logger.hrl"). -include_lib("emqx/include/logger.hrl").
-include_lib("emqx/include/emqx_trace.hrl").
-include_lib("typerefl/include/types.hrl"). -include_lib("typerefl/include/types.hrl").
-include_lib("snabbkaffe/include/snabbkaffe.hrl"). -include_lib("snabbkaffe/include/snabbkaffe.hrl").
-include_lib("emqx_resource/include/emqx_resource.hrl"). -include_lib("emqx_resource/include/emqx_resource.hrl").
@ -200,12 +201,10 @@ on_batch_query(
) -> ) ->
case maps:find(ChannelId, Channels) of case maps:find(ChannelId, Channels) of
{ok, #{batch := Tokens, opts := Opts}} -> {ok, #{batch := Tokens, opts := Opts}} ->
LogMetaData = logger:get_process_metadata(), TraceRenderedCTX = emqx_trace:make_rendered_action_template_trace_context(ChannelId),
TraceRenderedFuncContext = #{trace_ctx => LogMetaData, action_id => ChannelId},
TraceRenderedFunc = {fun trace_render_result/2, TraceRenderedFuncContext},
do_query_job( do_query_job(
InstanceId, InstanceId,
{?MODULE, do_batch_insert, [Tokens, BatchReq, Opts, TraceRenderedFunc]}, {?MODULE, do_batch_insert, [Tokens, BatchReq, Opts, TraceRenderedCTX]},
State State
); );
_ -> _ ->
@ -216,22 +215,6 @@ on_batch_query(InstanceId, BatchReq, State) ->
?SLOG(error, LogMeta#{msg => "invalid_request"}), ?SLOG(error, LogMeta#{msg => "invalid_request"}),
{error, {unrecoverable_error, invalid_request}}. {error, {unrecoverable_error, invalid_request}}.
trace_render_result(RenderResult, #{trace_ctx := LogMetaData, action_id := ActionID}) ->
OldMetaData =
case logger:get_process_metadata() of
undefined -> #{};
M -> M
end,
try
logger:set_process_metadata(LogMetaData),
emqx_trace:rendered_action_template(
ActionID,
RenderResult
)
after
logger:set_process_metadata(OldMetaData)
end.
on_get_status(_InstanceId, #{pool_name := PoolName} = State) -> on_get_status(_InstanceId, #{pool_name := PoolName} = State) ->
case case
emqx_resource_pool:health_check_workers( emqx_resource_pool:health_check_workers(
@ -358,13 +341,16 @@ do_query_job(InstanceId, Job, #{pool_name := PoolName} = State) ->
execute(Conn, Query, Opts) -> execute(Conn, Query, Opts) ->
tdengine:insert(Conn, Query, Opts). tdengine:insert(Conn, Query, Opts).
do_batch_insert(Conn, Tokens, BatchReqs, Opts, {TraceRenderedFun, TraceRenderedFunCTX}) -> do_batch_insert(Conn, Tokens, BatchReqs, Opts, TraceRenderedCTX) ->
SQL = aggregate_query(Tokens, BatchReqs, <<"INSERT INTO">>), SQL = aggregate_query(Tokens, BatchReqs, <<"INSERT INTO">>),
try try
TraceRenderedFun(#{query => SQL}, TraceRenderedFunCTX), emqx_trace:rendered_action_template_with_ctx(
TraceRenderedCTX,
#{query => SQL}
),
execute(Conn, SQL, Opts) execute(Conn, SQL, Opts)
catch catch
error:{unrecoverable_error, {action_stopped_after_template_rendering, _}} = Reason -> error:?EMQX_TRACE_STOP_ACTION_MATCH = Reason ->
{error, Reason} {error, Reason}
end. end.

View File

@ -18,6 +18,7 @@
-include("rule_engine.hrl"). -include("rule_engine.hrl").
-include_lib("emqx/include/logger.hrl"). -include_lib("emqx/include/logger.hrl").
-include_lib("emqx/include/emqx_trace.hrl").
-include_lib("emqx_resource/include/emqx_resource_errors.hrl"). -include_lib("emqx_resource/include/emqx_resource_errors.hrl").
-export([ -export([
@ -724,7 +725,7 @@ inc_action_metrics(TraceCtx, Result) ->
do_inc_action_metrics( do_inc_action_metrics(
#{rule_id := RuleId, action_id := ActId} = TraceContext, #{rule_id := RuleId, action_id := ActId} = TraceContext,
{error, {unrecoverable_error, {action_stopped_after_template_rendering, Explanation}} = _Reason} {error, ?EMQX_TRACE_STOP_ACTION(Explanation) = _Reason}
) -> ) ->
TraceContext1 = maps:remove(action_id, TraceContext), TraceContext1 = maps:remove(action_id, TraceContext),
trace_action( trace_action(