@@ -19,8 +19,6 @@ import Metrics
19
19
import NIO
20
20
import NIOConcurrencyHelpers
21
21
22
- private let loggingKeyID = String ( describing: RedisConnection . self)
23
-
24
22
extension RedisConnection {
25
23
/// The documented default port that Redis connects through.
26
24
///
@@ -54,15 +52,15 @@ extension RedisConnection {
54
52
/// - socket: The `NIO.SocketAddress` information of the Redis instance to connect to.
55
53
/// - eventLoop: The `NIO.EventLoop` that this connection will execute all tasks on.
56
54
/// - password: The optional password to use for authorizing the connection with Redis.
57
- /// - logger: The `Logging.Logger` instance to use for all logging purposes. If one is not provided, one will be created.
55
+ /// - logger: The `Logging.Logger` instance to use for all client logging purposes. If one is not provided, one will be created.
58
56
/// A `Foundation.UUID` will be attached to the metadata to uniquely identify this connection instance's logs.
59
- /// - tcpClient: If you have chosen to configure a `NIO.ClientBootstrap` yourself, this will.
57
+ /// - tcpClient: If you have chosen to configure a `NIO.ClientBootstrap` yourself, this will be used instead of the `makeRedisTCPClient` instance .
60
58
/// - Returns: A `NIO.EventLoopFuture` that resolves with the new connection after it has been opened, and if a `password` is provided, authenticated.
61
59
public static func connect(
62
60
to socket: SocketAddress ,
63
61
on eventLoop: EventLoop ,
64
62
password: String ? = nil ,
65
- logger: Logger = Logger ( label: " RediStack.RedisConnection " ) ,
63
+ logger: Logger = . init ( label: " RediStack.RedisConnection " ) ,
66
64
tcpClient: ClientBootstrap ? = nil
67
65
) -> EventLoopFuture < RedisConnection > {
68
66
let client = tcpClient ?? ClientBootstrap . makeRedisTCPClient ( group: eventLoop)
@@ -101,7 +99,13 @@ extension RedisConnection {
101
99
///
102
100
/// See `NIO.SocketAddress`, `NIO.EventLoop`, and `RedisClient`
103
101
public final class RedisConnection : RedisClient {
104
- /// See `RedisClient.eventLoop`
102
+ /// A unique identifer to represent this connection.
103
+ public let id = UUID ( )
104
+ public private( set) var logger : Logger {
105
+ didSet {
106
+ self . logger [ metadataKey: String ( describing: RedisConnection . self) ] = . string( self . id. description)
107
+ }
108
+ }
105
109
public var eventLoop : EventLoop { return self . channel. eventLoop }
106
110
/// Is the connection to Redis still open?
107
111
public var isConnected : Bool {
@@ -124,11 +128,10 @@ public final class RedisConnection: RedisClient {
124
128
}
125
129
126
130
internal let channel : Channel
127
- private var logger : Logger
128
131
129
132
private let autoflush = Atomic < Bool > ( value: true )
130
133
private let _stateLock = Lock ( )
131
- private var _state : ConnectionState
134
+ private var _state = ConnectionState . open
132
135
private var state : ConnectionState {
133
136
get { return _stateLock. withLock { self . _state } }
134
137
set ( newValue) { _stateLock. withLockVoid { self . _state = newValue } }
@@ -144,10 +147,7 @@ public final class RedisConnection: RedisClient {
144
147
internal init ( configuredRESPChannel: Channel , logger: Logger ) {
145
148
self . channel = configuredRESPChannel
146
149
self . logger = logger
147
-
148
- self . logger [ metadataKey: loggingKeyID] = " \( UUID ( ) ) "
149
- self . _state = . open
150
- self . logger. debug ( " Connection created. " )
150
+
151
151
RedisMetrics . activeConnectionCount. increment ( )
152
152
RedisMetrics . totalConnectionCount. increment ( )
153
153
@@ -159,9 +159,11 @@ public final class RedisConnection: RedisClient {
159
159
guard self . state == . open else { return }
160
160
161
161
self . state = . closed
162
- self . logger. warning ( " Channel was closed unexpectedly. " )
162
+ self . logger. error ( " Channel was closed unexpectedly. " )
163
163
RedisMetrics . activeConnectionCount. decrement ( )
164
164
}
165
+
166
+ self . logger. trace ( " Connection created. " )
165
167
}
166
168
167
169
internal enum ConnectionState {
@@ -182,6 +184,8 @@ extension RedisConnection {
182
184
/// - Returns: A `NIO.EventLoopFuture` that resolves with the command's result stored in a `RESPValue`.
183
185
/// If a `RedisError` is returned, the future will be failed instead.
184
186
public func send( command: String , with arguments: [ RESPValue ] ) -> EventLoopFuture < RESPValue > {
187
+ self . logger. trace ( " Received command " )
188
+
185
189
guard self . isConnected else {
186
190
let error = RedisClientError . connectionClosed
187
191
logger. warning ( " \( error. localizedDescription) " )
@@ -203,12 +207,17 @@ extension RedisConnection {
203
207
RedisMetrics . commandRoundTripTime. recordNanoseconds ( duration)
204
208
205
209
// log the error here instead
206
- guard case let . failure( error) = result else { return }
210
+ guard case let . failure( error) = result else {
211
+ self . logger. trace ( " Command completed. " )
212
+ return
213
+ }
207
214
self . logger. error ( " \( error. localizedDescription) " )
208
215
}
209
216
210
217
self . logger. debug ( " Sending command \" \( command) \" \( arguments. count > 0 ? " with \( arguments) " : " " ) " )
211
218
219
+ defer { self . logger. trace ( " Command sent through channel. " ) }
220
+
212
221
if self . sendCommandsImmediately {
213
222
return channel. writeAndFlush ( command) . flatMap { promise. futureResult }
214
223
} else {
@@ -228,6 +237,8 @@ extension RedisConnection {
228
237
/// - Returns: A `NIO.EventLoopFuture` that resolves when the connection has been closed.
229
238
@discardableResult
230
239
public func close( ) -> EventLoopFuture < Void > {
240
+ self . logger. trace ( " Received request to close the connection. " )
241
+
231
242
guard self . isConnected else {
232
243
// return the channel's close future, which is resolved as the last step in channel shutdown
233
244
return self . channel. closeFuture
@@ -257,9 +268,9 @@ extension RedisConnection {
257
268
message: . array( [ RESPValue ( bulk: " QUIT " ) ] ) ,
258
269
responsePromise: promise
259
270
)
260
-
261
- logger. debug ( " Sending QUIT command. " )
262
-
271
+
272
+ logger. trace ( " Sending QUIT command. " )
273
+
263
274
return channel. writeAndFlush ( command) // write the command
264
275
. flatMap { promise. futureResult } // chain the callback to the response's
265
276
. map { _ in ( ) } // ignore the result's value
@@ -290,3 +301,15 @@ extension RedisConnection {
290
301
}
291
302
}
292
303
}
304
+
305
+ // MARK: Logging
306
+
307
+ extension RedisConnection {
308
+ /// Updates the client's logger, attaching this connection's ID to the metadata.
309
+ ///
310
+ /// See `RedisClient.setLogging(to:)` and `RedisConnection.id`.
311
+ /// - Parameter logger: The `Logging.Logger` that is desired to receive all client logs.
312
+ public func setLogging( to logger: Logger ) {
313
+ self . logger = logger
314
+ }
315
+ }
0 commit comments