@@ -61,9 +61,6 @@ let globalRequestID = ManagedAtomic(0)
61
61
/// }
62
62
/// }
63
63
/// ```
64
- // #if TracingSupport
65
- // @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
66
- // #endif
67
64
public final class HTTPClient : Sendable {
68
65
/// The `EventLoopGroup` in use by this ``HTTPClient``.
69
66
///
@@ -80,8 +77,9 @@ public final class HTTPClient: Sendable {
80
77
81
78
#if TracingSupport
82
79
@_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
85
83
}
86
84
#endif // TracingSupport
87
85
@@ -368,8 +366,7 @@ public final class HTTPClient: Sendable {
368
366
/// - url: Remote URL.
369
367
/// - deadline: Point in time by which the request must complete.
370
368
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)
373
370
}
374
371
375
372
/// Execute `GET` request using specified URL.
@@ -496,7 +493,6 @@ public final class HTTPClient: Sendable {
496
493
) -> EventLoopFuture < Response > {
497
494
do {
498
495
let request = try Request ( url: url, method: method, body: body)
499
- print ( " [swift] request \( request) " )
500
496
return self . execute ( request: request, deadline: deadline, logger: logger ?? HTTPClient . loggingDisabled)
501
497
} catch {
502
498
return self . eventLoopGroup. any ( ) . makeFailedFuture ( error)
@@ -575,7 +571,7 @@ public final class HTTPClient: Sendable {
575
571
/// - deadline: Point in time by which the request must complete.
576
572
/// - logger: The logger to use for this request.
577
573
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)
579
575
return self . execute ( request: request, delegate: accumulator, deadline: deadline, logger: logger) . futureResult
580
576
}
581
577
@@ -688,8 +684,6 @@ public final class HTTPClient: Sendable {
688
684
deadline: NIODeadline ? = nil ,
689
685
logger: Logger ?
690
686
) -> Task < Delegate . Response > {
691
- print ( " [swift] EXECUTE HERE " )
692
- assert ( self . configuration. tracer != nil )
693
687
return self . _execute (
694
688
request: request,
695
689
delegate: delegate,
@@ -717,14 +711,28 @@ public final class HTTPClient: Sendable {
717
711
eventLoop eventLoopPreference: EventLoopPreference ,
718
712
deadline: NIODeadline ? = nil ,
719
713
logger originalLogger: Logger ? ,
720
- redirectState: RedirectState ?
714
+ redirectState: RedirectState ? ,
721
715
) -> Task < Delegate . Response > {
722
- assert ( self . configuration. tracer != nil )
723
716
let logger = ( originalLogger ?? HTTPClient . loggingDisabled) . attachingRequestInformation (
724
717
request,
725
718
requestID: globalRequestID. wrappingIncrementThenLoad ( ordering: . relaxed)
726
719
)
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
+
728
736
let taskEL : EventLoop
729
737
switch eventLoopPreference. preference {
730
738
case . indifferent:
@@ -760,10 +768,14 @@ public final class HTTPClient: Sendable {
760
768
return nil
761
769
case . shuttingDown, . shutDown:
762
770
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
764
776
return Task< Delegate . Response> . failedTask(
765
777
eventLoop: taskEL,
766
- error: HTTPClientError . alreadyShutdown ,
778
+ error: error ,
767
779
logger: logger,
768
780
tracer: tracer,
769
781
makeOrGetFileIOThreadPool: self . makeOrGetFileIOThreadPool
@@ -778,7 +790,6 @@ public final class HTTPClient: Sendable {
778
790
let redirectHandler : RedirectHandler < Delegate . Response > ? = {
779
791
guard let redirectState = redirectState else { return nil }
780
792
781
- // TODO: span for redirects?
782
793
return . init( request: request, redirectState: redirectState) { newRequest, newRedirectState in
783
794
self . _execute (
784
795
request: newRequest,
@@ -791,26 +802,12 @@ public final class HTTPClient: Sendable {
791
802
}
792
803
} ( )
793
804
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
804
805
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
+ )
814
811
815
812
do {
816
813
let requestBag = try RequestBag (
@@ -924,12 +921,7 @@ public final class HTTPClient: Sendable {
924
921
public var http2StreamChannelDebugInitializer : ( @Sendable ( Channel ) -> EventLoopFuture < Void > ) ?
925
922
926
923
#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( )
933
925
#endif
934
926
935
927
public init (
@@ -1059,9 +1051,6 @@ public final class HTTPClient: Sendable {
1059
1051
self . http1_1ConnectionDebugInitializer = http1_1ConnectionDebugInitializer
1060
1052
self . http2ConnectionDebugInitializer = http2ConnectionDebugInitializer
1061
1053
self . http2StreamChannelDebugInitializer = http2StreamChannelDebugInitializer
1062
- #if TracingSupport
1063
- self . tracer = InstrumentationSystem . tracer
1064
- #endif
1065
1054
}
1066
1055
1067
1056
#if TracingSupport
@@ -1076,7 +1065,7 @@ public final class HTTPClient: Sendable {
1076
1065
http1_1ConnectionDebugInitializer: ( @Sendable ( Channel ) -> EventLoopFuture < Void > ) ? = nil ,
1077
1066
http2ConnectionDebugInitializer: ( @Sendable ( Channel ) -> EventLoopFuture < Void > ) ? = nil ,
1078
1067
http2StreamChannelDebugInitializer: ( @Sendable ( Channel ) -> EventLoopFuture < Void > ) ? = nil ,
1079
- tracer : ( any Tracer ) ? = InstrumentationSystem . tracer
1068
+ tracing : TracingConfiguration = . init ( )
1080
1069
) {
1081
1070
self . init (
1082
1071
tlsConfiguration: tlsConfiguration,
@@ -1090,11 +1079,62 @@ public final class HTTPClient: Sendable {
1090
1079
self . http1_1ConnectionDebugInitializer = http1_1ConnectionDebugInitializer
1091
1080
self . http2ConnectionDebugInitializer = http2ConnectionDebugInitializer
1092
1081
self . http2StreamChannelDebugInitializer = http2StreamChannelDebugInitializer
1093
- self . tracer = tracer
1082
+ self . tracing = tracing
1094
1083
}
1095
1084
#endif
1096
1085
}
1097
1086
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
+
1098
1138
/// Specifies how `EventLoopGroup` will be created and establishes lifecycle ownership.
1099
1139
public enum EventLoopGroupProvider {
1100
1140
/// `EventLoopGroup` will be provided by the user. Owner of this group is responsible for its lifecycle.
0 commit comments