Skip to content

Commit e2a7069

Browse files
authored
feat: split extract_context, fix tracestate parsing on empty string, adjust to spec around traceparent/tracestate parsing order (#106)
* split extract_context, fix tracestate parsing, adjust to spec around traceparent/tracestate parsing order * Add test for dict based header * up v
1 parent 9e36f56 commit e2a7069

File tree

5 files changed

+94
-19
lines changed

5 files changed

+94
-19
lines changed

src/api/Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "OpenTelemetryAPI"
22
uuid = "4f63ef3d-5940-44e7-a611-2d97696cffc9"
33
authors = ["Jun Tian <tianjun.cpp@gmail.com>"]
4-
version = "0.5.0"
4+
version = "0.5.1"
55

66
[deps]
77
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"

src/api/src/propagator/trace_context_textmap_propagator.jl

Lines changed: 68 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -43,29 +43,80 @@ TRACEPARENT_HEADER_FORMAT =
4343
r"^[ \t]*(?P<version>[0-9a-f]{2})-(?P<trace_id>[0-9a-f]{32})-(?P<span_id>[0-9a-f]{16})-(?P<trace_flag>[0-9a-f]{2})(?P<rest>-.*)?[ \t]*$"
4444

4545
function extract_context(
46-
carrier::Union{
47-
AbstractVector{<:Pair{<:AbstractString,<:AbstractString}},
48-
AbstractDict{<:AbstractString,<:AbstractString},
49-
},
46+
carrier::AbstractDict{<:AbstractString,<:AbstractString},
5047
propagator::TraceContextTextMapPropagator,
5148
ctx::Context = current_context(),
5249
)
53-
trace_id, span_id, trace_flag, trace_state = nothing, nothing, nothing, TraceState()
54-
for (k, v) in carrier
55-
if k == "traceparent"
56-
m = match(TRACEPARENT_HEADER_FORMAT, v)
57-
if !isnothing(m)
58-
if m["version"] == "00" && isnothing(m["rest"])
59-
trace_id = parse(TraceIdType, m["trace_id"], base = 16)
60-
span_id = parse(SpanIdType, m["span_id"], base = 16)
61-
trace_flag = parse(TraceFlag, m["trace_flag"])
62-
end
50+
trace_id = nothing
51+
span_id = nothing
52+
trace_flag = nothing
53+
trace_state = TraceState()
54+
55+
carrier_keys = collect(keys(carrier))
56+
57+
traceparent_idx = findfirst(k -> lowercase(k) == "traceparent", carrier_keys)
58+
59+
if traceparent_idx !== nothing
60+
m = match(TRACEPARENT_HEADER_FORMAT, carrier[carrier_keys[traceparent_idx]])
61+
if m !== nothing && m["version"] == "00" && m["rest"] === nothing
62+
trace_id = parse(TraceIdType, m["trace_id"], base = 16)
63+
span_id = parse(SpanIdType, m["span_id"], base = 16)
64+
trace_flag = parse(TraceFlag, m["trace_flag"])
65+
66+
# we only look for/parse tracestate if traceparent is ok
67+
tracestate_idx = findfirst(k -> lowercase(k) == "tracestate", carrier_keys)
68+
if tracestate_idx !== nothing
69+
trace_state = parse(TraceState, carrier[carrier_keys[tracestate_idx]])
6370
end
64-
elseif k == "tracestate"
65-
trace_state = parse(TraceState, v)
6671
end
6772
end
68-
if isnothing(trace_id) || isnothing(span_id) || isnothing(trace_flag)
73+
74+
return _extract_context(trace_id, span_id, trace_flag, trace_state, propagator, ctx)
75+
end
76+
77+
function extract_context(
78+
carrier::AbstractVector{<:Pair{<:AbstractString,<:AbstractString}},
79+
propagator::TraceContextTextMapPropagator,
80+
ctx::Context = current_context(),
81+
)
82+
trace_id = nothing
83+
span_id = nothing
84+
trace_flag = nothing
85+
trace_state = TraceState()
86+
87+
traceparent_idx = findfirst(kv -> lowercase(kv[1]) == "traceparent", carrier)
88+
89+
if traceparent_idx !== nothing
90+
m = match(TRACEPARENT_HEADER_FORMAT, carrier[traceparent_idx][2])
91+
if m !== nothing && m["version"] == "00" && m["rest"] === nothing
92+
trace_id = parse(TraceIdType, m["trace_id"], base = 16)
93+
span_id = parse(SpanIdType, m["span_id"], base = 16)
94+
trace_flag = parse(TraceFlag, m["trace_flag"])
95+
96+
# we only look for/parse tracestate if traceparent is ok
97+
tracestate_idx = findfirst(kv -> lowercase(kv[1]) == "tracestate", carrier)
98+
if tracestate_idx !== nothing
99+
trace_state = parse(TraceState, carrier[tracestate_idx][2])
100+
end
101+
end
102+
end
103+
104+
return _extract_context(trace_id, span_id, trace_flag, trace_state, propagator, ctx)
105+
end
106+
107+
function _extract_context(
108+
trace_id,
109+
span_id,
110+
trace_flag,
111+
trace_state,
112+
propagator::TraceContextTextMapPropagator,
113+
ctx::Context = current_context(),
114+
)
115+
return if (
116+
trace_id === nothing ||
117+
span_id === nothing ||
118+
trace_flag === nothing
119+
)
69120
ctx
70121
else
71122
merge(

src/api/src/trace/tracer_basic.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,9 @@ function Base.show(io::IO, ts::TraceState)
107107
end
108108

109109
function Base.parse(::Type{TraceState}, s::AbstractString)
110-
TraceState((Pair(split(kv, '=')...) for kv in split(s, ','))...)
110+
kvs = split(s, ',')
111+
fkvs = filter(kv -> match(r"^[^=]*=[^=]*$", kv) !== nothing, kvs)
112+
TraceState((Pair(split(kv, '=')...) for kv in fkvs)...)
111113
end
112114

113115
"""

src/api/test/propagator.jl

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,24 @@
2020
@test sc.trace_flag == TraceFlag(false)
2121
end
2222

23+
24+
header = Dict{String,String}(
25+
"traceparent" => "00-$(string(test_trace_id, base=16, pad=32))-$(string(test_span_id,base=16,pad=16))-00",
26+
"tracestate" => tracestate_value,
27+
)
28+
with_context(; x = 123) do
29+
ctx = extract_context(header)
30+
@test ctx[:x] == 123
31+
@test ctx |> current_span |> span_status == SpanStatus(SPAN_STATUS_UNSET)
32+
33+
sc = span_context(ctx)
34+
@test sc.trace_id == test_trace_id
35+
@test sc.span_id == test_span_id
36+
@test string(sc.trace_state) ==
37+
string(TraceState("foo" => "1", "bar" => "2", "baz" => "3"))
38+
@test sc.trace_flag == TraceFlag(false)
39+
end
40+
2341
header = Dict("Content-Type" => "text/plain")
2442
with_span("test") do
2543
inject_context!(header)

src/api/test/trace.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818
@test haskey(ts, :foo)
1919
@test !haskey(ts, "^foo-_*/bar")
2020
@test ts[:foo] == "bar3"
21+
22+
@test isempty(parse(TraceState, ""))
23+
@test !isempty(parse(TraceState, "a=b,c=d"))
24+
@test !isempty(parse(TraceState, "a=b,ss=dwdw=dwdwd,c=d"))
2125
end
2226
end
2327

0 commit comments

Comments
 (0)