|
16 | 16 |
|
17 | 17 | #include "google/cloud/bigtable/internal/metrics.h" |
18 | 18 | #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" |
19 | 24 | #include <algorithm> |
20 | 25 | #include <map> |
21 | 26 | #include <set> |
@@ -85,6 +90,44 @@ GetResponseParamsFromTrailingMetadata( |
85 | 90 | return absl::nullopt; |
86 | 91 | } |
87 | 92 |
|
| 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(¶m, "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 | + |
88 | 131 | Metric::~Metric() = default; |
89 | 132 |
|
90 | 133 | OperationLatency::OperationLatency( |
@@ -267,6 +310,39 @@ std::unique_ptr<Metric> FirstResponseLatency::clone( |
267 | 310 | return m; |
268 | 311 | } |
269 | 312 |
|
| 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 | + |
270 | 346 | GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END |
271 | 347 | } // namespace bigtable_internal |
272 | 348 | } // namespace cloud |
|
0 commit comments