Commit c5d74f81 authored by Siebers, Michael's avatar Siebers, Michael
Browse files

Handle thrown api_error(_,_)

parent 993f510e
:- multifile http:map_exception_to_http_status_hook/4,
prolog:message//1,
prolog:error_message//1.
:- discontiguous http:map_exception_to_http_status_hook/4,
prolog:message//1,
prolog:error_message//1.
/*******************************************
* *
* Translating exceptions to user messages *
* *
*******************************************/
/************************
* Request JSON errors *
************************/
......@@ -136,11 +145,42 @@ item_not_relevant(Item) -->
/******************
* Server Errors *
******************/
/* api_error(Hash, Error) => server error
* error(api_error(Hash, Error), _) => server_error
*
* Some part of the code did not run as expected. This includes a handler
* failing, which the http-server architecture considers an error.
*/
prolog:message(api_error(Hash, Error)) -->
api_error_message(Error),
[
nl, "Please consult the server logs or the webmaster for more ",
"information (IncidentID: "
],
as_text(Hash),
[")."].
% prolog:error_message is used if an error(api_error(_,_),_) is thrown!
prolog:error_message(api_error(Hash, Error)) -->
prolog:message(api_error(Hash, Error)).
% Error messages for specific API errors
api_error_message(goal_failed) --> ["An internal function failed."].
api_error_message(E) --> ["Unknown internal error: "], as_text(E).
/***************************
* *
* Intercepting Exceptions *
* *
***************************/
/* error(goal_failed(web_api:Goal),C)
*
* Thrown by http_dispatch:call_action/2 if one of our handlers fails.
* Rethrown as error(api_error(goal_failed(PredIndicator)),C).
* Rethrown as error(api_error(IncidentID, goal_failed),C). Additional
* information on the error is stored in the log using the same incident ID.
*
* N.B.: The SWI-Prolog documentation states "The hook is not allowed to modify
* ExceptionOut in such a way that it no longer unifies with the catching
......@@ -149,17 +189,23 @@ item_not_relevant(Item) -->
*/
user:prolog_exception_hook(error(goal_failed(web_api:Goal),Context),
error(api_error(Hash, goal_failed),Context), Frame, _) :-
Goal =.. [PredName | Args],
Goal =.. [_PredName | Args],
last(Args, Request),
error_hash(Request, Hash),
incident_id(Request, Hash),
get_prolog_backtrace(20, Backtrace, [frame(Frame), clause_references(false)]),
http_log('incident(~a, ~q, ~q).~n',[Hash, goal_failed, [goal(Goal), prolog_stack(Backtrace), original_context(Context)]]).
%! error_hash(+Request, --Hash) is det
error_hash(Request, Hash) :-
/***********
* Helpers *
***********/
%! incident_id(+Request, --Hash) is det
% Constructs a likely unique identifier for an api_error. Hash is bound to an
% atom of the form XXXX-XXXX-XXXX-XXXX where each X is an hex digit.
incident_id(Request, Hash) :-
get_time(TimeStamp),
random_between(0,1000000,RandInt),
variant_sha1( error_hash(TimeStamp, RandInt, Request), FullHash),
......@@ -168,3 +214,7 @@ error_hash(Request, Hash) :-
append(HashStartChars,_,HashChars),
format(atom(Hash), '~s~s~s~s-~s~s~s~s-~s~s~s~s-~s~s~s~s', HashStartChars).
% as_text(Content)
% DCG returning the given Content as string.
as_text(Content, [ContentStr|Rest],Rest) :-
format(string(ContentStr), '~q', [Content]).
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment