Skip to content

Commit 25c33fd

Browse files
authored
Additional logging for connection pool (#1795)
Motivation: The connection pool logs information about various states but the logger doesn't have an id attached for the sub-pool making it hard determine the state of individual subpools. Modifications: - Add the subpool id to the logger metadata - Add a log when the pool is initialized - Add a log when the pool can't add any more connections Result: Better visibility
1 parent d2d187e commit 25c33fd

File tree

2 files changed

+93
-2
lines changed

2 files changed

+93
-2
lines changed

Sources/GRPC/ConnectionManager.swift

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,39 @@ internal final class ConnectionManager: @unchecked Sendable {
248248
}
249249
}
250250

251+
/// Returns whether the state is 'connecting'.
252+
private var isConnecting: Bool {
253+
self.eventLoop.assertInEventLoop()
254+
switch self.state {
255+
case .connecting:
256+
return true
257+
case .idle, .transientFailure, .active, .ready, .shutdown:
258+
return false
259+
}
260+
}
261+
262+
/// Returns whether the state is 'ready'.
263+
private var isReady: Bool {
264+
self.eventLoop.assertInEventLoop()
265+
switch self.state {
266+
case .ready:
267+
return true
268+
case .idle, .active, .connecting, .transientFailure, .shutdown:
269+
return false
270+
}
271+
}
272+
273+
/// Returns whether the state is 'ready'.
274+
private var isTransientFailure: Bool {
275+
self.eventLoop.assertInEventLoop()
276+
switch self.state {
277+
case .transientFailure:
278+
return true
279+
case .idle, .connecting, .active, .ready, .shutdown:
280+
return false
281+
}
282+
}
283+
251284
/// Returns whether the state is 'shutdown'.
252285
private var isShutdown: Bool {
253286
self.eventLoop.assertInEventLoop()
@@ -1140,7 +1173,22 @@ extension ConnectionManager {
11401173
return self.manager.isIdle
11411174
}
11421175

1143-
/// Returne `true` if the connection is in the shutdown state.
1176+
/// Returns `true` if the connection is in the connecting state.
1177+
internal var isConnecting: Bool {
1178+
return self.manager.isConnecting
1179+
}
1180+
1181+
/// Returns `true` if the connection is in the ready state.
1182+
internal var isReady: Bool {
1183+
return self.manager.isReady
1184+
}
1185+
1186+
/// Returns `true` if the connection is in the transient failure state.
1187+
internal var isTransientFailure: Bool {
1188+
return self.manager.isTransientFailure
1189+
}
1190+
1191+
/// Returns `true` if the connection is in the shutdown state.
11441192
internal var isShutdown: Bool {
11451193
return self.manager.isShutdown
11461194
}

Sources/GRPC/ConnectionPool/ConnectionPool.swift

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ internal final class ConnectionPool {
103103

104104
/// A logger which always sets "GRPC" as its source.
105105
@usableFromInline
106-
internal let logger: GRPCLogger
106+
private(set) var logger: GRPCLogger
107107

108108
/// Returns `NIODeadline` representing 'now'. This is useful for testing.
109109
@usableFromInline
@@ -139,6 +139,18 @@ internal final class ConnectionPool {
139139
/// The ID of waiter.
140140
@usableFromInline
141141
static let waiterID = "pool.waiter.id"
142+
/// The maximum number of connections allowed in the pool.
143+
@usableFromInline
144+
static let connectionsMax = "pool.connections.max"
145+
/// The number of connections in the ready state.
146+
@usableFromInline
147+
static let connectionsReady = "pool.connections.ready"
148+
/// The number of connections in the connecting state.
149+
@usableFromInline
150+
static let connectionsConnecting = "pool.connections.connecting"
151+
/// The number of connections in the transient failure state.
152+
@usableFromInline
153+
static let connectionsTransientFailure = "pool.connections.transientFailure"
142154
}
143155

144156
@usableFromInline
@@ -158,6 +170,7 @@ internal final class ConnectionPool {
158170
(0.0 ... 1.0).contains(reservationLoadThreshold),
159171
"reservationLoadThreshold must be within the range 0.0 ... 1.0"
160172
)
173+
161174
self.reservationLoadThreshold = reservationLoadThreshold
162175
self.assumedMaxConcurrentStreams = assumedMaxConcurrentStreams
163176

@@ -179,6 +192,14 @@ internal final class ConnectionPool {
179192
/// - Parameter connections: The number of connections to add to the pool.
180193
internal func initialize(connections: Int) {
181194
assert(self._connections.isEmpty)
195+
self.logger.logger[metadataKey: Metadata.id] = "\(ObjectIdentifier(self))"
196+
self.logger.debug(
197+
"initializing new sub-pool",
198+
metadata: [
199+
Metadata.waitersMax: .stringConvertible(self.maxWaiters),
200+
Metadata.connectionsMax: .stringConvertible(connections),
201+
]
202+
)
182203
self._connections.reserveCapacity(connections)
183204
while self._connections.count < connections {
184205
self.addConnectionToPool()
@@ -461,6 +482,20 @@ internal final class ConnectionPool {
461482
internal func _startConnectingIdleConnection() {
462483
if let index = self._connections.values.firstIndex(where: { $0.manager.sync.isIdle }) {
463484
self._connections.values[index].manager.sync.startConnecting()
485+
} else {
486+
let connecting = self._connections.values.count { $0.manager.sync.isConnecting }
487+
let ready = self._connections.values.count { $0.manager.sync.isReady }
488+
let transientFailure = self._connections.values.count { $0.manager.sync.isTransientFailure }
489+
490+
self.logger.debug(
491+
"no idle connections in pool",
492+
metadata: [
493+
Metadata.connectionsConnecting: .stringConvertible(connecting),
494+
Metadata.connectionsReady: .stringConvertible(ready),
495+
Metadata.connectionsTransientFailure: .stringConvertible(transientFailure),
496+
Metadata.waitersCount: .stringConvertible(self.waiters.count),
497+
]
498+
)
464499
}
465500
}
466501

@@ -965,3 +1000,11 @@ extension GRPCConnectionPoolError: GRPCStatusTransformable {
9651000
}
9661001
}
9671002
}
1003+
1004+
extension Sequence {
1005+
fileprivate func count(where predicate: (Element) -> Bool) -> Int {
1006+
return self.reduce(0) { count, element in
1007+
predicate(element) ? count + 1 : count
1008+
}
1009+
}
1010+
}

0 commit comments

Comments
 (0)