Skip to content

Commit bf46136

Browse files
author
Ignacio Bonafonte
committed
Add launched environment SpanContext to TracerSharedState, it allows automatic trace context propagation to child processes
Also fix tracestate propagation header in W3CTraceContextPropagation Fixes #78
1 parent 4a82e4c commit bf46136

File tree

6 files changed

+85
-6
lines changed

6 files changed

+85
-6
lines changed

Sources/OpenTelemetryApi/Trace/Propagation/W3CTraceContextPropagator.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public struct W3CTraceContextPropagator: TextMapPropagator {
3333
private static let traceparentLengthV0 = versionAndTraceIdAndSpanIdLength + optionsLength
3434

3535
static let traceparent = "traceparent"
36-
static let traceState = "traceState"
36+
static let traceState = "tracestate"
3737

3838
public init() {}
3939

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright 2020, OpenTelemetry Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
//
15+
16+
import Foundation
17+
import OpenTelemetryApi
18+
19+
/**
20+
* Implementation of a EnvironmentContextPropagation propagation, using W3CTraceContextPropagator
21+
*/
22+
23+
public struct EnvironmentContextPropagator: TextMapPropagator {
24+
static let traceParent = "OTEL_TRACE_PARENT"
25+
static let traceState = "OTEL_TRACE_STATE"
26+
let w3cPropagator = W3CTraceContextPropagator()
27+
28+
public let fields: Set<String> = [traceState, traceParent]
29+
30+
public init() {}
31+
32+
public func inject<S>(spanContext: SpanContext, carrier: inout [String: String], setter: S) where S: Setter {
33+
var auxCarrier = [String: String]()
34+
w3cPropagator.inject(spanContext: spanContext, carrier: &auxCarrier, setter: setter)
35+
carrier[EnvironmentContextPropagator.traceParent] = auxCarrier["traceparent"]
36+
carrier[EnvironmentContextPropagator.traceState] = auxCarrier["tracestate"]
37+
}
38+
39+
public func extract<G>(carrier: [String: String], getter: G) -> SpanContext? where G: Getter {
40+
var auxCarrier = [String: String]()
41+
auxCarrier["traceparent"] = carrier[EnvironmentContextPropagator.traceParent]
42+
auxCarrier["tracestate"] = carrier[EnvironmentContextPropagator.traceState]
43+
return w3cPropagator.extract(carrier: auxCarrier, getter: getter)
44+
}
45+
}

Sources/OpenTelemetrySdk/Trace/SpanBuilderSdk.swift

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -166,16 +166,20 @@ class SpanBuilderSdk: SpanBuilder {
166166

167167
private func getParentContext(parentType: ParentType, explicitParent: Span?, remoteParent: SpanContext?) -> SpanContext? {
168168
let currentSpan = OpenTelemetry.instance.contextProvider.activeSpan
169+
170+
var parentContext: SpanContext?
169171
switch parentType {
170172
case .noParent:
171-
return nil
173+
parentContext = nil
172174
case .currentSpan:
173-
return currentSpan?.context
175+
parentContext = currentSpan?.context
174176
case .explicitParent:
175-
return explicitParent?.context
177+
parentContext = explicitParent?.context
176178
case .explicitRemoteParent:
177-
return remoteParent
179+
parentContext = remoteParent
178180
}
181+
182+
return parentContext ?? tracerSharedState.launchEnvironmentContext
179183
}
180184

181185
private static func getParentSpan(parentType: ParentType, explicitParent: Span?) -> Span? {

Sources/OpenTelemetrySdk/Trace/TracerSharedState.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
//
1515

1616
import Foundation
17+
import OpenTelemetryApi
1718

1819
/// Represents the shared state/config between all Tracers created by the same TracerProvider.
1920
class TracerSharedState {
@@ -25,6 +26,7 @@ class TracerSharedState {
2526
var sampler: Sampler
2627
var activeSpanProcessor: SpanProcessor
2728
var hasBeenShutdown = false
29+
var launchEnvironmentContext: SpanContext?
2830

2931
var registeredSpanProcessors = [SpanProcessor]()
3032

@@ -49,6 +51,11 @@ class TracerSharedState {
4951
} else {
5052
activeSpanProcessor = NoopSpanProcessor()
5153
}
54+
55+
/// Recovers explicit parent context from process environment variables, it allows to automatic
56+
/// trace context propagation to child processes
57+
let environmentPropagator = EnvironmentContextPropagator()
58+
self.launchEnvironmentContext = environmentPropagator.extract(carrier: ProcessInfo.processInfo.environment, getter: EnvironmentGetter())
5259
}
5360

5461
/// Adds a new SpanProcessor
@@ -89,4 +96,13 @@ class TracerSharedState {
8996
return setSampler(Samplers.traceIdRatio(ratio: samplerProbability))
9097
}
9198
}
99+
100+
private struct EnvironmentGetter: Getter {
101+
func get(carrier: [String: String], key: String) -> [String]? {
102+
if let value = carrier[key] {
103+
return [value]
104+
}
105+
return nil
106+
}
107+
}
92108
}

Tests/OpenTelemetryApiTests/Trace/Propagation/W3CTraceContextPropagatorTest.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ class W3CTraceContextPropagatorTest: XCTestCase {
187187

188188
func testHeaderNames() {
189189
XCTAssertEqual(W3CTraceContextPropagator.traceparent, "traceparent")
190-
XCTAssertEqual(W3CTraceContextPropagator.traceState, "traceState")
190+
XCTAssertEqual(W3CTraceContextPropagator.traceState, "tracestate")
191191
}
192192

193193
func testExtract_EmptyCarrier() {

Tests/OpenTelemetrySdkTests/Trace/SpanBuilderSdkTests.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,20 @@ class SpanBuilderSdkTest: XCTestCase {
249249
span.end()
250250
}
251251

252+
func testParentEnvironmentContext() {
253+
setenv("OTEL_TRACE_PARENT", "00-ff000000000000000000000000000041-ff00000000000041-01", 1)
254+
let providerWithEnv = TracerProviderSdk()
255+
let tracerAux = providerWithEnv.get(instrumentationName: "SpanBuilderWithEnvTest")
256+
let parent = tracerAux.spanBuilder(spanName: spanName).setNoParent().startSpan()
257+
OpenTelemetry.instance.contextProvider.setActiveSpan(parent)
258+
let span = tracerAux.spanBuilder(spanName: spanName).setParent(parent).startSpan()
259+
XCTAssertEqual(span.context.traceId, parent.context.traceId)
260+
XCTAssertEqual(parent.context.traceId.hexString, "ff000000000000000000000000000041")
261+
span.end()
262+
parent.end()
263+
unsetenv("OTEL_TRACE_PARENT")
264+
}
265+
252266
func testParent_timestampConverter() {
253267
let parent = tracerSdk.spanBuilder(spanName: spanName).startSpan()
254268
let span = tracerSdk.spanBuilder(spanName: spanName).setParent(parent).startSpan() as! RecordEventsReadableSpan

0 commit comments

Comments
 (0)