@@ -61,9 +61,6 @@ let globalRequestID = ManagedAtomic(0)
6161/// }
6262/// }
6363/// ```
64- // #if TracingSupport
65- // @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
66- // #endif
6764public final class HTTPClient : Sendable {
6865 /// The `EventLoopGroup` in use by this ``HTTPClient``.
6966 ///
@@ -80,8 +77,9 @@ public final class HTTPClient: Sendable {
8077
8178 #if TracingSupport
8279 @_spi ( Tracing)
83- public var tracer : ( any Tracer ) ? { // Tracer requires macOS 10.15... so we're forced into annotating HTTPClient :-/
84- configuration. tracer
80+ @available ( macOS 10 . 15 , iOS 13 , tvOS 13 , watchOS 6 , * ) // for TaskLocal ServiceContext
81+ public var tracer : ( any Tracer ) ? {
82+ configuration. tracing. tracer
8583 }
8684 #endif // TracingSupport
8785
@@ -368,8 +366,7 @@ public final class HTTPClient: Sendable {
368366 /// - url: Remote URL.
369367 /// - deadline: Point in time by which the request must complete.
370368 public func get( url: String , deadline: NIODeadline ? = nil ) -> EventLoopFuture < Response > {
371- print ( " [swift] GET \( url) " )
372- return self . get ( url: url, deadline: deadline, logger: HTTPClient . loggingDisabled)
369+ self . get ( url: url, deadline: deadline, logger: HTTPClient . loggingDisabled)
373370 }
374371
375372 /// Execute `GET` request using specified URL.
@@ -496,7 +493,6 @@ public final class HTTPClient: Sendable {
496493 ) -> EventLoopFuture < Response > {
497494 do {
498495 let request = try Request ( url: url, method: method, body: body)
499- print ( " [swift] request \( request) " )
500496 return self . execute ( request: request, deadline: deadline, logger: logger ?? HTTPClient . loggingDisabled)
501497 } catch {
502498 return self . eventLoopGroup. any ( ) . makeFailedFuture ( error)
@@ -575,7 +571,7 @@ public final class HTTPClient: Sendable {
575571 /// - deadline: Point in time by which the request must complete.
576572 /// - logger: The logger to use for this request.
577573 public func execute( request: Request , deadline: NIODeadline ? = nil , logger: Logger ) -> EventLoopFuture < Response > {
578- let accumulator = ResponseAccumulator ( request: request) // FIXME: end here?
574+ let accumulator = ResponseAccumulator ( request: request)
579575 return self . execute ( request: request, delegate: accumulator, deadline: deadline, logger: logger) . futureResult
580576 }
581577
@@ -688,8 +684,6 @@ public final class HTTPClient: Sendable {
688684 deadline: NIODeadline ? = nil ,
689685 logger: Logger ?
690686 ) -> Task < Delegate . Response > {
691- print ( " [swift] EXECUTE HERE " )
692- assert ( self . configuration. tracer != nil )
693687 return self . _execute (
694688 request: request,
695689 delegate: delegate,
@@ -717,14 +711,28 @@ public final class HTTPClient: Sendable {
717711 eventLoop eventLoopPreference: EventLoopPreference ,
718712 deadline: NIODeadline ? = nil ,
719713 logger originalLogger: Logger ? ,
720- redirectState: RedirectState ?
714+ redirectState: RedirectState ? ,
721715 ) -> Task < Delegate . Response > {
722- assert ( self . configuration. tracer != nil )
723716 let logger = ( originalLogger ?? HTTPClient . loggingDisabled) . attachingRequestInformation (
724717 request,
725718 requestID: globalRequestID. wrappingIncrementThenLoad ( ordering: . relaxed)
726719 )
727- let tracer = self . configuration. tracer
720+
721+ // #if TracingSupport
722+ // let span: (any Span)? // we may be still executing the same span, e.g. under redirection etc.
723+ // if let activeSpan {
724+ // span = activeSpan
725+ // } else if let tracer = self.tracer {
726+ // let s = tracer.startSpan(request.method.rawValue)
727+ // let attrs = self.configuration.tracing.attributeKeys
728+ // s.attributes[attrs.requestMethod] = request.method.rawValue
729+ // s.attributes["loc"] = "\(#fileID):\(#line)"
730+ // span = s
731+ // } else {
732+ // span = nil
733+ // }
734+ // #endif
735+
728736 let taskEL : EventLoop
729737 switch eventLoopPreference. preference {
730738 case . indifferent:
@@ -760,10 +768,14 @@ public final class HTTPClient: Sendable {
760768 return nil
761769 case . shuttingDown, . shutDown:
762770 logger. debug ( " client is shutting down, failing request " )
763- // TODO: span immediately failed ops
771+ let error = HTTPClientError . alreadyShutdown
772+ // #if TracingSupport
773+ // span?.recordError(error)
774+ // span?.end()
775+ // #endif
764776 return Task< Delegate . Response> . failedTask(
765777 eventLoop: taskEL,
766- error: HTTPClientError . alreadyShutdown ,
778+ error: error ,
767779 logger: logger,
768780 tracer: tracer,
769781 makeOrGetFileIOThreadPool: self . makeOrGetFileIOThreadPool
@@ -778,7 +790,6 @@ public final class HTTPClient: Sendable {
778790 let redirectHandler : RedirectHandler < Delegate . Response > ? = {
779791 guard let redirectState = redirectState else { return nil }
780792
781- // TODO: span for redirects?
782793 return . init( request: request, redirectState: redirectState) { newRequest, newRedirectState in
783794 self . _execute (
784795 request: newRequest,
@@ -791,26 +802,12 @@ public final class HTTPClient: Sendable {
791802 }
792803 } ( )
793804
794- print ( " [swift]( \( #fileID) : \( #line) ) tracer was = \( tracer) " )
795- precondition ( tracer != nil , " Expected tracer to be set in \( #function) @ \( #fileID) : \( #line) " )
796- #if TracingSupport
797- let task = Task < Delegate . Response > (
798- eventLoop: taskEL,
799- logger: logger,
800- tracer: tracer,
801- makeOrGetFileIOThreadPool: self . makeOrGetFileIOThreadPool
802- )
803- #else
804805 let task = Task < Delegate . Response > (
805- eventLoop: taskEL,
806- logger: logger,
807- tracer: tracer,
808- makeOrGetFileIOThreadPool: self . makeOrGetFileIOThreadPool
809- )
810- #endif // TracingSupport
811-
812- precondition ( task. tracer != nil , " Expected tracer to be set in \( #function) " )
813- print ( " [swift] task.tracer was nil? \( task. tracer == nil ) " )
806+ eventLoop: taskEL,
807+ logger: logger,
808+ tracer: tracer,
809+ makeOrGetFileIOThreadPool: self . makeOrGetFileIOThreadPool
810+ )
814811
815812 do {
816813 let requestBag = try RequestBag (
@@ -924,12 +921,7 @@ public final class HTTPClient: Sendable {
924921 public var http2StreamChannelDebugInitializer : ( @Sendable ( Channel ) -> EventLoopFuture < Void > ) ?
925922
926923 #if TracingSupport
927- /// Tracer that should be used by the HTTPClient.
928- ///
929- /// This is selected at configuration creation time, and if no tracer is passed explicitly,
930- /// (including `nil` in order to disable traces), the default global bootstrapped tracer will
931- /// be stored in this property, and used for all subsequent requests made by this client.
932- public var tracer : ( any Tracer ) ? = InstrumentationSystem . tracer
924+ public var tracing : TracingConfiguration = . init( )
933925 #endif
934926
935927 public init (
@@ -1059,9 +1051,6 @@ public final class HTTPClient: Sendable {
10591051 self . http1_1ConnectionDebugInitializer = http1_1ConnectionDebugInitializer
10601052 self . http2ConnectionDebugInitializer = http2ConnectionDebugInitializer
10611053 self . http2StreamChannelDebugInitializer = http2StreamChannelDebugInitializer
1062- #if TracingSupport
1063- self . tracer = InstrumentationSystem . tracer
1064- #endif
10651054 }
10661055
10671056 #if TracingSupport
@@ -1076,7 +1065,7 @@ public final class HTTPClient: Sendable {
10761065 http1_1ConnectionDebugInitializer: ( @Sendable ( Channel ) -> EventLoopFuture < Void > ) ? = nil ,
10771066 http2ConnectionDebugInitializer: ( @Sendable ( Channel ) -> EventLoopFuture < Void > ) ? = nil ,
10781067 http2StreamChannelDebugInitializer: ( @Sendable ( Channel ) -> EventLoopFuture < Void > ) ? = nil ,
1079- tracer : ( any Tracer ) ? = InstrumentationSystem . tracer
1068+ tracing : TracingConfiguration = . init ( )
10801069 ) {
10811070 self . init (
10821071 tlsConfiguration: tlsConfiguration,
@@ -1090,11 +1079,62 @@ public final class HTTPClient: Sendable {
10901079 self . http1_1ConnectionDebugInitializer = http1_1ConnectionDebugInitializer
10911080 self . http2ConnectionDebugInitializer = http2ConnectionDebugInitializer
10921081 self . http2StreamChannelDebugInitializer = http2StreamChannelDebugInitializer
1093- self . tracer = tracer
1082+ self . tracing = tracing
10941083 }
10951084 #endif
10961085 }
10971086
1087+ #if TracingSupport
1088+ public struct TracingConfiguration : Sendable {
1089+
1090+ @usableFromInline
1091+ var _tracer : Optional < any Sendable > // erasure trick so we don't have to make Configuration @available
1092+
1093+ /// Tracer that should be used by the HTTPClient.
1094+ ///
1095+ /// This is selected at configuration creation time, and if no tracer is passed explicitly,
1096+ /// (including `nil` in order to disable traces), the default global bootstrapped tracer will
1097+ /// be stored in this property, and used for all subsequent requests made by this client.
1098+ @inlinable
1099+ @available ( macOS 10 . 15 , iOS 13 , tvOS 13 , watchOS 6 , * )
1100+ public var tracer : ( any Tracer ) ? {
1101+ get {
1102+ guard let _tracer else {
1103+ return nil
1104+ }
1105+ return _tracer as! ( any Tracer ) ?
1106+ }
1107+ set {
1108+ self . _tracer = newValue
1109+ }
1110+ }
1111+
1112+ public var attributeKeys : AttributeKeys
1113+
1114+ public init (
1115+ tracer: ( any Tracer ) ? = InstrumentationSystem . tracer,
1116+ attributeKeys: AttributeKeys = . init( )
1117+ ) {
1118+ self . _tracer = tracer
1119+ self . attributeKeys = attributeKeys
1120+ }
1121+
1122+ /// Span attribute keys that the HTTPClient should set automatically.
1123+ /// This struct allows the configuration of the attribute names (keys) which will be used for the apropriate values.
1124+ public struct AttributeKeys : Sendable {
1125+ public var requestMethod : String = " http.request.method "
1126+ public var requestBodySize : String = " http.request.body.size "
1127+
1128+ public var responseBodySize : String = " http.response.size "
1129+ public var responseStatusCode : String = " http.status_code "
1130+
1131+ public var httpFlavor : String = " http.flavor "
1132+
1133+ public init ( ) { }
1134+ }
1135+ }
1136+ #endif
1137+
10981138 /// Specifies how `EventLoopGroup` will be created and establishes lifecycle ownership.
10991139 public enum EventLoopGroupProvider {
11001140 /// `EventLoopGroup` will be provided by the user. Owner of this group is responsible for its lifecycle.
0 commit comments