diff --git a/source/extensions/filters/http/grpc_stats/grpc_stats_filter.cc b/source/extensions/filters/http/grpc_stats/grpc_stats_filter.cc index e155135a40902..7c91093d47121 100644 --- a/source/extensions/filters/http/grpc_stats/grpc_stats_filter.cc +++ b/source/extensions/filters/http/grpc_stats/grpc_stats_filter.cc @@ -207,6 +207,9 @@ class GrpcStatsFilter : public Http::PassThroughFilter { if (doStatTracking()) { config_->context_.chargeStat(*cluster_, Grpc::Context::Protocol::Grpc, request_names_, headers.GrpcStatus()); + if (end_stream) { + maybeChargeUpstreamStat(); + } } return Http::FilterHeadersStatus::Continue; } @@ -228,16 +231,7 @@ class GrpcStatsFilter : public Http::PassThroughFilter { if (doStatTracking()) { config_->context_.chargeStat(*cluster_, Grpc::Context::Protocol::Grpc, request_names_, trailers.GrpcStatus()); - - if (config_->enable_upstream_stats_ && - decoder_callbacks_->streamInfo().lastUpstreamTxByteSent().has_value() && - decoder_callbacks_->streamInfo().lastUpstreamRxByteReceived().has_value()) { - std::chrono::milliseconds chrono_duration = - std::chrono::duration_cast( - decoder_callbacks_->streamInfo().lastUpstreamRxByteReceived().value() - - decoder_callbacks_->streamInfo().lastUpstreamTxByteSent().value()); - config_->context_.chargeUpstreamStat(*cluster_, request_names_, chrono_duration); - } + maybeChargeUpstreamStat(); } return Http::FilterTrailersStatus::Continue; } @@ -260,6 +254,18 @@ class GrpcStatsFilter : public Http::PassThroughFilter { filter_object_->response_message_count = response_counter_.frameCount(); } + void maybeChargeUpstreamStat() { + if (config_->enable_upstream_stats_ && + decoder_callbacks_->streamInfo().lastUpstreamTxByteSent().has_value() && + decoder_callbacks_->streamInfo().lastUpstreamRxByteReceived().has_value()) { + std::chrono::milliseconds chrono_duration = + std::chrono::duration_cast( + decoder_callbacks_->streamInfo().lastUpstreamRxByteReceived().value() - + decoder_callbacks_->streamInfo().lastUpstreamTxByteSent().value()); + config_->context_.chargeUpstreamStat(*cluster_, request_names_, chrono_duration); + } + } + private: ConfigConstSharedPtr config_; GrpcStatsObject* filter_object_{}; diff --git a/test/extensions/filters/http/grpc_stats/config_test.cc b/test/extensions/filters/http/grpc_stats/config_test.cc index 532bfaba752a3..b75737b06cd28 100644 --- a/test/extensions/filters/http/grpc_stats/config_test.cc +++ b/test/extensions/filters/http/grpc_stats/config_test.cc @@ -436,6 +436,33 @@ TEST_F(GrpcStatsFilterConfigTest, UpstreamStats) { doRequestResponse(request_headers); } +TEST_F(GrpcStatsFilterConfigTest, UpstreamStatsWithTrailersOnly) { + config_.mutable_stats_for_all_methods()->set_value(true); + config_.set_emit_filter_state(true); + config_.set_enable_upstream_stats(true); + initialize(); + + ON_CALL(stream_info_, lastUpstreamRxByteReceived()) + .WillByDefault(testing::Return( + absl::optional(std::chrono::nanoseconds(30000000)))); + ON_CALL(stream_info_, lastUpstreamTxByteSent()) + .WillByDefault(testing::Return( + absl::optional(std::chrono::nanoseconds(20000000)))); + + EXPECT_CALL(stats_store_, + deliverHistogramToSinks( + Property(&Stats::Metric::name, + "grpc.lyft.users.BadCompanions.GetBadCompanions.upstream_rq_time"), + 10ul)); + Http::TestRequestHeaderMapImpl request_headers{ + {"content-type", "application/grpc+proto"}, + {":path", "/lyft.users.BadCompanions/GetBadCompanions"}}; + + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, false)); + Http::TestResponseHeaderMapImpl response_headers{{":status", "500"}}; + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->encodeHeaders(response_headers, true)); +} + } // namespace } // namespace GrpcStats } // namespace HttpFilters