mirror of
https://github.com/ninenines/cowboy.git
synced 2025-07-14 20:30:23 +00:00
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.
This commit is contained in:
parent
a14ecf19c6
commit
f673e191b3
3 changed files with 43 additions and 14 deletions
|
@ -102,7 +102,10 @@
|
||||||
%% 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(),
|
||||||
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]).
|
-export_type([metrics/0]).
|
||||||
|
|
||||||
|
@ -126,7 +129,8 @@
|
||||||
procs = #{} :: proc_metrics(),
|
procs = #{} :: proc_metrics(),
|
||||||
informational = [] :: [informational_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(),
|
||||||
|
user_data = #{} :: map()
|
||||||
}).
|
}).
|
||||||
|
|
||||||
-spec init(cowboy_stream:streamid(), cowboy_req:req(), cowboy:opts())
|
-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_end=RespEnd,
|
||||||
resp_body_length=RespBodyLen + resp_body_length(Data)
|
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) ->
|
||||||
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=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, informational=Infos,
|
procs=Procs, informational=Infos, user_data=UserData,
|
||||||
req_body_length=ReqBodyLen, resp_body_length=RespBodyLen}) ->
|
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(),
|
||||||
|
@ -284,7 +296,8 @@ terminate(StreamID, Reason, #state{next=Next, callback=Fun,
|
||||||
procs => Procs,
|
procs => Procs,
|
||||||
informational => lists:reverse(Infos),
|
informational => lists:reverse(Infos),
|
||||||
req_body_length => ReqBodyLen,
|
req_body_length => ReqBodyLen,
|
||||||
resp_body_length => RespBodyLen
|
resp_body_length => RespBodyLen,
|
||||||
|
user_data => UserData
|
||||||
},
|
},
|
||||||
Fun(Metrics),
|
Fun(Metrics),
|
||||||
Res.
|
Res.
|
||||||
|
|
|
@ -32,4 +32,9 @@ set_options(<<"idle_timeout_long">>, Req0, State) ->
|
||||||
#{pid := Pid, streamid := StreamID} = Req0,
|
#{pid := Pid, streamid := StreamID} = Req0,
|
||||||
Pid ! {{Pid, StreamID}, {set_options, #{idle_timeout => 60000}}},
|
Pid ! {{Pid, StreamID}, {set_options, #{idle_timeout => 60000}}},
|
||||||
{_, Body, Req} = cowboy_req:read_body(Req0),
|
{_, 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}.
|
||||||
|
|
|
@ -76,6 +76,7 @@ init_routes(_) -> [
|
||||||
{"/default", default_h, []},
|
{"/default", default_h, []},
|
||||||
{"/full/:key", echo_h, []},
|
{"/full/:key", echo_h, []},
|
||||||
{"/resp/:key[/:arg]", resp_h, []},
|
{"/resp/:key[/:arg]", resp_h, []},
|
||||||
|
{"/set_options/:key", set_options_h, []},
|
||||||
{"/ws_echo", ws_echo, []}
|
{"/ws_echo", ws_echo, []}
|
||||||
]}
|
]}
|
||||||
].
|
].
|
||||||
|
@ -98,9 +99,13 @@ do_metrics_callback() ->
|
||||||
|
|
||||||
hello_world(Config) ->
|
hello_world(Config) ->
|
||||||
doc("Confirm metrics are correct for a normal GET request."),
|
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.
|
%% Perform a GET request.
|
||||||
ConnPid = gun_open(Config),
|
ConnPid = gun_open(Config),
|
||||||
Ref = gun:get(ConnPid, Path, [
|
Ref = gun:get(ConnPid, Path, [
|
||||||
|
@ -153,7 +158,8 @@ do_get(Path, Config) ->
|
||||||
streamid := 1,
|
streamid := 1,
|
||||||
reason := normal,
|
reason := normal,
|
||||||
req := #{},
|
req := #{},
|
||||||
informational := []
|
informational := [],
|
||||||
|
user_data := UserData
|
||||||
} = Metrics,
|
} = Metrics,
|
||||||
%% All good!
|
%% All good!
|
||||||
ok
|
ok
|
||||||
|
@ -216,7 +222,8 @@ post_body(Config) ->
|
||||||
streamid := 1,
|
streamid := 1,
|
||||||
reason := normal,
|
reason := normal,
|
||||||
req := #{},
|
req := #{},
|
||||||
informational := []
|
informational := [],
|
||||||
|
user_data := #{}
|
||||||
} = Metrics,
|
} = Metrics,
|
||||||
%% All good!
|
%% All good!
|
||||||
ok
|
ok
|
||||||
|
@ -273,7 +280,8 @@ no_resp_body(Config) ->
|
||||||
streamid := 1,
|
streamid := 1,
|
||||||
reason := normal,
|
reason := normal,
|
||||||
req := #{},
|
req := #{},
|
||||||
informational := []
|
informational := [],
|
||||||
|
user_data := #{}
|
||||||
} = Metrics,
|
} = Metrics,
|
||||||
%% All good!
|
%% All good!
|
||||||
ok
|
ok
|
||||||
|
@ -361,7 +369,7 @@ do_early_error_request_line(Config) ->
|
||||||
%% This test is identical to normal GET except for the handler.
|
%% This test is identical to normal GET except for the handler.
|
||||||
stream_reply(Config) ->
|
stream_reply(Config) ->
|
||||||
doc("Confirm metrics are correct for long polling."),
|
doc("Confirm metrics are correct for long polling."),
|
||||||
do_get("/resp/stream_reply2/200", Config).
|
do_get("/resp/stream_reply2/200", #{}, Config).
|
||||||
|
|
||||||
ws(Config) ->
|
ws(Config) ->
|
||||||
case config(protocol, Config) of
|
case config(protocol, Config) of
|
||||||
|
@ -421,7 +429,8 @@ do_ws(Config) ->
|
||||||
<<"sec-websocket-accept">> := _
|
<<"sec-websocket-accept">> := _
|
||||||
},
|
},
|
||||||
time := _
|
time := _
|
||||||
}]
|
}],
|
||||||
|
user_data := #{}
|
||||||
} = Metrics,
|
} = Metrics,
|
||||||
%% All good!
|
%% All good!
|
||||||
ok
|
ok
|
||||||
|
@ -487,7 +496,8 @@ error_response(Config) ->
|
||||||
streamid := 1,
|
streamid := 1,
|
||||||
reason := {internal_error, {'EXIT', _Pid, {crash, _StackTrace}}, 'Stream process crashed.'},
|
reason := {internal_error, {'EXIT', _Pid, {crash, _StackTrace}}, 'Stream process crashed.'},
|
||||||
req := #{},
|
req := #{},
|
||||||
informational := []
|
informational := [],
|
||||||
|
user_data := #{}
|
||||||
} = Metrics,
|
} = Metrics,
|
||||||
%% All good!
|
%% All good!
|
||||||
ok
|
ok
|
||||||
|
@ -546,7 +556,8 @@ error_response_after_reply(Config) ->
|
||||||
streamid := 1,
|
streamid := 1,
|
||||||
reason := {internal_error, {'EXIT', _Pid, {crash, _StackTrace}}, 'Stream process crashed.'},
|
reason := {internal_error, {'EXIT', _Pid, {crash, _StackTrace}}, 'Stream process crashed.'},
|
||||||
req := #{},
|
req := #{},
|
||||||
informational := []
|
informational := [],
|
||||||
|
user_data := #{}
|
||||||
} = Metrics,
|
} = Metrics,
|
||||||
%% All good!
|
%% All good!
|
||||||
ok
|
ok
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue