@@ -35,6 +35,8 @@ import (
3535 "google.golang.org/grpc/balancer/pickfirst"
3636 "google.golang.org/grpc/codes"
3737 "google.golang.org/grpc/connectivity"
38+ "google.golang.org/grpc/credentials"
39+ expstats "google.golang.org/grpc/experimental/stats"
3840 "google.golang.org/grpc/internal"
3941 "google.golang.org/grpc/internal/channelz"
4042 "google.golang.org/grpc/internal/grpcsync"
@@ -98,6 +100,41 @@ var (
98100 errTransportCredentialsMissing = errors .New ("grpc: the credentials require transport level security (use grpc.WithTransportCredentials() to set)" )
99101)
100102
103+ var (
104+ disconnectionsMetric = expstats .RegisterInt64Count (expstats.MetricDescriptor {
105+ Name : "grpc.subchannel.disconnections" ,
106+ Description : "EXPERIMENTAL. Number of times the selected subchannel becomes disconnected." ,
107+ Unit : "{disconnection}" ,
108+ Labels : []string {"grpc.target" },
109+ OptionalLabels : []string {"grpc.lb.backend_service" , "grpc.lb.locality" , "grpc.disconnect_error" },
110+ Default : false ,
111+ })
112+ connectionAttemptsSucceededMetric = expstats .RegisterInt64Count (expstats.MetricDescriptor {
113+ Name : "grpc.subchannel.connection_attempts_succeeded" ,
114+ Description : "EXPERIMENTAL. Number of successful connection attempts." ,
115+ Unit : "{attempt}" ,
116+ Labels : []string {"grpc.target" },
117+ OptionalLabels : []string {"grpc.lb.backend_service" , "grpc.lb.locality" },
118+ Default : false ,
119+ })
120+ connectionAttemptsFailedMetric = expstats .RegisterInt64Count (expstats.MetricDescriptor {
121+ Name : "grpc.subchannel.connection_attempts_failed" ,
122+ Description : "EXPERIMENTAL. Number of failed connection attempts." ,
123+ Unit : "{attempt}" ,
124+ Labels : []string {"grpc.target" },
125+ OptionalLabels : []string {"grpc.lb.backend_service" , "grpc.lb.locality" },
126+ Default : false ,
127+ })
128+ openConnectionsMetric = expstats .RegisterInt64UpDownCount (expstats.MetricDescriptor {
129+ Name : "grpc.subchannel.open_connections" ,
130+ Description : "EXPERIMENTAL. Number of open connections." ,
131+ Unit : "{attempt}" ,
132+ Labels : []string {"grpc.target" },
133+ OptionalLabels : []string {"grpc.lb.backend_service" , "grpc.security_level" , "grpc.lb.locality" },
134+ Default : false ,
135+ })
136+ )
137+
101138const (
102139 defaultClientMaxReceiveMessageSize = 1024 * 1024 * 4
103140 defaultClientMaxSendMessageSize = math .MaxInt32
@@ -1223,6 +1260,11 @@ func (ac *addrConn) updateConnectivityState(s connectivity.State, lastErr error)
12231260 if ac .state == s {
12241261 return
12251262 }
1263+ locality , backendService := fetchLabels (ac )
1264+ if ac .state == connectivity .Ready || (ac .state == connectivity .Connecting && s == connectivity .Idle ) {
1265+ disconnectionsMetric .Record (ac .cc .metricsRecorderList , 1 , ac .cc .target , backendService , locality , "unknown" )
1266+ openConnectionsMetric .Record (ac .cc .metricsRecorderList , - 1 , ac .cc .target , backendService , ac .securityLevel (), locality )
1267+ }
12261268 ac .state = s
12271269 ac .channelz .ChannelMetrics .State .Store (& s )
12281270 if lastErr == nil {
@@ -1276,10 +1318,13 @@ func (ac *addrConn) resetTransportAndUnlock() {
12761318 // https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md#proposed-backoff-algorithm
12771319 connectDeadline := time .Now ().Add (dialDuration )
12781320
1321+ locality , backendService := fetchLabels (ac )
1322+
12791323 ac .updateConnectivityState (connectivity .Connecting , nil )
12801324 ac .mu .Unlock ()
12811325
12821326 if err := ac .tryAllAddrs (acCtx , addrs , connectDeadline ); err != nil {
1327+ connectionAttemptsFailedMetric .Record (ac .cc .metricsRecorderList , 1 , ac .cc .target , backendService , locality )
12831328 // TODO: #7534 - Move re-resolution requests into the pick_first LB policy
12841329 // to ensure one resolution request per pass instead of per subconn failure.
12851330 ac .cc .resolveNow (resolver.ResolveNowOptions {})
@@ -1319,10 +1364,43 @@ func (ac *addrConn) resetTransportAndUnlock() {
13191364 }
13201365 // Success; reset backoff.
13211366 ac .mu .Lock ()
1367+ connectionAttemptsSucceededMetric .Record (ac .cc .metricsRecorderList , 1 , ac .cc .target , backendService , locality )
1368+ openConnectionsMetric .Record (ac .cc .metricsRecorderList , 1 , ac .cc .target , backendService , ac .securityLevel (), locality )
13221369 ac .backoffIdx = 0
13231370 ac .mu .Unlock ()
13241371}
13251372
1373+ func fetchLabels (ac * addrConn ) (string , string ) {
1374+ var locality , backendService string
1375+ labelsFromAddress , ok := internal .AddressToTelemetryLabels .(func (resolver.Address ) map [string ]string )
1376+ if len (ac .addrs ) > 0 && internal .AddressToTelemetryLabels != nil && ok {
1377+ if ok {
1378+ labels := labelsFromAddress (ac .addrs [0 ])
1379+ locality = labels ["grpc.lb.locality" ]
1380+ backendService = labels ["grpc.lb.backend_service" ]
1381+ }
1382+ }
1383+ return locality , backendService
1384+ }
1385+
1386+ type securityLevelKey struct {}
1387+
1388+ func (ac * addrConn ) securityLevel () string {
1389+ var secLevel string
1390+ if ac .transport == nil {
1391+ secLevel , _ = ac .curAddr .Attributes .Value (securityLevelKey {}).(string )
1392+ return secLevel
1393+ }
1394+ authInfo := ac .transport .AuthInfo ()
1395+ if ci , ok := authInfo .(interface {
1396+ GetCommonAuthInfo () credentials.CommonAuthInfo
1397+ }); ok {
1398+ secLevel = ci .GetCommonAuthInfo ().SecurityLevel .String ()
1399+ ac .curAddr .Attributes = ac .curAddr .Attributes .WithValue (securityLevelKey {}, secLevel )
1400+ }
1401+ return secLevel
1402+ }
1403+
13261404// tryAllAddrs tries to create a connection to the addresses, and stop when at
13271405// the first successful one. It returns an error if no address was successfully
13281406// connected, or updates ac appropriately with the new transport.
0 commit comments