@@ -28,6 +28,8 @@ import (
28
28
"cloud.google.com/go/internal/trace"
29
29
sppb "cloud.google.com/go/spanner/apiv1/spannerpb"
30
30
"github.com/googleapis/gax-go/v2"
31
+ "go.opentelemetry.io/otel/attribute"
32
+ "go.opentelemetry.io/otel/metric"
31
33
"google.golang.org/api/iterator"
32
34
"google.golang.org/api/option"
33
35
"google.golang.org/api/option/internaloption"
@@ -104,6 +106,7 @@ type Client struct {
104
106
ct * commonTags
105
107
disableRouteToLeader bool
106
108
dro * sppb.DirectedReadOptions
109
+ otConfig * openTelemetryConfig
107
110
}
108
111
109
112
// DatabaseName returns the full name of a database, e.g.,
@@ -112,6 +115,11 @@ func (c *Client) DatabaseName() string {
112
115
return c .sc .database
113
116
}
114
117
118
+ // ClientID returns the id of the Client. This is not recommended for customer applications and used internally for testing.
119
+ func (c * Client ) ClientID () string {
120
+ return c .sc .id
121
+ }
122
+
115
123
// ClientConfig has configurations for the client.
116
124
type ClientConfig struct {
117
125
// NumChannels is the number of gRPC channels.
@@ -192,6 +200,23 @@ type ClientConfig struct {
192
200
// and ExecuteSqlRequests for the Client which indicate which replicas or regions
193
201
// should be used for non-transactional reads or queries.
194
202
DirectedReadOptions * sppb.DirectedReadOptions
203
+
204
+ OpenTelemetryMeterProvider metric.MeterProvider
205
+ }
206
+
207
+ type openTelemetryConfig struct {
208
+ meterProvider metric.MeterProvider
209
+ attributeMap []attribute.KeyValue
210
+ otMetricRegistration metric.Registration
211
+ openSessionCount metric.Int64ObservableGauge
212
+ maxAllowedSessionsCount metric.Int64ObservableGauge
213
+ sessionsCount metric.Int64ObservableGauge
214
+ maxInUseSessionsCount metric.Int64ObservableGauge
215
+ getSessionTimeoutsCount metric.Int64Counter
216
+ acquiredSessionsCount metric.Int64Counter
217
+ releasedSessionsCount metric.Int64Counter
218
+ gfeLatency metric.Int64Histogram
219
+ gfeHeaderMissingCount metric.Int64Counter
195
220
}
196
221
197
222
func contextWithOutgoingMetadata (ctx context.Context , md metadata.MD , disableRouteToLeader bool ) context.Context {
@@ -245,6 +270,7 @@ func NewClientWithConfig(ctx context.Context, database string, config ClientConf
245
270
if err != nil {
246
271
return nil , err
247
272
}
273
+
248
274
if hasNumChannelsConfig && pool .Num () != config .NumChannels {
249
275
pool .Close ()
250
276
return nil , spannerErrorf (codes .InvalidArgument , "Connection pool mismatch: NumChannels=%v, WithGRPCConnectionPool=%v. Only set one of these options, or set both to the same value." , config .NumChannels , pool .Num ())
@@ -276,16 +302,29 @@ func NewClientWithConfig(ctx context.Context, database string, config ClientConf
276
302
if config .Compression == gzip .Name {
277
303
md .Append (requestsCompressionHeader , gzip .Name )
278
304
}
305
+
279
306
// Create a session client.
280
307
sc := newSessionClient (pool , database , config .UserAgent , sessionLabels , config .DatabaseRole , config .DisableRouteToLeader , md , config .BatchTimeout , config .Logger , config .CallOptions )
281
308
309
+ // Create a OpenTelemetry configuration
310
+ otConfig , err := createOpenTelemetryConfig (config .OpenTelemetryMeterProvider , config .Logger , sc .id , database )
311
+ if err != nil {
312
+ // The error returned here will be due to database name parsing
313
+ return nil , err
314
+ }
315
+ // To prevent data race in unit tests (ex: TestClient_SessionNotFound)
316
+ sc .mu .Lock ()
317
+ sc .otConfig = otConfig
318
+ sc .mu .Unlock ()
319
+
282
320
// Create a session pool.
283
321
config .SessionPoolConfig .sessionLabels = sessionLabels
284
322
sp , err := newSessionPool (sc , config .SessionPoolConfig )
285
323
if err != nil {
286
324
sc .close ()
287
325
return nil , err
288
326
}
327
+
289
328
c = & Client {
290
329
sc : sc ,
291
330
idleSessions : sp ,
@@ -298,6 +337,7 @@ func NewClientWithConfig(ctx context.Context, database string, config ClientConf
298
337
ct : getCommonTags (sc ),
299
338
disableRouteToLeader : config .DisableRouteToLeader ,
300
339
dro : config .DirectedReadOptions ,
340
+ otConfig : otConfig ,
301
341
}
302
342
return c , nil
303
343
}
@@ -384,6 +424,7 @@ func (c *Client) Single() *ReadOnlyTransaction {
384
424
t .txReadOnly .qo .DirectedReadOptions = c .dro
385
425
t .txReadOnly .ro .DirectedReadOptions = c .dro
386
426
t .ct = c .ct
427
+ t .otConfig = c .otConfig
387
428
return t
388
429
}
389
430
@@ -409,6 +450,7 @@ func (c *Client) ReadOnlyTransaction() *ReadOnlyTransaction {
409
450
t .txReadOnly .qo .DirectedReadOptions = c .dro
410
451
t .txReadOnly .ro .DirectedReadOptions = c .dro
411
452
t .ct = c .ct
453
+ t .otConfig = c .otConfig
412
454
return t
413
455
}
414
456
@@ -479,6 +521,7 @@ func (c *Client) BatchReadOnlyTransaction(ctx context.Context, tb TimestampBound
479
521
t .txReadOnly .qo .DirectedReadOptions = c .dro
480
522
t .txReadOnly .ro .DirectedReadOptions = c .dro
481
523
t .ct = c .ct
524
+ t .otConfig = c .otConfig
482
525
return t , nil
483
526
}
484
527
@@ -512,6 +555,7 @@ func (c *Client) BatchReadOnlyTransactionFromID(tid BatchReadOnlyTransactionID)
512
555
t .txReadOnly .qo .DirectedReadOptions = c .dro
513
556
t .txReadOnly .ro .DirectedReadOptions = c .dro
514
557
t .ct = c .ct
558
+ t .otConfig = c .otConfig
515
559
return t
516
560
}
517
561
@@ -616,6 +660,7 @@ func (c *Client) rwTransaction(ctx context.Context, f func(context.Context, *Rea
616
660
t .wb = []* Mutation {}
617
661
t .txOpts = c .txo .merge (options )
618
662
t .ct = c .ct
663
+ t .otConfig = c .otConfig
619
664
620
665
trace .TracePrintf (ctx , map [string ]interface {}{"transactionSelector" : t .getTransactionSelector ().String ()},
621
666
"Starting transaction attempt" )
@@ -877,6 +922,9 @@ func (c *Client) BatchWriteWithOptions(ctx context.Context, mgs []*MutationGroup
877
922
trace .TracePrintf (ct , nil , "Error in recording GFE Latency. Try disabling and rerunning. Error: %v" , err )
878
923
}
879
924
}
925
+ if metricErr := recordGFELatencyMetricsOT (ct , md , "BatchWrite" , c .otConfig ); metricErr != nil {
926
+ trace .TracePrintf (ct , nil , "Error in recording GFE Latency through OpenTelemetry. Error: %v" , err )
927
+ }
880
928
return stream , rpcErr
881
929
}
882
930
0 commit comments