@@ -130,8 +130,9 @@ do_start_cowboy(Ref, Opts) ->
130130 TransportOpts = gen_mod :get_opt (transport_options , Opts , []),
131131 Modules = gen_mod :get_opt (modules , Opts ),
132132 Dispatch = cowboy_router :compile (get_routes (Modules )),
133- ProtocolOpts = [{env , [{dispatch , Dispatch }]} |
134- gen_mod :get_opt (protocol_options , Opts , [])],
133+ {MetricsEnv , MetricsProtoOpts } = maybe_init_metrics (Opts ),
134+ ProtocolOpts = [{env , [{dispatch , Dispatch } | MetricsEnv ]} |
135+ gen_mod :get_opt (protocol_options , Opts , [])] ++ MetricsProtoOpts ,
135136 case catch start_http_or_https (SSLOpts , Ref , NumAcceptors , TransportOpts , ProtocolOpts ) of
136137 {error , {{shutdown ,
137138 {failed_to_start_child , ranch_acceptors_sup ,
@@ -180,7 +181,9 @@ get_routes([], Routes) ->
180181 Routes ;
181182get_routes ([{Host , BasePath , Module } | Tail ], Routes ) ->
182183 get_routes ([{Host , BasePath , Module , []} | Tail ], Routes );
183- get_routes ([{Host , BasePath , Module , Opts } | Tail ], Routes ) ->
184+ get_routes ([{Host , BasePath , Module , HandlerOpts } | Tail ], Routes ) ->
185+ get_routes ([{Host , BasePath , Module , HandlerOpts , []} | Tail ], Routes );
186+ get_routes ([{Host , BasePath , Module , HandlerOpts , _Opts } | Tail ], Routes ) ->
184187 % % ejabberd_config tries to expand the atom '_' as a Macro, which fails.
185188 % % To work around that, use "_" instead and translate it to '_' here.
186189 CowboyHost = case Host of
@@ -190,8 +193,8 @@ get_routes([{Host, BasePath, Module, Opts} | Tail], Routes) ->
190193 {module , Module } = code :ensure_loaded (Module ),
191194 Paths = proplists :get_value (CowboyHost , Routes , []) ++
192195 case erlang :function_exported (Module , cowboy_router_paths , 2 ) of
193- true -> Module :cowboy_router_paths (BasePath , Opts );
194- _ -> [{BasePath , Module , Opts }]
196+ true -> Module :cowboy_router_paths (BasePath , HandlerOpts );
197+ _ -> [{BasePath , Module , HandlerOpts }]
195198 end ,
196199 get_routes (Tail , lists :keystore (CowboyHost , 1 , Routes , {CowboyHost , Paths })).
197200
@@ -224,3 +227,68 @@ maybe_insert_max_connections(TransportOpts, Opts) ->
224227 NewTuple = {Key , Value },
225228 lists :keystore (Key , 1 , TransportOpts , NewTuple )
226229 end .
230+
231+ -spec measured_methods () -> [mongoose_cowboy_metrics :method ()].
232+ measured_methods () ->
233+ [<<" GET" >>,
234+ <<" HEAD" >>,
235+ <<" POST" >>,
236+ <<" PUT" >>,
237+ <<" DELETE" >>,
238+ <<" OPTIONS" >>,
239+ <<" PATCH" >>].
240+
241+ -spec measured_classes () -> [mongoose_cowboy_metrics :status_class ()].
242+ measured_classes () ->
243+ [<<" 1XX" >>, <<" 2XX" >>, <<" 3XX" >>, <<" 4XX" >>, <<" 5XX" >>].
244+
245+ base_metrics_prefix () ->
246+ [http ].
247+
248+ middlewares_with_metrics () ->
249+ [mongoose_cowboy_metrics_mw_before ,
250+ cowboy_router ,
251+ mongoose_cowboy_metrics_mw_after ,
252+ cowboy_handler ].
253+
254+ -spec maybe_init_metrics (list ()) -> {MetricsEnv :: list (), MetricsProtocolOpts :: list ()}.
255+ maybe_init_metrics (Opts ) ->
256+ case proplists :get_value (metrics , Opts , false ) of
257+ true ->
258+ BasePrefix = base_metrics_prefix (),
259+ HandlerToPrefixMappings = build_metric_prefixes (
260+ BasePrefix , proplists :get_value (modules , Opts , []), #{}),
261+ [create_metrics (Prefix ) || Prefix <- maps :values (HandlerToPrefixMappings )],
262+ {[{record_metrics , true }, {handler_to_metric_prefix , HandlerToPrefixMappings }],
263+ [{middlewares , middlewares_with_metrics ()}]};
264+ false ->
265+ {[], []}
266+ end .
267+
268+ -spec build_metric_prefixes (BasePrefix :: list (), Modules :: [tuple ()], Acc ) -> Acc
269+ when Acc :: #{module () => mongoose_cowboy_metrics :prefix ()}.
270+ build_metric_prefixes (_BasePrefix , [], Acc ) ->
271+ Acc ;
272+ build_metric_prefixes (BasePrefix , [{_Host , _Path , Handler , _HandlerOpts , Opts } | Tail ], Acc ) ->
273+ case proplists :get_value (metrics , Opts , []) of
274+ MetricsOpts when is_list (MetricsOpts ) ->
275+ HandlerPrefix = proplists :get_value (prefix , MetricsOpts , Handler ),
276+ Prefix = BasePrefix ++ lists :flatten ([HandlerPrefix ]),
277+ build_metric_prefixes (BasePrefix , Tail , maps :put (Handler , Prefix , Acc ));
278+ false ->
279+ build_metric_prefixes (BasePrefix , Tail , Acc )
280+ end ;
281+ build_metric_prefixes (BasePrefix , [{Host , Path , Handler , HandlerOpts } | Tail ], Acc ) ->
282+ build_metric_prefixes (BasePrefix , [{Host , Path , Handler , HandlerOpts , []} | Tail ], Acc );
283+ build_metric_prefixes (BasePrefix , [{Host , Path , Handler } | Tail ], Acc ) ->
284+ build_metric_prefixes (BasePrefix , [{Host , Path , Handler , [], []} | Tail ], Acc ).
285+
286+ -spec create_metrics (mongoose_cowboy_metrics :prefix ()) -> any ().
287+ create_metrics (Prefix ) ->
288+ CountMetrics = [mongoose_cowboy_metrics :request_count_metric (Prefix , M ) || M <- measured_methods ()] ++
289+ [mongoose_cowboy_metrics :response_count_metric (Prefix , M , C )
290+ || M <- measured_methods (), C <- measured_classes ()],
291+ LatencyMetrics = [mongoose_cowboy_metrics :response_latency_metric (Prefix , M , C )
292+ || M <- measured_methods (), C <- measured_classes ()],
293+ [mongoose_metrics :ensure_metric (global , M , spiral ) || M <- CountMetrics ],
294+ [mongoose_metrics :ensure_metric (global , M , histogram ) || M <- LatencyMetrics ].
0 commit comments