Skip to content

Commit 59e0f6b

Browse files
authored
impl(bigtable): introduce server latency metrics (#15356)
* impl(bigtable): introduce server latency metrics
1 parent e16c808 commit 59e0f6b

File tree

4 files changed

+374
-8
lines changed

4 files changed

+374
-8
lines changed

google/cloud/bigtable/internal/metrics.cc

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@
1616

1717
#include "google/cloud/bigtable/internal/metrics.h"
1818
#include "google/cloud/bigtable/version.h"
19+
#include "absl/strings/charconv.h"
20+
#include "absl/strings/match.h"
21+
#include "absl/strings/numbers.h"
22+
#include "absl/strings/str_split.h"
23+
#include "absl/strings/strip.h"
1924
#include <algorithm>
2025
#include <map>
2126
#include <set>
@@ -85,6 +90,44 @@ GetResponseParamsFromTrailingMetadata(
8590
return absl::nullopt;
8691
}
8792

93+
absl::optional<double> GetServerLatencyFromInitialMetadata(
94+
grpc::ClientContext const& client_context) {
95+
auto const& initial_metadata = client_context.GetServerInitialMetadata();
96+
auto it = initial_metadata.find("server-timing");
97+
if (it == initial_metadata.end()) {
98+
return absl::nullopt;
99+
}
100+
101+
absl::string_view value(it->second.data(), it->second.length());
102+
103+
for (absl::string_view entry : absl::StrSplit(value, ',')) {
104+
entry = absl::StripAsciiWhitespace(entry);
105+
std::vector<absl::string_view> parts = absl::StrSplit(entry, ';');
106+
if (parts.empty()) {
107+
continue;
108+
}
109+
110+
absl::string_view metric_name = absl::StripAsciiWhitespace(parts[0]);
111+
if (metric_name == "gfet4t7") {
112+
// Look for the "dur" parameter within its parts.
113+
for (size_t i = 1; i < parts.size(); ++i) {
114+
absl::string_view param = absl::StripAsciiWhitespace(parts[i]);
115+
if (absl::ConsumePrefix(&param, "dur=")) {
116+
double dur_value;
117+
auto result = absl::from_chars(
118+
param.data(), param.data() + param.size(), dur_value);
119+
if (result.ec == std::errc()) {
120+
return dur_value;
121+
}
122+
return absl::nullopt;
123+
}
124+
}
125+
}
126+
}
127+
128+
return absl::nullopt;
129+
}
130+
88131
Metric::~Metric() = default;
89132

90133
OperationLatency::OperationLatency(
@@ -267,6 +310,39 @@ std::unique_ptr<Metric> FirstResponseLatency::clone(
267310
return m;
268311
}
269312

313+
ServerLatency::ServerLatency(
314+
std::string const& instrumentation_scope,
315+
opentelemetry::nostd::shared_ptr<
316+
opentelemetry::metrics::MeterProvider> const& provider)
317+
: server_latencies_(provider
318+
->GetMeter(instrumentation_scope,
319+
kMeterInstrumentationScopeVersion)
320+
->CreateDoubleHistogram("server_latencies")) {}
321+
322+
void ServerLatency::PostCall(opentelemetry::context::Context const& context,
323+
grpc::ClientContext const& client_context,
324+
PostCallParams const& p) {
325+
auto response_params = GetResponseParamsFromTrailingMetadata(client_context);
326+
if (response_params) {
327+
resource_labels_.cluster = response_params->cluster_id();
328+
resource_labels_.zone = response_params->zone_id();
329+
}
330+
data_labels_.status = StatusCodeToString(p.attempt_status.code());
331+
auto server_latency = GetServerLatencyFromInitialMetadata(client_context);
332+
if (server_latency) {
333+
auto m = IntoLabelMap(resource_labels_, data_labels_);
334+
server_latencies_->Record(*server_latency, std::move(m), context);
335+
}
336+
}
337+
338+
std::unique_ptr<Metric> ServerLatency::clone(ResourceLabels resource_labels,
339+
DataLabels data_labels) const {
340+
auto m = std::make_unique<ServerLatency>(*this);
341+
m->resource_labels_ = std::move(resource_labels);
342+
m->data_labels_ = std::move(data_labels);
343+
return m;
344+
}
345+
270346
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
271347
} // namespace bigtable_internal
272348
} // namespace cloud

google/cloud/bigtable/internal/metrics.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ absl::optional<google::bigtable::v2::ResponseParams>
6060
GetResponseParamsFromTrailingMetadata(
6161
grpc::ClientContext const& client_context);
6262

63+
absl::optional<double> GetServerLatencyFromInitialMetadata(
64+
grpc::ClientContext const& client_context);
65+
6366
struct PreCallParams {
6467
OperationContext::Clock::time_point attempt_start;
6568
bool first_attempt;
@@ -200,6 +203,25 @@ class FirstResponseLatency : public Metric {
200203
absl::optional<LatencyDuration> first_response_latency_;
201204
};
202205

206+
class ServerLatency : public Metric {
207+
public:
208+
ServerLatency(std::string const& instrumentation_scope,
209+
opentelemetry::nostd::shared_ptr<
210+
opentelemetry::metrics::MeterProvider> const& provider);
211+
void PostCall(opentelemetry::context::Context const& context,
212+
grpc::ClientContext const& client_context,
213+
PostCallParams const& p) override;
214+
215+
std::unique_ptr<Metric> clone(ResourceLabels resource_labels,
216+
DataLabels data_labels) const override;
217+
218+
private:
219+
ResourceLabels resource_labels_;
220+
DataLabels data_labels_;
221+
opentelemetry::nostd::shared_ptr<opentelemetry::metrics::Histogram<double>>
222+
server_latencies_;
223+
};
224+
203225
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
204226
} // namespace bigtable_internal
205227
} // namespace cloud

0 commit comments

Comments
 (0)