Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trace HTTPClient request execution #320

Draft
wants to merge 24 commits into
base: tracing-development
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
a72c5ad
Fix Timeout snippet in README.md (#323)
0xpablo Jan 5, 2021
1aec5d7
Add defensive connection closure. (#328)
Lukasa Jan 19, 2021
9671de7
Use welcoming language (#333)
fabianfett Jan 22, 2021
bbebce3
fix doc generation setup (#336)
tomerd Jan 24, 2021
2bacb97
Address flakiness of testSSLHandshakeErrorPropagation (#335)
Lukasa Jan 25, 2021
ba845ee
Update Readme to account for Package.swift format (#339)
winsmith Feb 9, 2021
5d9b784
Fixes bi-directional streaming (#344)
artemredkin Mar 3, 2021
0dda95c
Fix CoW in HTTPResponseAggregator (#345)
Lukasa Mar 8, 2021
ae5f185
Use synchronous pipeline hops to remove windows. (#346)
Lukasa Mar 16, 2021
b075d19
Unconditionally insert TLSEventsHandler (#349)
Lukasa Mar 18, 2021
e4fded7
Better backpressure management. (#352)
Lukasa Mar 30, 2021
f352103
Fix tests (#356)
Davidde94 Apr 27, 2021
abac00a
add 5.4 docker setup for CI (#360)
tomerd May 7, 2021
b5b04ac
add 5.4 docker setup for CI (#361)
tomerd May 7, 2021
ca722d8
Support request specific TLS configuration (#358)
madsodgaard May 7, 2021
e2d03ff
cache NIOSSLContext (saves 27k allocs per conn) (#362)
weissi May 13, 2021
06daedf
TLS on Darwin: Add explainer that MTELG supports all options
weissi May 12, 2021
9cdf8a0
Generate trust roots SecCertificate for Transport Services (#350)
adam-fowler May 13, 2021
8ccba73
SSLContextCache: use DispatchQueue instead of NIOThreadPool (#368)
weissi May 13, 2021
cddb69d
fix Swift Package Index build (#369)
weissi May 14, 2021
ddc5304
Inject instrumentation metadata into HTTP headers
slashmo Dec 5, 2020
59b61eb
Trace request execution
slashmo May 25, 2021
10f2642
Fix building on macOS 12
0xTim Jan 10, 2022
e6e48ef
Merge pull request #1 from 0xTim/monterey-tracing
slashmo Jan 14, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.build
.git
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ Package.resolved
DerivedData
.DS_Store
.swiftpm/
.SourceKitten
9 changes: 6 additions & 3 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,20 @@ let package = Package(
.library(name: "AsyncHTTPClient", targets: ["AsyncHTTPClient"]),
],
dependencies: [
.package(url: "https://github.com/apple/swift-nio.git", from: "2.19.0"),
.package(url: "https://github.com/apple/swift-nio-ssl.git", from: "2.8.0"),
.package(url: "https://github.com/apple/swift-nio.git", from: "2.27.0"),
.package(url: "https://github.com/apple/swift-nio-ssl.git", from: "2.13.0"),
.package(url: "https://github.com/apple/swift-nio-extras.git", from: "1.3.0"),
.package(url: "https://github.com/apple/swift-nio-transport-services.git", from: "1.5.1"),
.package(url: "https://github.com/apple/swift-log.git", from: "1.4.0"),
.package(url: "https://github.com/apple/swift-distributed-tracing.git", from: "0.1.1"),
.package(url: "https://github.com/apple/swift-distributed-tracing-baggage", .upToNextMinor(from: "0.1.1")),
],
targets: [
.target(
name: "AsyncHTTPClient",
dependencies: ["NIO", "NIOHTTP1", "NIOSSL", "NIOConcurrencyHelpers", "NIOHTTPCompression",
"NIOFoundationCompat", "NIOTransportServices", "Logging"]
"NIOFoundationCompat", "NIOTransportServices", "Logging", "Instrumentation",
"Tracing", "TracingOpenTelemetrySupport", "Baggage"]
),
.testTarget(
name: "AsyncHTTPClientTests",
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Add the following entry in your <code>Package.swift</code> to start using <code>
```
and `AsyncHTTPClient` dependency to your target:
```swift
.target(name: "MyApp", dependencies: ["AsyncHTTPClient"]),
.target(name: "MyApp", dependencies: [.product(name: "AsyncHTTPClient", package: "async-http-client")]),
```

#### Request-Response API
Expand Down Expand Up @@ -94,7 +94,7 @@ let httpClient = HTTPClient(eventLoopGroupProvider: .createNew,
### Timeouts
Timeouts (connect and read) can also be set using the client configuration:
```swift
let timeout = HTTPClient.Timeout(connect: .seconds(1), read: .seconds(1))
let timeout = HTTPClient.Configuration.Timeout(connect: .seconds(1), read: .seconds(1))
let httpClient = HTTPClient(eventLoopGroupProvider: .createNew,
configuration: HTTPClient.Configuration(timeout: timeout))
```
Expand Down
32 changes: 32 additions & 0 deletions Sources/AsyncHTTPClient/BestEffortHashableTLSConfiguration.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the AsyncHTTPClient open source project
//
// Copyright (c) 2021 Apple Inc. and the AsyncHTTPClient project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of AsyncHTTPClient project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

import NIOSSL

/// Wrapper around `TLSConfiguration` from NIOSSL to provide a best effort implementation of `Hashable`
struct BestEffortHashableTLSConfiguration: Hashable {
let base: TLSConfiguration

init(wrapping base: TLSConfiguration) {
self.base = base
}

func hash(into hasher: inout Hasher) {
self.base.bestEffortHash(into: &hasher)
}

static func == (lhs: BestEffortHashableTLSConfiguration, rhs: BestEffortHashableTLSConfiguration) -> Bool {
return lhs.base.bestEffortEquals(rhs.base)
}
}
31 changes: 18 additions & 13 deletions Sources/AsyncHTTPClient/Connection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
//
//===----------------------------------------------------------------------===//

import Baggage
import Foundation
import Logging
import NIO
Expand Down Expand Up @@ -51,27 +52,31 @@ extension Connection {
/// Release this `Connection` to its associated `HTTP1ConnectionProvider`.
///
/// - Warning: This only releases the connection and doesn't take care of cleaning handlers in the `Channel` pipeline.
func release(closing: Bool, logger: Logger) {
func release(closing: Bool, context: LoggingContext) {
self.channel.eventLoop.assertInEventLoop()
self.provider.release(connection: self, closing: closing, logger: logger)
self.provider.release(connection: self, closing: closing, context: context)
}

/// Called when channel exceeds idle time in pool.
func timeout(logger: Logger) {
func timeout(context: LoggingContext) {
self.channel.eventLoop.assertInEventLoop()
self.provider.timeout(connection: self, logger: logger)
self.provider.timeout(connection: self, context: context)
}

/// Called when channel goes inactive while in the pool.
func remoteClosed(logger: Logger) {
func remoteClosed(context: LoggingContext) {
self.channel.eventLoop.assertInEventLoop()
self.provider.remoteClosed(connection: self, logger: logger)
self.provider.remoteClosed(connection: self, context: context)
}

/// Called from `HTTP1ConnectionProvider.close` when client is shutting down.
func close() -> EventLoopFuture<Void> {
return self.channel.close()
}

func close(promise: EventLoopPromise<Void>?) {
return self.channel.close(promise: promise)
}
}

/// Methods of Connection which are used in ConnectionsState extracted as protocol
Expand Down Expand Up @@ -100,9 +105,9 @@ extension Connection: PoolManageableConnection {

extension Connection {
/// Sets idle timeout handler and channel inactivity listener.
func setIdleTimeout(timeout: TimeAmount?, logger: Logger) {
func setIdleTimeout(timeout: TimeAmount?, context: LoggingContext) {
_ = self.channel.pipeline.addHandler(IdleStateHandler(writeTimeout: timeout), position: .first).flatMap { _ in
self.channel.pipeline.addHandler(IdlePoolConnectionHandler(connection: self, logger: logger))
self.channel.pipeline.addHandler(IdlePoolConnectionHandler(connection: self, loggingContext: context))
}
}

Expand All @@ -119,27 +124,27 @@ class IdlePoolConnectionHandler: ChannelInboundHandler, RemovableChannelHandler

let connection: Connection
var eventSent: Bool
let logger: Logger
let loggingContext: LoggingContext

init(connection: Connection, logger: Logger) {
init(connection: Connection, loggingContext: LoggingContext) {
self.connection = connection
self.eventSent = false
self.logger = logger
self.loggingContext = loggingContext
}

// this is needed to detect when remote end closes connection while connection is in the pool idling
func channelInactive(context: ChannelHandlerContext) {
if !self.eventSent {
self.eventSent = true
self.connection.remoteClosed(logger: self.logger)
self.connection.remoteClosed(context: loggingContext)
}
}

func userInboundEventTriggered(context: ChannelHandlerContext, event: Any) {
if let idleEvent = event as? IdleStateHandler.IdleStateEvent, idleEvent == .write {
if !self.eventSent {
self.eventSent = true
self.connection.timeout(logger: self.logger)
self.connection.timeout(context: loggingContext)
}
} else {
context.fireUserInboundEventTriggered(event)
Expand Down
Loading