Skip to content

Commit d695802

Browse files
authored
feat(spanner): Add gRPC A66/A94 metrics (#13825)
This change adds `grpc.client.attempt.started` metric in gRPC A66 and all the subchannel metrics in gRPC A94. Similar to the Java counterpart, this change also updates the exporter to handle the gauge metric correctly. Local tests show confirm that `Int64UpDownCounter` generates `Sum` data points (with `IsMonotonic=false`) instead of `Gauge` data.
1 parent 7724d79 commit d695802

File tree

2 files changed

+36
-9
lines changed

2 files changed

+36
-9
lines changed

spanner/metrics.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ const (
6969
metricLabelKeyGRPCLBPickResult = "grpc.lb.pick_result"
7070
metricLabelKeyGRPCLBDataPlaneTarget = "grpc.lb.rls.data_plane_target"
7171
metricLabelKeyGRPCXDSResourceType = "grpc.xds.resource_type"
72+
metricLabelKeyGRPCLBLocality = "grpc.lb.locality"
73+
metricLabelKeyGRPCLBBackendService = "grpc.lb.backend_service"
74+
metricLabelKeyGRPCDisconnectError = "grpc.disconnect_error"
7275

7376
// Metric names
7477
metricNameOperationLatencies = "operation_latencies"
@@ -222,12 +225,23 @@ var (
222225
}
223226

224227
grpcMetricsToEnable = []string{
228+
"grpc.client.attempt.started",
229+
"grpc.subchannel.open_connections",
230+
"grpc.subchannel.disconnections",
231+
"grpc.subchannel.connection_attempts_succeeded",
232+
"grpc.subchannel.connection_attempts_failed",
225233
"grpc.lb.rls.default_target_picks",
226234
"grpc.lb.rls.target_picks",
227235
"grpc.xds_client.server_failure",
228236
"grpc.xds_client.resource_updates_invalid",
229237
"grpc.xds_client.resource_updates_valid",
230238
}
239+
240+
grpcOptionalLabels = []string{
241+
"grpc.disconnect_error",
242+
"grpc.lb.backend_service",
243+
"grpc.lb.locality",
244+
}
231245
)
232246

233247
type metricInfo struct {
@@ -299,8 +313,9 @@ func newBuiltinMetricsTracerFactory(ctx context.Context, dbpath, compression str
299313

300314
if isEnableGRPCBuiltInMetrics {
301315
mo := opentelemetry.MetricsOptions{
302-
MeterProvider: meterProvider,
303-
Metrics: stats.NewMetrics(grpcMetricsToEnable...),
316+
MeterProvider: meterProvider,
317+
Metrics: stats.NewMetrics(grpcMetricsToEnable...),
318+
OptionalLabels: grpcOptionalLabels,
304319
}
305320

306321
// Configure gRPC dial options to enable gRPC metrics collection and static method call option.

spanner/metrics_monitoring_exporter.go

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ var (
6767
metricLabelKeyGRPCLBPickResult: true,
6868
metricLabelKeyGRPCLBDataPlaneTarget: true,
6969
metricLabelKeyGRPCXDSResourceType: true,
70+
metricLabelKeyGRPCLBLocality: true,
71+
metricLabelKeyGRPCLBBackendService: true,
72+
metricLabelKeyGRPCDisconnectError: true,
7073
metricLabelKeyClientUID: true,
7174
metricLabelKeyClientName: true,
7275
metricLabelKeyDatabase: true,
@@ -290,7 +293,10 @@ func (me *monitoringExporter) recordToTimeSeriesPb(m otelmetricdata.Metrics) ([]
290293
metric, mr := me.recordToMetricAndMonitoredResourcePbs(m, point.Attributes)
291294
var ts *monitoringpb.TimeSeries
292295
var err error
293-
ts, err = sumToTimeSeries[int64](point, m, mr)
296+
// Int64UpDownCounter contains Sum data with IsMonotonic = false.
297+
// See https://tinyurl.com/yzks9ene.
298+
isGauge := !a.IsMonotonic
299+
ts, err = sumToTimeSeries[int64](point, m, mr, isGauge)
294300
if err != nil {
295301
errs = append(errs, err)
296302
continue
@@ -304,16 +310,20 @@ func (me *monitoringExporter) recordToTimeSeriesPb(m otelmetricdata.Metrics) ([]
304310
return tss, errors.Join(errs...)
305311
}
306312

307-
func sumToTimeSeries[N int64 | float64](point otelmetricdata.DataPoint[N], metrics otelmetricdata.Metrics, mr *monitoredrespb.MonitoredResource) (*monitoringpb.TimeSeries, error) {
308-
interval, err := toNonemptyTimeIntervalpb(point.StartTime, point.Time)
313+
func sumToTimeSeries[N int64 | float64](point otelmetricdata.DataPoint[N], metrics otelmetricdata.Metrics, mr *monitoredrespb.MonitoredResource, isGauge bool) (*monitoringpb.TimeSeries, error) {
314+
interval, err := toNonemptyTimeIntervalpb(point.StartTime, point.Time, isGauge)
309315
if err != nil {
310316
return nil, err
311317
}
312318
value, valueType := numberDataPointToValue[N](point)
319+
metricKind := googlemetricpb.MetricDescriptor_CUMULATIVE
320+
if isGauge {
321+
metricKind = googlemetricpb.MetricDescriptor_GAUGE
322+
}
313323
return &monitoringpb.TimeSeries{
314324
Resource: mr,
315325
Unit: string(metrics.Unit),
316-
MetricKind: googlemetricpb.MetricDescriptor_CUMULATIVE,
326+
MetricKind: metricKind,
317327
ValueType: valueType,
318328
Points: []*monitoringpb.Point{{
319329
Interval: interval,
@@ -323,7 +333,7 @@ func sumToTimeSeries[N int64 | float64](point otelmetricdata.DataPoint[N], metri
323333
}
324334

325335
func histogramToTimeSeries[N int64 | float64](point otelmetricdata.HistogramDataPoint[N], metrics otelmetricdata.Metrics, mr *monitoredrespb.MonitoredResource) (*monitoringpb.TimeSeries, error) {
326-
interval, err := toNonemptyTimeIntervalpb(point.StartTime, point.Time)
336+
interval, err := toNonemptyTimeIntervalpb(point.StartTime, point.Time, false)
327337
if err != nil {
328338
return nil, err
329339
}
@@ -344,11 +354,13 @@ func histogramToTimeSeries[N int64 | float64](point otelmetricdata.HistogramData
344354
}, nil
345355
}
346356

347-
func toNonemptyTimeIntervalpb(start, end time.Time) (*monitoringpb.TimeInterval, error) {
357+
func toNonemptyTimeIntervalpb(start, end time.Time, isGauge bool) (*monitoringpb.TimeInterval, error) {
348358
// The end time of a new interval must be at least a millisecond after the end time of the
349359
// previous interval, for all non-gauge types.
350360
// https://cloud.google.com/monitoring/api/ref_v3/rpc/google.monitoring.v3#timeinterval
351-
if end.Sub(start).Milliseconds() <= 1 {
361+
if isGauge {
362+
end = start
363+
} else if end.Sub(start).Milliseconds() <= 1 {
352364
end = start.Add(time.Millisecond)
353365
}
354366
startpb := timestamppb.New(start)

0 commit comments

Comments
 (0)