Merge pull request #12916 from kjellwinblad/kjell/fix_traces/EMQX-12025
Improve log structure for HTTP action and add after render trace to other actions
This commit is contained in:
commit
cad5d8bc31
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
@ -87,7 +95,7 @@ unsubscribe(<<"$SYS/", _/binary>>, _SubOpts) ->
|
||||||
unsubscribe(Topic, SubOpts) ->
|
unsubscribe(Topic, SubOpts) ->
|
||||||
?TRACE("UNSUBSCRIBE", "unsubscribe", #{topic => Topic, sub_opts => SubOpts}).
|
?TRACE("UNSUBSCRIBE", "unsubscribe", #{topic => Topic, sub_opts => SubOpts}).
|
||||||
|
|
||||||
rendered_action_template(ActionID, RenderResult) ->
|
rendered_action_template(<<"action:", _/binary>> = ActionID, RenderResult) ->
|
||||||
TraceResult = ?TRACE(
|
TraceResult = ?TRACE(
|
||||||
"QUERY_RENDER",
|
"QUERY_RENDER",
|
||||||
"action_template_rendered",
|
"action_template_rendered",
|
||||||
|
@ -107,11 +115,55 @@ rendered_action_template(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) ->
|
||||||
|
%% 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.
|
||||||
|
|
||||||
|
%% 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).
|
||||||
|
|
|
@ -48,6 +48,21 @@ prepare_log_map(LogMap, PEncode) ->
|
||||||
NewKeyValuePairs = [prepare_key_value(K, V, PEncode) || {K, V} <- maps:to_list(LogMap)],
|
NewKeyValuePairs = [prepare_key_value(K, V, PEncode) || {K, V} <- maps:to_list(LogMap)],
|
||||||
maps:from_list(NewKeyValuePairs).
|
maps:from_list(NewKeyValuePairs).
|
||||||
|
|
||||||
|
prepare_key_value(K, {Formatter, V}, PEncode) when is_function(Formatter, 1) ->
|
||||||
|
%% A cusom formatter is provided with the value
|
||||||
|
try
|
||||||
|
NewV = Formatter(V),
|
||||||
|
prepare_key_value(K, NewV, PEncode)
|
||||||
|
catch
|
||||||
|
_:_ ->
|
||||||
|
{K, V}
|
||||||
|
end;
|
||||||
|
prepare_key_value(K, {ok, Status, Headers, Body}, PEncode) when
|
||||||
|
is_integer(Status), is_list(Headers), is_binary(Body)
|
||||||
|
->
|
||||||
|
%% This is unlikely anything else then info about a HTTP request so we make
|
||||||
|
%% it more structured
|
||||||
|
prepare_key_value(K, #{status => Status, headers => Headers, body => Body}, PEncode);
|
||||||
prepare_key_value(payload = K, V, PEncode) ->
|
prepare_key_value(payload = K, V, PEncode) ->
|
||||||
NewV =
|
NewV =
|
||||||
try
|
try
|
||||||
|
|
|
@ -223,6 +223,11 @@ do_single_query(InstId, Request, Async, #{pool_name := PoolName} = State) ->
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
{PreparedKeyOrCQL1, Data} = proc_cql_params(Type, PreparedKeyOrCQL, Params, State),
|
{PreparedKeyOrCQL1, Data} = proc_cql_params(Type, PreparedKeyOrCQL, Params, State),
|
||||||
|
emqx_trace:rendered_action_template(PreparedKeyOrCQL, #{
|
||||||
|
type => Type,
|
||||||
|
key_or_cql => PreparedKeyOrCQL1,
|
||||||
|
data => Data
|
||||||
|
}),
|
||||||
Res = exec_cql_query(InstId, PoolName, Type, Async, PreparedKeyOrCQL1, Data),
|
Res = exec_cql_query(InstId, PoolName, Type, Async, PreparedKeyOrCQL1, Data),
|
||||||
handle_result(Res).
|
handle_result(Res).
|
||||||
|
|
||||||
|
@ -261,6 +266,14 @@ do_batch_query(InstId, Requests, Async, #{pool_name := PoolName} = State) ->
|
||||||
state => State
|
state => State
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
ChannelID =
|
||||||
|
case Requests of
|
||||||
|
[{CID, _} | _] -> CID;
|
||||||
|
_ -> none
|
||||||
|
end,
|
||||||
|
emqx_trace:rendered_action_template(ChannelID, #{
|
||||||
|
cqls => CQLs
|
||||||
|
}),
|
||||||
Res = exec_cql_batch_query(InstId, PoolName, Async, CQLs),
|
Res = exec_cql_batch_query(InstId, PoolName, Async, CQLs),
|
||||||
handle_result(Res).
|
handle_result(Res).
|
||||||
|
|
||||||
|
|
|
@ -386,7 +386,7 @@ on_query(
|
||||||
SimplifiedRequestType = query_type(RequestType),
|
SimplifiedRequestType = query_type(RequestType),
|
||||||
Templates = get_templates(RequestType, State),
|
Templates = get_templates(RequestType, State),
|
||||||
SQL = get_sql(SimplifiedRequestType, Templates, DataOrSQL),
|
SQL = get_sql(SimplifiedRequestType, Templates, DataOrSQL),
|
||||||
ClickhouseResult = execute_sql_in_clickhouse_server(PoolName, SQL),
|
ClickhouseResult = execute_sql_in_clickhouse_server(RequestType, PoolName, SQL),
|
||||||
transform_and_log_clickhouse_result(ClickhouseResult, ResourceID, SQL).
|
transform_and_log_clickhouse_result(ClickhouseResult, ResourceID, SQL).
|
||||||
|
|
||||||
get_templates(ChannId, State) ->
|
get_templates(ChannId, State) ->
|
||||||
|
@ -398,7 +398,7 @@ get_templates(ChannId, State) ->
|
||||||
end.
|
end.
|
||||||
|
|
||||||
get_sql(channel_message, #{send_message_template := PreparedSQL}, Data) ->
|
get_sql(channel_message, #{send_message_template := PreparedSQL}, Data) ->
|
||||||
emqx_placeholder:proc_tmpl(PreparedSQL, Data);
|
emqx_placeholder:proc_tmpl(PreparedSQL, Data, #{return => full_binary});
|
||||||
get_sql(_, _, SQL) ->
|
get_sql(_, _, SQL) ->
|
||||||
SQL.
|
SQL.
|
||||||
|
|
||||||
|
@ -425,7 +425,7 @@ on_batch_query(ResourceID, BatchReq, #{pool_name := PoolName} = State) ->
|
||||||
%% Create batch insert SQL statement
|
%% Create batch insert SQL statement
|
||||||
SQL = objects_to_sql(ObjectsToInsert, Templates),
|
SQL = objects_to_sql(ObjectsToInsert, Templates),
|
||||||
%% Do the actual query in the database
|
%% Do the actual query in the database
|
||||||
ResultFromClickhouse = execute_sql_in_clickhouse_server(PoolName, SQL),
|
ResultFromClickhouse = execute_sql_in_clickhouse_server(ChannId, PoolName, SQL),
|
||||||
%% Transform the result to a better format
|
%% Transform the result to a better format
|
||||||
transform_and_log_clickhouse_result(ResultFromClickhouse, ResourceID, SQL).
|
transform_and_log_clickhouse_result(ResultFromClickhouse, ResourceID, SQL).
|
||||||
|
|
||||||
|
@ -464,7 +464,8 @@ objects_to_sql(_, _) ->
|
||||||
|
|
||||||
%% This function is used by on_query/3 and on_batch_query/3 to send a query to
|
%% This function is used by on_query/3 and on_batch_query/3 to send a query to
|
||||||
%% the database server and receive a result
|
%% the database server and receive a result
|
||||||
execute_sql_in_clickhouse_server(PoolName, SQL) ->
|
execute_sql_in_clickhouse_server(Id, PoolName, SQL) ->
|
||||||
|
emqx_trace:rendered_action_template(Id, #{rendered_sql => SQL}),
|
||||||
ecpool:pick_and_do(
|
ecpool:pick_and_do(
|
||||||
PoolName,
|
PoolName,
|
||||||
{?MODULE, execute_sql_in_clickhouse_server_using_connection, [SQL]},
|
{?MODULE, execute_sql_in_clickhouse_server_using_connection, [SQL]},
|
||||||
|
|
|
@ -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,12 +247,16 @@ do_query(
|
||||||
table := Table,
|
table := Table,
|
||||||
templates := Templates
|
templates := Templates
|
||||||
} = ChannelState,
|
} = ChannelState,
|
||||||
|
TraceRenderedCTX =
|
||||||
|
emqx_trace:make_rendered_action_template_trace_context(ChannelId),
|
||||||
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, [Table, QueryTuple, Templates]},
|
{emqx_bridge_dynamo_connector_client, query, [
|
||||||
|
Table, QueryTuple, Templates, TraceRenderedCTX
|
||||||
|
]},
|
||||||
no_handover
|
no_handover
|
||||||
);
|
);
|
||||||
_ ->
|
_ ->
|
||||||
|
@ -259,6 +264,8 @@ do_query(
|
||||||
end,
|
end,
|
||||||
|
|
||||||
case Result of
|
case Result of
|
||||||
|
{error, ?EMQX_TRACE_STOP_ACTION(_)} = Error ->
|
||||||
|
Error;
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
?tp(
|
?tp(
|
||||||
dynamo_connector_query_return,
|
dynamo_connector_query_return,
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
-export([
|
-export([
|
||||||
start_link/1,
|
start_link/1,
|
||||||
is_connected/2,
|
is_connected/2,
|
||||||
query/4
|
query/5
|
||||||
]).
|
]).
|
||||||
|
|
||||||
%% gen_server callbacks
|
%% gen_server callbacks
|
||||||
|
@ -40,8 +40,8 @@ is_connected(Pid, Timeout) ->
|
||||||
{false, Error}
|
{false, Error}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
query(Pid, Table, Query, Templates) ->
|
query(Pid, Table, Query, Templates, TraceRenderedCTX) ->
|
||||||
gen_server:call(Pid, {query, Table, Query, Templates}, infinity).
|
gen_server:call(Pid, {query, Table, Query, Templates, TraceRenderedCTX}, infinity).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% @doc
|
%% @doc
|
||||||
|
@ -77,14 +77,14 @@ handle_call(is_connected, _From, State) ->
|
||||||
{false, Error}
|
{false, Error}
|
||||||
end,
|
end,
|
||||||
{reply, IsConnected, State};
|
{reply, IsConnected, State};
|
||||||
handle_call({query, Table, Query, Templates}, _From, State) ->
|
handle_call({query, Table, Query, Templates, TraceRenderedCTX}, _From, State) ->
|
||||||
Result = do_query(Table, Query, Templates),
|
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}.
|
||||||
|
|
||||||
handle_cast({query, Table, Query, Templates, {ReplyFun, [Context]}}, State) ->
|
handle_cast({query, Table, Query, Templates, {ReplyFun, [Context]}}, State) ->
|
||||||
Result = do_query(Table, Query, Templates),
|
Result = do_query(Table, Query, Templates, {fun(_, _) -> ok end, none}),
|
||||||
ReplyFun(Context, Result),
|
ReplyFun(Context, Result),
|
||||||
{noreply, State};
|
{noreply, State};
|
||||||
handle_cast(_Request, State) ->
|
handle_cast(_Request, State) ->
|
||||||
|
@ -102,15 +102,29 @@ code_change(_OldVsn, State, _Extra) ->
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% Internal functions
|
%%% Internal functions
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
do_query(Table, Query0, Templates) ->
|
do_query(Table, Query0, Templates, TraceRenderedCTX) ->
|
||||||
try
|
try
|
||||||
Query = apply_template(Query0, Templates),
|
Query = apply_template(Query0, Templates),
|
||||||
|
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}};
|
||||||
_Type:Reason ->
|
_Type:Reason ->
|
||||||
{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),
|
||||||
|
|
|
@ -284,6 +284,13 @@ do_send_requests_sync(ConnectorState, Requests, InstanceId) ->
|
||||||
Method = post,
|
Method = post,
|
||||||
ReqOpts = #{request_ttl => RequestTTL},
|
ReqOpts = #{request_ttl => RequestTTL},
|
||||||
Request = {prepared_request, {Method, Path, Body}, ReqOpts},
|
Request = {prepared_request, {Method, Path, Body}, ReqOpts},
|
||||||
|
emqx_trace:rendered_action_template(MessageTag, #{
|
||||||
|
method => Method,
|
||||||
|
path => Path,
|
||||||
|
body => Body,
|
||||||
|
options => ReqOpts,
|
||||||
|
is_async => false
|
||||||
|
}),
|
||||||
Result = emqx_bridge_gcp_pubsub_client:query_sync(Request, Client),
|
Result = emqx_bridge_gcp_pubsub_client:query_sync(Request, Client),
|
||||||
QueryMode = sync,
|
QueryMode = sync,
|
||||||
handle_result(Result, Request, QueryMode, InstanceId).
|
handle_result(Result, Request, QueryMode, InstanceId).
|
||||||
|
@ -312,6 +319,13 @@ do_send_requests_async(ConnectorState, Requests, ReplyFunAndArgs0) ->
|
||||||
ReqOpts = #{request_ttl => RequestTTL},
|
ReqOpts = #{request_ttl => RequestTTL},
|
||||||
Request = {prepared_request, {Method, Path, Body}, ReqOpts},
|
Request = {prepared_request, {Method, Path, Body}, ReqOpts},
|
||||||
ReplyFunAndArgs = {fun ?MODULE:reply_delegator/2, [ReplyFunAndArgs0]},
|
ReplyFunAndArgs = {fun ?MODULE:reply_delegator/2, [ReplyFunAndArgs0]},
|
||||||
|
emqx_trace:rendered_action_template(MessageTag, #{
|
||||||
|
method => Method,
|
||||||
|
path => Path,
|
||||||
|
body => Body,
|
||||||
|
options => ReqOpts,
|
||||||
|
is_async => true
|
||||||
|
}),
|
||||||
emqx_bridge_gcp_pubsub_client:query_async(
|
emqx_bridge_gcp_pubsub_client:query_async(
|
||||||
Request, ReplyFunAndArgs, Client
|
Request, ReplyFunAndArgs, Client
|
||||||
).
|
).
|
||||||
|
|
|
@ -128,7 +128,7 @@ on_query(InstId, {Channel, Message}, State) ->
|
||||||
greptimedb_connector_send_query,
|
greptimedb_connector_send_query,
|
||||||
#{points => Points, batch => false, mode => sync}
|
#{points => Points, batch => false, mode => sync}
|
||||||
),
|
),
|
||||||
do_query(InstId, Client, Points);
|
do_query(InstId, Channel, Client, Points);
|
||||||
{error, ErrorPoints} ->
|
{error, ErrorPoints} ->
|
||||||
?tp(
|
?tp(
|
||||||
greptimedb_connector_send_query_error,
|
greptimedb_connector_send_query_error,
|
||||||
|
@ -152,7 +152,7 @@ on_batch_query(InstId, [{Channel, _} | _] = BatchData, State) ->
|
||||||
greptimedb_connector_send_query,
|
greptimedb_connector_send_query,
|
||||||
#{points => Points, batch => true, mode => sync}
|
#{points => Points, batch => true, mode => sync}
|
||||||
),
|
),
|
||||||
do_query(InstId, Client, Points);
|
do_query(InstId, Channel, Client, Points);
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
?tp(
|
?tp(
|
||||||
greptimedb_connector_send_query_error,
|
greptimedb_connector_send_query_error,
|
||||||
|
@ -173,7 +173,7 @@ on_query_async(InstId, {Channel, Message}, {ReplyFun, Args}, State) ->
|
||||||
greptimedb_connector_send_query,
|
greptimedb_connector_send_query,
|
||||||
#{points => Points, batch => false, mode => async}
|
#{points => Points, batch => false, mode => async}
|
||||||
),
|
),
|
||||||
do_async_query(InstId, Client, Points, {ReplyFun, Args});
|
do_async_query(InstId, Channel, Client, Points, {ReplyFun, Args});
|
||||||
{error, ErrorPoints} = Err ->
|
{error, ErrorPoints} = Err ->
|
||||||
?tp(
|
?tp(
|
||||||
greptimedb_connector_send_query_error,
|
greptimedb_connector_send_query_error,
|
||||||
|
@ -195,7 +195,7 @@ on_batch_query_async(InstId, [{Channel, _} | _] = BatchData, {ReplyFun, Args}, S
|
||||||
greptimedb_connector_send_query,
|
greptimedb_connector_send_query,
|
||||||
#{points => Points, batch => true, mode => async}
|
#{points => Points, batch => true, mode => async}
|
||||||
),
|
),
|
||||||
do_async_query(InstId, Client, Points, {ReplyFun, Args});
|
do_async_query(InstId, Channel, Client, Points, {ReplyFun, Args});
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
?tp(
|
?tp(
|
||||||
greptimedb_connector_send_query_error,
|
greptimedb_connector_send_query_error,
|
||||||
|
@ -420,7 +420,8 @@ is_auth_key(_) ->
|
||||||
|
|
||||||
%% -------------------------------------------------------------------------------------------------
|
%% -------------------------------------------------------------------------------------------------
|
||||||
%% Query
|
%% Query
|
||||||
do_query(InstId, Client, Points) ->
|
do_query(InstId, Channel, Client, Points) ->
|
||||||
|
emqx_trace:rendered_action_template(Channel, #{points => Points, is_async => false}),
|
||||||
case greptimedb:write_batch(Client, Points) of
|
case greptimedb:write_batch(Client, Points) of
|
||||||
{ok, #{response := {affected_rows, #{value := Rows}}}} ->
|
{ok, #{response := {affected_rows, #{value := Rows}}}} ->
|
||||||
?SLOG(debug, #{
|
?SLOG(debug, #{
|
||||||
|
@ -452,12 +453,13 @@ do_query(InstId, Client, Points) ->
|
||||||
end
|
end
|
||||||
end.
|
end.
|
||||||
|
|
||||||
do_async_query(InstId, Client, Points, ReplyFunAndArgs) ->
|
do_async_query(InstId, Channel, Client, Points, ReplyFunAndArgs) ->
|
||||||
?SLOG(info, #{
|
?SLOG(info, #{
|
||||||
msg => "greptimedb_write_point_async",
|
msg => "greptimedb_write_point_async",
|
||||||
connector => InstId,
|
connector => InstId,
|
||||||
points => Points
|
points => Points
|
||||||
}),
|
}),
|
||||||
|
emqx_trace:rendered_action_template(Channel, #{points => Points, is_async => true}),
|
||||||
WrappedReplyFunAndArgs = {fun ?MODULE:reply_callback/2, [ReplyFunAndArgs]},
|
WrappedReplyFunAndArgs = {fun ?MODULE:reply_callback/2, [ReplyFunAndArgs]},
|
||||||
ok = greptimedb:async_write_batch(Client, Points, WrappedReplyFunAndArgs).
|
ok = greptimedb:async_write_batch(Client, Points, WrappedReplyFunAndArgs).
|
||||||
|
|
||||||
|
|
|
@ -134,8 +134,11 @@ on_query(
|
||||||
#{
|
#{
|
||||||
producer := Producer, partition_key := PartitionKey, record_template := HRecordTemplate
|
producer := Producer, partition_key := PartitionKey, record_template := HRecordTemplate
|
||||||
} = maps:get(ChannelID, Channels),
|
} = maps:get(ChannelID, Channels),
|
||||||
try to_record(PartitionKey, HRecordTemplate, Data) of
|
try
|
||||||
Record -> append_record(InstId, Producer, Record, false)
|
KeyAndRawRecord = to_key_and_raw_record(PartitionKey, HRecordTemplate, Data),
|
||||||
|
emqx_trace:rendered_action_template(ChannelID, #{record => KeyAndRawRecord}),
|
||||||
|
Record = to_record(KeyAndRawRecord),
|
||||||
|
append_record(InstId, Producer, Record, false)
|
||||||
catch
|
catch
|
||||||
_:_ -> ?FAILED_TO_APPLY_HRECORD_TEMPLATE
|
_:_ -> ?FAILED_TO_APPLY_HRECORD_TEMPLATE
|
||||||
end.
|
end.
|
||||||
|
@ -148,8 +151,13 @@ on_batch_query(
|
||||||
#{
|
#{
|
||||||
producer := Producer, partition_key := PartitionKey, record_template := HRecordTemplate
|
producer := Producer, partition_key := PartitionKey, record_template := HRecordTemplate
|
||||||
} = maps:get(ChannelID, Channels),
|
} = maps:get(ChannelID, Channels),
|
||||||
try to_multi_part_records(PartitionKey, HRecordTemplate, BatchList) of
|
try
|
||||||
Records -> append_record(InstId, Producer, Records, true)
|
KeyAndRawRecordList = to_multi_part_key_and_partition_key(
|
||||||
|
PartitionKey, HRecordTemplate, BatchList
|
||||||
|
),
|
||||||
|
emqx_trace:rendered_action_template(ChannelID, #{records => KeyAndRawRecordList}),
|
||||||
|
Records = [to_record(Item) || Item <- KeyAndRawRecordList],
|
||||||
|
append_record(InstId, Producer, Records, true)
|
||||||
catch
|
catch
|
||||||
_:_ -> ?FAILED_TO_APPLY_HRECORD_TEMPLATE
|
_:_ -> ?FAILED_TO_APPLY_HRECORD_TEMPLATE
|
||||||
end.
|
end.
|
||||||
|
@ -348,20 +356,20 @@ ensure_start_producer(ProducerName, ProducerOptions) ->
|
||||||
produce_name(ActionId) ->
|
produce_name(ActionId) ->
|
||||||
list_to_binary("backend_hstream_producer:" ++ to_string(ActionId)).
|
list_to_binary("backend_hstream_producer:" ++ to_string(ActionId)).
|
||||||
|
|
||||||
to_record(PartitionKeyTmpl, HRecordTmpl, Data) ->
|
to_key_and_raw_record(PartitionKeyTmpl, HRecordTmpl, Data) ->
|
||||||
PartitionKey = emqx_placeholder:proc_tmpl(PartitionKeyTmpl, Data),
|
PartitionKey = emqx_placeholder:proc_tmpl(PartitionKeyTmpl, Data),
|
||||||
RawRecord = emqx_placeholder:proc_tmpl(HRecordTmpl, Data),
|
RawRecord = emqx_placeholder:proc_tmpl(HRecordTmpl, Data),
|
||||||
to_record(PartitionKey, RawRecord).
|
#{partition_key => PartitionKey, raw_record => RawRecord}.
|
||||||
|
|
||||||
to_record(PartitionKey, RawRecord) when is_binary(PartitionKey) ->
|
to_record(#{partition_key := PartitionKey, raw_record := RawRecord}) when is_binary(PartitionKey) ->
|
||||||
to_record(binary_to_list(PartitionKey), RawRecord);
|
to_record(#{partition_key => binary_to_list(PartitionKey), raw_record => RawRecord});
|
||||||
to_record(PartitionKey, RawRecord) ->
|
to_record(#{partition_key := PartitionKey, raw_record := RawRecord}) ->
|
||||||
hstreamdb:to_record(PartitionKey, raw, RawRecord).
|
hstreamdb:to_record(PartitionKey, raw, RawRecord).
|
||||||
|
|
||||||
to_multi_part_records(PartitionKeyTmpl, HRecordTmpl, BatchList) ->
|
to_multi_part_key_and_partition_key(PartitionKeyTmpl, HRecordTmpl, BatchList) ->
|
||||||
lists:map(
|
lists:map(
|
||||||
fun({_, Data}) ->
|
fun({_, Data}) ->
|
||||||
to_record(PartitionKeyTmpl, HRecordTmpl, Data)
|
to_key_and_raw_record(PartitionKeyTmpl, HRecordTmpl, Data)
|
||||||
end,
|
end,
|
||||||
BatchList
|
BatchList
|
||||||
).
|
).
|
||||||
|
|
|
@ -359,7 +359,7 @@ on_query(InstId, {Method, Request, Timeout}, State) ->
|
||||||
on_query(
|
on_query(
|
||||||
InstId,
|
InstId,
|
||||||
{ActionId, KeyOrNum, Method, Request, Timeout, Retry},
|
{ActionId, KeyOrNum, Method, Request, Timeout, Retry},
|
||||||
#{base_path := BasePath} = State
|
#{base_path := BasePath, host := Host} = State
|
||||||
) ->
|
) ->
|
||||||
?TRACE(
|
?TRACE(
|
||||||
"QUERY",
|
"QUERY",
|
||||||
|
@ -373,7 +373,7 @@ on_query(
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
NRequest = formalize_request(Method, BasePath, Request),
|
NRequest = formalize_request(Method, BasePath, Request),
|
||||||
trace_rendered_action_template(ActionId, Method, NRequest, Timeout),
|
trace_rendered_action_template(ActionId, Host, Method, NRequest, Timeout),
|
||||||
Worker = resolve_pool_worker(State, KeyOrNum),
|
Worker = resolve_pool_worker(State, KeyOrNum),
|
||||||
Result0 = ehttpc:request(
|
Result0 = ehttpc:request(
|
||||||
Worker,
|
Worker,
|
||||||
|
@ -469,7 +469,7 @@ on_query_async(
|
||||||
InstId,
|
InstId,
|
||||||
{ActionId, KeyOrNum, Method, Request, Timeout},
|
{ActionId, KeyOrNum, Method, Request, Timeout},
|
||||||
ReplyFunAndArgs,
|
ReplyFunAndArgs,
|
||||||
#{base_path := BasePath} = State
|
#{base_path := BasePath, host := Host} = State
|
||||||
) ->
|
) ->
|
||||||
Worker = resolve_pool_worker(State, KeyOrNum),
|
Worker = resolve_pool_worker(State, KeyOrNum),
|
||||||
?TRACE(
|
?TRACE(
|
||||||
|
@ -483,7 +483,7 @@ on_query_async(
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
NRequest = formalize_request(Method, BasePath, Request),
|
NRequest = formalize_request(Method, BasePath, Request),
|
||||||
trace_rendered_action_template(ActionId, Method, NRequest, Timeout),
|
trace_rendered_action_template(ActionId, Host, Method, NRequest, Timeout),
|
||||||
MaxAttempts = maps:get(max_attempts, State, 3),
|
MaxAttempts = maps:get(max_attempts, State, 3),
|
||||||
Context = #{
|
Context = #{
|
||||||
attempt => 1,
|
attempt => 1,
|
||||||
|
@ -503,15 +503,16 @@ on_query_async(
|
||||||
),
|
),
|
||||||
{ok, Worker}.
|
{ok, Worker}.
|
||||||
|
|
||||||
trace_rendered_action_template(ActionId, Method, NRequest, Timeout) ->
|
trace_rendered_action_template(ActionId, Host, Method, NRequest, Timeout) ->
|
||||||
case NRequest of
|
case NRequest of
|
||||||
{Path, Headers} ->
|
{Path, Headers} ->
|
||||||
emqx_trace:rendered_action_template(
|
emqx_trace:rendered_action_template(
|
||||||
ActionId,
|
ActionId,
|
||||||
#{
|
#{
|
||||||
|
host => Host,
|
||||||
path => Path,
|
path => Path,
|
||||||
method => Method,
|
method => Method,
|
||||||
headers => emqx_utils_redact:redact_headers(Headers),
|
headers => {fun emqx_utils_redact:redact_headers/1, Headers},
|
||||||
timeout => Timeout
|
timeout => Timeout
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -519,15 +520,19 @@ trace_rendered_action_template(ActionId, Method, NRequest, Timeout) ->
|
||||||
emqx_trace:rendered_action_template(
|
emqx_trace:rendered_action_template(
|
||||||
ActionId,
|
ActionId,
|
||||||
#{
|
#{
|
||||||
|
host => Host,
|
||||||
path => Path,
|
path => Path,
|
||||||
method => Method,
|
method => Method,
|
||||||
headers => emqx_utils_redact:redact_headers(Headers),
|
headers => {fun emqx_utils_redact:redact_headers/1, Headers},
|
||||||
timeout => Timeout,
|
timeout => Timeout,
|
||||||
body => Body
|
body => {fun log_format_body/1, Body}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
log_format_body(Body) ->
|
||||||
|
unicode:characters_to_binary(Body).
|
||||||
|
|
||||||
resolve_pool_worker(State, undefined) ->
|
resolve_pool_worker(State, undefined) ->
|
||||||
resolve_pool_worker(State, self());
|
resolve_pool_worker(State, self());
|
||||||
resolve_pool_worker(#{pool_name := PoolName} = State, Key) ->
|
resolve_pool_worker(#{pool_name := PoolName} = State, Key) ->
|
||||||
|
|
|
@ -130,7 +130,7 @@ on_query(InstId, {Channel, Message}, #{channels := ChannelConf}) ->
|
||||||
influxdb_connector_send_query,
|
influxdb_connector_send_query,
|
||||||
#{points => Points, batch => false, mode => sync}
|
#{points => Points, batch => false, mode => sync}
|
||||||
),
|
),
|
||||||
do_query(InstId, Client, Points);
|
do_query(InstId, Channel, Client, Points);
|
||||||
{error, ErrorPoints} ->
|
{error, ErrorPoints} ->
|
||||||
?tp(
|
?tp(
|
||||||
influxdb_connector_send_query_error,
|
influxdb_connector_send_query_error,
|
||||||
|
@ -152,7 +152,7 @@ on_batch_query(InstId, BatchData, #{channels := ChannelConf}) ->
|
||||||
influxdb_connector_send_query,
|
influxdb_connector_send_query,
|
||||||
#{points => Points, batch => true, mode => sync}
|
#{points => Points, batch => true, mode => sync}
|
||||||
),
|
),
|
||||||
do_query(InstId, Client, Points);
|
do_query(InstId, Channel, Client, Points);
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
?tp(
|
?tp(
|
||||||
influxdb_connector_send_query_error,
|
influxdb_connector_send_query_error,
|
||||||
|
@ -175,7 +175,7 @@ on_query_async(
|
||||||
influxdb_connector_send_query,
|
influxdb_connector_send_query,
|
||||||
#{points => Points, batch => false, mode => async}
|
#{points => Points, batch => false, mode => async}
|
||||||
),
|
),
|
||||||
do_async_query(InstId, Client, Points, {ReplyFun, Args});
|
do_async_query(InstId, Channel, Client, Points, {ReplyFun, Args});
|
||||||
{error, ErrorPoints} = Err ->
|
{error, ErrorPoints} = Err ->
|
||||||
?tp(
|
?tp(
|
||||||
influxdb_connector_send_query_error,
|
influxdb_connector_send_query_error,
|
||||||
|
@ -200,7 +200,7 @@ on_batch_query_async(
|
||||||
influxdb_connector_send_query,
|
influxdb_connector_send_query,
|
||||||
#{points => Points, batch => true, mode => async}
|
#{points => Points, batch => true, mode => async}
|
||||||
),
|
),
|
||||||
do_async_query(InstId, Client, Points, {ReplyFun, Args});
|
do_async_query(InstId, Channel, Client, Points, {ReplyFun, Args});
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
?tp(
|
?tp(
|
||||||
influxdb_connector_send_query_error,
|
influxdb_connector_send_query_error,
|
||||||
|
@ -496,7 +496,8 @@ is_auth_key(_) ->
|
||||||
|
|
||||||
%% -------------------------------------------------------------------------------------------------
|
%% -------------------------------------------------------------------------------------------------
|
||||||
%% Query
|
%% Query
|
||||||
do_query(InstId, Client, Points) ->
|
do_query(InstId, Channel, Client, Points) ->
|
||||||
|
emqx_trace:rendered_action_template(Channel, #{points => Points, is_async => false}),
|
||||||
case influxdb:write(Client, Points) of
|
case influxdb:write(Client, Points) of
|
||||||
ok ->
|
ok ->
|
||||||
?SLOG(debug, #{
|
?SLOG(debug, #{
|
||||||
|
@ -527,12 +528,13 @@ do_query(InstId, Client, Points) ->
|
||||||
end
|
end
|
||||||
end.
|
end.
|
||||||
|
|
||||||
do_async_query(InstId, Client, Points, ReplyFunAndArgs) ->
|
do_async_query(InstId, Channel, Client, Points, ReplyFunAndArgs) ->
|
||||||
?SLOG(info, #{
|
?SLOG(info, #{
|
||||||
msg => "influxdb_write_point_async",
|
msg => "influxdb_write_point_async",
|
||||||
connector => InstId,
|
connector => InstId,
|
||||||
points => Points
|
points => Points
|
||||||
}),
|
}),
|
||||||
|
emqx_trace:rendered_action_template(Channel, #{points => Points, is_async => true}),
|
||||||
WrappedReplyFunAndArgs = {fun ?MODULE:reply_callback/2, [ReplyFunAndArgs]},
|
WrappedReplyFunAndArgs = {fun ?MODULE:reply_callback/2, [ReplyFunAndArgs]},
|
||||||
{ok, _WorkerPid} = influxdb:write_async(Client, Points, WrappedReplyFunAndArgs).
|
{ok, _WorkerPid} = influxdb:write_async(Client, Points, WrappedReplyFunAndArgs).
|
||||||
|
|
||||||
|
|
|
@ -319,6 +319,9 @@ on_query(
|
||||||
emqx_bridge_kafka_impl_producer_sync_query,
|
emqx_bridge_kafka_impl_producer_sync_query,
|
||||||
#{headers_config => KafkaHeaders, instance_id => InstId}
|
#{headers_config => KafkaHeaders, instance_id => InstId}
|
||||||
),
|
),
|
||||||
|
emqx_trace:rendered_action_template(MessageTag, #{
|
||||||
|
message => KafkaMessage, send_type => sync
|
||||||
|
}),
|
||||||
do_send_msg(sync, KafkaMessage, Producers, SyncTimeout)
|
do_send_msg(sync, KafkaMessage, Producers, SyncTimeout)
|
||||||
catch
|
catch
|
||||||
throw:{bad_kafka_header, _} = Error ->
|
throw:{bad_kafka_header, _} = Error ->
|
||||||
|
@ -376,6 +379,9 @@ on_query_async(
|
||||||
emqx_bridge_kafka_impl_producer_async_query,
|
emqx_bridge_kafka_impl_producer_async_query,
|
||||||
#{headers_config => KafkaHeaders, instance_id => InstId}
|
#{headers_config => KafkaHeaders, instance_id => InstId}
|
||||||
),
|
),
|
||||||
|
emqx_trace:rendered_action_template(MessageTag, #{
|
||||||
|
message => KafkaMessage, send_type => async
|
||||||
|
}),
|
||||||
do_send_msg(async, KafkaMessage, Producers, AsyncReplyFn)
|
do_send_msg(async, KafkaMessage, Producers, AsyncReplyFn)
|
||||||
catch
|
catch
|
||||||
error:{invalid_partition_count, _Count, _Partitioner} ->
|
error:{invalid_partition_count, _Count, _Partitioner} ->
|
||||||
|
|
|
@ -261,6 +261,11 @@ do_send_requests_sync(
|
||||||
stream_name := StreamName
|
stream_name := StreamName
|
||||||
} = maps:get(ChannelId, InstalledChannels),
|
} = maps:get(ChannelId, InstalledChannels),
|
||||||
Records = render_records(Requests, Templates),
|
Records = render_records(Requests, Templates),
|
||||||
|
StructuredRecords = [
|
||||||
|
#{data => Data, partition_key => PartitionKey}
|
||||||
|
|| {Data, PartitionKey} <- Records
|
||||||
|
],
|
||||||
|
emqx_trace:rendered_action_template(ChannelId, StructuredRecords),
|
||||||
Result = ecpool:pick_and_do(
|
Result = ecpool:pick_and_do(
|
||||||
PoolName,
|
PoolName,
|
||||||
{emqx_bridge_kinesis_connector_client, query, [Records, StreamName]},
|
{emqx_bridge_kinesis_connector_client, query, [Records, StreamName]},
|
||||||
|
|
|
@ -66,10 +66,15 @@ on_query(InstanceId, {Channel, Message0}, #{channels := Channels, connector_stat
|
||||||
payload_template := PayloadTemplate,
|
payload_template := PayloadTemplate,
|
||||||
collection_template := CollectionTemplate
|
collection_template := CollectionTemplate
|
||||||
} = ChannelState0 = maps:get(Channel, Channels),
|
} = ChannelState0 = maps:get(Channel, Channels),
|
||||||
|
Collection = emqx_placeholder:proc_tmpl(CollectionTemplate, Message0),
|
||||||
ChannelState = ChannelState0#{
|
ChannelState = ChannelState0#{
|
||||||
collection => emqx_placeholder:proc_tmpl(CollectionTemplate, Message0)
|
collection => Collection
|
||||||
},
|
},
|
||||||
Message = render_message(PayloadTemplate, Message0),
|
Message = render_message(PayloadTemplate, Message0),
|
||||||
|
emqx_trace:rendered_action_template(Channel, #{
|
||||||
|
collection => Collection,
|
||||||
|
data => Message
|
||||||
|
}),
|
||||||
Res = emqx_mongodb:on_query(
|
Res = emqx_mongodb:on_query(
|
||||||
InstanceId,
|
InstanceId,
|
||||||
{Channel, Message},
|
{Channel, Message},
|
||||||
|
|
|
@ -264,7 +264,7 @@ on_query(
|
||||||
),
|
),
|
||||||
Channels = maps:get(installed_channels, State),
|
Channels = maps:get(installed_channels, State),
|
||||||
ChannelConfig = maps:get(ChannelId, Channels),
|
ChannelConfig = maps:get(ChannelId, Channels),
|
||||||
handle_send_result(with_egress_client(PoolName, send, [Msg, ChannelConfig]));
|
handle_send_result(with_egress_client(ChannelId, PoolName, send, [Msg, ChannelConfig]));
|
||||||
on_query(ResourceId, {_ChannelId, Msg}, #{}) ->
|
on_query(ResourceId, {_ChannelId, Msg}, #{}) ->
|
||||||
?SLOG(error, #{
|
?SLOG(error, #{
|
||||||
msg => "forwarding_unavailable",
|
msg => "forwarding_unavailable",
|
||||||
|
@ -283,7 +283,7 @@ on_query_async(
|
||||||
Callback = {fun on_async_result/2, [CallbackIn]},
|
Callback = {fun on_async_result/2, [CallbackIn]},
|
||||||
Channels = maps:get(installed_channels, State),
|
Channels = maps:get(installed_channels, State),
|
||||||
ChannelConfig = maps:get(ChannelId, Channels),
|
ChannelConfig = maps:get(ChannelId, Channels),
|
||||||
Result = with_egress_client(PoolName, send_async, [Msg, Callback, ChannelConfig]),
|
Result = with_egress_client(ChannelId, PoolName, send_async, [Msg, Callback, ChannelConfig]),
|
||||||
case Result of
|
case Result of
|
||||||
ok ->
|
ok ->
|
||||||
ok;
|
ok;
|
||||||
|
@ -300,8 +300,11 @@ on_query_async(ResourceId, {_ChannelId, Msg}, _Callback, #{}) ->
|
||||||
reason => "Egress is not configured"
|
reason => "Egress is not configured"
|
||||||
}).
|
}).
|
||||||
|
|
||||||
with_egress_client(ResourceId, Fun, Args) ->
|
with_egress_client(ActionID, ResourceId, Fun, Args) ->
|
||||||
ecpool:pick_and_do(ResourceId, {emqx_bridge_mqtt_egress, Fun, Args}, no_handover).
|
TraceRenderedCTX = emqx_trace:make_rendered_action_template_trace_context(ActionID),
|
||||||
|
ecpool:pick_and_do(
|
||||||
|
ResourceId, {emqx_bridge_mqtt_egress, Fun, [TraceRenderedCTX | Args]}, no_handover
|
||||||
|
).
|
||||||
|
|
||||||
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)).
|
||||||
|
@ -337,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}.
|
||||||
|
|
||||||
|
|
|
@ -22,8 +22,8 @@
|
||||||
|
|
||||||
-export([
|
-export([
|
||||||
config/1,
|
config/1,
|
||||||
send/3,
|
send/4,
|
||||||
send_async/4
|
send_async/5
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-type message() :: emqx_types:message() | map().
|
-type message() :: emqx_types:message() | map().
|
||||||
|
@ -42,25 +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(), message(), egress()) -> ok.
|
-spec send(pid(), emqx_trace:rendered_action_template_ctx(), message(), egress()) ->
|
||||||
send(Pid, MsgIn, Egress) ->
|
ok | {error, {unrecoverable_error, term()}}.
|
||||||
emqtt:publish(Pid, export_msg(MsgIn, Egress)).
|
send(Pid, TraceRenderedCTX, MsgIn, Egress) ->
|
||||||
|
try
|
||||||
|
emqtt:publish(Pid, export_msg(MsgIn, Egress, TraceRenderedCTX))
|
||||||
|
catch
|
||||||
|
error:{unrecoverable_error, Reason} ->
|
||||||
|
{error, {unrecoverable_error, Reason}}
|
||||||
|
end.
|
||||||
|
|
||||||
-spec send_async(pid(), 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, MsgIn, Callback, Egress) ->
|
send_async(Pid, TraceRenderedCTX, MsgIn, Callback, Egress) ->
|
||||||
ok = emqtt:publish_async(Pid, export_msg(MsgIn, Egress), _Timeout = infinity, Callback),
|
try
|
||||||
{ok, Pid}.
|
ok = emqtt:publish_async(
|
||||||
|
Pid, export_msg(MsgIn, Egress, TraceRenderedCTX), _Timeout = infinity, Callback
|
||||||
|
),
|
||||||
|
{ok, Pid}
|
||||||
|
catch
|
||||||
|
error:{unrecoverable_error, Reason} ->
|
||||||
|
{error, {unrecoverable_error, Reason}}
|
||||||
|
end.
|
||||||
|
|
||||||
export_msg(Msg, #{remote := Remote}) ->
|
export_msg(Msg, #{remote := Remote}, TraceRenderedCTX) ->
|
||||||
to_remote_msg(Msg, Remote).
|
to_remote_msg(Msg, Remote, TraceRenderedCTX).
|
||||||
|
|
||||||
-spec to_remote_msg(message(), emqx_bridge_mqtt_msg:msgvars()) ->
|
-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) ->
|
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);
|
to_remote_msg(EventMsg#{retain => maps:get(retain, Flags, false)}, Vars, TraceRenderedCTX);
|
||||||
to_remote_msg(Msg = #{}, Remote) ->
|
to_remote_msg(Msg = #{}, Remote, TraceRenderedCTX) ->
|
||||||
#{
|
#{
|
||||||
topic := Topic,
|
topic := Topic,
|
||||||
payload := Payload,
|
payload := Payload,
|
||||||
|
@ -68,6 +83,13 @@ to_remote_msg(Msg = #{}, Remote) ->
|
||||||
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, #{}),
|
||||||
|
emqx_trace:rendered_action_template_with_ctx(TraceRenderedCTX, #{
|
||||||
|
qos => QoS,
|
||||||
|
retain => Retain,
|
||||||
|
topic => Topic,
|
||||||
|
props => PubProps,
|
||||||
|
payload => Payload
|
||||||
|
}),
|
||||||
#mqtt_msg{
|
#mqtt_msg{
|
||||||
qos = QoS,
|
qos = QoS,
|
||||||
retain = Retain,
|
retain = Retain,
|
||||||
|
|
|
@ -104,10 +104,12 @@ on_query(
|
||||||
#{channels := Channels, connector_state := ConnectorState}
|
#{channels := Channels, connector_state := ConnectorState}
|
||||||
) when is_binary(Channel) ->
|
) when is_binary(Channel) ->
|
||||||
ChannelConfig = maps:get(Channel, Channels),
|
ChannelConfig = maps:get(Channel, Channels),
|
||||||
|
MergedState0 = maps:merge(ConnectorState, ChannelConfig),
|
||||||
|
MergedState1 = MergedState0#{channel_id => Channel},
|
||||||
Result = emqx_mysql:on_query(
|
Result = emqx_mysql:on_query(
|
||||||
InstanceId,
|
InstanceId,
|
||||||
Request,
|
Request,
|
||||||
maps:merge(ConnectorState, ChannelConfig)
|
MergedState1
|
||||||
),
|
),
|
||||||
?tp(mysql_connector_on_query_return, #{instance_id => InstanceId, result => Result}),
|
?tp(mysql_connector_on_query_return, #{instance_id => InstanceId, result => Result}),
|
||||||
Result;
|
Result;
|
||||||
|
@ -121,10 +123,12 @@ on_batch_query(
|
||||||
) when is_binary(element(1, Req)) ->
|
) when is_binary(element(1, Req)) ->
|
||||||
Channel = element(1, Req),
|
Channel = element(1, Req),
|
||||||
ChannelConfig = maps:get(Channel, Channels),
|
ChannelConfig = maps:get(Channel, Channels),
|
||||||
|
MergedState0 = maps:merge(ConnectorState, ChannelConfig),
|
||||||
|
MergedState1 = MergedState0#{channel_id => Channel},
|
||||||
Result = emqx_mysql:on_batch_query(
|
Result = emqx_mysql:on_batch_query(
|
||||||
InstanceId,
|
InstanceId,
|
||||||
BatchRequest,
|
BatchRequest,
|
||||||
maps:merge(ConnectorState, ChannelConfig)
|
MergedState1
|
||||||
),
|
),
|
||||||
?tp(mysql_connector_on_batch_query_return, #{instance_id => InstanceId, result => Result}),
|
?tp(mysql_connector_on_batch_query_return, #{instance_id => InstanceId, result => Result}),
|
||||||
Result;
|
Result;
|
||||||
|
|
|
@ -167,9 +167,10 @@ on_batch_query(
|
||||||
BatchReq,
|
BatchReq,
|
||||||
#{channels := Channels} = State
|
#{channels := Channels} = State
|
||||||
) ->
|
) ->
|
||||||
|
[{ChannelId, _} | _] = BatchReq,
|
||||||
case try_render_messages(BatchReq, Channels) of
|
case try_render_messages(BatchReq, Channels) of
|
||||||
{ok, Datas} ->
|
{ok, Datas} ->
|
||||||
do_query(InstanceId, Datas, State);
|
do_query(InstanceId, ChannelId, Datas, State);
|
||||||
Error ->
|
Error ->
|
||||||
Error
|
Error
|
||||||
end.
|
end.
|
||||||
|
@ -222,12 +223,13 @@ on_get_channel_status(InstanceId, ChannelId, #{channels := Channels} = State) ->
|
||||||
%% Helper fns
|
%% Helper fns
|
||||||
%%========================================================================================
|
%%========================================================================================
|
||||||
|
|
||||||
do_query(InstanceId, Query, #{pool_name := PoolName} = State) ->
|
do_query(InstanceId, ChannelID, Query, #{pool_name := PoolName} = State) ->
|
||||||
?TRACE(
|
?TRACE(
|
||||||
"QUERY",
|
"QUERY",
|
||||||
"opents_connector_received",
|
"opents_connector_received",
|
||||||
#{connector => InstanceId, query => Query, state => State}
|
#{connector => InstanceId, query => Query, state => State}
|
||||||
),
|
),
|
||||||
|
emqx_trace:rendered_action_template(ChannelID, #{query => Query}),
|
||||||
|
|
||||||
?tp(opents_bridge_on_query, #{instance_id => InstanceId}),
|
?tp(opents_bridge_on_query, #{instance_id => InstanceId}),
|
||||||
|
|
||||||
|
|
|
@ -196,6 +196,11 @@ on_query(_InstanceId, {ChannelId, Message}, State) ->
|
||||||
{error, channel_not_found};
|
{error, channel_not_found};
|
||||||
{ok, #{message := MessageTmpl, sync_timeout := SyncTimeout, producers := Producers}} ->
|
{ok, #{message := MessageTmpl, sync_timeout := SyncTimeout, producers := Producers}} ->
|
||||||
PulsarMessage = render_message(Message, MessageTmpl),
|
PulsarMessage = render_message(Message, MessageTmpl),
|
||||||
|
emqx_trace:rendered_action_template(ChannelId, #{
|
||||||
|
message => PulsarMessage,
|
||||||
|
sync_timeout => SyncTimeout,
|
||||||
|
is_async => false
|
||||||
|
}),
|
||||||
try
|
try
|
||||||
pulsar:send_sync(Producers, [PulsarMessage], SyncTimeout)
|
pulsar:send_sync(Producers, [PulsarMessage], SyncTimeout)
|
||||||
catch
|
catch
|
||||||
|
@ -217,12 +222,16 @@ on_query_async(_InstanceId, {ChannelId, Message}, AsyncReplyFn, State) ->
|
||||||
?tp_span(
|
?tp_span(
|
||||||
pulsar_producer_on_query_async,
|
pulsar_producer_on_query_async,
|
||||||
#{instance_id => _InstanceId, message => Message},
|
#{instance_id => _InstanceId, message => Message},
|
||||||
on_query_async2(Producers, Message, MessageTmpl, AsyncReplyFn)
|
on_query_async2(ChannelId, Producers, Message, MessageTmpl, AsyncReplyFn)
|
||||||
)
|
)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
on_query_async2(Producers, Message, MessageTmpl, AsyncReplyFn) ->
|
on_query_async2(ChannelId, Producers, Message, MessageTmpl, AsyncReplyFn) ->
|
||||||
PulsarMessage = render_message(Message, MessageTmpl),
|
PulsarMessage = render_message(Message, MessageTmpl),
|
||||||
|
emqx_trace:rendered_action_template(ChannelId, #{
|
||||||
|
message => PulsarMessage,
|
||||||
|
is_async => true
|
||||||
|
}),
|
||||||
pulsar:send(Producers, [PulsarMessage], #{callback_fn => AsyncReplyFn}).
|
pulsar:send(Producers, [PulsarMessage], #{callback_fn => AsyncReplyFn}).
|
||||||
|
|
||||||
%%-------------------------------------------------------------------------------------
|
%%-------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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").
|
||||||
|
|
||||||
|
@ -41,7 +42,7 @@
|
||||||
-export([connect/1]).
|
-export([connect/1]).
|
||||||
|
|
||||||
%% Internal callbacks
|
%% Internal callbacks
|
||||||
-export([publish_messages/4]).
|
-export([publish_messages/5]).
|
||||||
|
|
||||||
namespace() -> "rabbitmq".
|
namespace() -> "rabbitmq".
|
||||||
|
|
||||||
|
@ -214,9 +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}} ->
|
||||||
|
TraceRenderedCTX = emqx_trace:make_rendered_action_template_trace_context(ChannelId),
|
||||||
Res = ecpool:pick_and_do(
|
Res = ecpool:pick_and_do(
|
||||||
ResourceID,
|
ResourceID,
|
||||||
{?MODULE, publish_messages, [RabbitMQ, ProcParam, [MsgReq]]},
|
{?MODULE, publish_messages, [RabbitMQ, ProcParam, [MsgReq], TraceRenderedCTX]},
|
||||||
no_handover
|
no_handover
|
||||||
),
|
),
|
||||||
handle_result(Res);
|
handle_result(Res);
|
||||||
|
@ -234,9 +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}} ->
|
||||||
|
TraceRenderedCTX = emqx_trace:make_rendered_action_template_trace_context(ChannelId),
|
||||||
Res = ecpool:pick_and_do(
|
Res = ecpool:pick_and_do(
|
||||||
ResourceID,
|
ResourceID,
|
||||||
{?MODULE, publish_messages, [RabbitMQ, ProcParam, Batch]},
|
{?MODULE, publish_messages, [RabbitMQ, ProcParam, Batch, TraceRenderedCTX]},
|
||||||
no_handover
|
no_handover
|
||||||
),
|
),
|
||||||
handle_result(Res);
|
handle_result(Res);
|
||||||
|
@ -255,7 +258,8 @@ publish_messages(
|
||||||
wait_for_publish_confirmations := WaitForPublishConfirmations,
|
wait_for_publish_confirmations := WaitForPublishConfirmations,
|
||||||
publish_confirmation_timeout := PublishConfirmationTimeout
|
publish_confirmation_timeout := PublishConfirmationTimeout
|
||||||
},
|
},
|
||||||
Messages
|
Messages,
|
||||||
|
TraceRenderedCTX
|
||||||
) ->
|
) ->
|
||||||
try
|
try
|
||||||
publish_messages(
|
publish_messages(
|
||||||
|
@ -267,15 +271,18 @@ publish_messages(
|
||||||
PayloadTmpl,
|
PayloadTmpl,
|
||||||
Messages,
|
Messages,
|
||||||
WaitForPublishConfirmations,
|
WaitForPublishConfirmations,
|
||||||
PublishConfirmationTimeout
|
PublishConfirmationTimeout,
|
||||||
|
TraceRenderedCTX
|
||||||
)
|
)
|
||||||
catch
|
catch
|
||||||
|
error:?EMQX_TRACE_STOP_ACTION_MATCH = 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 '/'">>}
|
||||||
%% so we catch and return {recoverable_error, Reason} to increase metrics
|
%% so we catch and return {recoverable_error, Reason} to increase metrics
|
||||||
_Type:Reason ->
|
_Type:Reason ->
|
||||||
Msg = iolist_to_binary(io_lib:format("RabbitMQ: publish_failed: ~p", [Reason])),
|
Msg = iolist_to_binary(io_lib:format("RabbitMQ: publish_failed: ~p", [Reason])),
|
||||||
erlang:error({recoverable_error, Msg})
|
{error, {recoverable_error, Msg}}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
publish_messages(
|
publish_messages(
|
||||||
|
@ -287,7 +294,8 @@ publish_messages(
|
||||||
PayloadTmpl,
|
PayloadTmpl,
|
||||||
Messages,
|
Messages,
|
||||||
WaitForPublishConfirmations,
|
WaitForPublishConfirmations,
|
||||||
PublishConfirmationTimeout
|
PublishConfirmationTimeout,
|
||||||
|
TraceRenderedCTX
|
||||||
) ->
|
) ->
|
||||||
case maps:find(Conn, RabbitMQ) of
|
case maps:find(Conn, RabbitMQ) of
|
||||||
{ok, Channel} ->
|
{ok, Channel} ->
|
||||||
|
@ -299,18 +307,33 @@ publish_messages(
|
||||||
exchange = Exchange,
|
exchange = Exchange,
|
||||||
routing_key = RoutingKey
|
routing_key = RoutingKey
|
||||||
},
|
},
|
||||||
|
FormattedMsgs = [
|
||||||
|
format_data(PayloadTmpl, M)
|
||||||
|
|| {_, M} <- Messages
|
||||||
|
],
|
||||||
|
emqx_trace:rendered_action_template_with_ctx(TraceRenderedCTX, #{
|
||||||
|
messages => FormattedMsgs,
|
||||||
|
properties => #{
|
||||||
|
headers => [],
|
||||||
|
delivery_mode => DeliveryMode
|
||||||
|
},
|
||||||
|
method => #{
|
||||||
|
exchange => Exchange,
|
||||||
|
routing_key => RoutingKey
|
||||||
|
}
|
||||||
|
}),
|
||||||
lists:foreach(
|
lists:foreach(
|
||||||
fun({_, MsgRaw}) ->
|
fun(Msg) ->
|
||||||
amqp_channel:cast(
|
amqp_channel:cast(
|
||||||
Channel,
|
Channel,
|
||||||
Method,
|
Method,
|
||||||
#amqp_msg{
|
#amqp_msg{
|
||||||
payload = format_data(PayloadTmpl, MsgRaw),
|
payload = Msg,
|
||||||
props = MessageProperties
|
props = MessageProperties
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
end,
|
end,
|
||||||
Messages
|
FormattedMsgs
|
||||||
),
|
),
|
||||||
case WaitForPublishConfirmations of
|
case WaitForPublishConfirmations of
|
||||||
true ->
|
true ->
|
||||||
|
|
|
@ -107,7 +107,7 @@ on_query(InstId, {cmd, Cmd}, #{conn_st := RedisConnSt}) ->
|
||||||
Result;
|
Result;
|
||||||
on_query(
|
on_query(
|
||||||
InstId,
|
InstId,
|
||||||
{_MessageTag, _Data} = Msg,
|
{MessageTag, _Data} = Msg,
|
||||||
#{channels := Channels, conn_st := RedisConnSt}
|
#{channels := Channels, conn_st := RedisConnSt}
|
||||||
) ->
|
) ->
|
||||||
case try_render_message([Msg], Channels) of
|
case try_render_message([Msg], Channels) of
|
||||||
|
@ -116,6 +116,10 @@ on_query(
|
||||||
redis_bridge_connector_cmd,
|
redis_bridge_connector_cmd,
|
||||||
#{cmd => Cmd, batch => false, mode => sync}
|
#{cmd => Cmd, batch => false, mode => sync}
|
||||||
),
|
),
|
||||||
|
emqx_trace:rendered_action_template(
|
||||||
|
MessageTag,
|
||||||
|
#{command => Cmd, batch => false, mode => sync}
|
||||||
|
),
|
||||||
Result = query(InstId, {cmd, Cmd}, RedisConnSt),
|
Result = query(InstId, {cmd, Cmd}, RedisConnSt),
|
||||||
?tp(
|
?tp(
|
||||||
redis_bridge_connector_send_done,
|
redis_bridge_connector_send_done,
|
||||||
|
@ -135,6 +139,11 @@ on_batch_query(
|
||||||
redis_bridge_connector_send,
|
redis_bridge_connector_send,
|
||||||
#{batch_data => BatchData, batch => true, mode => sync}
|
#{batch_data => BatchData, batch => true, mode => sync}
|
||||||
),
|
),
|
||||||
|
[{ChannelID, _} | _] = BatchData,
|
||||||
|
emqx_trace:rendered_action_template(
|
||||||
|
ChannelID,
|
||||||
|
#{commands => Cmds, batch => ture, mode => sync}
|
||||||
|
),
|
||||||
Result = query(InstId, {cmds, Cmds}, RedisConnSt),
|
Result = query(InstId, {cmds, Cmds}, RedisConnSt),
|
||||||
?tp(
|
?tp(
|
||||||
redis_bridge_connector_send_done,
|
redis_bridge_connector_send_done,
|
||||||
|
|
|
@ -264,7 +264,11 @@ do_query(
|
||||||
|
|
||||||
TopicKey = get_topic_key(Query, TopicTks),
|
TopicKey = get_topic_key(Query, TopicTks),
|
||||||
Data = apply_template(Query, Templates, DispatchStrategy),
|
Data = apply_template(Query, Templates, DispatchStrategy),
|
||||||
|
emqx_trace:rendered_action_template(ChannelId, #{
|
||||||
|
topic_key => TopicKey,
|
||||||
|
data => Data,
|
||||||
|
request_timeout => RequestTimeout
|
||||||
|
}),
|
||||||
Result = safe_do_produce(
|
Result = safe_do_produce(
|
||||||
ChannelId, InstanceId, QueryFunc, ClientId, TopicKey, Data, ProducerOpts, RequestTimeout
|
ChannelId, InstanceId, QueryFunc, ClientId, TopicKey, Data, ProducerOpts, RequestTimeout
|
||||||
),
|
),
|
||||||
|
|
|
@ -168,13 +168,14 @@ init_channel_state(#{parameters := Parameters}) ->
|
||||||
on_query(InstId, {Tag, Data}, #{client_config := Config, channels := Channels}) ->
|
on_query(InstId, {Tag, Data}, #{client_config := Config, channels := Channels}) ->
|
||||||
case maps:get(Tag, Channels, undefined) of
|
case maps:get(Tag, Channels, undefined) of
|
||||||
ChannelState = #{} ->
|
ChannelState = #{} ->
|
||||||
run_simple_upload(InstId, Data, ChannelState, Config);
|
run_simple_upload(InstId, Tag, Data, ChannelState, Config);
|
||||||
undefined ->
|
undefined ->
|
||||||
{error, {unrecoverable_error, {invalid_message_tag, Tag}}}
|
{error, {unrecoverable_error, {invalid_message_tag, Tag}}}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
run_simple_upload(
|
run_simple_upload(
|
||||||
InstId,
|
InstId,
|
||||||
|
ChannelID,
|
||||||
Data,
|
Data,
|
||||||
#{
|
#{
|
||||||
bucket := BucketTemplate,
|
bucket := BucketTemplate,
|
||||||
|
@ -188,6 +189,11 @@ run_simple_upload(
|
||||||
Client = emqx_s3_client:create(Bucket, Config),
|
Client = emqx_s3_client:create(Bucket, Config),
|
||||||
Key = render_key(KeyTemplate, Data),
|
Key = render_key(KeyTemplate, Data),
|
||||||
Content = render_content(ContentTemplate, Data),
|
Content = render_content(ContentTemplate, Data),
|
||||||
|
emqx_trace:rendered_action_template(ChannelID, #{
|
||||||
|
bucket => Bucket,
|
||||||
|
key => Key,
|
||||||
|
content => Content
|
||||||
|
}),
|
||||||
case emqx_s3_client:put_object(Client, Key, UploadOpts, Content) of
|
case emqx_s3_client:put_object(Client, Key, UploadOpts, Content) of
|
||||||
ok ->
|
ok ->
|
||||||
?tp(s3_bridge_connector_upload_ok, #{
|
?tp(s3_bridge_connector_upload_ok, #{
|
||||||
|
|
|
@ -413,6 +413,9 @@ do_query(
|
||||||
%% only insert sql statement for single query and batch query
|
%% only insert sql statement for single query and batch query
|
||||||
case apply_template(QueryTuple, Templates) of
|
case apply_template(QueryTuple, Templates) of
|
||||||
{?ACTION_SEND_MESSAGE, SQL} ->
|
{?ACTION_SEND_MESSAGE, SQL} ->
|
||||||
|
emqx_trace:rendered_action_template(ChannelId, #{
|
||||||
|
sql => SQL
|
||||||
|
}),
|
||||||
Result = ecpool:pick_and_do(
|
Result = ecpool:pick_and_do(
|
||||||
PoolName,
|
PoolName,
|
||||||
{?MODULE, worker_do_insert, [SQL, State]},
|
{?MODULE, worker_do_insert, [SQL, State]},
|
||||||
|
|
|
@ -273,6 +273,8 @@ do_query(
|
||||||
Result =
|
Result =
|
||||||
case try_render_message(Query, Channels) of
|
case try_render_message(Query, Channels) of
|
||||||
{ok, Msg} ->
|
{ok, Msg} ->
|
||||||
|
[{ChannelID, _} | _] = Query,
|
||||||
|
emqx_trace:rendered_action_template(ChannelID, #{message => Msg}),
|
||||||
ecpool:pick_and_do(
|
ecpool:pick_and_do(
|
||||||
PoolName,
|
PoolName,
|
||||||
{emqx_bridge_syskeeper_client, forward, [Msg, AckTimeout + ?EXTRA_CALL_TIMEOUT]},
|
{emqx_bridge_syskeeper_client, forward, [Msg, AckTimeout + ?EXTRA_CALL_TIMEOUT]},
|
||||||
|
|
|
@ -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").
|
||||||
|
@ -32,7 +33,7 @@
|
||||||
|
|
||||||
-export([connector_examples/1]).
|
-export([connector_examples/1]).
|
||||||
|
|
||||||
-export([connect/1, do_get_status/1, execute/3, do_batch_insert/4]).
|
-export([connect/1, do_get_status/1, execute/3, do_batch_insert/5]).
|
||||||
|
|
||||||
-import(hoconsc, [mk/2, enum/1, ref/2]).
|
-import(hoconsc, [mk/2, enum/1, ref/2]).
|
||||||
|
|
||||||
|
@ -186,6 +187,7 @@ on_query(InstanceId, {ChannelId, Data}, #{channels := Channels} = State) ->
|
||||||
case maps:find(ChannelId, Channels) of
|
case maps:find(ChannelId, Channels) of
|
||||||
{ok, #{insert := Tokens, opts := Opts}} ->
|
{ok, #{insert := Tokens, opts := Opts}} ->
|
||||||
Query = emqx_placeholder:proc_tmpl(Tokens, Data),
|
Query = emqx_placeholder:proc_tmpl(Tokens, Data),
|
||||||
|
emqx_trace:rendered_action_template(ChannelId, #{query => Query}),
|
||||||
do_query_job(InstanceId, {?MODULE, execute, [Query, Opts]}, State);
|
do_query_job(InstanceId, {?MODULE, execute, [Query, Opts]}, State);
|
||||||
_ ->
|
_ ->
|
||||||
{error, {unrecoverable_error, {invalid_channel_id, InstanceId}}}
|
{error, {unrecoverable_error, {invalid_channel_id, InstanceId}}}
|
||||||
|
@ -199,9 +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}} ->
|
||||||
|
TraceRenderedCTX = emqx_trace:make_rendered_action_template_trace_context(ChannelId),
|
||||||
do_query_job(
|
do_query_job(
|
||||||
InstanceId,
|
InstanceId,
|
||||||
{?MODULE, do_batch_insert, [Tokens, BatchReq, Opts]},
|
{?MODULE, do_batch_insert, [Tokens, BatchReq, Opts, TraceRenderedCTX]},
|
||||||
State
|
State
|
||||||
);
|
);
|
||||||
_ ->
|
_ ->
|
||||||
|
@ -338,9 +341,18 @@ 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) ->
|
do_batch_insert(Conn, Tokens, BatchReqs, Opts, TraceRenderedCTX) ->
|
||||||
SQL = aggregate_query(Tokens, BatchReqs, <<"INSERT INTO">>),
|
SQL = aggregate_query(Tokens, BatchReqs, <<"INSERT INTO">>),
|
||||||
execute(Conn, SQL, Opts).
|
try
|
||||||
|
emqx_trace:rendered_action_template_with_ctx(
|
||||||
|
TraceRenderedCTX,
|
||||||
|
#{query => SQL}
|
||||||
|
),
|
||||||
|
execute(Conn, SQL, Opts)
|
||||||
|
catch
|
||||||
|
error:?EMQX_TRACE_STOP_ACTION_MATCH = Reason ->
|
||||||
|
{error, Reason}
|
||||||
|
end.
|
||||||
|
|
||||||
aggregate_query(BatchTks, BatchReqs, Acc) ->
|
aggregate_query(BatchTks, BatchReqs, Acc) ->
|
||||||
lists:foldl(
|
lists:foldl(
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{application, emqx_mysql, [
|
{application, emqx_mysql, [
|
||||||
{description, "EMQX MySQL Database Connector"},
|
{description, "EMQX MySQL Database Connector"},
|
||||||
{vsn, "0.1.8"},
|
{vsn, "0.1.9"},
|
||||||
{registered, []},
|
{registered, []},
|
||||||
{applications, [
|
{applications, [
|
||||||
kernel,
|
kernel,
|
||||||
|
|
|
@ -498,6 +498,8 @@ on_sql_query(
|
||||||
) ->
|
) ->
|
||||||
LogMeta = #{connector => InstId, sql => SQLOrKey, state => State},
|
LogMeta = #{connector => InstId, sql => SQLOrKey, state => State},
|
||||||
?TRACE("QUERY", "mysql_connector_received", LogMeta),
|
?TRACE("QUERY", "mysql_connector_received", LogMeta),
|
||||||
|
ChannelID = maps:get(channel_id, State, no_channel),
|
||||||
|
emqx_trace:rendered_action_template(ChannelID, #{sql => SQLOrKey}),
|
||||||
Worker = ecpool:get_client(PoolName),
|
Worker = ecpool:get_client(PoolName),
|
||||||
case ecpool_worker:client(Worker) of
|
case ecpool_worker:client(Worker) of
|
||||||
{ok, Conn} ->
|
{ok, Conn} ->
|
||||||
|
|
|
@ -210,7 +210,7 @@ on_query(
|
||||||
}),
|
}),
|
||||||
Type = query,
|
Type = query,
|
||||||
{NameOrSQL2, Data} = proc_sql_params(TypeOrKey, NameOrSQL, Params, State),
|
{NameOrSQL2, Data} = proc_sql_params(TypeOrKey, NameOrSQL, Params, State),
|
||||||
Res = on_sql_query(InstId, PoolName, Type, ?SYNC_QUERY_MODE, NameOrSQL2, Data),
|
Res = on_sql_query(InstId, TypeOrKey, PoolName, Type, ?SYNC_QUERY_MODE, NameOrSQL2, Data),
|
||||||
handle_result(Res).
|
handle_result(Res).
|
||||||
|
|
||||||
on_batch_query(
|
on_batch_query(
|
||||||
|
@ -244,7 +244,9 @@ on_batch_query(
|
||||||
Datas2 = [emqx_placeholder:proc_sql(TokenList, Data) || Data <- Datas],
|
Datas2 = [emqx_placeholder:proc_sql(TokenList, Data) || Data <- Datas],
|
||||||
St = maps:get(BinKey, Sts),
|
St = maps:get(BinKey, Sts),
|
||||||
case
|
case
|
||||||
on_sql_query(InstId, PoolName, execute_batch, ?SYNC_QUERY_MODE, St, Datas2)
|
on_sql_query(
|
||||||
|
InstId, BinKey, PoolName, execute_batch, ?SYNC_QUERY_MODE, St, Datas2
|
||||||
|
)
|
||||||
of
|
of
|
||||||
{ok, Results} ->
|
{ok, Results} ->
|
||||||
handle_batch_result(Results, 0);
|
handle_batch_result(Results, 0);
|
||||||
|
@ -281,7 +283,13 @@ proc_sql_params(TypeOrKey, SQLOrData, Params, #{
|
||||||
end
|
end
|
||||||
end.
|
end.
|
||||||
|
|
||||||
on_sql_query(InstId, PoolName, Type, ApplyMode, NameOrSQL, Data) ->
|
on_sql_query(InstId, ChannelID, PoolName, Type, ApplyMode, NameOrSQL, Data) ->
|
||||||
|
emqx_trace:rendered_action_template(ChannelID, #{
|
||||||
|
type => Type,
|
||||||
|
apply_mode => ApplyMode,
|
||||||
|
name_or_sql => NameOrSQL,
|
||||||
|
data => Data
|
||||||
|
}),
|
||||||
case ecpool:pick_and_do(PoolName, {?MODULE, Type, [NameOrSQL, Data]}, ApplyMode) of
|
case ecpool:pick_and_do(PoolName, {?MODULE, Type, [NameOrSQL, Data]}, ApplyMode) of
|
||||||
{error, Reason} = Result ->
|
{error, Reason} = Result ->
|
||||||
?tp(
|
?tp(
|
||||||
|
|
|
@ -304,7 +304,7 @@ on_query(
|
||||||
}),
|
}),
|
||||||
Type = pgsql_query_type(TypeOrKey),
|
Type = pgsql_query_type(TypeOrKey),
|
||||||
{NameOrSQL2, Data} = proc_sql_params(TypeOrKey, NameOrSQL, Params, State),
|
{NameOrSQL2, Data} = proc_sql_params(TypeOrKey, NameOrSQL, Params, State),
|
||||||
Res = on_sql_query(InstId, PoolName, Type, NameOrSQL2, Data),
|
Res = on_sql_query(TypeOrKey, InstId, PoolName, Type, NameOrSQL2, Data),
|
||||||
?tp(postgres_bridge_connector_on_query_return, #{instance_id => InstId, result => Res}),
|
?tp(postgres_bridge_connector_on_query_return, #{instance_id => InstId, result => Res}),
|
||||||
handle_result(Res).
|
handle_result(Res).
|
||||||
|
|
||||||
|
@ -337,7 +337,7 @@ on_batch_query(
|
||||||
{_Statement, RowTemplate} ->
|
{_Statement, RowTemplate} ->
|
||||||
PrepStatement = get_prepared_statement(BinKey, State),
|
PrepStatement = get_prepared_statement(BinKey, State),
|
||||||
Rows = [render_prepare_sql_row(RowTemplate, Data) || {_Key, Data} <- BatchReq],
|
Rows = [render_prepare_sql_row(RowTemplate, Data) || {_Key, Data} <- BatchReq],
|
||||||
case on_sql_query(InstId, PoolName, execute_batch, PrepStatement, Rows) of
|
case on_sql_query(Key, InstId, PoolName, execute_batch, PrepStatement, Rows) of
|
||||||
{error, _Error} = Result ->
|
{error, _Error} = Result ->
|
||||||
handle_result(Result);
|
handle_result(Result);
|
||||||
{_Column, Results} ->
|
{_Column, Results} ->
|
||||||
|
@ -386,7 +386,15 @@ get_prepared_statement(Key, #{prepares := PrepStatements}) ->
|
||||||
BinKey = to_bin(Key),
|
BinKey = to_bin(Key),
|
||||||
maps:get(BinKey, PrepStatements).
|
maps:get(BinKey, PrepStatements).
|
||||||
|
|
||||||
on_sql_query(InstId, PoolName, Type, NameOrSQL, Data) ->
|
on_sql_query(Key, InstId, PoolName, Type, NameOrSQL, Data) ->
|
||||||
|
emqx_trace:rendered_action_template(
|
||||||
|
Key,
|
||||||
|
#{
|
||||||
|
statement_type => Type,
|
||||||
|
statement_or_name => NameOrSQL,
|
||||||
|
data => Data
|
||||||
|
}
|
||||||
|
),
|
||||||
try ecpool:pick_and_do(PoolName, {?MODULE, Type, [NameOrSQL, Data]}, no_handover) of
|
try ecpool:pick_and_do(PoolName, {?MODULE, Type, [NameOrSQL, Data]}, no_handover) of
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
?tp(
|
?tp(
|
||||||
|
|
|
@ -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([
|
||||||
|
@ -141,22 +142,24 @@ apply_rule(Rule = #{id := RuleID}, Columns, Envs) ->
|
||||||
|
|
||||||
set_process_trace_metadata(RuleID, #{clientid := ClientID} = Columns) ->
|
set_process_trace_metadata(RuleID, #{clientid := ClientID} = Columns) ->
|
||||||
logger:update_process_metadata(#{
|
logger:update_process_metadata(#{
|
||||||
clientid => ClientID
|
clientid => ClientID,
|
||||||
}),
|
rule_id => RuleID,
|
||||||
set_process_trace_metadata(RuleID, maps:remove(clientid, Columns));
|
rule_trigger_time => rule_trigger_time(Columns)
|
||||||
|
});
|
||||||
set_process_trace_metadata(RuleID, Columns) ->
|
set_process_trace_metadata(RuleID, Columns) ->
|
||||||
EventTimestamp =
|
|
||||||
case Columns of
|
|
||||||
#{timestamp := Timestamp} ->
|
|
||||||
Timestamp;
|
|
||||||
_ ->
|
|
||||||
erlang:system_time(millisecond)
|
|
||||||
end,
|
|
||||||
logger:update_process_metadata(#{
|
logger:update_process_metadata(#{
|
||||||
rule_id => RuleID,
|
rule_id => RuleID,
|
||||||
rule_trigger_time => EventTimestamp
|
rule_trigger_time => rule_trigger_time(Columns)
|
||||||
}).
|
}).
|
||||||
|
|
||||||
|
rule_trigger_time(Columns) ->
|
||||||
|
case Columns of
|
||||||
|
#{timestamp := Timestamp} ->
|
||||||
|
Timestamp;
|
||||||
|
_ ->
|
||||||
|
erlang:system_time(millisecond)
|
||||||
|
end.
|
||||||
|
|
||||||
reset_process_trace_metadata(#{clientid := _ClientID}) ->
|
reset_process_trace_metadata(#{clientid := _ClientID}) ->
|
||||||
Meta = logger:get_process_metadata(),
|
Meta = logger:get_process_metadata(),
|
||||||
Meta1 = maps:remove(clientid, Meta),
|
Meta1 = maps:remove(clientid, Meta),
|
||||||
|
@ -722,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(
|
||||||
|
|
Loading…
Reference in New Issue