1212
1313% % Metrics API
1414-export ([start_request /1 ,
15- finish_request /2 ,
16- get_metrics_engine /0 ]).
15+ finish_request /2 ]).
1716
1817% % Backward compatibility API
1918-export ([get_state /1 , async_response_pid /1 ]).
2322-export ([init /1 , handle_call /3 , handle_cast /2 , handle_info /2 ,
2423 terminate /2 , code_change /3 ]).
2524
26- -record (state , {
27- metrics_engine
28- }).
25+ -record (state , {}).
2926
3027% %====================================================================
3128% % API
@@ -41,11 +38,6 @@ start_request(Host) ->
4138finish_request (Host , StartTime ) ->
4239 gen_server :cast (? MODULE , {finish_request , Host , StartTime }).
4340
44- % % @doc Get the current metrics engine.
45- -spec get_metrics_engine () -> module ().
46- get_metrics_engine () ->
47- hackney_metrics :get_engine ().
48-
4941% % @doc Check the state of a connection (backward compatibility).
5042% % In the old architecture, this tracked request state.
5143% % In the new architecture, we simply check if the connection process is alive.
@@ -63,20 +55,15 @@ get_state(ConnPid) when is_pid(ConnPid) ->
6355get_state (_ ) ->
6456 req_not_found .
6557
66- % % @doc Check if a connection is in async mode (backward compatibility).
67- % % In the old architecture, this returned the async response process PID.
68- % % In the new architecture, we check if the connection process is in async mode.
69- % % Returns `{error, req_not_async}' if not in async mode.
70- -spec async_response_pid (pid () | term ()) -> {ok , pid ()} | {error , req_not_async }.
71- async_response_pid (ConnPid ) when is_pid (ConnPid ) ->
72- case is_process_alive (ConnPid ) of
73- false -> {error , req_not_async };
74- true ->
75- case hackney_conn :get_state (ConnPid ) of
76- {ok , State } when State =:= receiving ; State =:= streaming ->
77- {ok , ConnPid };
78- _ ->
79- {error , req_not_async }
58+ % % @doc Get the async response pid (backward compatibility).
59+ -spec async_response_pid (pid ()) -> {ok , pid ()} | {error , req_not_found | req_not_async }.
60+ async_response_pid (Ref ) when is_pid (Ref ) ->
61+ case get_state (Ref ) of
62+ req_not_found -> {error , req_not_found };
63+ State ->
64+ case proplists :get_value (async , State , false ) of
65+ false -> {error , req_not_async };
66+ true -> {ok , Ref }
8067 end
8168 end ;
8269async_response_pid (_ ) ->
@@ -90,28 +77,27 @@ start_link() ->
9077 gen_server :start_link ({local , ? MODULE }, ? MODULE , [], []).
9178
9279init ([]) ->
93- % % Initialize metrics
94- Engine = hackney_metrics :get_engine (),
95- _ = metrics :new (Engine , counter , [hackney , nb_requests ]),
96- _ = metrics :new (Engine , counter , [hackney , total_requests ]),
97- _ = metrics :new (Engine , counter , [hackney , finished_requests ]),
98- {ok , # state {metrics_engine = Engine }}.
80+ {ok , # state {}}.
9981
10082handle_call (_Request , _From , State ) ->
10183 {reply , ok , State }.
10284
103- handle_cast ({start_request , Host }, # state {metrics_engine = Engine } = State ) ->
104- _ = metrics :increment_counter (Engine , [hackney , Host , nb_requests ]),
105- _ = metrics :increment_counter (Engine , [hackney , nb_requests ]),
106- _ = metrics :increment_counter (Engine , [hackney , total_requests ]),
85+ handle_cast ({start_request , Host }, State ) ->
86+ HostBin = to_binary (Host ),
87+ Labels = #{host => HostBin },
88+ _ = hackney_metrics :counter_inc (hackney_requests_total , Labels ),
89+ _ = hackney_metrics :gauge_inc (hackney_requests_active , Labels ),
10790 {noreply , State };
10891
109- handle_cast ({finish_request , Host , StartTime }, # state {metrics_engine = Engine } = State ) ->
110- RequestTime = timer :now_diff (os :timestamp (), StartTime ) / 1000 ,
111- _ = metrics :update_histogram (Engine , [hackney , Host , request_time ], RequestTime ),
112- _ = metrics :decrement_counter (Engine , [hackney , Host , nb_requests ]),
113- _ = metrics :decrement_counter (Engine , [hackney , nb_requests ]),
114- _ = metrics :increment_counter (Engine , [hackney , finished_requests ]),
92+ handle_cast ({finish_request , Host , StartTime }, State ) ->
93+ HostBin = to_binary (Host ),
94+ Labels = #{host => HostBin },
95+ % % Calculate duration in seconds (Prometheus convention)
96+ DurationMicros = timer :now_diff (os :timestamp (), StartTime ),
97+ DurationSeconds = DurationMicros / 1000000 ,
98+ _ = hackney_metrics :histogram_observe (hackney_request_duration_seconds , Labels , DurationSeconds ),
99+ _ = hackney_metrics :gauge_dec (hackney_requests_active , Labels ),
100+ _ = hackney_metrics :counter_inc (hackney_requests_finished_total , Labels ),
115101 {noreply , State };
116102
117103handle_cast (_Msg , State ) ->
@@ -125,3 +111,11 @@ terminate(_Reason, _State) ->
125111
126112code_change (_OldVsn , State , _Extra ) ->
127113 {ok , State }.
114+
115+ % %====================================================================
116+ % % Internal functions
117+ % %====================================================================
118+
119+ to_binary (Host ) when is_binary (Host ) -> Host ;
120+ to_binary (Host ) when is_list (Host ) -> list_to_binary (Host );
121+ to_binary (Host ) when is_atom (Host ) -> atom_to_binary (Host , utf8 ).
0 commit comments