Просмотр исходного кода

Add informational responses to metrics

Loïc Hoguin 7 лет назад
Родитель
Сommit
a97640d56d
3 измененных файлов с 46 добавлено и 8 удалено
  1. 2 2
      src/cowboy_http.erl
  2. 26 1
      src/cowboy_metrics_h.erl
  3. 18 5
      test/metrics_SUITE.erl

+ 2 - 2
src/cowboy_http.erl

@@ -908,9 +908,9 @@ commands(State0=#state{ref=Ref, parent=Parent, socket=Socket, transport=Transpor
 		[{switch_protocol, Headers, Protocol, InitialState}|_Tail]) ->
 		[{switch_protocol, Headers, Protocol, InitialState}|_Tail]) ->
 	%% @todo This should be the last stream running otherwise we need to wait before switching.
 	%% @todo This should be the last stream running otherwise we need to wait before switching.
 	%% @todo If there's streams opened after this one, fail instead of 101.
 	%% @todo If there's streams opened after this one, fail instead of 101.
-	State = cancel_timeout(State0),
+	State1 = cancel_timeout(State0),
 	%% Send a 101 response, then terminate the stream.
 	%% Send a 101 response, then terminate the stream.
-	State = #state{streams=Streams} = commands(State, StreamID, [{inform, 101, Headers}]),
+	State = #state{streams=Streams} = info(State1, StreamID, {inform, 101, Headers}),
 	#stream{state=StreamState} = lists:keyfind(StreamID, #stream.id, Streams),
 	#stream{state=StreamState} = lists:keyfind(StreamID, #stream.id, Streams),
 	%% @todo We need to shutdown processes here first.
 	%% @todo We need to shutdown processes here first.
 	stream_call_terminate(StreamID, switch_protocol, StreamState),
 	stream_call_terminate(StreamID, switch_protocol, StreamState),

+ 26 - 1
src/cowboy_metrics_h.erl

@@ -32,6 +32,17 @@
 	reason => any()
 	reason => any()
 }}.
 }}.
 
 
+-type informational_metrics() :: #{
+	%% Informational response status.
+	status := cowboy:http_status(),
+
+	%% Headers sent with the informational response.
+	headers := cowboy:http_headers(),
+
+	%% Time when the informational response was sent.
+	time := integer()
+}.
+
 -type metrics() :: #{
 -type metrics() :: #{
 	%% The identifier for this listener.
 	%% The identifier for this listener.
 	ref := ranch:ref(),
 	ref := ranch:ref(),
@@ -86,6 +97,9 @@
 	%% process: the request process.
 	%% process: the request process.
 	procs => proc_metrics(),
 	procs => proc_metrics(),
 
 
+	%% Informational responses sent before the final response.
+	informational => [informational_metrics()],
+
 	%% Length of the request and response bodies. This does
 	%% Length of the request and response bodies. This does
 	%% not include the framing.
 	%% not include the framing.
 	req_body_length => non_neg_integer(),
 	req_body_length => non_neg_integer(),
@@ -108,6 +122,7 @@
 	resp_start :: undefined | integer(),
 	resp_start :: undefined | integer(),
 	resp_end :: undefined | integer(),
 	resp_end :: undefined | integer(),
 	procs = #{} :: proc_metrics(),
 	procs = #{} :: proc_metrics(),
+	informational = [] :: [informational_metrics()],
 	req_body_length = 0 :: non_neg_integer(),
 	req_body_length = 0 :: non_neg_integer(),
 	resp_body_length = 0 :: non_neg_integer()
 	resp_body_length = 0 :: non_neg_integer()
 }).
 }).
@@ -184,6 +199,14 @@ fold([{spawn, Pid, _}|Tail], State0=#state{procs=Procs}) ->
 	ProcStart = erlang:monotonic_time(),
 	ProcStart = erlang:monotonic_time(),
 	State = State0#state{procs=Procs#{Pid => #{spawn => ProcStart}}},
 	State = State0#state{procs=Procs#{Pid => #{spawn => ProcStart}}},
 	fold(Tail, State);
 	fold(Tail, State);
+fold([{inform, Status, Headers}|Tail],
+		State=#state{informational=Infos}) ->
+	Time = erlang:monotonic_time(),
+	fold(Tail, State#state{informational=[#{
+		status => Status,
+		headers => Headers,
+		time => Time
+	}|Infos]});
 fold([{response, Status, Headers, Body}|Tail],
 fold([{response, Status, Headers, Body}|Tail],
 		State=#state{resp_headers_filter=RespHeadersFilter}) ->
 		State=#state{resp_headers_filter=RespHeadersFilter}) ->
 	Resp = erlang:monotonic_time(),
 	Resp = erlang:monotonic_time(),
@@ -226,7 +249,8 @@ terminate(StreamID, Reason, #state{next=Next, callback=Fun,
 		req=Req, resp_status=RespStatus, resp_headers=RespHeaders, ref=Ref,
 		req=Req, resp_status=RespStatus, resp_headers=RespHeaders, ref=Ref,
 		req_start=ReqStart, req_body_start=ReqBodyStart,
 		req_start=ReqStart, req_body_start=ReqBodyStart,
 		req_body_end=ReqBodyEnd, resp_start=RespStart, resp_end=RespEnd,
 		req_body_end=ReqBodyEnd, resp_start=RespStart, resp_end=RespEnd,
-		procs=Procs, req_body_length=ReqBodyLen, resp_body_length=RespBodyLen}) ->
+		procs=Procs, informational=Infos,
+		req_body_length=ReqBodyLen, resp_body_length=RespBodyLen}) ->
 	Res = cowboy_stream:terminate(StreamID, Reason, Next),
 	Res = cowboy_stream:terminate(StreamID, Reason, Next),
 	ReqEnd = erlang:monotonic_time(),
 	ReqEnd = erlang:monotonic_time(),
 	Metrics = #{
 	Metrics = #{
@@ -244,6 +268,7 @@ terminate(StreamID, Reason, #state{next=Next, callback=Fun,
 		resp_start => RespStart,
 		resp_start => RespStart,
 		resp_end => RespEnd,
 		resp_end => RespEnd,
 		procs => Procs,
 		procs => Procs,
+		informational => lists:reverse(Infos),
 		req_body_length => ReqBodyLen,
 		req_body_length => ReqBodyLen,
 		resp_body_length => RespBodyLen
 		resp_body_length => RespBodyLen
 	},
 	},

+ 18 - 5
test/metrics_SUITE.erl

@@ -143,7 +143,8 @@ do_get(Path, Config) ->
 				pid := From,
 				pid := From,
 				streamid := 1,
 				streamid := 1,
 				reason := normal,
 				reason := normal,
-				req := #{}
+				req := #{},
+				informational := []
 			} = Metrics,
 			} = Metrics,
 			%% All good!
 			%% All good!
 			ok
 			ok
@@ -205,7 +206,8 @@ post_body(Config) ->
 				pid := From,
 				pid := From,
 				streamid := 1,
 				streamid := 1,
 				reason := normal,
 				reason := normal,
-				req := #{}
+				req := #{},
+				informational := []
 			} = Metrics,
 			} = Metrics,
 			%% All good!
 			%% All good!
 			ok
 			ok
@@ -261,7 +263,8 @@ no_resp_body(Config) ->
 				pid := From,
 				pid := From,
 				streamid := 1,
 				streamid := 1,
 				reason := normal,
 				reason := normal,
-				req := #{}
+				req := #{},
+				informational := []
 			} = Metrics,
 			} = Metrics,
 			%% All good!
 			%% All good!
 			ok
 			ok
@@ -353,7 +356,7 @@ do_ws(Config) ->
 			%% is called. We therefore only check when it spawned.
 			%% is called. We therefore only check when it spawned.
 			#{procs := Procs} = Metrics,
 			#{procs := Procs} = Metrics,
 			[{_, #{
 			[{_, #{
-				spawn := ProcSpawn
+				spawn := _
 			}}] = maps:to_list(Procs),
 			}}] = maps:to_list(Procs),
 			%% Confirm other metadata are as expected.
 			%% Confirm other metadata are as expected.
 			#{
 			#{
@@ -361,7 +364,17 @@ do_ws(Config) ->
 				pid := From,
 				pid := From,
 				streamid := 1,
 				streamid := 1,
 				reason := switch_protocol,
 				reason := switch_protocol,
-				req := #{}
+				req := #{},
+				%% A 101 upgrade response was sent.
+				informational := [#{
+					status := 101,
+					headers := #{
+						<<"connection">> := <<"Upgrade">>,
+						<<"upgrade">> := <<"websocket">>,
+						<<"sec-websocket-accept">> := _
+					},
+					time := _
+				}]
 			} = Metrics,
 			} = Metrics,
 			%% All good!
 			%% All good!
 			ok
 			ok