@@ -130,8 +130,9 @@ do_start_cowboy(Ref, Opts) ->
130
130
TransportOpts = gen_mod :get_opt (transport_options , Opts , []),
131
131
Modules = gen_mod :get_opt (modules , Opts ),
132
132
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 ,
135
136
case catch start_http_or_https (SSLOpts , Ref , NumAcceptors , TransportOpts , ProtocolOpts ) of
136
137
{error , {{shutdown ,
137
138
{failed_to_start_child , ranch_acceptors_sup ,
@@ -180,7 +181,9 @@ get_routes([], Routes) ->
180
181
Routes ;
181
182
get_routes ([{Host , BasePath , Module } | Tail ], Routes ) ->
182
183
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 ) ->
184
187
% % ejabberd_config tries to expand the atom '_' as a Macro, which fails.
185
188
% % To work around that, use "_" instead and translate it to '_' here.
186
189
CowboyHost = case Host of
@@ -190,8 +193,8 @@ get_routes([{Host, BasePath, Module, Opts} | Tail], Routes) ->
190
193
{module , Module } = code :ensure_loaded (Module ),
191
194
Paths = proplists :get_value (CowboyHost , Routes , []) ++
192
195
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 }]
195
198
end ,
196
199
get_routes (Tail , lists :keystore (CowboyHost , 1 , Routes , {CowboyHost , Paths })).
197
200
@@ -224,3 +227,68 @@ maybe_insert_max_connections(TransportOpts, Opts) ->
224
227
NewTuple = {Key , Value },
225
228
lists :keystore (Key , 1 , TransportOpts , NewTuple )
226
229
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