aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/cowboy_metrics_h.erl21
-rw-r--r--test/handlers/set_options_h.erl7
-rw-r--r--test/metrics_SUITE.erl29
3 files changed, 43 insertions, 14 deletions
diff --git a/src/cowboy_metrics_h.erl b/src/cowboy_metrics_h.erl
index 309afde..4107aac 100644
--- a/src/cowboy_metrics_h.erl
+++ b/src/cowboy_metrics_h.erl
@@ -102,7 +102,10 @@
%% Length of the request and response bodies. This does
%% not include the framing.
req_body_length => non_neg_integer(),
- resp_body_length => non_neg_integer()
+ resp_body_length => non_neg_integer(),
+
+ %% Additional metadata set by the user.
+ user_data => map()
}.
-export_type([metrics/0]).
@@ -126,7 +129,8 @@
procs = #{} :: proc_metrics(),
informational = [] :: [informational_metrics()],
req_body_length = 0 :: non_neg_integer(),
- resp_body_length = 0 :: non_neg_integer()
+ resp_body_length = 0 :: non_neg_integer(),
+ user_data = #{} :: map()
}).
-spec init(cowboy_stream:streamid(), cowboy_req:req(), cowboy:opts())
@@ -255,6 +259,14 @@ fold([{data, fin, Data}|Tail], State=#state{resp_body_length=RespBodyLen}) ->
resp_end=RespEnd,
resp_body_length=RespBodyLen + resp_body_length(Data)
});
+fold([{set_options, SetOpts}|Tail], State0=#state{user_data=OldUserData}) ->
+ State = case SetOpts of
+ #{metrics_user_data := NewUserData} ->
+ State0#state{user_data=maps:merge(OldUserData, NewUserData)};
+ _ ->
+ State0
+ end,
+ fold(Tail, State);
fold([_|Tail], State) ->
fold(Tail, State).
@@ -263,7 +275,7 @@ terminate(StreamID, Reason, #state{next=Next, callback=Fun,
req=Req, resp_status=RespStatus, resp_headers=RespHeaders, ref=Ref,
req_start=ReqStart, req_body_start=ReqBodyStart,
req_body_end=ReqBodyEnd, resp_start=RespStart, resp_end=RespEnd,
- procs=Procs, informational=Infos,
+ procs=Procs, informational=Infos, user_data=UserData,
req_body_length=ReqBodyLen, resp_body_length=RespBodyLen}) ->
Res = cowboy_stream:terminate(StreamID, Reason, Next),
ReqEnd = erlang:monotonic_time(),
@@ -284,7 +296,8 @@ terminate(StreamID, Reason, #state{next=Next, callback=Fun,
procs => Procs,
informational => lists:reverse(Infos),
req_body_length => ReqBodyLen,
- resp_body_length => RespBodyLen
+ resp_body_length => RespBodyLen,
+ user_data => UserData
},
Fun(Metrics),
Res.
diff --git a/test/handlers/set_options_h.erl b/test/handlers/set_options_h.erl
index 1cefe92..ef88a6f 100644
--- a/test/handlers/set_options_h.erl
+++ b/test/handlers/set_options_h.erl
@@ -32,4 +32,9 @@ set_options(<<"idle_timeout_long">>, Req0, State) ->
#{pid := Pid, streamid := StreamID} = Req0,
Pid ! {{Pid, StreamID}, {set_options, #{idle_timeout => 60000}}},
{_, Body, Req} = cowboy_req:read_body(Req0),
- {ok, cowboy_req:reply(200, #{}, Body, Req), State}.
+ {ok, cowboy_req:reply(200, #{}, Body, Req), State};
+set_options(<<"metrics_user_data">>, Req, State) ->
+ %% @todo This should be replaced by a cowboy_req:cast/cowboy_stream:cast.
+ #{pid := Pid, streamid := StreamID} = Req,
+ Pid ! {{Pid, StreamID}, {set_options, #{metrics_user_data => #{handler => ?MODULE}}}},
+ {ok, cowboy_req:reply(200, #{}, <<"Hello world!">>, Req), State}.
diff --git a/test/metrics_SUITE.erl b/test/metrics_SUITE.erl
index 4ead60c..d9ff7ea 100644
--- a/test/metrics_SUITE.erl
+++ b/test/metrics_SUITE.erl
@@ -76,6 +76,7 @@ init_routes(_) -> [
{"/default", default_h, []},
{"/full/:key", echo_h, []},
{"/resp/:key[/:arg]", resp_h, []},
+ {"/set_options/:key", set_options_h, []},
{"/ws_echo", ws_echo, []}
]}
].
@@ -98,9 +99,13 @@ do_metrics_callback() ->
hello_world(Config) ->
doc("Confirm metrics are correct for a normal GET request."),
- do_get("/", Config).
+ do_get("/", #{}, Config).
-do_get(Path, Config) ->
+user_data(Config) ->
+ doc("Confirm user data can be attached to metrics."),
+ do_get("/set_options/metrics_user_data", #{handler => set_options_h}, Config).
+
+do_get(Path, UserData, Config) ->
%% Perform a GET request.
ConnPid = gun_open(Config),
Ref = gun:get(ConnPid, Path, [
@@ -153,7 +158,8 @@ do_get(Path, Config) ->
streamid := 1,
reason := normal,
req := #{},
- informational := []
+ informational := [],
+ user_data := UserData
} = Metrics,
%% All good!
ok
@@ -216,7 +222,8 @@ post_body(Config) ->
streamid := 1,
reason := normal,
req := #{},
- informational := []
+ informational := [],
+ user_data := #{}
} = Metrics,
%% All good!
ok
@@ -273,7 +280,8 @@ no_resp_body(Config) ->
streamid := 1,
reason := normal,
req := #{},
- informational := []
+ informational := [],
+ user_data := #{}
} = Metrics,
%% All good!
ok
@@ -361,7 +369,7 @@ do_early_error_request_line(Config) ->
%% This test is identical to normal GET except for the handler.
stream_reply(Config) ->
doc("Confirm metrics are correct for long polling."),
- do_get("/resp/stream_reply2/200", Config).
+ do_get("/resp/stream_reply2/200", #{}, Config).
ws(Config) ->
case config(protocol, Config) of
@@ -421,7 +429,8 @@ do_ws(Config) ->
<<"sec-websocket-accept">> := _
},
time := _
- }]
+ }],
+ user_data := #{}
} = Metrics,
%% All good!
ok
@@ -487,7 +496,8 @@ error_response(Config) ->
streamid := 1,
reason := {internal_error, {'EXIT', _Pid, {crash, _StackTrace}}, 'Stream process crashed.'},
req := #{},
- informational := []
+ informational := [],
+ user_data := #{}
} = Metrics,
%% All good!
ok
@@ -546,7 +556,8 @@ error_response_after_reply(Config) ->
streamid := 1,
reason := {internal_error, {'EXIT', _Pid, {crash, _StackTrace}}, 'Stream process crashed.'},
req := #{},
- informational := []
+ informational := [],
+ user_data := #{}
} = Metrics,
%% All good!
ok