Skip to content

Commit 69f7f8a

Browse files
authored
impl(bigtable): implement application blocking latencies metrics (#15373)
* impl(bigtable): implement application blocking latencies metrics.
1 parent bfc7515 commit 69f7f8a

File tree

4 files changed

+254
-14
lines changed

4 files changed

+254
-14
lines changed

google/cloud/bigtable/internal/metrics.cc

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,56 @@ std::unique_ptr<Metric> ServerLatency::clone(ResourceLabels resource_labels,
344344
return m;
345345
}
346346

347+
ApplicationBlockingLatency::ApplicationBlockingLatency(
348+
std::string const& instrumentation_scope,
349+
opentelemetry::nostd::shared_ptr<
350+
opentelemetry::metrics::MeterProvider> const& provider)
351+
: application_blocking_latencies_(
352+
provider
353+
->GetMeter(instrumentation_scope,
354+
kMeterInstrumentationScopeVersion)
355+
->CreateDoubleHistogram("application_latencies")) {}
356+
357+
void ApplicationBlockingLatency::ElementDelivery(
358+
opentelemetry::context::Context const&, ElementDeliveryParams const& p) {
359+
element_delivery_time_ = p.element_delivery;
360+
}
361+
362+
void ApplicationBlockingLatency::ElementRequest(
363+
opentelemetry::context::Context const&, ElementRequestParams const& p) {
364+
auto application_blocking_latency =
365+
std::chrono::duration_cast<LatencyDuration>(p.element_request -
366+
element_delivery_time_);
367+
pending_latencies_.push_back(application_blocking_latency);
368+
}
369+
370+
void ApplicationBlockingLatency::PostCall(
371+
opentelemetry::context::Context const&,
372+
grpc::ClientContext const& client_context, PostCallParams const&) {
373+
auto response_params = GetResponseParamsFromTrailingMetadata(client_context);
374+
if (response_params) {
375+
resource_labels_.cluster = response_params->cluster_id();
376+
resource_labels_.zone = response_params->zone_id();
377+
}
378+
}
379+
380+
void ApplicationBlockingLatency::OnDone(
381+
opentelemetry::context::Context const& context, OnDoneParams const&) {
382+
auto m = IntoLabelMap(resource_labels_, data_labels_,
383+
std::set<std::string>{"streaming", "status"});
384+
for (auto const& latency : pending_latencies_) {
385+
application_blocking_latencies_->Record(latency.count(), m, context);
386+
}
387+
}
388+
389+
std::unique_ptr<Metric> ApplicationBlockingLatency::clone(
390+
ResourceLabels resource_labels, DataLabels data_labels) const {
391+
auto m = std::make_unique<ApplicationBlockingLatency>(*this);
392+
m->resource_labels_ = std::move(resource_labels);
393+
m->data_labels_ = std::move(data_labels);
394+
return m;
395+
}
396+
347397
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
348398
} // namespace bigtable_internal
349399
} // namespace cloud

google/cloud/bigtable/internal/metrics.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,34 @@ class ServerLatency : public Metric {
222222
server_latencies_;
223223
};
224224

225+
class ApplicationBlockingLatency : public Metric {
226+
public:
227+
ApplicationBlockingLatency(
228+
std::string const& instrumentation_scope,
229+
opentelemetry::nostd::shared_ptr<
230+
opentelemetry::metrics::MeterProvider> const& provider);
231+
void PostCall(opentelemetry::context::Context const& context,
232+
grpc::ClientContext const& client_context,
233+
PostCallParams const& p) override;
234+
void ElementDelivery(opentelemetry::context::Context const&,
235+
ElementDeliveryParams const&) override;
236+
void ElementRequest(opentelemetry::context::Context const&,
237+
ElementRequestParams const&) override;
238+
void OnDone(opentelemetry::context::Context const& context,
239+
OnDoneParams const&) override;
240+
241+
std::unique_ptr<Metric> clone(ResourceLabels resource_labels,
242+
DataLabels data_labels) const override;
243+
244+
private:
245+
ResourceLabels resource_labels_;
246+
DataLabels data_labels_;
247+
opentelemetry::nostd::shared_ptr<opentelemetry::metrics::Histogram<double>>
248+
application_blocking_latencies_;
249+
OperationContext::Clock::time_point element_delivery_time_;
250+
std::vector<LatencyDuration> pending_latencies_;
251+
};
252+
225253
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
226254
} // namespace bigtable_internal
227255
} // namespace cloud

google/cloud/bigtable/internal/metrics_test.cc

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1574,6 +1574,168 @@ TEST(ServerLatency, NoServerTiming) {
15741574
{clock->Now(), Status{StatusCode::kOk, "ok"}});
15751575
}
15761576

1577+
TEST(ApplicationBlockingLatency, Success) {
1578+
auto mock_histogram = std::make_unique<MockHistogram<double>>();
1579+
EXPECT_CALL(
1580+
*mock_histogram,
1581+
Record(A<double>(), A<opentelemetry::common::KeyValueIterable const&>(),
1582+
A<opentelemetry::context::Context const&>()))
1583+
.WillOnce([](double value,
1584+
opentelemetry::common::KeyValueIterable const& attributes,
1585+
opentelemetry::context::Context const&) {
1586+
EXPECT_THAT(value, Eq(1.234));
1587+
EXPECT_THAT(
1588+
MakeAttributesMap(attributes),
1589+
UnorderedElementsAre(
1590+
Pair("project_id", "my-project-id"),
1591+
Pair("instance", "my-instance"), Pair("cluster", "my-cluster"),
1592+
Pair("table", "my-table"), Pair("zone", "my-zone"),
1593+
Pair("method", "my-method"),
1594+
Pair("client_name", "my-client-name"),
1595+
Pair("client_uid", "my-client-uid"),
1596+
Pair("app_profile", "my-app-profile")));
1597+
});
1598+
1599+
opentelemetry::nostd::shared_ptr<MockMeter> mock_meter =
1600+
std::make_shared<MockMeter>();
1601+
EXPECT_CALL(*mock_meter, CreateDoubleHistogram)
1602+
.WillOnce([mock = std::move(mock_histogram)](
1603+
opentelemetry::nostd::string_view name,
1604+
opentelemetry::nostd::string_view,
1605+
opentelemetry::nostd::string_view) mutable {
1606+
EXPECT_THAT(name, Eq("application_latencies"));
1607+
return std::move(mock);
1608+
});
1609+
1610+
opentelemetry::nostd::shared_ptr<MockMeterProvider> mock_provider =
1611+
std::make_shared<MockMeterProvider>();
1612+
EXPECT_CALL(*mock_provider, GetMeter)
1613+
#if OPENTELEMETRY_ABI_VERSION_NO >= 2
1614+
.WillOnce([&](opentelemetry::nostd::string_view scope,
1615+
opentelemetry::nostd::string_view scope_version,
1616+
opentelemetry::nostd::string_view,
1617+
opentelemetry::common::KeyValueIterable const*) mutable {
1618+
#else
1619+
.WillOnce([&](opentelemetry::nostd::string_view scope,
1620+
opentelemetry::nostd::string_view scope_version,
1621+
opentelemetry::nostd::string_view) mutable {
1622+
#endif
1623+
EXPECT_THAT(scope, Eq("my-instrument-scope"));
1624+
EXPECT_THAT(scope_version, Eq("v1"));
1625+
return mock_meter;
1626+
});
1627+
1628+
ApplicationBlockingLatency application_blocking_latency("my-instrument-scope",
1629+
mock_provider);
1630+
ResourceLabels resource_labels{"my-project-id", "my-instance", "my-table", "",
1631+
""};
1632+
DataLabels data_labels{"my-method", "my-streaming", "my-client-name",
1633+
"my-client-uid", "my-app-profile", ""};
1634+
auto clone = application_blocking_latency.clone(resource_labels, data_labels);
1635+
1636+
grpc::ClientContext client_context;
1637+
SetClusterZone(client_context, "my-cluster", "my-zone");
1638+
auto otel_context = opentelemetry::context::RuntimeContext::GetCurrent();
1639+
auto clock = std::make_shared<FakeSteadyClock>();
1640+
1641+
clock->SetTime(std::chrono::steady_clock::now());
1642+
clone->ElementDelivery(otel_context, {clock->Now(), true});
1643+
clock->AdvanceTime(std::chrono::microseconds(1234));
1644+
clone->ElementRequest(otel_context, {clock->Now()});
1645+
clone->PostCall(otel_context, client_context, {clock->Now(), Status{}});
1646+
clone->OnDone(otel_context, {clock->Now(), Status{}});
1647+
}
1648+
1649+
TEST(ApplicationBlockingLatency, StreamingData) {
1650+
auto mock_histogram = std::make_unique<MockHistogram<double>>();
1651+
EXPECT_CALL(
1652+
*mock_histogram,
1653+
Record(A<double>(), A<opentelemetry::common::KeyValueIterable const&>(),
1654+
A<opentelemetry::context::Context const&>()))
1655+
.WillOnce([](double value,
1656+
opentelemetry::common::KeyValueIterable const& attributes,
1657+
opentelemetry::context::Context const&) {
1658+
EXPECT_THAT(value, Eq(1.0));
1659+
EXPECT_THAT(
1660+
MakeAttributesMap(attributes),
1661+
UnorderedElementsAre(
1662+
Pair("project_id", "my-project-id"),
1663+
Pair("instance", "my-instance"), Pair("cluster", "my-cluster"),
1664+
Pair("table", "my-table"), Pair("zone", "my-zone"),
1665+
Pair("method", "my-method"),
1666+
Pair("client_name", "my-client-name"),
1667+
Pair("client_uid", "my-client-uid"),
1668+
Pair("app_profile", "my-app-profile")));
1669+
})
1670+
.WillOnce([](double value,
1671+
opentelemetry::common::KeyValueIterable const& attributes,
1672+
opentelemetry::context::Context const&) {
1673+
EXPECT_THAT(value, Eq(5.0));
1674+
EXPECT_THAT(
1675+
MakeAttributesMap(attributes),
1676+
UnorderedElementsAre(
1677+
Pair("project_id", "my-project-id"),
1678+
Pair("instance", "my-instance"), Pair("cluster", "my-cluster"),
1679+
Pair("table", "my-table"), Pair("zone", "my-zone"),
1680+
Pair("method", "my-method"),
1681+
Pair("client_name", "my-client-name"),
1682+
Pair("client_uid", "my-client-uid"),
1683+
Pair("app_profile", "my-app-profile")));
1684+
});
1685+
1686+
opentelemetry::nostd::shared_ptr<MockMeter> mock_meter =
1687+
std::make_shared<MockMeter>();
1688+
EXPECT_CALL(*mock_meter, CreateDoubleHistogram)
1689+
.WillOnce([mock = std::move(mock_histogram)](
1690+
opentelemetry::nostd::string_view name,
1691+
opentelemetry::nostd::string_view,
1692+
opentelemetry::nostd::string_view) mutable {
1693+
EXPECT_THAT(name, Eq("application_latencies"));
1694+
return std::move(mock);
1695+
});
1696+
1697+
opentelemetry::nostd::shared_ptr<MockMeterProvider> mock_provider =
1698+
std::make_shared<MockMeterProvider>();
1699+
EXPECT_CALL(*mock_provider, GetMeter)
1700+
#if OPENTELEMETRY_ABI_VERSION_NO >= 2
1701+
.WillOnce([&](opentelemetry::nostd::string_view scope,
1702+
opentelemetry::nostd::string_view scope_version,
1703+
opentelemetry::nostd::string_view,
1704+
opentelemetry::common::KeyValueIterable const*) mutable {
1705+
#else
1706+
.WillOnce([&](opentelemetry::nostd::string_view scope,
1707+
opentelemetry::nostd::string_view scope_version,
1708+
opentelemetry::nostd::string_view) mutable {
1709+
#endif
1710+
EXPECT_THAT(scope, Eq("my-instrument-scope"));
1711+
EXPECT_THAT(scope_version, Eq("v1"));
1712+
return mock_meter;
1713+
});
1714+
1715+
ApplicationBlockingLatency application_blocking_latency("my-instrument-scope",
1716+
mock_provider);
1717+
ResourceLabels resource_labels{"my-project-id", "my-instance", "my-table", "",
1718+
""};
1719+
DataLabels data_labels{"my-method", "my-streaming", "my-client-name",
1720+
"my-client-uid", "my-app-profile", ""};
1721+
auto clone = application_blocking_latency.clone(resource_labels, data_labels);
1722+
1723+
grpc::ClientContext client_context;
1724+
SetClusterZone(client_context, "my-cluster", "my-zone");
1725+
auto otel_context = opentelemetry::context::RuntimeContext::GetCurrent();
1726+
auto clock = std::make_shared<FakeSteadyClock>();
1727+
1728+
clock->SetTime(std::chrono::steady_clock::now());
1729+
clone->ElementDelivery(otel_context, {clock->Now(), true});
1730+
clock->AdvanceTime(std::chrono::milliseconds(1));
1731+
clone->ElementRequest(otel_context, {clock->Now()});
1732+
clock->AdvanceTime(std::chrono::milliseconds(10));
1733+
clone->ElementDelivery(otel_context, {clock->Now(), true});
1734+
clock->AdvanceTime(std::chrono::milliseconds(5));
1735+
clone->ElementRequest(otel_context, {clock->Now()});
1736+
clone->PostCall(otel_context, client_context, {clock->Now(), Status{}});
1737+
clone->OnDone(otel_context, {clock->Now(), Status{}});
1738+
}
15771739
} // namespace
15781740
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
15791741
} // namespace bigtable_internal

google/cloud/bigtable/internal/operation_context_factory.cc

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -238,8 +238,8 @@ std::shared_ptr<OperationContext> MetricsOperationContextFactory::ReadRow(
238238
v.emplace_back(std::make_shared<OperationLatency>(kRpc, provider_));
239239
v.emplace_back(std::make_shared<AttemptLatency>(kRpc, provider_));
240240
v.emplace_back(std::make_shared<RetryCount>(kRpc, provider_));
241-
// v.emplace_back(std::make_shared<ApplicationBlockingLatency>(kRpc,
242-
// provider_));
241+
v.emplace_back(
242+
std::make_shared<ApplicationBlockingLatency>(kRpc, provider_));
243243
v.emplace_back(std::make_shared<ServerLatency>(kRpc, provider_));
244244
// v.emplace_back(std::make_shared<ConnectivityErrorCount>(kRpc,
245245
// provider_));
@@ -267,8 +267,8 @@ std::shared_ptr<OperationContext> MetricsOperationContextFactory::ReadRows(
267267
v.emplace_back(std::make_shared<AttemptLatency>(kRpc, provider_));
268268
v.emplace_back(std::make_shared<RetryCount>(kRpc, provider_));
269269
v.emplace_back(std::make_shared<FirstResponseLatency>(kRpc, provider_));
270-
// v.emplace_back(std::make_shared<ApplicationBlockingLatency>(kRpc,
271-
// provider_));
270+
v.emplace_back(
271+
std::make_shared<ApplicationBlockingLatency>(kRpc, provider_));
272272
v.emplace_back(std::make_shared<ServerLatency>(kRpc, provider_));
273273
// v.emplace_back(std::make_shared<ConnectivityErrorCount>(kRpc,
274274
// provider_));
@@ -295,8 +295,8 @@ std::shared_ptr<OperationContext> MetricsOperationContextFactory::MutateRow(
295295
v.emplace_back(std::make_shared<OperationLatency>(kRpc, provider_));
296296
v.emplace_back(std::make_shared<AttemptLatency>(kRpc, provider_));
297297
v.emplace_back(std::make_shared<RetryCount>(kRpc, provider_));
298-
// v.emplace_back(std::make_shared<ApplicationBlockingLatency>(kRpc,
299-
// provider_));
298+
v.emplace_back(
299+
std::make_shared<ApplicationBlockingLatency>(kRpc, provider_));
300300
v.emplace_back(std::make_shared<ServerLatency>(kRpc, provider_));
301301
// v.emplace_back(std::make_shared<ConnectivityErrorCount>(kRpc,
302302
// provider_));
@@ -323,8 +323,8 @@ std::shared_ptr<OperationContext> MetricsOperationContextFactory::MutateRows(
323323
v.emplace_back(std::make_shared<OperationLatency>(kRpc, provider_));
324324
v.emplace_back(std::make_shared<AttemptLatency>(kRpc, provider_));
325325
v.emplace_back(std::make_shared<RetryCount>(kRpc, provider_));
326-
// v.emplace_back(std::make_shared<ApplicationBlockingLatency>(kRpc,
327-
// provider_));
326+
v.emplace_back(
327+
std::make_shared<ApplicationBlockingLatency>(kRpc, provider_));
328328
v.emplace_back(std::make_shared<ServerLatency>(kRpc, provider_));
329329
// v.emplace_back(std::make_shared<ConnectivityErrorCount>(kRpc,
330330
// provider_));
@@ -352,8 +352,8 @@ MetricsOperationContextFactory::CheckAndMutateRow(
352352
v.emplace_back(std::make_shared<OperationLatency>(kRpc, provider_));
353353
v.emplace_back(std::make_shared<AttemptLatency>(kRpc, provider_));
354354
v.emplace_back(std::make_shared<RetryCount>(kRpc, provider_));
355-
// v.emplace_back(std::make_shared<ApplicationBlockingLatency>(kRpc,
356-
// provider_));
355+
v.emplace_back(
356+
std::make_shared<ApplicationBlockingLatency>(kRpc, provider_));
357357
v.emplace_back(std::make_shared<ServerLatency>(kRpc, provider_));
358358
// v.emplace_back(std::make_shared<ConnectivityErrorCount>(kRpc,
359359
// provider_));
@@ -381,8 +381,8 @@ std::shared_ptr<OperationContext> MetricsOperationContextFactory::SampleRowKeys(
381381
v.emplace_back(std::make_shared<OperationLatency>(kRpc, provider_));
382382
v.emplace_back(std::make_shared<AttemptLatency>(kRpc, provider_));
383383
v.emplace_back(std::make_shared<RetryCount>(kRpc, provider_));
384-
// v.emplace_back(std::make_shared<ApplicationBlockingLatency>(kRpc,
385-
// provider_));
384+
v.emplace_back(
385+
std::make_shared<ApplicationBlockingLatency>(kRpc, provider_));
386386
v.emplace_back(std::make_shared<ServerLatency>(kRpc, provider_));
387387
// v.emplace_back(std::make_shared<ConnectivityErrorCount>(kRpc,
388388
// provider_));
@@ -410,8 +410,8 @@ MetricsOperationContextFactory::ReadModifyWriteRow(
410410
v.emplace_back(std::make_shared<OperationLatency>(kRpc, provider_));
411411
v.emplace_back(std::make_shared<AttemptLatency>(kRpc, provider_));
412412
v.emplace_back(std::make_shared<RetryCount>(kRpc, provider_));
413-
// v.emplace_back(std::make_shared<ApplicationBlockingLatency>(kRpc,
414-
// provider_));
413+
v.emplace_back(
414+
std::make_shared<ApplicationBlockingLatency>(kRpc, provider_));
415415
v.emplace_back(std::make_shared<ServerLatency>(kRpc, provider_));
416416
// v.emplace_back(std::make_shared<ConnectivityErrorCount>(kRpc,
417417
// provider_));

0 commit comments

Comments
 (0)