Browse Source

No longer use erlang:get_stacktrace/0

It has been deprecated in OTP and the new way is available
on all supported OTP versions.
Loïc Hoguin 5 years ago
parent
commit
3a7232b019

+ 1 - 3
doc/src/manual/cowboy_handler.asciidoc

@@ -53,9 +53,7 @@ normal::
 
 {crash, Class, Reason}::
     A crash occurred in the handler. `Class` and `Reason` can be
-    used to obtain more information about the crash. The function
-    `erlang:get_stacktrace/0` can also be called to obtain the
-    stacktrace of the process when the crash occurred.
+    used to obtain more information about the crash.
 
 == Exports
 

+ 1 - 3
doc/src/manual/cowboy_loop.asciidoc

@@ -65,9 +65,7 @@ stop::
 
 {crash, Class, Reason}::
     A crash occurred in the handler. `Class` and `Reason` can be
-    used to obtain more information about the crash. The function
-    `erlang:get_stacktrace/0` can also be called to obtain the
-    stacktrace of the process when the crash occurred.
+    used to obtain more information about the crash.
 
 == Changelog
 

+ 1 - 3
doc/src/manual/cowboy_rest.asciidoc

@@ -76,9 +76,7 @@ normal::
 
 {crash, Class, Reason}::
     A crash occurred in the handler. `Class` and `Reason` can be
-    used to obtain more information about the crash. The function
-    `erlang:get_stacktrace/0` can also be called to obtain the
-    stacktrace of the process when the crash occurred.
+    used to obtain more information about the crash.
 
 == REST callbacks
 

+ 1 - 3
doc/src/manual/cowboy_websocket.asciidoc

@@ -112,9 +112,7 @@ timeout::
 
 {crash, Class, Reason}::
     A crash occurred in the handler. `Class` and `Reason` can be
-    used to obtain more information about the crash. The function
-    `erlang:get_stacktrace/0` can also be called to obtain the
-    stacktrace of the process when the crash occurred.
+    used to obtain more information about the crash.
 
 {error, badencoding}::
     A text frame was sent by the client with invalid encoding. All

+ 2 - 7
src/cowboy_handler.erl

@@ -20,10 +20,6 @@
 -module(cowboy_handler).
 -behaviour(cowboy_middleware).
 
--ifdef(OTP_RELEASE).
--compile({nowarn_deprecated_function, [{erlang, get_stacktrace, 0}]}).
--endif.
-
 -export([execute/2]).
 -export([terminate/4]).
 
@@ -46,10 +42,9 @@ execute(Req, Env=#{handler := Handler, handler_opts := HandlerOpts}) ->
 			Mod:upgrade(Req2, Env, Handler, State);
 		{Mod, Req2, State, Opts} ->
 			Mod:upgrade(Req2, Env, Handler, State, Opts)
-	catch Class:Reason ->
-		StackTrace = erlang:get_stacktrace(),
+	catch Class:Reason:Stacktrace ->
 		terminate({crash, Class, Reason}, Req, HandlerOpts, Handler),
-		erlang:raise(Class, Reason, StackTrace)
+		erlang:raise(Class, Reason, Stacktrace)
 	end.
 
 -spec terminate(any(), Req | undefined, any(), module()) -> ok when Req::cowboy_req:req().

+ 10 - 14
src/cowboy_http.erl

@@ -14,10 +14,6 @@
 
 -module(cowboy_http).
 
--ifdef(OTP_RELEASE).
--compile({nowarn_deprecated_function, [{erlang, get_stacktrace, 0}]}).
--endif.
-
 -export([init/6]).
 
 -export([system_continue/3]).
@@ -335,10 +331,10 @@ after_parse({request, Req=#{streamid := StreamID, method := Method,
 			end,
 			State = set_timeout(State1, idle_timeout),
 			parse(Buffer, commands(State, StreamID, Commands))
-	catch Class:Exception ->
+	catch Class:Exception:Stacktrace ->
 		cowboy:log(cowboy_stream:make_error_log(init,
 			[StreamID, Req, Opts],
-			Class, Exception, erlang:get_stacktrace()), Opts),
+			Class, Exception, Stacktrace), Opts),
 		early_error(500, State0, {internal_error, {Class, Exception},
 			'Unhandled exception in cowboy_stream:init/3.'}, Req),
 		parse(Buffer, State0)
@@ -357,10 +353,10 @@ after_parse({data, StreamID, IsFin, Data, State0=#state{opts=Opts, buffer=Buffer
 			end),
 			State = update_flow(IsFin, Data, State1#state{streams=Streams}),
 			parse(Buffer, commands(State, StreamID, Commands))
-	catch Class:Exception ->
+	catch Class:Exception:Stacktrace ->
 		cowboy:log(cowboy_stream:make_error_log(data,
 			[StreamID, IsFin, Data, StreamState0],
-			Class, Exception, erlang:get_stacktrace()), Opts),
+			Class, Exception, Stacktrace), Opts),
 		%% @todo Should call parse after this.
 		stream_terminate(State0, StreamID, {internal_error, {Class, Exception},
 			'Unhandled exception in cowboy_stream:data/4.'})
@@ -904,10 +900,10 @@ info(State=#state{opts=Opts, streams=Streams0}, StreamID, Msg) ->
 					Streams = lists:keyreplace(StreamID, #stream.id, Streams0,
 						Stream#stream{state=StreamState}),
 					commands(State#state{streams=Streams}, StreamID, Commands)
-			catch Class:Exception ->
+			catch Class:Exception:Stacktrace ->
 				cowboy:log(cowboy_stream:make_error_log(info,
 					[StreamID, Msg, StreamState0],
-					Class, Exception, erlang:get_stacktrace()), Opts),
+					Class, Exception, Stacktrace), Opts),
 				stream_terminate(State, StreamID, {internal_error, {Class, Exception},
 					'Unhandled exception in cowboy_stream:info/3.'})
 			end;
@@ -1286,10 +1282,10 @@ stream_terminate(State0=#state{opts=Opts, in_streamid=InStreamID, in_state=InSta
 stream_call_terminate(StreamID, Reason, StreamState, #state{opts=Opts}) ->
 	try
 		cowboy_stream:terminate(StreamID, Reason, StreamState)
-	catch Class:Exception ->
+	catch Class:Exception:Stacktrace ->
 		cowboy:log(cowboy_stream:make_error_log(terminate,
 			[StreamID, Reason, StreamState],
-			Class, Exception, erlang:get_stacktrace()), Opts)
+			Class, Exception, Stacktrace), Opts)
 	end.
 
 maybe_req_close(#state{opts=#{http10_keepalive := false}}, _, 'HTTP/1.0') ->
@@ -1386,10 +1382,10 @@ early_error(StatusCode0, #state{socket=Socket, transport=Transport,
 				%% @todo Technically we allow the sendfile tuple.
 				RespBody
 			])
-	catch Class:Exception ->
+	catch Class:Exception:Stacktrace ->
 		cowboy:log(cowboy_stream:make_error_log(early_error,
 			[StreamID, Reason, PartialReq, Resp, Opts],
-			Class, Exception, erlang:get_stacktrace()), Opts),
+			Class, Exception, Stacktrace), Opts),
 		%% We still need to send an error response, so send what we initially
 		%% wanted to send. It's better than nothing.
 		Transport:send(Socket, cow_http:response(StatusCode0,

+ 10 - 14
src/cowboy_http2.erl

@@ -14,10 +14,6 @@
 
 -module(cowboy_http2).
 
--ifdef(OTP_RELEASE).
--compile({nowarn_deprecated_function, [{erlang, get_stacktrace, 0}]}).
--endif.
-
 -export([init/6]).
 -export([init/10]).
 -export([init/12]).
@@ -384,10 +380,10 @@ data_frame(State0=#state{opts=Opts, flow=Flow, streams=Streams}, StreamID, IsFin
 							flow=max(0, StreamFlow - Size), state=StreamState}}},
 						StreamID),
 					commands(State, StreamID, Commands)
-			catch Class:Exception ->
+			catch Class:Exception:Stacktrace ->
 				cowboy:log(cowboy_stream:make_error_log(data,
 					[StreamID, IsFin, Data, StreamState0],
-					Class, Exception, erlang:get_stacktrace()), Opts),
+					Class, Exception, Stacktrace), Opts),
 				reset_stream(State0, StreamID, {internal_error, {Class, Exception},
 					'Unhandled exception in cowboy_stream:data/4.'})
 			end;
@@ -491,10 +487,10 @@ headers_frame(State=#state{opts=Opts, streams=Streams}, StreamID, Req) ->
 			commands(State#state{
 				streams=Streams#{StreamID => #stream{state=StreamState}}},
 				StreamID, Commands)
-	catch Class:Exception ->
+	catch Class:Exception:Stacktrace ->
 		cowboy:log(cowboy_stream:make_error_log(init,
 			[StreamID, Req, Opts],
-			Class, Exception, erlang:get_stacktrace()), Opts),
+			Class, Exception, Stacktrace), Opts),
 		reset_stream(State, StreamID, {internal_error, {Class, Exception},
 			'Unhandled exception in cowboy_stream:init/3.'})
 	end.
@@ -518,10 +514,10 @@ early_error(State0=#state{ref=Ref, opts=Opts, peer=Peer},
 	try cowboy_stream:early_error(StreamID, Reason, PartialReq, Resp, Opts) of
 		{response, StatusCode, RespHeaders, RespBody} ->
 			send_response(State0, StreamID, StatusCode, RespHeaders, RespBody)
-	catch Class:Exception ->
+	catch Class:Exception:Stacktrace ->
 		cowboy:log(cowboy_stream:make_error_log(early_error,
 			[StreamID, Reason, PartialReq, Resp, Opts],
-			Class, Exception, erlang:get_stacktrace()), Opts),
+			Class, Exception, Stacktrace), Opts),
 		%% We still need to send an error response, so send what we initially
 		%% wanted to send. It's better than nothing.
 		send_headers(State0, StreamID, fin, StatusCode0, RespHeaders0)
@@ -579,10 +575,10 @@ info(State=#state{opts=Opts, http2_machine=HTTP2Machine, streams=Streams}, Strea
 				{Commands, StreamState} ->
 					commands(State#state{streams=Streams#{StreamID => Stream#stream{state=StreamState}}},
 						StreamID, Commands)
-			catch Class:Exception ->
+			catch Class:Exception:Stacktrace ->
 				cowboy:log(cowboy_stream:make_error_log(info,
 					[StreamID, Msg, StreamState0],
-					Class, Exception, erlang:get_stacktrace()), Opts),
+					Class, Exception, Stacktrace), Opts),
 				reset_stream(State, StreamID, {internal_error, {Class, Exception},
 					'Unhandled exception in cowboy_stream:info/3.'})
 			end;
@@ -1030,10 +1026,10 @@ terminate_stream(State=#state{flow=Flow, streams=Streams0, children=Children0},
 terminate_stream_handler(#state{opts=Opts}, StreamID, Reason, StreamState) ->
 	try
 		cowboy_stream:terminate(StreamID, Reason, StreamState)
-	catch Class:Exception ->
+	catch Class:Exception:Stacktrace ->
 		cowboy:log(cowboy_stream:make_error_log(terminate,
 			[StreamID, Reason, StreamState],
-			Class, Exception, erlang:get_stacktrace()), Opts)
+			Class, Exception, Stacktrace), Opts)
 	end.
 
 %% System callbacks.

+ 2 - 7
src/cowboy_loop.erl

@@ -15,10 +15,6 @@
 -module(cowboy_loop).
 -behaviour(cowboy_sub_protocol).
 
--ifdef(OTP_RELEASE).
--compile({nowarn_deprecated_function, [{erlang, get_stacktrace, 0}]}).
--endif.
-
 -export([upgrade/4]).
 -export([upgrade/5]).
 -export([loop/4]).
@@ -81,10 +77,9 @@ call(Req0, Env, Handler, HandlerState0, Message) ->
 			suspend(Req, Env, Handler, HandlerState);
 		{stop, Req, HandlerState} ->
 			terminate(Req, Env, Handler, HandlerState, stop)
-	catch Class:Reason ->
-		StackTrace = erlang:get_stacktrace(),
+	catch Class:Reason:Stacktrace ->
 		cowboy_handler:terminate({crash, Class, Reason}, Req0, HandlerState0, Handler),
-		erlang:raise(Class, Reason, StackTrace)
+		erlang:raise(Class, Reason, Stacktrace)
 	end.
 
 suspend(Req, Env, Handler, HandlerState) ->

+ 8 - 12
src/cowboy_req.erl

@@ -15,10 +15,6 @@
 
 -module(cowboy_req).
 
--ifdef(OTP_RELEASE).
--compile({nowarn_deprecated_function, [{erlang, get_stacktrace, 0}]}).
--endif.
-
 %% Request.
 -export([method/1]).
 -export([version/1]).
@@ -224,10 +220,10 @@ qs(#{qs := Qs}) ->
 parse_qs(#{qs := Qs}) ->
 	try
 		cow_qs:parse_qs(Qs)
-	catch _:_ ->
+	catch _:_:Stacktrace ->
 		erlang:raise(exit, {request_error, qs,
 			'Malformed query string; application/x-www-form-urlencoded expected.'
-		}, erlang:get_stacktrace())
+		}, Stacktrace)
 	end.
 
 -spec match_qs(cowboy:fields(), req()) -> map().
@@ -415,10 +411,10 @@ parse_header(Name, Req) ->
 parse_header(Name, Req, Default) ->
 	try
 		parse_header(Name, Req, Default, parse_header_fun(Name))
-	catch _:_ ->
+	catch _:_:Stacktrace ->
 		erlang:raise(exit, {request_error, {header, Name},
 			'Malformed header. Please consult the relevant specification.'
-		}, erlang:get_stacktrace())
+		}, Stacktrace)
 	end.
 
 parse_header_fun(<<"accept">>) -> fun cow_http_hd:parse_accept/1;
@@ -546,10 +542,10 @@ read_urlencoded_body(Req0, Opts) ->
 		{ok, Body, Req} ->
 			try
 				{ok, cow_qs:parse_qs(Body), Req}
-			catch _:_ ->
+			catch _:_:Stacktrace ->
 				erlang:raise(exit, {request_error, urlencoded_body,
 					'Malformed body; application/x-www-form-urlencoded expected.'
-				}, erlang:get_stacktrace())
+				}, Stacktrace)
 			end;
 		{more, Body, _} ->
 			Length = maps:get(length, Opts, 64000),
@@ -616,10 +612,10 @@ read_part(Buffer, Opts, Req=#{multipart := {Boundary, _}}) ->
 		%% Ignore epilogue.
 		{done, _} ->
 			{done, Req#{multipart => done}}
-	catch _:_ ->
+	catch _:_:Stacktrace ->
 		erlang:raise(exit, {request_error, {multipart, headers},
 			'Malformed body; multipart expected.'
-		}, erlang:get_stacktrace())
+		}, Stacktrace)
 	end.
 
 -spec read_part_body(Req)

+ 36 - 38
src/cowboy_rest.erl

@@ -17,10 +17,6 @@
 -module(cowboy_rest).
 -behaviour(cowboy_sub_protocol).
 
--ifdef(OTP_RELEASE).
--compile({nowarn_deprecated_function, [{erlang, get_stacktrace, 0}]}).
--endif.
-
 -export([upgrade/4]).
 -export([upgrade/5]).
 
@@ -812,8 +808,8 @@ variances(Req, State=#state{content_types_p=CTP,
 						<<"vary">>, [H|Variances5], Req2),
 					resource_exists(Req3, State2)
 			end
-	catch Class:Reason ->
-		error_terminate(Req, State, Class, Reason)
+	catch Class:Reason:Stacktrace ->
+		error_terminate(Req, State, Class, Reason, Stacktrace)
 	end.
 
 variances(Req, State, Variances) ->
@@ -850,8 +846,8 @@ if_match(Req, State, EtagsList) ->
 				%% Etag may be `undefined' which cannot be a member.
 				false -> precondition_failed(Req2, State2)
 			end
-	catch Class:Reason ->
-		error_terminate(Req, State, Class, Reason)
+	catch Class:Reason:Stacktrace ->
+		error_terminate(Req, State, Class, Reason, Stacktrace)
 	end.
 
 if_match_must_not_exist(Req, State) ->
@@ -878,8 +874,8 @@ if_unmodified_since(Req, State, IfUnmodifiedSince) ->
 				true -> precondition_failed(Req2, State2);
 				false -> if_none_match_exists(Req2, State2)
 			end
-	catch Class:Reason ->
-		error_terminate(Req, State, Class, Reason)
+	catch Class:Reason:Stacktrace ->
+		error_terminate(Req, State, Class, Reason, Stacktrace)
 	end.
 
 if_none_match_exists(Req, State) ->
@@ -904,8 +900,8 @@ if_none_match(Req, State, EtagsList) ->
 						false -> method(Req2, State2)
 					end
 			end
-	catch Class:Reason ->
-		error_terminate(Req, State, Class, Reason)
+	catch Class:Reason:Stacktrace ->
+		error_terminate(Req, State, Class, Reason, Stacktrace)
 	end.
 
 %% Weak Etag comparison: only check the opaque tag.
@@ -947,8 +943,8 @@ if_modified_since(Req, State, IfModifiedSince) ->
 				true -> method(Req2, State2);
 				false -> not_modified(Req2, State2)
 			end
-	catch Class:Reason ->
-		error_terminate(Req, State, Class, Reason)
+	catch Class:Reason:Stacktrace ->
+		error_terminate(Req, State, Class, Reason, Stacktrace)
 	end.
 
 not_modified(Req, State) ->
@@ -958,11 +954,11 @@ not_modified(Req, State) ->
 			try set_resp_expires(Req3, State2) of
 				{Req4, State3} ->
 					respond(Req4, State3, 304)
-			catch Class:Reason ->
-				error_terminate(Req, State2, Class, Reason)
+			catch Class:Reason:Stacktrace ->
+				error_terminate(Req, State2, Class, Reason, Stacktrace)
 			end
-	catch Class:Reason ->
-		error_terminate(Req, State, Class, Reason)
+	catch Class:Reason:Stacktrace ->
+		error_terminate(Req, State, Class, Reason, Stacktrace)
 	end.
 
 precondition_failed(Req, State) ->
@@ -1115,8 +1111,8 @@ process_content_type(Req, State=#state{method=Method, exists=Exists}, Fun) ->
 				Exists -> respond(Req3, State2, 303);
 				true -> respond(Req3, State2, 201)
 			end
-	end catch Class:Reason = {case_clause, no_call} ->
-		error_terminate(Req, State, Class, Reason)
+	end catch Class:Reason = {case_clause, no_call}:Stacktrace ->
+		error_terminate(Req, State, Class, Reason, Stacktrace)
 	end.
 
 %% If PUT was used then the resource has been created at the current URL.
@@ -1142,8 +1138,8 @@ set_resp_body_etag(Req, State) ->
 	try set_resp_etag(Req, State) of
 		{Req2, State2} ->
 			set_resp_body_last_modified(Req2, State2)
-	catch Class:Reason ->
-		error_terminate(Req, State, Class, Reason)
+	catch Class:Reason:Stacktrace ->
+		error_terminate(Req, State, Class, Reason, Stacktrace)
 	end.
 
 %% Set the Last-Modified header if any for the response provided.
@@ -1159,8 +1155,8 @@ set_resp_body_last_modified(Req, State) ->
 						<<"last-modified">>, LastModifiedBin, Req2),
 					set_resp_body_expires(Req3, State2)
 			end
-	catch Class:Reason ->
-		error_terminate(Req, State, Class, Reason)
+	catch Class:Reason:Stacktrace ->
+		error_terminate(Req, State, Class, Reason, Stacktrace)
 	end.
 
 %% Set the Expires header if any for the response provided.
@@ -1168,8 +1164,8 @@ set_resp_body_expires(Req, State) ->
 	try set_resp_expires(Req, State) of
 		{Req2, State2} ->
 			if_range(Req2, State2)
-	catch Class:Reason ->
-		error_terminate(Req, State, Class, Reason)
+	catch Class:Reason:Stacktrace ->
+		error_terminate(Req, State, Class, Reason, Stacktrace)
 	end.
 
 %% When both the if-range and range headers are set, we perform
@@ -1254,9 +1250,10 @@ set_ranged_body_auto(Req, State=#state{handler=Handler, content_type_a={_, Callb
 			switch_handler(Switch, Req2, State2);
 		{Body, Req2, State2} ->
 			maybe_set_ranged_body_auto(Req2, State2, Body)
-	end catch Class:{case_clause, no_call} ->
+	end catch Class:{case_clause, no_call}:Stacktrace ->
 		error_terminate(Req, State, Class, {error, {missing_callback, {Handler, Callback, 2}},
-			'A callback specified in content_types_provided/2 is not exported.'})
+			'A callback specified in content_types_provided/2 is not exported.'},
+			Stacktrace)
 	end.
 
 maybe_set_ranged_body_auto(Req=#{range := {_, Ranges}}, State, Body) ->
@@ -1379,9 +1376,10 @@ set_ranged_body_callback(Req, State=#state{handler=Handler}, Callback) ->
 				true -> send_multipart_ranged_body(Req2, State2, Ranges);
 				false -> set_multipart_ranged_body(Req2, State2, Ranges)
 			end
-	end catch Class:{case_clause, no_call} ->
+	end catch Class:{case_clause, no_call}:Stacktrace ->
 		error_terminate(Req, State, Class, {error, {missing_callback, {Handler, Callback, 2}},
-			'A callback specified in ranges_provided/2 is not exported.'})
+			'A callback specified in ranges_provided/2 is not exported.'},
+			Stacktrace)
 	end.
 
 set_one_ranged_body(Req0, State, OneRange) ->
@@ -1471,9 +1469,10 @@ set_resp_body(Req, State=#state{handler=Handler, content_type_a={_, Callback}})
 		{Body, Req2, State2} ->
 			Req3 = cowboy_req:set_resp_body(Body, Req2),
 			multiple_choices(Req3, State2)
-	end catch Class:{case_clause, no_call} ->
+	end catch Class:{case_clause, no_call}:Stacktrace ->
 		error_terminate(Req, State, Class, {error, {missing_callback, {Handler, Callback, 2}},
-			'A callback specified in content_types_provided/2 is not exported.'})
+			'A callback specified in content_types_provided/2 is not exported.'},
+			Stacktrace)
 	end.
 
 multiple_choices(Req, State) ->
@@ -1578,8 +1577,8 @@ call(Req0, State=#state{handler=Handler,
 					no_call;
 				{Result, Req, HandlerState} ->
 					{Result, Req, State#state{handler_state=HandlerState}}
-			catch Class:Reason ->
-				error_terminate(Req0, State, Class, Reason)
+			catch Class:Reason:Stacktrace ->
+				error_terminate(Req0, State, Class, Reason, Stacktrace)
 			end;
 		false ->
 			no_call
@@ -1620,11 +1619,10 @@ switch_handler({switch_handler, Mod}, Req, #state{handler_state=HandlerState}) -
 switch_handler({switch_handler, Mod, Opts}, Req, #state{handler_state=HandlerState}) ->
 	{Mod, Req, HandlerState, Opts}.
 
--spec error_terminate(cowboy_req:req(), #state{}, atom(), any()) -> no_return().
-error_terminate(Req, #state{handler=Handler, handler_state=HandlerState}, Class, Reason) ->
-	StackTrace = erlang:get_stacktrace(),
+-spec error_terminate(cowboy_req:req(), #state{}, atom(), any(), any()) -> no_return().
+error_terminate(Req, #state{handler=Handler, handler_state=HandlerState}, Class, Reason, Stacktrace) ->
 	cowboy_handler:terminate({crash, Class, Reason}, Req, HandlerState, Handler),
-	erlang:raise(Class, Reason, StackTrace).
+	erlang:raise(Class, Reason, Stacktrace).
 
 terminate(Req, #state{handler=Handler, handler_state=HandlerState}) ->
 	Result = cowboy_handler:terminate(normal, Req, HandlerState, Handler),

+ 5 - 26
src/cowboy_stream_h.erl

@@ -15,10 +15,6 @@
 -module(cowboy_stream_h).
 -behavior(cowboy_stream).
 
--ifdef(OTP_RELEASE).
--compile({nowarn_deprecated_function, [{erlang, get_stacktrace, 0}]}).
--endif.
-
 -export([init/3]).
 -export([data/4]).
 -export([info/3]).
@@ -285,33 +281,16 @@ send_request_body(Pid, Ref, fin, BodyLen, Data) ->
 
 %% Request process.
 
-%% We catch all exceptions in order to add the stacktrace to
-%% the exit reason as it is not propagated by proc_lib otherwise
-%% and therefore not present in the 'EXIT' message. We want
-%% the stacktrace in order to simplify debugging of errors.
-%%
-%% This + the behavior in proc_lib means that we will get a
-%% {Reason, Stacktrace} tuple for every exceptions, instead of
-%% just for errors and throws.
-%%
-%% @todo Better spec.
+%% We add the stacktrace to exit exceptions here in order
+%% to simplify the debugging of errors. The proc_lib library
+%% already adds the stacktrace to other types of exceptions.
 -spec request_process(cowboy_req:req(), cowboy_middleware:env(), [module()]) -> ok.
 request_process(Req, Env, Middlewares) ->
-	OTP = erlang:system_info(otp_release),
 	try
 		execute(Req, Env, Middlewares)
 	catch
-		exit:Reason ->
-			Stacktrace = erlang:get_stacktrace(),
-			erlang:raise(exit, {Reason, Stacktrace}, Stacktrace);
-		%% OTP 19 does not propagate any exception stacktraces,
-		%% we therefore add it for every class of exception.
-		_:Reason when OTP =:= "19" ->
-			Stacktrace = erlang:get_stacktrace(),
-			erlang:raise(exit, {Reason, Stacktrace}, Stacktrace);
-		%% @todo I don't think this clause is necessary.
-		Class:Reason ->
-			erlang:raise(Class, Reason, erlang:get_stacktrace())
+		exit:Reason:Stacktrace ->
+			erlang:raise(exit, {Reason, Stacktrace}, Stacktrace)
 	end.
 
 execute(_, _, []) ->

+ 2 - 7
src/cowboy_websocket.erl

@@ -17,10 +17,6 @@
 -module(cowboy_websocket).
 -behaviour(cowboy_sub_protocol).
 
--ifdef(OTP_RELEASE).
--compile({nowarn_deprecated_function, [{erlang, get_stacktrace, 0}]}).
--endif.
-
 -export([is_upgrade_request/1]).
 -export([upgrade/4]).
 -export([upgrade/5]).
@@ -513,11 +509,10 @@ handler_call(State=#state{handler=Handler}, HandlerState,
 			end;
 		{stop, HandlerState2} ->
 			websocket_close(State, HandlerState2, stop)
-	catch Class:Reason ->
-		StackTrace = erlang:get_stacktrace(),
+	catch Class:Reason:Stacktrace ->
 		websocket_send_close(State, {crash, Class, Reason}),
 		handler_terminate(State, HandlerState, {crash, Class, Reason}),
-		erlang:raise(Class, Reason, StackTrace)
+		erlang:raise(Class, Reason, Stacktrace)
 	end.
 
 -spec handler_call_result(#state{}, any(), parse_state(), fun(), commands()) -> no_return().