Skip to content

Commit 206d663

Browse files
slashmoktoso
andauthored
Add Sampler protocol & ConstantSampler conformance (#7)
Co-authored-by: Konrad `ktoso` Malawski <ktoso@apple.com>
2 parents d02cc74 + d69e456 commit 206d663

File tree

10 files changed

+162
-72
lines changed

10 files changed

+162
-72
lines changed

Package.resolved

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ let package = Package(
1010
dependencies: [
1111
.package(name: "swift-context", url: "https://github.com/slashmo/gsoc-swift-baggage-context", from: "0.5.0"),
1212
.package(url: "https://github.com/slashmo/gsoc-swift-tracing.git", .branch("main")),
13-
.package(url: "https://github.com/slashmo/swift-w3c-trace-context.git", from: "0.4.0"),
13+
.package(url: "https://github.com/slashmo/swift-w3c-trace-context.git", from: "0.5.0"),
1414
.package(url: "https://github.com/slashmo/swift-nio.git", .branch("feature/baggage-context")),
1515
],
1616
targets: [

Sources/Jaeger/JaegerSpan.swift

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@ import W3CTraceContext
1818

1919
public final class JaegerSpan: Span {
2020
public var attributes: SpanAttributes = [:]
21-
public private(set) var isRecording: Bool
21+
22+
public var isRecording: Bool {
23+
self.baggage.traceContext?.sampled ?? false
24+
}
25+
2226
public let startTimestamp: Timestamp
2327
public let baggage: Baggage
2428
public private(set) var endTimestamp: Timestamp?
@@ -40,19 +44,7 @@ public final class JaegerSpan: Span {
4044
self.kind = kind
4145
self.startTimestamp = startTimestamp
4246
self.onReport = onReport
43-
44-
if baggage.traceContext != nil {
45-
var childBaggage = baggage
46-
childBaggage.traceContext?.regenerateParentID()
47-
self.baggage = childBaggage
48-
self.isRecording = false
49-
self.addLink(SpanLink(baggage: baggage))
50-
} else {
51-
var baggage = baggage
52-
baggage.traceContext = TraceContext(parent: .random(), state: .none)
53-
self.baggage = baggage
54-
self.isRecording = true
55-
}
47+
self.baggage = baggage
5648
}
5749

5850
public func setStatus(_ status: SpanStatus) {}

Sources/Jaeger/JaegerTracer.swift

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,14 @@ public final class JaegerTracer: Tracer {
4242
initialDelay: self.settings.flushInterval,
4343
delay: self.settings.flushInterval
4444
) { _ in
45-
self.flush()
46-
}
45+
self.flush()
46+
}
4747
}
4848

4949
public func extract<Carrier, Extractor>(_ carrier: Carrier, into baggage: inout Baggage, using extractor: Extractor)
5050
where
5151
Carrier == Extractor.Carrier,
52-
Extractor: ExtractorProtocol
53-
{
52+
Extractor: ExtractorProtocol {
5453
if let parent = extractor.extract(key: TraceParent.headerName, from: carrier) {
5554
let state = extractor.extract(key: TraceState.headerName, from: carrier) ?? ""
5655
baggage.traceContext = TraceContext(parent: parent, state: state)
@@ -60,8 +59,7 @@ public final class JaegerTracer: Tracer {
6059
public func inject<Carrier, Injector>(_ baggage: Baggage, into carrier: inout Carrier, using injector: Injector)
6160
where
6261
Carrier == Injector.Carrier,
63-
Injector: InjectorProtocol
64-
{
62+
Injector: InjectorProtocol {
6563
guard let traceContext = baggage.traceContext else { return }
6664
injector.inject(traceContext.parent.rawValue, forKey: TraceParent.headerName, into: &carrier)
6765
injector.inject(traceContext.state.rawValue, forKey: TraceState.headerName, into: &carrier)
@@ -73,14 +71,46 @@ public final class JaegerTracer: Tracer {
7371
ofKind kind: SpanKind,
7472
at timestamp: Timestamp
7573
) -> Span {
76-
return JaegerSpan(
74+
let parentBaggage = baggage
75+
var childBaggage = baggage
76+
var samplingAttributes: SpanAttributes = [:]
77+
78+
if parentBaggage.traceContext != nil {
79+
// reuse trace-id and trace flags from parent, but generate new parent id
80+
childBaggage.traceContext?.regenerateParentID()
81+
} else {
82+
// start a new trace context
83+
var traceContext = TraceContext(parent: .random(), state: .none)
84+
let samplingStatus = self.settings.sampler.sample(
85+
operationName: operationName,
86+
traceID: traceContext.parent.traceID
87+
)
88+
samplingAttributes = samplingStatus.attributes
89+
traceContext.sampled = samplingStatus.isSampled
90+
childBaggage.traceContext = traceContext
91+
}
92+
93+
let span = JaegerSpan(
7794
operationName: operationName,
7895
kind: kind,
7996
startTimestamp: timestamp,
80-
baggage: baggage
97+
baggage: childBaggage
8198
) { [weak self] endedSpan in
8299
self?.spansToEmit.append(endedSpan)
83100
}
101+
102+
// link as child of previous trace context
103+
if parentBaggage.traceContext != nil {
104+
span.addLink(SpanLink(baggage: parentBaggage))
105+
}
106+
107+
// add sampling attributes
108+
samplingAttributes.forEach { key, attribute in
109+
// TODO: `SpanAttributes.merge`?
110+
span.attributes[key] = attribute
111+
}
112+
113+
return span
84114
}
85115

86116
public func forceFlush() {
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Jaeger Client Swift open source project
4+
//
5+
// Copyright (c) 2020 Moritz Lang and the Jaeger Client Swift project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
//
10+
// SPDX-License-Identifier: Apache-2.0
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
public struct ConstantSampler: Sampler {
15+
private let samples: Bool
16+
17+
public init(samples: Bool) {
18+
self.samples = samples
19+
}
20+
21+
public func sample(operationName: String, traceID: String) -> SamplingStatus {
22+
SamplingStatus(isSampled: self.samples, attributes: [
23+
"sampler.type": "const",
24+
"sampler.param": self.samples ? "true" : "false",
25+
])
26+
}
27+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Jaeger Client Swift open source project
4+
//
5+
// Copyright (c) 2020 Moritz Lang and the Jaeger Client Swift project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
//
10+
// SPDX-License-Identifier: Apache-2.0
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
import Tracing
15+
16+
public struct SamplingStatus {
17+
var isSampled: Bool
18+
var attributes: SpanAttributes
19+
}
20+
21+
public protocol Sampler {
22+
func sample(operationName: String, traceID: String) -> SamplingStatus
23+
}

Sources/Jaeger/Settings.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ extension JaegerTracer {
1818
public struct Settings {
1919
public let serviceName: String
2020
public let reporter: Reporter
21+
public let sampler: Sampler
2122
public let logger: Logger
2223

2324
public var flushInterval: TimeAmount
@@ -28,6 +29,7 @@ extension JaegerTracer {
2829
public init(
2930
serviceName: String,
3031
reporter: Reporter,
32+
sampler: Sampler,
3133
logger: Logger = Logger(label: "JaegerTracer"),
3234
flushInterval: TimeAmount = .seconds(1),
3335
flushTimeout: TimeAmount = .seconds(5),
@@ -36,6 +38,7 @@ extension JaegerTracer {
3638
) {
3739
self.serviceName = serviceName
3840
self.reporter = reporter
41+
self.sampler = sampler
3942
self.logger = logger
4043
self.flushInterval = flushInterval
4144
self.flushTimeout = flushTimeout

Tests/JaegerTests/JaegerSpanTests.swift

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,6 @@ import W3CTraceContext
1818
import XCTest
1919

2020
final class JaegerSpanTests: XCTestCase {
21-
func test_adds_trace_context_if_not_yet_recorded() {
22-
let span = JaegerSpan()
23-
24-
XCTAssertNotNil(span.baggage.traceContext)
25-
}
26-
2721
func test_recordError_sets_exception_attributes() {
2822
let span = JaegerSpan()
2923
XCTAssertEqual(span.attributes, [:])
@@ -59,26 +53,6 @@ final class JaegerSpanTests: XCTestCase {
5953

6054
XCTAssertEqual(invocationCount, 1)
6155
}
62-
63-
func test_creates_trace_context_for_root_span() {
64-
let span = JaegerSpan()
65-
66-
XCTAssertNotNil(span.baggage.traceContext)
67-
}
68-
69-
func test_regenerates_parent_id_in_existing_trace_context() {
70-
var baggage = Baggage.topLevel
71-
baggage.traceContext = TraceContext(parent: .random(), state: TraceState(rawValue: "rojo=123")!)
72-
73-
let span = JaegerSpan(baggage: baggage)
74-
75-
XCTAssertNotNil(span.baggage.traceContext)
76-
XCTAssertEqual(span.baggage.traceContext?.state, baggage.traceContext?.state)
77-
XCTAssertEqual(span.baggage.traceContext?.parent.traceID, baggage.traceContext?.parent.traceID)
78-
XCTAssertNotEqual(span.baggage.traceContext?.parent.parentID, baggage.traceContext?.parent.parentID)
79-
XCTAssertEqual(span.baggage.traceContext?.parent.traceFlags, baggage.traceContext?.parent.traceFlags)
80-
XCTAssertEqual(span.links.first?.baggage.traceContext, baggage.traceContext)
81-
}
8256
}
8357

8458
extension JaegerSpan {

Tests/JaegerTests/JaegerTracerTests.swift

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ final class JaegerTracerTests: XCTestCase {
2727
func test_extract_w3c_trace_context_into_baggage() {
2828
let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1)
2929
let reporter = TestSpanReporter(eventLoop: eventLoopGroup.next())
30-
let settings = JaegerTracer.Settings(serviceName: "test", reporter: .custom(reporter))
30+
let settings = JaegerTracer.Settings(serviceName: "test", reporter: .custom(reporter), sampler: ConstantSampler(samples: false))
3131
let tracer = JaegerTracer(settings: settings, group: eventLoopGroup)
3232

3333
let traceContext = TraceContext(parent: .random(), state: .none)
@@ -45,7 +45,7 @@ final class JaegerTracerTests: XCTestCase {
4545
func test_extract_missing_w3c_trace_context_into_baggage() {
4646
let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1)
4747
let reporter = TestSpanReporter(eventLoop: eventLoopGroup.next())
48-
let settings = JaegerTracer.Settings(serviceName: "test", reporter: .custom(reporter))
48+
let settings = JaegerTracer.Settings(serviceName: "test", reporter: .custom(reporter), sampler: ConstantSampler(samples: false))
4949
let tracer = JaegerTracer(settings: settings, group: eventLoopGroup)
5050

5151
var baggage = Baggage.topLevel
@@ -58,7 +58,7 @@ final class JaegerTracerTests: XCTestCase {
5858
func test_extract_missing_w3c_trace_context_without_state_into_baggage() {
5959
let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1)
6060
let reporter = TestSpanReporter(eventLoop: eventLoopGroup.next())
61-
let settings = JaegerTracer.Settings(serviceName: "test", reporter: .custom(reporter))
61+
let settings = JaegerTracer.Settings(serviceName: "test", reporter: .custom(reporter), sampler: ConstantSampler(samples: false))
6262
let tracer = JaegerTracer(settings: settings, group: eventLoopGroup)
6363

6464
let traceContext = TraceContext(parent: .random(), state: .none)
@@ -76,7 +76,7 @@ final class JaegerTracerTests: XCTestCase {
7676
func test_inject_w3c_trace_context_into_headers() {
7777
let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1)
7878
let reporter = TestSpanReporter(eventLoop: eventLoopGroup.next())
79-
let settings = JaegerTracer.Settings(serviceName: "test", reporter: .custom(reporter))
79+
let settings = JaegerTracer.Settings(serviceName: "test", reporter: .custom(reporter), sampler: ConstantSampler(samples: false))
8080
let tracer = JaegerTracer(settings: settings, group: eventLoopGroup)
8181

8282
let traceContext = TraceContext(parent: .random(), state: .none)
@@ -94,7 +94,7 @@ final class JaegerTracerTests: XCTestCase {
9494
func test_inject_missing_w3c_trace_context_into_headers() {
9595
let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1)
9696
let reporter = TestSpanReporter(eventLoop: eventLoopGroup.next())
97-
let settings = JaegerTracer.Settings(serviceName: "test", reporter: .custom(reporter))
97+
let settings = JaegerTracer.Settings(serviceName: "test", reporter: .custom(reporter), sampler: ConstantSampler(samples: false))
9898
let tracer = JaegerTracer(settings: settings, group: eventLoopGroup)
9999

100100
let baggage = Baggage.topLevel
@@ -105,13 +105,43 @@ final class JaegerTracerTests: XCTestCase {
105105
XCTAssertTrue(headers.isEmpty)
106106
}
107107

108+
func test_creates_trace_context_for_root_span() {
109+
let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1)
110+
let reporter = TestSpanReporter(eventLoop: eventLoopGroup.next())
111+
let settings = JaegerTracer.Settings(serviceName: "test", reporter: .custom(reporter), sampler: ConstantSampler(samples: false))
112+
let tracer = JaegerTracer(settings: settings, group: eventLoopGroup)
113+
114+
let span = tracer.startSpan(named: "test", baggage: .topLevel, ofKind: .server, at: .now())
115+
XCTAssertNotNil(span.baggage.traceContext)
116+
}
117+
118+
func test_regenerates_parent_id_in_existing_trace_context() {
119+
let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1)
120+
let reporter = TestSpanReporter(eventLoop: eventLoopGroup.next())
121+
let settings = JaegerTracer.Settings(serviceName: "test", reporter: .custom(reporter), sampler: ConstantSampler(samples: false))
122+
let tracer = JaegerTracer(settings: settings, group: eventLoopGroup)
123+
124+
var parentBaggage = Baggage.topLevel
125+
parentBaggage.traceContext = TraceContext(parent: .random(), state: TraceState(rawValue: "rojo=123")!)
126+
127+
let parent = tracer.startSpan(named: "test", baggage: parentBaggage, ofKind: .server, at: .now()) as! JaegerSpan
128+
let child = tracer.startSpan(named: "test", baggage: parent.baggage, ofKind: .server, at: .now()) as! JaegerSpan
129+
130+
XCTAssertNotNil(child.baggage.traceContext)
131+
XCTAssertEqual(child.baggage.traceContext?.state, parentBaggage.traceContext?.state)
132+
XCTAssertEqual(child.baggage.traceContext?.parent.traceID, parentBaggage.traceContext?.parent.traceID)
133+
XCTAssertNotEqual(child.baggage.traceContext?.parent.parentID, parentBaggage.traceContext?.parent.parentID)
134+
XCTAssertEqual(child.baggage.traceContext?.parent.traceFlags, parentBaggage.traceContext?.parent.traceFlags)
135+
XCTAssertEqual(child.links.first?.baggage.traceContext, parent.baggage.traceContext)
136+
}
137+
108138
// MARK: - Flushing
109139

110140
func test_emits_spans_to_reporter_on_forceFlush() {
111141
let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1)
112142
let reporter = TestSpanReporter(eventLoop: eventLoopGroup.next())
113143

114-
let settings = JaegerTracer.Settings(serviceName: "test", reporter: .custom(reporter))
144+
let settings = JaegerTracer.Settings(serviceName: "test", reporter: .custom(reporter), sampler: ConstantSampler(samples: false))
115145
let tracer = JaegerTracer(settings: settings, group: eventLoopGroup)
116146

117147
var spans = [JaegerSpan]()

0 commit comments

Comments
 (0)