aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLoïc Hoguin <[email protected]>2019-10-02 15:23:23 +0200
committerLoïc Hoguin <[email protected]>2019-10-02 15:23:23 +0200
commitf673e191b30ab440440c924476bb03000fff52c6 (patch)
tree0f74c7940c1a8f38ef1ca4e5e86552924072eccf
parenta14ecf19c68ba5b9eb828a41356b1adbc1c5739c (diff)
downloadcowboy-f673e191b30ab440440c924476bb03000fff52c6.tar.gz
cowboy-f673e191b30ab440440c924476bb03000fff52c6.tar.bz2
cowboy-f673e191b30ab440440c924476bb03000fff52c6.zip
Add {set_options, #{metrics_user_data := Map}}
This allows giving custom metadata to the metrics stream handler. This can be useful to for example provide the name of the module handling the request which is only known after routing. But any user data is allowed. When called multiple times the user data maps are merged.
-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