Skip to content

Commit 2d9c03b

Browse files
committed
[Tracing] Initial tracing support implementation
1 parent 7dc119c commit 2d9c03b

File tree

11 files changed

+621
-13
lines changed

11 files changed

+621
-13
lines changed

Package.swift

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// swift-tools-version:5.10
1+
// swift-tools-version:6.1
22
//===----------------------------------------------------------------------===//
33
//
44
// This source file is part of the AsyncHTTPClient open source project
@@ -35,9 +35,16 @@ let strictConcurrencySettings: [SwiftSetting] = {
3535

3636
let package = Package(
3737
name: "async-http-client",
38+
platforms: [ // FIXME: must remove this
39+
.macOS("10.15")
40+
],
3841
products: [
3942
.library(name: "AsyncHTTPClient", targets: ["AsyncHTTPClient"])
4043
],
44+
traits: [
45+
.trait(name: "TracingSupport"),
46+
.default(enabledTraits: ["TracingSupport"]),
47+
],
4148
dependencies: [
4249
.package(url: "https://github.com/apple/swift-nio.git", from: "2.81.0"),
4350
.package(url: "https://github.com/apple/swift-nio-ssl.git", from: "2.30.0"),
@@ -47,6 +54,7 @@ let package = Package(
4754
.package(url: "https://github.com/apple/swift-log.git", from: "1.6.0"),
4855
.package(url: "https://github.com/apple/swift-atomics.git", from: "1.0.2"),
4956
.package(url: "https://github.com/apple/swift-algorithms.git", from: "1.0.0"),
57+
.package(url: "https://github.com/apple/swift-distributed-tracing.git", from: "1.2.0"),
5058
],
5159
targets: [
5260
.target(
@@ -73,6 +81,8 @@ let package = Package(
7381
.product(name: "Logging", package: "swift-log"),
7482
.product(name: "Atomics", package: "swift-atomics"),
7583
.product(name: "Algorithms", package: "swift-algorithms"),
84+
// Observability support
85+
.product(name: "Tracing", package: "swift-distributed-tracing", condition: .when(traits: ["TracingSupport"])),
7686
],
7787
swiftSettings: strictConcurrencySettings
7888
),

Package@swift-6.1.swift

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
// swift-tools-version:6.1
2+
//===----------------------------------------------------------------------===//
3+
//
4+
// This source file is part of the AsyncHTTPClient open source project
5+
//
6+
// Copyright (c) 2018-2019 Apple Inc. and the AsyncHTTPClient project authors
7+
// Licensed under Apache License v2.0
8+
//
9+
// See LICENSE.txt for license information
10+
// See CONTRIBUTORS.txt for the list of AsyncHTTPClient project authors
11+
//
12+
// SPDX-License-Identifier: Apache-2.0
13+
//
14+
//===----------------------------------------------------------------------===//
15+
16+
import PackageDescription
17+
18+
let strictConcurrencyDevelopment = false
19+
20+
let strictConcurrencySettings: [SwiftSetting] = {
21+
var initialSettings: [SwiftSetting] = []
22+
initialSettings.append(contentsOf: [
23+
.enableUpcomingFeature("StrictConcurrency"),
24+
.enableUpcomingFeature("InferSendableFromCaptures"),
25+
])
26+
27+
if strictConcurrencyDevelopment {
28+
// -warnings-as-errors here is a workaround so that IDE-based development can
29+
// get tripped up on -require-explicit-sendable.
30+
initialSettings.append(.unsafeFlags(["-Xfrontend", "-require-explicit-sendable", "-warnings-as-errors"]))
31+
}
32+
33+
return initialSettings
34+
}()
35+
36+
let package = Package(
37+
name: "async-http-client",
38+
platforms: [ // FIXME: must remove this
39+
.macOS("10.15")
40+
],
41+
products: [
42+
.library(name: "AsyncHTTPClient", targets: ["AsyncHTTPClient"])
43+
],
44+
traits: [
45+
.trait(name: "TracingSupport"),
46+
.default(enabledTraits: ["TracingSupport"]),
47+
],
48+
dependencies: [
49+
.package(url: "https://github.com/apple/swift-nio.git", from: "2.81.0"),
50+
.package(url: "https://github.com/apple/swift-nio-ssl.git", from: "2.30.0"),
51+
.package(url: "https://github.com/apple/swift-nio-http2.git", from: "1.36.0"),
52+
.package(url: "https://github.com/apple/swift-nio-extras.git", from: "1.26.0"),
53+
.package(url: "https://github.com/apple/swift-nio-transport-services.git", from: "1.24.0"),
54+
.package(url: "https://github.com/apple/swift-log.git", from: "1.6.0"),
55+
.package(url: "https://github.com/apple/swift-atomics.git", from: "1.0.2"),
56+
.package(url: "https://github.com/apple/swift-algorithms.git", from: "1.0.0"),
57+
.package(url: "https://github.com/apple/swift-distributed-tracing.git", from: "1.0.0"),
58+
],
59+
targets: [
60+
.target(
61+
name: "CAsyncHTTPClient",
62+
cSettings: [
63+
.define("_GNU_SOURCE")
64+
]
65+
),
66+
.target(
67+
name: "AsyncHTTPClient",
68+
dependencies: [
69+
.target(name: "CAsyncHTTPClient"),
70+
.product(name: "NIO", package: "swift-nio"),
71+
.product(name: "NIOTLS", package: "swift-nio"),
72+
.product(name: "NIOCore", package: "swift-nio"),
73+
.product(name: "NIOPosix", package: "swift-nio"),
74+
.product(name: "NIOHTTP1", package: "swift-nio"),
75+
.product(name: "NIOConcurrencyHelpers", package: "swift-nio"),
76+
.product(name: "NIOHTTP2", package: "swift-nio-http2"),
77+
.product(name: "NIOSSL", package: "swift-nio-ssl"),
78+
.product(name: "NIOHTTPCompression", package: "swift-nio-extras"),
79+
.product(name: "NIOSOCKS", package: "swift-nio-extras"),
80+
.product(name: "NIOTransportServices", package: "swift-nio-transport-services"),
81+
.product(name: "Logging", package: "swift-log"),
82+
.product(name: "Atomics", package: "swift-atomics"),
83+
.product(name: "Algorithms", package: "swift-algorithms"),
84+
// Observability support
85+
.product(name: "Tracing", package: "swift-distributed-tracing", condition: .when(traits: ["TracingSupport"])),
86+
.product(name: "InMemoryTracing", package: "swift-distributed-tracing", condition: .when(traits: ["TracingSupport"])),
87+
],
88+
swiftSettings: strictConcurrencySettings
89+
),
90+
.testTarget(
91+
name: "AsyncHTTPClientTests",
92+
dependencies: [
93+
.target(name: "AsyncHTTPClient"),
94+
.product(name: "NIOTLS", package: "swift-nio"),
95+
.product(name: "NIOCore", package: "swift-nio"),
96+
.product(name: "NIOConcurrencyHelpers", package: "swift-nio"),
97+
.product(name: "NIOEmbedded", package: "swift-nio"),
98+
.product(name: "NIOFoundationCompat", package: "swift-nio"),
99+
.product(name: "NIOTestUtils", package: "swift-nio"),
100+
.product(name: "NIOSSL", package: "swift-nio-ssl"),
101+
.product(name: "NIOHTTP2", package: "swift-nio-http2"),
102+
.product(name: "NIOSOCKS", package: "swift-nio-extras"),
103+
.product(name: "Logging", package: "swift-log"),
104+
.product(name: "Atomics", package: "swift-atomics"),
105+
.product(name: "Algorithms", package: "swift-algorithms"),
106+
// Observability support
107+
.product(name: "Tracing", package: "swift-distributed-tracing", condition: .when(traits: ["TracingSupport"])),
108+
.product(name: "InMemoryTracing", package: "swift-distributed-tracing", condition: .when(traits: ["TracingSupport"])),
109+
],
110+
resources: [
111+
.copy("Resources/self_signed_cert.pem"),
112+
.copy("Resources/self_signed_key.pem"),
113+
.copy("Resources/example.com.cert.pem"),
114+
.copy("Resources/example.com.private-key.pem"),
115+
],
116+
swiftSettings: strictConcurrencySettings
117+
),
118+
]
119+
)
120+
121+
// --- STANDARD CROSS-REPO SETTINGS DO NOT EDIT --- //
122+
for target in package.targets {
123+
switch target.type {
124+
case .regular, .test, .executable:
125+
var settings = target.swiftSettings ?? []
126+
// https://github.com/swiftlang/swift-evolution/blob/main/proposals/0444-member-import-visibility.md
127+
settings.append(.enableUpcomingFeature("MemberImportVisibility"))
128+
target.swiftSettings = settings
129+
case .macro, .plugin, .system, .binary:
130+
() // not applicable
131+
@unknown default:
132+
() // we don't know what to do here, do nothing
133+
}
134+
}
135+
// --- END: STANDARD CROSS-REPO SETTINGS DO NOT EDIT --- //

Sources/AsyncHTTPClient/AsyncAwait/HTTPClient+execute.swift

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
import Logging
1616
import NIOCore
1717
import NIOHTTP1
18+
#if TracingSupport
19+
import Tracing
20+
#endif
1821

1922
import struct Foundation.URL
2023

@@ -36,12 +39,27 @@ extension HTTPClient {
3639
deadline: NIODeadline,
3740
logger: Logger? = nil
3841
) async throws -> HTTPClientResponse {
39-
try await self.executeAndFollowRedirectsIfNeeded(
40-
request,
41-
deadline: deadline,
42-
logger: logger ?? Self.loggingDisabled,
43-
redirectState: RedirectState(self.configuration.redirectConfiguration.mode, initialURL: request.url)
44-
)
42+
func doExecute() async throws -> HTTPClientResponse {
43+
try await self.executeAndFollowRedirectsIfNeeded(
44+
request,
45+
deadline: deadline,
46+
logger: logger ?? Self.loggingDisabled,
47+
redirectState: RedirectState(self.configuration.redirectConfiguration.mode, initialURL: request.url)
48+
)
49+
}
50+
51+
#if TracingSupport
52+
if let tracer = self.tracer {
53+
return try await tracer.withSpan("\(request.method)") { span -> (HTTPClientResponse) in
54+
let attr = self.configuration.tracing.attributeKeys
55+
span.attributes[attr.requestMethod] = request.method.rawValue
56+
// Set more attributes on the span
57+
return try await doExecute()
58+
}
59+
}
60+
#endif
61+
62+
return try await doExecute()
4563
}
4664
}
4765

Sources/AsyncHTTPClient/AsyncAwait/Transaction.swift

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ import NIOCore
1818
import NIOHTTP1
1919
import NIOSSL
2020

21+
#if TracingSupport
22+
import Tracing
23+
#endif // TracingSupport
24+
2125
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
2226
@usableFromInline
2327
final class Transaction:
@@ -32,26 +36,57 @@ final class Transaction:
3236
let preferredEventLoop: EventLoop
3337
let requestOptions: RequestOptions
3438

39+
#if TracingSupport
40+
let span: (any Span)?
41+
#endif
42+
3543
private let state: NIOLockedValueBox<StateMachine>
3644

45+
#if TracingSupport
3746
init(
3847
request: HTTPClientRequest.Prepared,
3948
requestOptions: RequestOptions,
4049
logger: Logger,
4150
connectionDeadline: NIODeadline,
4251
preferredEventLoop: EventLoop,
52+
span: (any Span)?,
4353
responseContinuation: CheckedContinuation<HTTPClientResponse, Error>
4454
) {
4555
self.request = request
4656
self.requestOptions = requestOptions
4757
self.logger = logger
4858
self.connectionDeadline = connectionDeadline
4959
self.preferredEventLoop = preferredEventLoop
60+
self.span = span
61+
self.state = NIOLockedValueBox(StateMachine(responseContinuation))
62+
}
63+
#endif // TracingSupport
64+
65+
init(
66+
request: HTTPClientRequest.Prepared,
67+
requestOptions: RequestOptions,
68+
logger: Logger,
69+
connectionDeadline: NIODeadline,
70+
preferredEventLoop: EventLoop,
71+
responseContinuation: CheckedContinuation<HTTPClientResponse, Error>
72+
) {
73+
print("[swift] new transaction = \(request)")
74+
self.request = request
75+
self.requestOptions = requestOptions
76+
self.logger = logger
77+
self.connectionDeadline = connectionDeadline
78+
self.preferredEventLoop = preferredEventLoop
79+
self.span = nil
5080
self.state = NIOLockedValueBox(StateMachine(responseContinuation))
5181
}
5282

5383
func cancel() {
54-
self.fail(CancellationError())
84+
let error = CancellationError()
85+
self.fail(error)
86+
#if TracingSupport
87+
self.span?.recordError(error)
88+
self.span?.end()
89+
#endif
5590
}
5691

5792
// MARK: Request body helpers

0 commit comments

Comments
 (0)