Skip to content
This repository has been archived by the owner on Nov 30, 2021. It is now read-only.

Commit

Permalink
Merge branch 'support-ot-headers' of https://github.com/lightstep/kon…
Browse files Browse the repository at this point in the history
…g-plugin-zipkin into lightstep-support-ot-headers
  • Loading branch information
kikito committed Feb 16, 2021
2 parents 9b3ece0 + 9767f7e commit 12ad7ba
Show file tree
Hide file tree
Showing 5 changed files with 299 additions and 19 deletions.
4 changes: 2 additions & 2 deletions kong/plugins/zipkin/schema.lua
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,9 @@ return {
{ include_credential = { type = "boolean", required = true, default = true } },
{ traceid_byte_count = { type = "integer", required = true, default = 16, one_of = { 8, 16 } } },
{ header_type = { type = "string", required = true, default = "preserve",
one_of = { "preserve", "b3", "b3-single", "w3c", "jaeger" } } },
one_of = { "preserve", "b3", "b3-single", "w3c", "jaeger", "ot" } } },
{ default_header_type = { type = "string", required = true, default = "b3",
one_of = { "b3", "b3-single", "w3c", "jaeger" } } },
one_of = { "b3", "b3-single", "w3c", "jaeger", "ot" } } },
{ tags_header = { type = "string", required = true, default = "Zipkin-Tags" } },
{ static_tags = { type = "array", elements = static_tag,
custom_validator = validate_static_tags } },
Expand Down
85 changes: 77 additions & 8 deletions kong/plugins/zipkin/tracing_headers.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
local to_hex = require "resty.string".to_hex

local table_merge = require "kong.tools.utils".table_merge
local unescape_uri = ngx.unescape_uri
local char = string.char
local match = string.match
Expand All @@ -17,8 +17,9 @@ local B3_SINGLE_PATTERN =
"^(%x+)%-(%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x)%-?([01d]?)%-?(%x*)$"

local W3C_TRACECONTEXT_PATTERN = "^(%x+)%-(%x+)%-(%x+)%-(%x+)$"

local JAEGER_TRACECONTEXT_PATTERN = "^(%x+):(%x+):(%x+):(%x+)$"
local JAEGER_BAGGAGE_PATTERN = "^uberctx%-(.*)$"
local OT_BAGGAGE_PATTERN = "^ot-baggage%-(.*)$"

local function hex_to_char(c)
return char(tonumber(c, 16))
Expand All @@ -33,10 +34,11 @@ local function from_hex(str)
end


local function parse_jaeger_baggage_headers(headers)
local function parse_baggage_headers(headers, header_pattern)
-- account for both ot and uber baggage headers
local baggage
for k, v in pairs(headers) do
local baggage_key = match(k, "^uberctx%-(.*)$")
local baggage_key = match(k, header_pattern)
if baggage_key then
if baggage then
baggage[baggage_key] = unescape_uri(v)
Expand Down Expand Up @@ -205,6 +207,48 @@ local function parse_w3c_trace_context_headers(w3c_header)
return trace_id, parent_id, should_sample
end

local function parse_ot_headers(headers)
local warn = kong.log.warn

local should_sample = headers["ot-tracer-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("ot-tracer-sampled header invalid; ignoring.")
should_sample = nil
end

local trace_id, span_id
local had_invalid_id = false

local trace_id_header = headers["ot-tracer-traceid"]
if trace_id_header and ((#trace_id_header ~= 16 and #trace_id_header ~= 32) or trace_id_header:match("%X")) then
warn("ot-tracer-traceid header invalid; ignoring.")
had_invalid_id = true
else
trace_id = trace_id_header
end

local span_id_header = headers["ot-tracer-spanid"]
if span_id_header and (#span_id_header ~= 16 or span_id_header:match("%X")) then
warn("ot-tracer-spanid header invalid; ignoring.")
had_invalid_id = true
else
span_id = span_id_header
end

if trace_id == nil or had_invalid_id then
return nil, nil, should_sample
end

trace_id = from_hex(trace_id)
span_id = from_hex(span_id)

return trace_id, span_id, should_sample
end


local function parse_jaeger_trace_context_headers(jaeger_header)
-- allow testing to spy on this.
Expand Down Expand Up @@ -267,7 +311,7 @@ end
-- The plugin expects request to be using *one* of these types. If several of them are
-- encountered on one request, only one kind will be transmitted further. The order is
--
-- B3-single > B3 > W3C
-- B3-single > B3 > W3C > Jaeger > OT
--
-- Exceptions:
--
Expand Down Expand Up @@ -308,6 +352,11 @@ local function find_header_type(headers)
if jaeger_header then
return "jaeger", jaeger_header
end

local ot_header = headers["ot-tracer-traceid"]
if ot_header then
return "ot", ot_header
end
end


Expand All @@ -322,13 +371,24 @@ local function parse(headers)
trace_id, parent_id, should_sample = parse_w3c_trace_context_headers(composed_header)
elseif header_type == "jaeger" then
trace_id, span_id, parent_id, should_sample = parse_jaeger_trace_context_headers(composed_header)
elseif header_type == "ot" then
trace_id, parent_id, should_sample = parse_ot_headers(headers)
end

if not trace_id then
return header_type, trace_id, span_id, parent_id, should_sample
end

local baggage = parse_jaeger_baggage_headers(headers)
-- Parse baggage headers
local baggage
local ot_baggage = parse_baggage_headers(headers, OT_BAGGAGE_PATTERN)
local jaeger_baggage = parse_baggage_headers(headers, JAEGER_BAGGAGE_PATTERN)
if ot_baggage and jaeger_baggage then
baggage = table_merge(ot_baggage, jaeger_baggage)
else
baggage = ot_baggage or jaeger_baggage or nil
end


return header_type, trace_id, span_id, parent_id, should_sample, baggage
end
Expand All @@ -346,8 +406,7 @@ local function set(conf_header_type, found_header_type, proxy_span, conf_default

found_header_type = found_header_type or conf_default_header_type or "b3"

if conf_header_type == "b3"
or found_header_type == "b3"
if conf_header_type == "b3" or found_header_type == "b3"
then
set_header("x-b3-traceid", to_hex(proxy_span.trace_id))
set_header("x-b3-spanid", to_hex(proxy_span.span_id))
Expand Down Expand Up @@ -385,6 +444,16 @@ local function set(conf_header_type, found_header_type, proxy_span, conf_default
proxy_span.should_sample and "01" or "00"))
end

if conf_header_type == "ot" or found_header_type == "ot" then
set_header("ot-tracer-traceid", to_hex(proxy_span.trace_id))
set_header("ot-tracer-spanid", to_hex(proxy_span.span_id))
set_header("ot-tracer-sampled", proxy_span.should_sample and "1" or "0")

for key, value in proxy_span:each_baggage_item() do
set_header("ot-baggage-"..key, ngx.escape_uri(value))
end
end

for key, value in proxy_span:each_baggage_item() do
-- XXX: https://github.com/opentracing/specification/issues/117
set_header("uberctx-"..key, ngx.escape_uri(value))
Expand Down
163 changes: 155 additions & 8 deletions spec/tracing_headers_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@ local set = tracing_headers.set
local from_hex = tracing_headers.from_hex

local trace_id = "0000000000000001"
local big_trace_id = "fffffffffffffff1"
local trace_id_32 = "00000000000000000000000000000001"
local big_trace_id_32 = "fffffffffffffffffffffffffffffff1"
local parent_id = "0000000000000002"
local span_id = "0000000000000003"
local big_span_id = "fffffffffffffff3"
local non_hex_id = "vvvvvvvvvvvvvvvv"
local too_short_id = "123"
local too_long_id = "1234567890123456789012345678901234567890" -- 40 digits
Expand All @@ -33,9 +36,9 @@ describe("tracing_headers.parse", function()
}

describe("b3 single header parsing", function()
local warn
local warn = spy.on(kong.log, "warn")
before_each(function()
warn = spy.on(kong.log, "warn")
warn:clear()
end)

it("1-char", function()
Expand Down Expand Up @@ -101,6 +104,13 @@ describe("tracing_headers.parse", function()
assert.spy(warn).not_called()
end)

it("big 32-digit trace_id, span_id and sample, no parent_id", function()
local b3 = fmt("%s-%s-%s", big_trace_id_32, span_id, "1")
local t = { parse({ b3 = b3 }) }
assert.same({ "b3-single", big_trace_id_32, span_id, nil, true }, to_hex_ids(t))
assert.spy(warn).not_called()
end)

it("sample debug = always sample", function()
local b3 = fmt("%s-%s-%s-%s", trace_id, span_id, "d", parent_id)
local t = { parse({ b3 = b3 }) }
Expand Down Expand Up @@ -191,9 +201,9 @@ describe("tracing_headers.parse", function()
end)

describe("W3C header parsing", function()
local warn
local warn = spy.on(kong.log, "warn")
before_each(function()
warn = spy.on(kong.log, "warn")
warn:clear()
end)

it("valid traceparent with sampling", function()
Expand Down Expand Up @@ -304,11 +314,10 @@ describe("tracing_headers.parse", function()
end)
end)


describe("Jaeger header parsing", function()
local warn
local warn = spy.on(kong.log, "warn")
before_each(function()
warn = spy.on(kong.log, "warn")
warn:clear()
end)

it("valid uber-trace-id with sampling", function()
Expand Down Expand Up @@ -418,6 +427,80 @@ describe("tracing_headers.parse", function()
end)
end)
end)

describe("OT header parsing", function()
local warn = spy.on(kong.log, "warn")
before_each(function()
warn:clear()
end)

it("valid trace_id, valid span_id, sampled", function()
local t = { parse({
["ot-tracer-traceid"] = trace_id,
["ot-tracer-spanid"] = span_id,
["ot-tracer-sampled"] = "1",
})}
assert.same({ "ot", trace_id, nil, span_id, true }, to_hex_ids(t))
assert.spy(warn).not_called()
end)

it("valid big trace_id, valid big span_id, sampled", function()
local t = { parse({
["ot-tracer-traceid"] = big_trace_id,
["ot-tracer-spanid"] = big_span_id,
["ot-tracer-sampled"] = "1",
})}
assert.same({ "ot", big_trace_id, nil, big_span_id, true }, to_hex_ids(t))
assert.spy(warn).not_called()
end)

it("valid trace_id, valid span_id, not sampled", function()
local t = { parse({
["ot-tracer-traceid"] = trace_id,
["ot-tracer-spanid"] = span_id,
["ot-tracer-sampled"] = "0",
})}
assert.same({ "ot", trace_id, nil, span_id, false }, to_hex_ids(t))
assert.spy(warn).not_called()
end)

it("valid trace_id, valid span_id, sampled", function()
local t = { parse({
["ot-tracer-traceid"] = trace_id,
["ot-tracer-spanid"] = span_id,
["ot-tracer-sampled"] = "1",
})}
assert.same({ "ot", trace_id, nil, span_id, true }, to_hex_ids(t))
assert.spy(warn).not_called()
end)

it("valid trace_id, valid span_id, no sampled flag", function()
local t = { parse({
["ot-tracer-traceid"] = trace_id,
["ot-tracer-spanid"] = span_id,
})}
assert.same({ "ot", trace_id, nil, span_id }, to_hex_ids(t))
assert.spy(warn).not_called()
end)

it("32 trace_id, valid span_id, no sampled flag", function()
local t = { parse({
["ot-tracer-traceid"] = trace_id_32,
["ot-tracer-spanid"] = span_id,
})}
assert.same({ "ot", trace_id_32, nil, span_id }, to_hex_ids(t))
assert.spy(warn).not_called()
end)

it("big 32 trace_id, valid big_span_id, no sampled flag", function()
local t = { parse({
["ot-tracer-traceid"] = big_trace_id_32,
["ot-tracer-spanid"] = big_span_id,
})}
assert.same({ "ot", big_trace_id_32, nil, big_span_id }, to_hex_ids(t))
assert.spy(warn).not_called()
end)
end)
end)

describe("tracing_headers.set", function()
Expand Down Expand Up @@ -471,6 +554,12 @@ describe("tracing_headers.set", function()
["uber-trace-id"] = fmt("%s:%s:%s:%s", trace_id, span_id, parent_id, "01")
}

local ot_headers = {
["ot-tracer-traceid"] = trace_id,
["ot-tracer-spanid"] = span_id,
["ot-tracer-sampled"] = "1"
}

before_each(function()
headers = {}
warnings = {}
Expand Down Expand Up @@ -522,6 +611,11 @@ describe("tracing_headers.set", function()

set("preserve", nil, proxy_span, "jaeger")
assert.same(jaeger_headers, headers)

headers = {}

set("preserve", "ot", proxy_span, "ot")
assert.same(ot_headers, headers)
end)
end)

Expand Down Expand Up @@ -669,6 +763,59 @@ describe("tracing_headers.set", function()
assert.equals(1, #warnings)
assert.matches("Mismatched header types", warnings[1])
end)

it("sets both the jaeger and ot headers when a ot header is encountered.", function()
set("jaeger", "ot", proxy_span)
assert.same(table_merge(jaeger_headers, ot_headers), headers)

-- but it generates a warning
assert.equals(1, #warnings)
assert.matches("Mismatched header types", warnings[1])
end)
end)
end)

describe("conf.header_type = 'ot'", function()
it("sets headers to ot when conf.header_type = ot", function()
set("ot", "ot", proxy_span)
assert.same(ot_headers, headers)
assert.same({}, warnings)
end)

it("sets both the b3 and ot headers when a ot header is encountered.", function()
set("ot", "b3", proxy_span)
assert.same(table_merge(b3_headers, ot_headers), headers)

-- but it generates a warning
assert.equals(1, #warnings)
assert.matches("Mismatched header types", warnings[1])
end)

it("sets both the b3-single and ot headers when a ot header is encountered.", function()
set("ot", "b3-single", proxy_span)
assert.same(table_merge(b3_single_headers, ot_headers), headers)

-- but it generates a warning
assert.equals(1, #warnings)
assert.matches("Mismatched header types", warnings[1])
end)

it("sets both the w3c and ot headers when a ot header is encountered.", function()
set("ot", "w3c", proxy_span)
assert.same(table_merge(w3c_headers, ot_headers), headers)

-- but it generates a warning
assert.equals(1, #warnings)
assert.matches("Mismatched header types", warnings[1])
end)

it("sets both the ot and jaeger headers when a jaeger header is encountered.", function()
set("ot", "jaeger", proxy_span)
assert.same(table_merge(ot_headers, jaeger_headers), headers)

-- but it generates a warning
assert.equals(1, #warnings)
assert.matches("Mismatched header types", warnings[1])
end)
end)

end)
Loading

0 comments on commit 12ad7ba

Please sign in to comment.