Добавить авто-регистрацию тикетов (hash/dedupe/500/WS). Refs EventHub/EventHubBack#35
This commit is contained in:
@@ -27,7 +27,9 @@
|
||||
subscription_to_json/1,
|
||||
trails_for_crud/4,
|
||||
is_superadmin/1,
|
||||
pagination_headers/2
|
||||
pagination_headers/2,
|
||||
maybe_report_internal_error/3,
|
||||
report_and_send_error/4
|
||||
]).
|
||||
-export([admin_to_json/1, audit_to_json/1]).
|
||||
|
||||
@@ -91,15 +93,91 @@ send_json(Req, Status, Data, ExtraHeaders) ->
|
||||
Req1 = cowboy_req:reply(Status, Headers, Body, Req),
|
||||
{ok, Body, Req1}.
|
||||
|
||||
%% @doc Отправляет JSON-ошибку.
|
||||
-spec send_error(cowboy_req:req(), cowboy:http_status(), binary()) ->
|
||||
%% @doc Отправляет JSON-ошибку. При Status >= 500 асинхронно регистрирует тикет.
|
||||
-spec send_error(cowboy_req:req(), cowboy:http_status(), binary() | term()) ->
|
||||
{ok, binary(), cowboy_req:req()}.
|
||||
send_error(Req, Status, Message) when Status >= 500 ->
|
||||
MsgBin = ensure_error_binary(Message),
|
||||
maybe_report_internal_error(Req, MsgBin, #{}),
|
||||
do_send_error(Req, Status, MsgBin);
|
||||
send_error(Req, Status, Message) ->
|
||||
do_send_error(Req, Status, ensure_error_binary(Message)).
|
||||
|
||||
%% @doc Отправить ошибку и явно зарегистрировать тикет с доп. контекстом.
|
||||
-spec report_and_send_error(cowboy_req:req(), cowboy:http_status(),
|
||||
binary() | term(), map()) -> {ok, binary(), cowboy_req:req()}.
|
||||
report_and_send_error(Req, Status, Message, Context) when Status >= 500 ->
|
||||
MsgBin = ensure_error_binary(Message),
|
||||
maybe_report_internal_error(Req, MsgBin, Context),
|
||||
do_send_error(Req, Status, MsgBin);
|
||||
report_and_send_error(Req, Status, Message, _Context) ->
|
||||
do_send_error(Req, Status, ensure_error_binary(Message)).
|
||||
|
||||
%% @doc Асинхронно зарегистрировать внутреннюю ошибку как тикет (backend).
|
||||
-spec maybe_report_internal_error(cowboy_req:req() | map(), binary() | term(), map()) -> ok.
|
||||
maybe_report_internal_error(ReqOrCtx, Message, ExtraContext) ->
|
||||
case get(eventhub_reporting_ticket) of
|
||||
true -> ok;
|
||||
_ ->
|
||||
case should_skip_ticket_report(ReqOrCtx) of
|
||||
true -> ok;
|
||||
false ->
|
||||
MsgBin = ensure_error_binary(Message),
|
||||
Context = maps:merge(request_error_context(ReqOrCtx), ExtraContext),
|
||||
Stack = maps:get(<<"stacktrace">>, Context, <<>>),
|
||||
Context1 = maps:remove(<<"stacktrace">>, Context),
|
||||
spawn(fun() ->
|
||||
try logic_ticket:report_error(backend, MsgBin, Stack, Context1)
|
||||
catch
|
||||
_:_ -> ok
|
||||
end
|
||||
end),
|
||||
ok
|
||||
end
|
||||
end.
|
||||
|
||||
should_skip_ticket_report(Ctx) when is_map(Ctx) ->
|
||||
Route = maps:get(<<"route">>, Ctx, maps:get(route, Ctx, <<>>)),
|
||||
is_ticket_route(ensure_error_binary(Route));
|
||||
should_skip_ticket_report(Req) ->
|
||||
try is_ticket_route(cowboy_req:path(Req))
|
||||
catch
|
||||
_:_ -> false
|
||||
end.
|
||||
|
||||
is_ticket_route(Path) when is_binary(Path) ->
|
||||
binary:match(Path, <<"/tickets">>) =/= nomatch;
|
||||
is_ticket_route(_) ->
|
||||
false.
|
||||
|
||||
do_send_error(Req, Status, Message) ->
|
||||
Body = jsx:encode(#{error => Message}),
|
||||
Headers = #{<<"content-type">> => <<"application/json">>},
|
||||
Req1 = cowboy_req:reply(Status, Headers, Body, Req),
|
||||
{ok, Body, Req1}.
|
||||
|
||||
ensure_error_binary(V) when is_binary(V) -> V;
|
||||
ensure_error_binary(V) when is_atom(V) -> atom_to_binary(V, utf8);
|
||||
ensure_error_binary(V) when is_list(V) ->
|
||||
try unicode:characters_to_binary(V)
|
||||
catch _:_ -> list_to_binary(io_lib:format("~p", [V]))
|
||||
end;
|
||||
ensure_error_binary(V) ->
|
||||
list_to_binary(io_lib:format("~p", [V])).
|
||||
|
||||
request_error_context(Ctx) when is_map(Ctx) -> Ctx;
|
||||
request_error_context(Req) ->
|
||||
try
|
||||
Method = cowboy_req:method(Req),
|
||||
Path = cowboy_req:path(Req),
|
||||
#{
|
||||
<<"method">> => Method,
|
||||
<<"route">> => Path
|
||||
}
|
||||
catch
|
||||
_:_ -> #{}
|
||||
end.
|
||||
|
||||
%%%===================================================================
|
||||
%%% Парсинг параметров запроса
|
||||
%%%===================================================================
|
||||
@@ -330,9 +408,15 @@ ticket_to_json(Ticket) ->
|
||||
status => Ticket#ticket.status,
|
||||
assigned_to => Ticket#ticket.assigned_to,
|
||||
resolution_note => Ticket#ticket.resolution_note,
|
||||
closed_at => datetime_to_iso8601(Ticket#ticket.closed_at)
|
||||
closed_at => datetime_to_iso8601(Ticket#ticket.closed_at),
|
||||
source => ticket_source(Ticket)
|
||||
}.
|
||||
|
||||
ticket_source(#ticket{source = Source}) when is_binary(Source), Source =/= <<>> ->
|
||||
Source;
|
||||
ticket_source(_) ->
|
||||
<<"backend">>.
|
||||
|
||||
%% @doc Преобразует #calendar{} в JSON-карту.
|
||||
-spec calendar_to_json(#calendar{}) -> map().
|
||||
calendar_to_json(Calendar) ->
|
||||
|
||||
Reference in New Issue
Block a user