Skip to content

Commit 59b61eb

Browse files
committed
Trace request execution
1 parent ddc5304 commit 59b61eb

File tree

7 files changed

+161
-94
lines changed

7 files changed

+161
-94
lines changed

Diff for: Package.swift

+2-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ let package = Package(
3232
.target(
3333
name: "AsyncHTTPClient",
3434
dependencies: ["NIO", "NIOHTTP1", "NIOSSL", "NIOConcurrencyHelpers", "NIOHTTPCompression",
35-
"NIOFoundationCompat", "NIOTransportServices", "Logging", "Instrumentation"]
35+
"NIOFoundationCompat", "NIOTransportServices", "Logging", "Instrumentation",
36+
"Tracing", "TracingOpenTelemetrySupport"]
3637
),
3738
.testTarget(
3839
name: "AsyncHTTPClientTests",

Diff for: Sources/AsyncHTTPClient/Connection.swift

+14-13
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
//
1313
//===----------------------------------------------------------------------===//
1414

15+
import Baggage
1516
import Foundation
1617
import Logging
1718
import NIO
@@ -51,21 +52,21 @@ extension Connection {
5152
/// Release this `Connection` to its associated `HTTP1ConnectionProvider`.
5253
///
5354
/// - Warning: This only releases the connection and doesn't take care of cleaning handlers in the `Channel` pipeline.
54-
func release(closing: Bool, logger: Logger) {
55+
func release(closing: Bool, context: LoggingContext) {
5556
self.channel.eventLoop.assertInEventLoop()
56-
self.provider.release(connection: self, closing: closing, logger: logger)
57+
self.provider.release(connection: self, closing: closing, context: context)
5758
}
5859

5960
/// Called when channel exceeds idle time in pool.
60-
func timeout(logger: Logger) {
61+
func timeout(context: LoggingContext) {
6162
self.channel.eventLoop.assertInEventLoop()
62-
self.provider.timeout(connection: self, logger: logger)
63+
self.provider.timeout(connection: self, context: context)
6364
}
6465

6566
/// Called when channel goes inactive while in the pool.
66-
func remoteClosed(logger: Logger) {
67+
func remoteClosed(context: LoggingContext) {
6768
self.channel.eventLoop.assertInEventLoop()
68-
self.provider.remoteClosed(connection: self, logger: logger)
69+
self.provider.remoteClosed(connection: self, context: context)
6970
}
7071

7172
/// Called from `HTTP1ConnectionProvider.close` when client is shutting down.
@@ -104,9 +105,9 @@ extension Connection: PoolManageableConnection {
104105

105106
extension Connection {
106107
/// Sets idle timeout handler and channel inactivity listener.
107-
func setIdleTimeout(timeout: TimeAmount?, logger: Logger) {
108+
func setIdleTimeout(timeout: TimeAmount?, context: LoggingContext) {
108109
_ = self.channel.pipeline.addHandler(IdleStateHandler(writeTimeout: timeout), position: .first).flatMap { _ in
109-
self.channel.pipeline.addHandler(IdlePoolConnectionHandler(connection: self, logger: logger))
110+
self.channel.pipeline.addHandler(IdlePoolConnectionHandler(connection: self, loggingContext: context))
110111
}
111112
}
112113

@@ -123,27 +124,27 @@ class IdlePoolConnectionHandler: ChannelInboundHandler, RemovableChannelHandler
123124

124125
let connection: Connection
125126
var eventSent: Bool
126-
let logger: Logger
127+
let loggingContext: LoggingContext
127128

128-
init(connection: Connection, logger: Logger) {
129+
init(connection: Connection, loggingContext: LoggingContext) {
129130
self.connection = connection
130131
self.eventSent = false
131-
self.logger = logger
132+
self.loggingContext = loggingContext
132133
}
133134

134135
// this is needed to detect when remote end closes connection while connection is in the pool idling
135136
func channelInactive(context: ChannelHandlerContext) {
136137
if !self.eventSent {
137138
self.eventSent = true
138-
self.connection.remoteClosed(logger: self.logger)
139+
self.connection.remoteClosed(context: loggingContext)
139140
}
140141
}
141142

142143
func userInboundEventTriggered(context: ChannelHandlerContext, event: Any) {
143144
if let idleEvent = event as? IdleStateHandler.IdleStateEvent, idleEvent == .write {
144145
if !self.eventSent {
145146
self.eventSent = true
146-
self.connection.timeout(logger: self.logger)
147+
self.connection.timeout(context: loggingContext)
147148
}
148149
} else {
149150
context.fireUserInboundEventTriggered(event)

Diff for: Sources/AsyncHTTPClient/ConnectionPool.swift

+40-41
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
//
1313
//===----------------------------------------------------------------------===//
1414

15+
import Baggage
1516
import Foundation
1617
import Logging
1718
import NIO
@@ -76,7 +77,7 @@ final class ConnectionPool {
7677
taskEventLoop: EventLoop,
7778
deadline: NIODeadline?,
7879
setupComplete: EventLoopFuture<Void>,
79-
logger: Logger) -> EventLoopFuture<Connection> {
80+
context: LoggingContext) -> EventLoopFuture<Connection> {
8081
let key = Key(request)
8182

8283
let provider: HTTP1ConnectionProvider = self.lock.withLock {
@@ -95,7 +96,7 @@ final class ConnectionPool {
9596
}
9697
}
9798

98-
return provider.getConnection(preference: preference, setupComplete: setupComplete, logger: logger)
99+
return provider.getConnection(preference: preference, setupComplete: setupComplete, context: context)
99100
}
100101

101102
func delete(_ provider: HTTP1ConnectionProvider) {
@@ -240,66 +241,65 @@ class HTTP1ConnectionProvider {
240241
self.state.assertInvariants()
241242
}
242243

243-
func execute(_ action: Action<Connection>, logger: Logger) {
244+
func execute(_ action: Action<Connection>, context: LoggingContext) {
244245
switch action {
245246
case .lease(let connection, let waiter):
246247
// if connection is became inactive, we create a new one.
247248
connection.cancelIdleTimeout().whenComplete { _ in
248249
if connection.isActiveEstimation {
249-
logger.trace("leasing existing connection",
250+
context.logger.trace("leasing existing connection",
250251
metadata: ["ahc-connection": "\(connection)"])
251252
waiter.promise.succeed(connection)
252253
} else {
253-
logger.trace("opening fresh connection (found matching but inactive connection)",
254+
context.logger.trace("opening fresh connection (found matching but inactive connection)",
254255
metadata: ["ahc-dead-connection": "\(connection)"])
255-
self.makeChannel(preference: waiter.preference,
256-
logger: logger).whenComplete { result in
257-
self.connect(result, waiter: waiter, logger: logger)
256+
self.makeChannel(preference: waiter.preference, context: context).whenComplete { result in
257+
self.connect(result, waiter: waiter, context: context)
258258
}
259259
}
260260
}
261261
case .create(let waiter):
262-
logger.trace("opening fresh connection (no connections to reuse available)")
263-
self.makeChannel(preference: waiter.preference, logger: logger).whenComplete { result in
264-
self.connect(result, waiter: waiter, logger: logger)
262+
context.logger.trace("opening fresh connection (no connections to reuse available)")
263+
self.makeChannel(preference: waiter.preference, context: context).whenComplete { result in
264+
self.connect(result, waiter: waiter, context: context)
265265
}
266266
case .replace(let connection, let waiter):
267267
connection.cancelIdleTimeout().flatMap {
268268
connection.close()
269269
}.whenComplete { _ in
270-
logger.trace("opening fresh connection (replacing exising connection)",
270+
context.logger.trace("opening fresh connection (replacing exising connection)",
271271
metadata: ["ahc-old-connection": "\(connection)",
272272
"ahc-waiter": "\(waiter)"])
273-
self.makeChannel(preference: waiter.preference, logger: logger).whenComplete { result in
274-
self.connect(result, waiter: waiter, logger: logger)
273+
self.makeChannel(preference: waiter.preference, context: context).whenComplete { result in
274+
self.connect(result, waiter: waiter, context: context)
275275
}
276276
}
277277
case .park(let connection):
278-
logger.trace("parking connection",
278+
context.logger.trace("parking connection",
279279
metadata: ["ahc-connection": "\(connection)"])
280280
connection.setIdleTimeout(timeout: self.configuration.connectionPool.idleTimeout,
281-
logger: self.backgroundActivityLogger)
281+
context: DefaultLoggingContext(context: context).withLogger(backgroundActivityLogger))
282282
case .closeProvider:
283-
logger.debug("closing provider",
283+
context.logger.debug("closing provider",
284284
metadata: ["ahc-provider": "\(self)"])
285285
self.closeAndDelete()
286286
case .none:
287287
break
288288
case .parkAnd(let connection, let action):
289-
logger.trace("parking connection & doing further action",
289+
context.logger.trace("parking connection & doing further action",
290290
metadata: ["ahc-connection": "\(connection)",
291291
"ahc-action": "\(action)"])
292292
connection.setIdleTimeout(timeout: self.configuration.connectionPool.idleTimeout,
293-
logger: self.backgroundActivityLogger)
294-
self.execute(action, logger: logger)
293+
context: DefaultLoggingContext(context: context).withLogger(backgroundActivityLogger))
294+
self.execute(action, context: context)
295295
case .closeAnd(let connection, let action):
296-
logger.trace("closing connection & doing further action",
296+
context.logger.trace("closing connection & doing further action",
297297
metadata: ["ahc-connection": "\(connection)",
298298
"ahc-action": "\(action)"])
299299
connection.channel.close(promise: nil)
300-
self.execute(action, logger: logger)
300+
self.execute(action, context: context)
301301
case .fail(let waiter, let error):
302-
logger.debug("failing connection for waiter",
302+
context.logger.debug("failing connection for waiter",
303303
metadata: ["ahc-waiter": "\(waiter)",
304304
"ahc-error": "\(error)"])
305305
waiter.promise.fail(error)
@@ -315,23 +315,23 @@ class HTTP1ConnectionProvider {
315315

316316
func getConnection(preference: HTTPClient.EventLoopPreference,
317317
setupComplete: EventLoopFuture<Void>,
318-
logger: Logger) -> EventLoopFuture<Connection> {
318+
context: LoggingContext) -> EventLoopFuture<Connection> {
319319
let waiter = Waiter<Connection>(promise: self.eventLoop.makePromise(), setupComplete: setupComplete, preference: preference)
320320

321321
let action: Action = self.lock.withLock {
322322
self.state.acquire(waiter: waiter)
323323
}
324324

325-
self.execute(action, logger: logger)
325+
self.execute(action, context: context)
326326

327327
return waiter.promise.futureResult
328328
}
329329

330-
func connect(_ result: Result<Channel, Error>, waiter: Waiter<Connection>, logger: Logger) {
330+
func connect(_ result: Result<Channel, Error>, waiter: Waiter<Connection>, context: LoggingContext) {
331331
let action: Action<Connection>
332332
switch result {
333333
case .success(let channel):
334-
logger.trace("successfully created connection",
334+
context.logger.trace("successfully created connection",
335335
metadata: ["ahc-connection": "\(channel)"])
336336
let connection = Connection(channel: channel, provider: self)
337337
action = self.lock.withLock {
@@ -341,15 +341,15 @@ class HTTP1ConnectionProvider {
341341
switch action {
342342
case .closeAnd:
343343
// This happens when client was shut down during connect
344-
logger.trace("connection cancelled due to client shutdown",
344+
context.logger.trace("connection cancelled due to client shutdown",
345345
metadata: ["ahc-connection": "\(channel)"])
346346
connection.channel.close(promise: nil)
347347
waiter.promise.fail(HTTPClientError.cancelled)
348348
default:
349349
waiter.promise.succeed(connection)
350350
}
351351
case .failure(let error):
352-
logger.debug("connection attempt failed",
352+
context.logger.debug("connection attempt failed",
353353
metadata: ["ahc-error": "\(error)"])
354354
action = self.lock.withLock {
355355
self.state.connectFailed()
@@ -358,12 +358,12 @@ class HTTP1ConnectionProvider {
358358
}
359359

360360
waiter.setupComplete.whenComplete { _ in
361-
self.execute(action, logger: logger)
361+
self.execute(action, context: context)
362362
}
363363
}
364364

365-
func release(connection: Connection, closing: Bool, logger: Logger) {
366-
logger.debug("releasing connection, request complete",
365+
func release(connection: Connection, closing: Bool, context: LoggingContext) {
366+
context.logger.debug("releasing connection, request complete",
367367
metadata: ["ahc-closing": "\(closing)"])
368368
let action: Action = self.lock.withLock {
369369
self.state.release(connection: connection, closing: closing)
@@ -383,31 +383,31 @@ class HTTP1ConnectionProvider {
383383
case .park, .closeProvider:
384384
// Since both `.park` and `.deleteProvider` are terminal in terms of execution,
385385
// we can execute them immediately
386-
self.execute(action, logger: logger)
386+
self.execute(action, context: context)
387387
case .closeAnd, .create, .fail, .lease, .parkAnd, .replace:
388388
// This is needed to start a new stack, otherwise, since this is called on a previous
389389
// future completion handler chain, it will be growing indefinitely until the connection is closed.
390390
// We might revisit this when https://github.com/apple/swift-nio/issues/970 is resolved.
391391
connection.eventLoop.execute {
392-
self.execute(action, logger: logger)
392+
self.execute(action, context: context)
393393
}
394394
}
395395
}
396396

397-
func remoteClosed(connection: Connection, logger: Logger) {
397+
func remoteClosed(connection: Connection, context: LoggingContext) {
398398
let action: Action = self.lock.withLock {
399399
self.state.remoteClosed(connection: connection)
400400
}
401401

402-
self.execute(action, logger: logger)
402+
self.execute(action, context: context)
403403
}
404404

405-
func timeout(connection: Connection, logger: Logger) {
405+
func timeout(connection: Connection, context: LoggingContext) {
406406
let action: Action = self.lock.withLock {
407407
self.state.timeout(connection: connection)
408408
}
409409

410-
self.execute(action, logger: logger)
410+
self.execute(action, context: context)
411411
}
412412

413413
private func closeAndDelete() {
@@ -438,14 +438,13 @@ class HTTP1ConnectionProvider {
438438
return self.closePromise.futureResult.map { true }
439439
}
440440

441-
private func makeChannel(preference: HTTPClient.EventLoopPreference,
442-
logger: Logger) -> EventLoopFuture<Channel> {
441+
private func makeChannel(preference: HTTPClient.EventLoopPreference, context: LoggingContext) -> EventLoopFuture<Channel> {
443442
return NIOClientTCPBootstrap.makeHTTP1Channel(destination: self.key,
444443
eventLoop: self.eventLoop,
445444
configuration: self.configuration,
446445
sslContextCache: self.pool.sslContextCache,
447446
preference: preference,
448-
logger: logger)
447+
context: context)
449448
}
450449

451450
/// A `Waiter` represents a request that waits for a connection when none is

0 commit comments

Comments
 (0)