-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implements #21 * refactor(zipkin) extract parse_http_req_headers to module * feat(zipkin) parse b3 single header * tests(zipkin) extract wait_for_spans to aux function
- Loading branch information
Showing
5 changed files
with
507 additions
and
124 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
local unescape_uri = ngx.unescape_uri | ||
local char = string.char | ||
local match = string.match | ||
local gsub = string.gsub | ||
|
||
|
||
local baggage_mt = { | ||
__newindex = function() | ||
error("attempt to set immutable baggage", 2) | ||
end, | ||
} | ||
|
||
local B3_SINGLE_PATTERN = | ||
"^(%x+)%-(%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x)%-?([01d]?)%-?(%x*)$" | ||
|
||
|
||
local function hex_to_char(c) | ||
return char(tonumber(c, 16)) | ||
end | ||
|
||
|
||
local function from_hex(str) | ||
if str ~= nil then -- allow nil to pass through | ||
str = gsub(str, "%x%x", hex_to_char) | ||
end | ||
return str | ||
end | ||
|
||
|
||
local function parse_jaeger_baggage_headers(headers) | ||
local baggage | ||
for k, v in pairs(headers) do | ||
local baggage_key = match(k, "^uberctx%-(.*)$") | ||
if baggage_key then | ||
if baggage then | ||
baggage[baggage_key] = unescape_uri(v) | ||
else | ||
baggage = { [baggage_key] = unescape_uri(v) } | ||
end | ||
end | ||
end | ||
|
||
if baggage then | ||
return setmetatable(baggage, baggage_mt) | ||
end | ||
end | ||
|
||
|
||
local function parse_zipkin_b3_headers(headers) | ||
local warn = kong.log.warn | ||
|
||
-- X-B3-Sampled: if an upstream decided to sample this request, we do too. | ||
local should_sample = headers["x-b3-sampled"] | ||
if should_sample == "1" or should_sample == "true" then | ||
should_sample = true | ||
elseif should_sample == "0" or should_sample == "false" then | ||
should_sample = false | ||
elseif should_sample ~= nil then | ||
warn("x-b3-sampled header invalid; ignoring.") | ||
should_sample = nil | ||
end | ||
|
||
-- X-B3-Flags: if it equals '1' then it overrides sampling policy | ||
-- We still want to warn on invalid sample header, so do this after the above | ||
local debug_header = headers["x-b3-flags"] | ||
if debug_header == "1" then | ||
should_sample = true | ||
elseif debug_header ~= nil then | ||
warn("x-b3-flags header invalid; ignoring.") | ||
end | ||
|
||
local trace_id, span_id, sampled, parent_id | ||
local had_invalid_id = false | ||
|
||
-- B3 single header | ||
-- The docs for this header are located here: | ||
-- https://github.com/openzipkin/b3-propagation/blob/master/RATIONALE.md#b3-single-header-format | ||
-- | ||
-- This code makes some assumptions about edge cases not covered on those docs: | ||
-- * X-B3-Sampled and X-B3-Flags can be used in conjunction with B3 single. This doesn't raise any errors. | ||
-- * The id headers (X-B3-TraceId, X-B3-SpanId, X-B3-ParentId) can also be used along with B3 but: | ||
-- * When both the single header an a id header specify an id, the single header "wins" (overrides) | ||
-- * All provided id headers are parsed (even those overriden by B3 single) | ||
-- * An erroneous formatting on *any* header (even those overriden by B3 single) results | ||
-- in rejection (ignoring) of all headers. This rejection is logged. | ||
-- * The "sampled" section activates sampling with both "1" and "d". This is to match the | ||
-- behavior of the X-B3-Flags header | ||
-- * For speed, the "-" separators between sampled and parent_id are optional on this implementation | ||
-- This is not guaranteed to happen in future versions and won't be considered a breaking change | ||
local b3_single_header = headers["b3"] | ||
if not b3_single_header then | ||
local tracestate_header = headers["tracestate"] | ||
if tracestate_header then | ||
b3_single_header = match(tracestate_header, "^b3=(.+)$") | ||
end | ||
end | ||
|
||
if b3_single_header and type(b3_single_header) == "string" then | ||
if b3_single_header == "1" or b3_single_header == "d" then | ||
should_sample = true | ||
|
||
elseif b3_single_header == "0" then | ||
should_sample = should_sample or false | ||
|
||
else | ||
trace_id, span_id, sampled, parent_id = | ||
match(b3_single_header, B3_SINGLE_PATTERN) | ||
|
||
local trace_id_len = trace_id and #trace_id or 0 | ||
if trace_id | ||
and (trace_id_len == 16 or trace_id_len == 32) | ||
and (parent_id == "" or #parent_id == 16) | ||
then | ||
|
||
if should_sample or sampled == "1" or sampled == "d" then | ||
should_sample = true | ||
elseif sampled == "0" then | ||
should_sample = false | ||
end | ||
|
||
if parent_id == "" then | ||
parent_id = nil | ||
end | ||
|
||
else | ||
warn("b3 single header invalid; ignoring.") | ||
had_invalid_id = true | ||
end | ||
end | ||
end | ||
|
||
local trace_id_header = headers["x-b3-traceid"] | ||
if trace_id_header and ((#trace_id_header ~= 16 and #trace_id_header ~= 32) | ||
or trace_id_header:match("%X")) then | ||
warn("x-b3-traceid header invalid; ignoring.") | ||
had_invalid_id = true | ||
else | ||
trace_id = trace_id or trace_id_header -- b3 single header overrides x-b3-traceid | ||
end | ||
|
||
local span_id_header = headers["x-b3-spanid"] | ||
if span_id_header and (#span_id_header ~= 16 or span_id_header:match("%X")) then | ||
warn("x-b3-spanid header invalid; ignoring.") | ||
had_invalid_id = true | ||
else | ||
span_id = span_id or span_id_header -- b3 single header overrides x-b3-spanid | ||
end | ||
|
||
local parent_id_header = headers["x-b3-parentspanid"] | ||
if parent_id_header and (#parent_id_header ~= 16 or parent_id_header:match("%X")) then | ||
warn("x-b3-parentspanid header invalid; ignoring.") | ||
had_invalid_id = true | ||
else | ||
parent_id = parent_id or parent_id_header -- b3 single header overrides x-b3-parentid | ||
end | ||
|
||
if trace_id == nil or had_invalid_id then | ||
return nil, nil, nil, should_sample | ||
end | ||
|
||
trace_id = from_hex(trace_id) | ||
span_id = from_hex(span_id) | ||
parent_id = from_hex(parent_id) | ||
|
||
return trace_id, span_id, parent_id, should_sample | ||
end | ||
|
||
|
||
local function parse_http_req_headers(headers) | ||
local trace_id, span_id, parent_id, should_sample = parse_zipkin_b3_headers(headers) | ||
|
||
if not trace_id then | ||
return trace_id, span_id, parent_id, should_sample | ||
end | ||
|
||
local baggage = parse_jaeger_baggage_headers(headers) | ||
|
||
return trace_id, span_id, parent_id, should_sample, baggage | ||
end | ||
|
||
|
||
return parse_http_req_headers |
Oops, something went wrong.