Skip to content

Commit d1c9a28

Browse files
ktosoglbrntt
authored andcommitted
+tracing implement TraceID handling using swift-distributed-tracing
1 parent 57b7a59 commit d1c9a28

18 files changed

+305
-97
lines changed

Package.swift

+11-3
Original file line numberDiff line numberDiff line change
@@ -51,19 +51,25 @@ let packageDependencies: [Package.Dependency] = [
5151
from: "1.20.2"
5252
),
5353
.package(
54-
url: "https://github.com/apple/swift-log.git",
55-
from: "1.4.4"
54+
// url: "https://github.com/apple/swift-log.git",
55+
// from: "1.4.4"
56+
url: "https://github.com/slashmo/swift-log.git",
57+
branch: "feature/baggage"
5658
),
5759
.package(
5860
url: "https://github.com/apple/swift-argument-parser.git",
5961
// Version is higher than in other Package@swift manifests: 1.1.0 raised the minimum Swift
60-
// version and indluded async support.
62+
// version and included async support.
6163
from: "1.1.1"
6264
),
6365
.package(
6466
url: "https://github.com/apple/swift-docc-plugin",
6567
from: "1.0.0"
6668
),
69+
.package(
70+
url: "https://github.com/apple/swift-distributed-tracing",
71+
branch: "main"
72+
),
6773
].appending(
6874
.package(
6975
url: "https://github.com/apple/swift-nio-ssl.git",
@@ -114,6 +120,7 @@ extension Target.Dependency {
114120
package: "swift-nio-transport-services"
115121
)
116122
static let logging: Self = .product(name: "Logging", package: "swift-log")
123+
static let tracing: Self = .product(name: "Tracing", package: "swift-distributed-tracing")
117124
static let protobuf: Self = .product(name: "SwiftProtobuf", package: "swift-protobuf")
118125
static let protobufPluginLibrary: Self = .product(
119126
name: "SwiftProtobufPluginLibrary",
@@ -139,6 +146,7 @@ extension Target {
139146
.nioHTTP2,
140147
.nioExtras,
141148
.logging,
149+
.tracing,
142150
.protobuf,
143151
].appending(
144152
.nioSSL, if: includeNIOSSL

Sources/GRPC/AsyncAwaitSupport/GRPCAsyncServerHandler.swift

+21-6
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import DequeModule
1818
import Logging
1919
import NIOCore
2020
import NIOHPACK
21+
import Tracing
2122

2223
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
2324
public struct GRPCAsyncServerHandler<
@@ -193,8 +194,13 @@ internal final class AsyncServerHandler<
193194
@usableFromInline
194195
internal var logger: Logger
195196

197+
/// Contextual baggage which can be used to start tracing spans,
198+
// or carry additional contextual information through the handler.
196199
@usableFromInline
197-
internal let traceIDExtractor: Server.Configuration.TraceIDExtractor?
200+
internal var baggage: Baggage
201+
202+
@usableFromInline
203+
internal let tracer: Tracing.Tracer? // FIXME: tri state "don't trace" / "global" / "configured"
198204

199205
/// A reference to the user info. This is shared with the interceptor pipeline and may be accessed
200206
/// from the async call context. `UserInfo` is _not_ `Sendable` and must always be accessed from
@@ -270,7 +276,8 @@ internal final class AsyncServerHandler<
270276
self.compressionEnabledOnRPC = context.encoding.isEnabled
271277
self.compressResponsesIfPossible = true
272278
self.logger = context.logger
273-
self.traceIDExtractor = context.traceIDExtractor
279+
self.baggage = .topLevel // TODO: or carry from context?
280+
self.tracer = context.tracer
274281

275282
self.userInfoRef = Ref(UserInfo())
276283
self.handlerStateMachine = .init()
@@ -299,9 +306,17 @@ internal final class AsyncServerHandler<
299306
internal func receiveMetadata(_ headers: HPACKHeaders) {
300307
switch self.interceptorStateMachine.interceptRequestMetadata() {
301308
case .intercept:
302-
if let extractor = self.traceIDExtractor, let id = extractor.extract(from: headers) {
303-
self.logger[metadataKey: extractor.loggerKey] = "\(id)"
304-
self.interceptors?.logger[metadataKey: extractor.loggerKey] = "\(id)"
309+
if let tracer = self.tracer {
310+
tracer.extract(headers, into: &baggage, using: HPACKHeadersExtractor())
311+
312+
if let metadata: Logger.Metadata = self.logger.metadataProvider?.metadata(baggage) { // FIXME: function naming a bit ugly here
313+
for (k, v) in metadata {
314+
self.logger[metadataKey: k] = v
315+
self.interceptors?.logger[metadataKey: k] = v
316+
// self.logger[metadataKey: extractor.loggerKey] = "\(id)"
317+
// self.interceptors?.logger[metadataKey: extractor.loggerKey] = "\(id)"
318+
}
319+
}
305320
}
306321
self.interceptors?.receive(.metadata(headers))
307322
case .cancel:
@@ -323,7 +338,7 @@ internal final class AsyncServerHandler<
323338

324339
switch self.interceptorStateMachine.interceptRequestMessage() {
325340
case .intercept:
326-
self.interceptors?.receive(.message(request))
341+
self.interceptors?.receive(.message(request)) // TODO: if we wrapped this in a withSpan, would that be correct?
327342
case .cancel:
328343
self.cancel(error: nil)
329344
case .drop:

Sources/GRPC/CallHandlers/BidirectionalStreamingServerHandler.swift

+14-3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import Logging
1717
import NIOCore
1818
import NIOHPACK
19+
import Tracing
1920

2021
public final class BidirectionalStreamingServerHandler<
2122
Serializer: MessageSerializer,
@@ -60,6 +61,9 @@ public final class BidirectionalStreamingServerHandler<
6061
@usableFromInline
6162
internal var logger: Logger
6263

64+
@usableFromInline
65+
internal var baggage: Baggage
66+
6367
@usableFromInline
6468
internal enum State {
6569
// No headers have been received.
@@ -90,6 +94,7 @@ public final class BidirectionalStreamingServerHandler<
9094
let userInfoRef = Ref(UserInfo())
9195
self.userInfoRef = userInfoRef
9296
self.logger = context.logger
97+
self.baggage = .topLevel
9398
self.interceptors = ServerInterceptorPipeline(
9499
logger: context.logger,
95100
eventLoop: context.eventLoop,
@@ -107,9 +112,15 @@ public final class BidirectionalStreamingServerHandler<
107112

108113
@inlinable
109114
public func receiveMetadata(_ headers: HPACKHeaders) {
110-
if let extractor = self.context.traceIDExtractor, let id = extractor.extract(from: headers) {
111-
self.logger[metadataKey: extractor.loggerKey] = "\(id)"
112-
self.interceptors.logger[metadataKey: extractor.loggerKey] = "\(id)"
115+
if let tracer = self.context.tracer {
116+
tracer.extract(headers, into: &self.baggage, using: HPACKHeadersExtractor())
117+
118+
if let metadata: Logger.Metadata = self.logger.metadataProvider?.metadata(baggage) { // FIXME: function naming a bit ugly here
119+
for (k, v) in metadata {
120+
self.logger[metadataKey: k] = v
121+
self.interceptors?.logger[metadataKey: k] = v
122+
}
123+
}
113124
}
114125
self.interceptors.receive(.metadata(headers))
115126
}

Sources/GRPC/CallHandlers/ClientStreamingServerHandler.swift

+16-3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import Logging
1717
import NIOCore
1818
import NIOHPACK
19+
import Tracing
1920

2021
public final class ClientStreamingServerHandler<
2122
Serializer: MessageSerializer,
@@ -60,6 +61,9 @@ public final class ClientStreamingServerHandler<
6061
@usableFromInline
6162
internal var logger: Logger
6263

64+
@usableFromInline
65+
internal var baggage: Baggage
66+
6367
@usableFromInline
6468
internal enum State {
6569
// Nothing has happened yet.
@@ -91,6 +95,7 @@ public final class ClientStreamingServerHandler<
9195
let userInfoRef = Ref(UserInfo())
9296
self.userInfoRef = userInfoRef
9397
self.logger = context.logger
98+
self.baggage = .topLevel
9499
self.interceptors = ServerInterceptorPipeline(
95100
logger: context.logger,
96101
eventLoop: context.eventLoop,
@@ -108,9 +113,17 @@ public final class ClientStreamingServerHandler<
108113

109114
@inlinable
110115
public func receiveMetadata(_ headers: HPACKHeaders) {
111-
if let extractor = self.context.traceIDExtractor, let id = extractor.extract(from: headers) {
112-
self.logger[metadataKey: extractor.loggerKey] = "\(id)"
113-
self.interceptors.logger[metadataKey: extractor.loggerKey] = "\(id)"
116+
if let tracer = self.context.tracer {
117+
var baggage = Baggage.topLevel
118+
tracer.extract(headers, into: &baggage, using: HPACKHeadersExtractor())
119+
self.baggage = baggage
120+
121+
if let metadata: Logger.Metadata = self.logger.metadataProvider?.metadata(baggage) { // FIXME: function naming a bit ugly here
122+
for (k, v) in metadata {
123+
self.logger[metadataKey: k] = v
124+
self.interceptors?.logger[metadataKey: k] = v
125+
}
126+
}
114127
}
115128
self.interceptors.receive(.metadata(headers))
116129
}

Sources/GRPC/CallHandlers/ServerStreamingServerHandler.swift

+14-3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import Logging
1717
import NIOCore
1818
import NIOHPACK
19+
import Tracing
1920

2021
public final class ServerStreamingServerHandler<
2122
Serializer: MessageSerializer,
@@ -56,6 +57,9 @@ public final class ServerStreamingServerHandler<
5657
@usableFromInline
5758
internal var logger: Logger
5859

60+
@usableFromInline
61+
internal var baggage: Baggage
62+
5963
@usableFromInline
6064
internal enum State {
6165
// Initial state. Nothing has happened yet.
@@ -87,6 +91,7 @@ public final class ServerStreamingServerHandler<
8791
let userInfoRef = Ref(UserInfo())
8892
self.userInfoRef = userInfoRef
8993
self.logger = context.logger
94+
self.baggage = .topLevel
9095
self.interceptors = ServerInterceptorPipeline(
9196
logger: context.logger,
9297
eventLoop: context.eventLoop,
@@ -104,9 +109,15 @@ public final class ServerStreamingServerHandler<
104109

105110
@inlinable
106111
public func receiveMetadata(_ headers: HPACKHeaders) {
107-
if let extractor = self.context.traceIDExtractor, let id = extractor.extract(from: headers) {
108-
self.logger[metadataKey: extractor.loggerKey] = "\(id)"
109-
self.interceptors.logger[metadataKey: extractor.loggerKey] = "\(id)"
112+
if let tracer = self.context.tracer {
113+
tracer.extract(headers, into: &self.baggage, using: HPACKHeadersExtractor())
114+
115+
if let metadata: Logger.Metadata = self.logger.metadataProvider?.metadata(baggage) { // FIXME: function naming a bit ugly here
116+
for (k, v) in metadata {
117+
self.logger[metadataKey: k] = v
118+
self.interceptors?.logger[metadataKey: k] = v
119+
}
120+
}
110121
}
111122
self.interceptors.receive(.metadata(headers))
112123
}

Sources/GRPC/CallHandlers/UnaryServerHandler.swift

+14-3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import Logging
1717
import NIOCore
1818
import NIOHPACK
19+
import Tracing
1920

2021
public final class UnaryServerHandler<
2122
Serializer: MessageSerializer,
@@ -55,6 +56,9 @@ public final class UnaryServerHandler<
5556
@usableFromInline
5657
internal var logger: Logger
5758

59+
@usableFromInline
60+
internal var baggage: Baggage
61+
5862
@usableFromInline
5963
internal enum State {
6064
// Initial state. Nothing has happened yet.
@@ -81,6 +85,7 @@ public final class UnaryServerHandler<
8185
self.serializer = responseSerializer
8286
self.deserializer = requestDeserializer
8387
self.context = context
88+
self.baggage = .topLevel // TODO: decide if rather we set it from somewhere here?
8489
self.logger = context.logger
8590

8691
let userInfoRef = Ref(UserInfo())
@@ -102,9 +107,15 @@ public final class UnaryServerHandler<
102107

103108
@inlinable
104109
public func receiveMetadata(_ metadata: HPACKHeaders) {
105-
if let extractor = self.context.traceIDExtractor, let id = extractor.extract(from: metadata) {
106-
self.logger[metadataKey: extractor.loggerKey] = "\(id)"
107-
self.interceptors.logger[metadataKey: extractor.loggerKey] = "\(id)"
110+
if let tracer = self.context.tracer {
111+
tracer.extract(metadata, into: &baggage, using: HPACKHeadersExtractor())
112+
113+
if let metadata: Logger.Metadata = self.logger.metadataProvider?.metadata(baggage) { // FIXME: function naming a bit ugly here
114+
for (k, v) in metadata {
115+
self.logger[metadataKey: k] = v
116+
self.interceptors?.logger[metadataKey: k] = v
117+
}
118+
}
108119
}
109120
self.interceptors.receive(.metadata(metadata))
110121
}

Sources/GRPC/GRPCServerPipelineConfigurator.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ final class GRPCServerPipelineConfigurator: ChannelInboundHandler, RemovableChan
143143
normalizeHeaders: normalizeHeaders,
144144
maximumReceiveMessageLength: self.configuration.maximumReceiveMessageLength,
145145
logger: logger,
146-
traceIDExtractor: self.configuration.traceIDExtractor
146+
tracer: self.configuration.tracer
147147
)
148148
}
149149

Sources/GRPC/GRPCServerRequestRoutingHandler.swift

+3-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import NIOHPACK
1919
import NIOHTTP1
2020
import NIOHTTP2
2121
import SwiftProtobuf
22+
import Tracing
2223

2324
/// Provides ``GRPCServerHandlerProtocol`` objects for the methods on a particular service name.
2425
///
@@ -45,6 +46,7 @@ public struct CallHandlerContext {
4546
internal var errorDelegate: ServerErrorDelegate?
4647
@usableFromInline
4748
internal var logger: Logger
49+
// TODO: does this need baggage?
4850
@usableFromInline
4951
internal var encoding: ServerMessageEncoding
5052
@usableFromInline
@@ -60,7 +62,7 @@ public struct CallHandlerContext {
6062
@usableFromInline
6163
internal var closeFuture: EventLoopFuture<Void>
6264
@usableFromInline
63-
internal var traceIDExtractor: Server.Configuration.TraceIDExtractor?
65+
internal var tracer: Tracing.Tracer?
6466
}
6567

6668
/// A call URI split into components.

Sources/GRPC/HTTP2ToRawGRPCServerCodec.swift

+5-4
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,14 @@ import Logging
1717
import NIOCore
1818
import NIOHPACK
1919
import NIOHTTP2
20+
import Tracing
2021

2122
internal final class HTTP2ToRawGRPCServerCodec: ChannelInboundHandler, GRPCServerResponseWriter {
2223
typealias InboundIn = HTTP2Frame.FramePayload
2324
typealias OutboundOut = HTTP2Frame.FramePayload
2425

2526
private var logger: Logger
26-
private let traceIDExtractor: Server.Configuration.TraceIDExtractor?
27+
private var tracer: Tracing.Tracer?
2728
private var state: HTTP2ToRawGRPCStateMachine
2829
private let errorDelegate: ServerErrorDelegate?
2930
private var context: ChannelHandlerContext!
@@ -75,10 +76,10 @@ internal final class HTTP2ToRawGRPCServerCodec: ChannelInboundHandler, GRPCServe
7576
normalizeHeaders: Bool,
7677
maximumReceiveMessageLength: Int,
7778
logger: Logger,
78-
traceIDExtractor: Server.Configuration.TraceIDExtractor?
79+
tracer: Tracing.Tracer?
7980
) {
8081
self.logger = logger
81-
self.traceIDExtractor = traceIDExtractor
82+
self.tracer = tracer
8283
self.errorDelegate = errorDelegate
8384
self.servicesByName = servicesByName
8485
self.encoding = encoding
@@ -131,7 +132,7 @@ internal final class HTTP2ToRawGRPCServerCodec: ChannelInboundHandler, GRPCServe
131132
services: self.servicesByName,
132133
encoding: self.encoding,
133134
normalizeHeaders: self.normalizeHeaders,
134-
traceIDExtractor: self.traceIDExtractor
135+
tracer: self.tracer
135136
)
136137

137138
switch receiveHeaders {

0 commit comments

Comments
 (0)