@@ -43,6 +43,9 @@ const HTTP_SERVER_ACTIVE_REQUESTS_UNIT: &str = "{request}";
4343const HTTP_SERVER_REQUEST_BODY_SIZE_METRIC : & str = "http.server.request.body.size" ;
4444const HTTP_SERVER_REQUEST_BODY_SIZE_UNIT : & str = "By" ;
4545
46+ const HTTP_SERVER_RESPONSE_BODY_SIZE_METRIC : & str = "http.server.response.body.size" ;
47+ const HTTP_SERVER_RESPONSE_BODY_SIZE_UNIT : & str = "By" ;
48+
4649const NETWORK_PROTOCOL_NAME_LABEL : & str = "network.protocol.name" ;
4750const NETWORK_PROTOCOL_VERSION_LABEL : & str = "network.protocol.version" ;
4851const URL_SCHEME_LABEL : & str = "url.scheme" ;
@@ -61,6 +64,7 @@ struct HTTPMetricsLayerState {
6164 pub server_request_duration : Histogram < f64 > ,
6265 pub server_active_requests : UpDownCounter < i64 > ,
6366 pub server_request_body_size : Histogram < u64 > ,
67+ pub server_response_body_size : Histogram < u64 > ,
6468}
6569
6670#[ derive( Clone ) ]
@@ -150,6 +154,11 @@ impl HTTPMetricsLayerBuilder {
150154 . with_description ( "Size of HTTP server request bodies." )
151155 . with_unit ( HTTP_SERVER_REQUEST_BODY_SIZE_UNIT )
152156 . build ( ) ,
157+ server_response_body_size : meter
158+ . u64_histogram ( HTTP_SERVER_RESPONSE_BODY_SIZE_METRIC )
159+ . with_description ( "Size of HTTP server response bodies." )
160+ . with_unit ( HTTP_SERVER_RESPONSE_BODY_SIZE_UNIT )
161+ . build ( ) ,
153162 }
154163 }
155164}
@@ -177,7 +186,7 @@ struct ResponseFutureMetricsState {
177186 // https://opentelemetry.io/docs/specs/semconv/http/http-metrics/#metric-httpserverrequestduration
178187 duration_start : Instant ,
179188 // https://opentelemetry.io/docs/specs/semconv/http/http-metrics/#metric-httpserverrequestbodysize
180- body_size : Option < u64 > ,
189+ req_body_size : Option < u64 > ,
181190
182191 // fields for metric labels
183192 protocol_name_kv : KeyValue ,
@@ -197,7 +206,7 @@ pin_project! {
197206 }
198207}
199208
200- impl < S , ReqBody , ResBody > Service < http:: Request < ReqBody > > for HTTPMetricsService < S >
209+ impl < S , ReqBody , ResBody : http_body :: Body > Service < http:: Request < ReqBody > > for HTTPMetricsService < S >
201210where
202211 S : Service < http:: Request < ReqBody > , Response = http:: Response < ResBody > > ,
203212{
@@ -246,7 +255,7 @@ where
246255 layer_state : self . state . clone ( ) ,
247256 metrics_state : ResponseFutureMetricsState {
248257 duration_start,
249- body_size : content_length,
258+ req_body_size : content_length,
250259
251260 protocol_name_kv,
252261 protocol_version_kv,
@@ -258,7 +267,7 @@ where
258267 }
259268}
260269
261- impl < F , ResBody , E > Future for HTTPMetricsResponseFuture < F >
270+ impl < F , ResBody : http_body :: Body , E > Future for HTTPMetricsResponseFuture < F >
262271where
263272 F : Future < Output = result:: Result < http:: Response < ResBody > , E > > ,
264273{
@@ -287,10 +296,17 @@ where
287296 & label_superset,
288297 ) ;
289298
290- if let Some ( content_length ) = this. metrics_state . body_size {
299+ if let Some ( req_content_length ) = this. metrics_state . req_body_size {
291300 this. layer_state
292301 . server_request_body_size
293- . record ( content_length, & label_superset) ;
302+ . record ( req_content_length, & label_superset) ;
303+ }
304+
305+ // use same approach for `http.server.response.body.size` as hyper does to set content-length
306+ if let Some ( resp_content_length) = response. body ( ) . size_hint ( ) . exact ( ) {
307+ this. layer_state
308+ . server_response_body_size
309+ . record ( resp_content_length, & label_superset) ;
294310 }
295311
296312 this. layer_state . server_active_requests . add (
0 commit comments