Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(tracing): Add instana header support in propagation #13915

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions changelog/unreleased/kong/instana-header-support.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
message: |
**OpenTelemetry**: include instana header support in propagation
type: feature
scope: Plugin
2 changes: 2 additions & 0 deletions kong-3.10.0-0.rockspec
Original file line number Diff line number Diff line change
Expand Up @@ -700,6 +700,7 @@ build = {
["kong.observability.tracing.propagation.extractors.gcp"] = "kong/observability/tracing/propagation/extractors/gcp.lua",
["kong.observability.tracing.propagation.extractors.aws"] = "kong/observability/tracing/propagation/extractors/aws.lua",
["kong.observability.tracing.propagation.extractors.datadog"] = "kong/observability/tracing/propagation/extractors/datadog.lua",
["kong.observability.tracing.propagation.extractors.instana"] = "kong/observability/tracing/propagation/extractors/instana.lua",
["kong.observability.tracing.propagation.injectors._base"] = "kong/observability/tracing/propagation/injectors/_base.lua",
["kong.observability.tracing.propagation.injectors.w3c"] = "kong/observability/tracing/propagation/injectors/w3c.lua",
["kong.observability.tracing.propagation.injectors.b3"] = "kong/observability/tracing/propagation/injectors/b3.lua",
Expand All @@ -709,6 +710,7 @@ build = {
["kong.observability.tracing.propagation.injectors.gcp"] = "kong/observability/tracing/propagation/injectors/gcp.lua",
["kong.observability.tracing.propagation.injectors.aws"] = "kong/observability/tracing/propagation/injectors/aws.lua",
["kong.observability.tracing.propagation.injectors.datadog"] = "kong/observability/tracing/propagation/injectors/datadog.lua",
["kong.observability.tracing.propagation.injectors.instana"] = "kong/observability/tracing/propagation/injectors/instana.lua",
["kong.observability.tracing.request_id"] = "kong/observability/tracing/request_id.lua",
["kong.observability.tracing.tracing_context"] = "kong/observability/tracing/tracing_context.lua",

Expand Down
64 changes: 64 additions & 0 deletions kong/observability/tracing/propagation/extractors/instana.lua
samugi marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
local _EXTRACTOR = require "kong.observability.tracing.propagation.extractors._base"
local propagation_utils = require "kong.observability.tracing.propagation.utils"
local from_hex = propagation_utils.from_hex

local INSTANA_EXTRACTOR = _EXTRACTOR:new({
headers_validate = {
any = {
"x-instana-t",
"x-instana-s",
"x-instana-l",
}
}
})

function INSTANA_EXTRACTOR:get_context(headers)

local trace_id_raw = headers["x-instana-t"]

if type(trace_id_raw) ~= "string" then
return
end

if trace_id_raw then
trace_id_raw = trace_id_raw:match("^(%x+)")
if not trace_id_raw then
kong.log.warn("x-instana-t header invalid; ignoring.")
end
end

local span_id_raw = headers["x-instana-s"]

if type(span_id_raw) ~= "string" then
return
end

if span_id_raw then
span_id_raw = span_id_raw:match("^(%x+)")
if not span_id_raw then
kong.log.warn("x-instana-s header invalid; ignoring.")
end
end

local level_id_raw = headers["x-instana-l"]

if level_id_raw then
-- the flag can come in as "0" or "1"
-- or something like the following format
-- "1,correlationType=web;correlationId=1234567890abcdef"
-- here we only care about the first value
level_id_raw = level_id_raw:sub(1, 1)
end
local should_sample = level_id_raw == "1"

local trace_id = trace_id_raw and from_hex(trace_id_raw) or nil
local span_id = span_id_raw and from_hex(span_id_raw) or nil

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have updated trace_id, span_id, level_id variable name to trace_id_raw, span_id_raw and level_id_raw

Also since we dont use correlation_type and correlationId here, changed

level_id_raw = level_id_raw:match("^([0-1])$") 
              or level_id_raw:match("^([0-1]),correlationType=(.-);correlationId=(.*)")

to

  level_id_raw = level_id_raw:match("^([0-1])$") 
                or level_id_raw:match("^([0-1]).")

return {
trace_id = trace_id,
span_id = span_id,
should_sample = should_sample,
}
end

return INSTANA_EXTRACTOR
3 changes: 2 additions & 1 deletion kong/observability/tracing/propagation/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ local function get_plugin_params(config)
formats.DATADOG,
formats.AWS,
formats.GCP,

formats.INSTANA
}
propagation_config.inject = { "preserve" }

Expand All @@ -63,6 +63,7 @@ local function get_plugin_params(config)
formats.DATADOG,
formats.AWS,
formats.GCP,
formats.INSTANA,
}
propagation_config.inject = {
-- the old logic used to propagate the "found" incoming format
Expand Down
31 changes: 31 additions & 0 deletions kong/observability/tracing/propagation/injectors/instana.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
local _INJECTOR = require "kong.observability.tracing.propagation.injectors._base"
local to_hex = require "resty.string".to_hex

local INSTANA_INJECTOR = _INJECTOR:new({
name = "instana",
context_validate = {}, -- all fields are optional
trace_id_allowed_sizes = { 16 },
span_id_size_bytes = 16,
})


function INSTANA_INJECTOR:create_headers(out_tracing_ctx)
local headers = {
["x-instana-t"] = to_hex(out_tracing_ctx.trace_id) or nil,
["x-instana-s"] = to_hex(out_tracing_ctx.span_id) or nil,
}

if out_tracing_ctx.should_sample ~= nil then
headers["x-instana-l"] = out_tracing_ctx.should_sample and "1" or "0"
end
samugi marked this conversation as resolved.
Show resolved Hide resolved

return headers
end


function INSTANA_INJECTOR:get_formatted_trace_id(trace_id)
return { instana = to_hex(trace_id) }
end


return INSTANA_INJECTOR
1 change: 1 addition & 0 deletions kong/observability/tracing/propagation/utils.lua
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ local FORMATS = {
DATADOG = "datadog",
AWS = "aws",
GCP = "gcp",
INSTANA = "instana",
}

local function hex_to_char(c)
Expand Down
2 changes: 1 addition & 1 deletion kong/plugins/opentelemetry/schema.lua
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ return {
old_default = "preserve" },
required = false,
default = "preserve",
one_of = { "preserve", "ignore", "b3", "b3-single", "w3c", "jaeger", "ot", "aws", "gcp", "datadog" } } },
one_of = { "preserve", "ignore", "b3", "b3-single", "w3c", "jaeger", "ot", "aws", "gcp", "datadog", "instana" } } },
{ sampling_rate = {
description = "Tracing sampling rate for configuring the probability-based sampler. When set, this value supersedes the global `tracing_sampling_rate` setting from kong.conf.",
type = "number",
Expand Down
4 changes: 2 additions & 2 deletions kong/plugins/zipkin/schema.lua
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,11 @@ return {
{ include_credential = { description = "Specify whether the credential of the currently authenticated consumer should be included in metadata sent to the Zipkin server.", type = "boolean", required = true, default = true } },
{ traceid_byte_count = { description = "The length in bytes of each request's Trace ID.", type = "integer", required = true, default = 16, one_of = { 8, 16 } } },
{ header_type = { description = "All HTTP requests going through the plugin are tagged with a tracing HTTP request. This property codifies what kind of tracing header the plugin expects on incoming requests", type = "string", required = true, default = "preserve",
one_of = { "preserve", "ignore", "b3", "b3-single", "w3c", "jaeger", "ot", "aws", "datadog", "gcp" },
one_of = { "preserve", "ignore", "b3", "b3-single", "w3c", "jaeger", "ot", "aws", "datadog", "gcp", "instana" },
deprecation = { message = "zipkin: config.header_type is deprecated, please use config.propagation options instead", removal_in_version = "4.0", old_default = "preserve" }
} },
{ default_header_type = { description = "Allows specifying the type of header to be added to requests with no pre-existing tracing headers and when `config.header_type` is set to `\"preserve\"`. When `header_type` is set to any other value, `default_header_type` is ignored.", type = "string", required = true, default = "b3",
one_of = { "b3", "b3-single", "w3c", "jaeger", "ot", "aws", "datadog", "gcp" },
one_of = { "b3", "b3-single", "w3c", "jaeger", "ot", "aws", "datadog", "gcp", "instana" },
deprecation = { message = "zipkin: config.default_header_type is deprecated, please use config.propagation.default_format instead", removal_in_version = "4.0", old_default = "b3" }
} },
{ tags_header = { description = "The Zipkin plugin will add extra headers to the tags associated with any HTTP requests that come with a header named as configured by this property.", type = "string", required = true, default = "Zipkin-Tags" } },
Expand Down
68 changes: 65 additions & 3 deletions spec/03-plugins/34-zipkin/zipkin_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ local http_route_host = "http-route"
local http_route_ignore_host = "http-route-ignore"
local http_route_w3c_host = "http-route-w3c"
local http_route_dd_host = "http-route-dd"
local http_route_ins_host = "http-route-ins"
local http_route_clear_host = "http-clear-route"
local http_route_no_preserve_host = "http-no-preserve-route"

Expand Down Expand Up @@ -671,6 +672,21 @@ local function setup_zipkin_old_propagation(bp, service, traceid_byte_count)
default_header_type = "datadog",
}
})

-- header_type = "instana"
bp.plugins:insert({
name = "zipkin",
route = {id = bp.routes:insert({
service = service,
hosts = { http_route_ins_host },
}).id},
config = {
sample_ratio = 1,
http_endpoint = fmt("http://%s:%d/api/v2/spans", ZIPKIN_HOST, ZIPKIN_PORT),
header_type = "instana",
default_header_type = "instana",
}
})
end

local function setup_zipkin_new_propagation(bp, service, traceid_byte_count)
Expand All @@ -687,7 +703,7 @@ local function setup_zipkin_new_propagation(bp, service, traceid_byte_count)
{ name = "static", value = "ok" },
},
propagation = {
extract = { "b3", "w3c", "jaeger", "ot", "datadog", "aws", "gcp" },
extract = { "b3", "w3c", "jaeger", "ot", "datadog", "aws", "gcp", "instana" },
inject = { "preserve" },
default_format = "b3-single",
},
Expand Down Expand Up @@ -723,7 +739,7 @@ local function setup_zipkin_new_propagation(bp, service, traceid_byte_count)
sample_ratio = 1,
http_endpoint = fmt("http://%s:%d/api/v2/spans", ZIPKIN_HOST, ZIPKIN_PORT),
propagation = {
extract = { "b3", "w3c", "jaeger", "ot", "datadog", "aws", "gcp" },
extract = { "b3", "w3c", "jaeger", "ot", "datadog", "aws", "gcp", "instana" },
inject = { "preserve", "w3c" },
default_format = "b3-single",
},
Expand All @@ -741,13 +757,31 @@ local function setup_zipkin_new_propagation(bp, service, traceid_byte_count)
sample_ratio = 1,
http_endpoint = fmt("http://%s:%d/api/v2/spans", ZIPKIN_HOST, ZIPKIN_PORT),
propagation = {
extract = { "b3", "w3c", "jaeger", "ot", "aws", "datadog", "gcp" },
extract = { "b3", "w3c", "jaeger", "ot", "aws", "datadog", "gcp", "instana" },
inject = { "preserve", "datadog" },
default_format = "datadog",
},
}
})

-- header_type = "instana"
bp.plugins:insert({
name = "zipkin",
route = {id = bp.routes:insert({
service = service,
hosts = { http_route_ins_host },
}).id},
config = {
sample_ratio = 1,
http_endpoint = fmt("http://%s:%d/api/v2/spans", ZIPKIN_HOST, ZIPKIN_PORT),
propagation = {
extract = { "b3", "w3c", "jaeger", "ot", "aws", "datadog", "gcp", "instana" },
inject = { "preserve", "instana" },
default_format = "instana",
},
}
})

-- available with new configuration only:
-- no preserve
bp.plugins:insert({
Expand Down Expand Up @@ -1579,6 +1613,34 @@ describe("http integration tests with zipkin server [#"
end)
end)

describe("propagates instana tracing headers", function()
it("with instana headers in client request", function()
local trace_id = gen_trace_id(16)
local span_id = gen_span_id()
local r = proxy_client:get("/", {
headers = {
["x-instana-t"] = trace_id,
["x-instana-s"] = span_id,
host = http_route_host,
},
})
local body = assert.response(r).has.status(200)
local json = cjson.decode(body)

assert.equals(trace_id, json.headers["x-instana-t"])
end)

it("without instana headers in client request", function()
local r = proxy_client:get("/", {
headers = { host = http_route_ins_host },
})
local body = assert.response(r).has.status(200)
local json = cjson.decode(body)

assert.is_not_nil(tonumber(json.headers["x-instana-t"]))
end)
end)

if propagation_config == "new" then
it("clears non-propagated headers when configured to do so", function()
local trace_id = gen_trace_id(16)
Expand Down
51 changes: 47 additions & 4 deletions spec/03-plugins/37-opentelemetry/03-propagation_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ local http_route_ignore_host = "http-route-ignore"
local http_route_w3c_host = "http-route-w3c"
local http_route_dd_host = "http-route-dd"
local http_route_b3_single_host = "http-route-b3-single"
local http_route_ins_host = "http-route-ins"
local http_route_clear_host = "http-clear-route"
local http_route_no_preserve_host = "http-no-preserve-route"

Expand Down Expand Up @@ -124,6 +125,18 @@ local function setup_otel_old_propagation(bp, service)
header_type = "b3-single",
}
})

bp.plugins:insert({
name = "opentelemetry",
route = {id = bp.routes:insert({
service = service,
hosts = { http_route_ins_host },
}).id},
config = {
traces_endpoint = "http://localhost:8080/v1/traces",
header_type = "instana",
}
})
end

-- same configurations as "setup_otel_old_propagation", using the new
Expand All @@ -138,7 +151,7 @@ local function setup_otel_new_propagation(bp, service)
config = {
traces_endpoint = "http://localhost:8080/v1/traces",
propagation = {
extract = { "b3", "w3c", "jaeger", "ot", "datadog", "aws", "gcp" },
extract = { "b3", "w3c", "jaeger", "ot", "datadog", "aws", "gcp", "instana" },
inject = { "preserve" },
default_format = "w3c",
}
Expand Down Expand Up @@ -170,7 +183,7 @@ local function setup_otel_new_propagation(bp, service)
config = {
traces_endpoint = "http://localhost:8080/v1/traces",
propagation = {
extract = { "b3", "w3c", "jaeger", "ot", "datadog", "aws", "gcp" },
extract = { "b3", "w3c", "jaeger", "ot", "datadog", "aws", "gcp", "instana" },
inject = { "preserve", "w3c" },
default_format = "w3c",
}
Expand All @@ -186,7 +199,7 @@ local function setup_otel_new_propagation(bp, service)
config = {
traces_endpoint = "http://localhost:8080/v1/traces",
propagation = {
extract = { "b3", "w3c", "jaeger", "ot", "datadog", "aws", "gcp" },
extract = { "b3", "w3c", "jaeger", "ot", "datadog", "aws", "gcp", "instana" },
inject = { "preserve", "datadog" },
default_format = "datadog",
}
Expand All @@ -202,13 +215,28 @@ local function setup_otel_new_propagation(bp, service)
config = {
traces_endpoint = "http://localhost:8080/v1/traces",
propagation = {
extract = { "b3", "w3c", "jaeger", "ot", "datadog", "aws", "gcp" },
extract = { "b3", "w3c", "jaeger", "ot", "datadog", "aws", "gcp", "instana" },
inject = { "preserve", "b3-single" },
default_format = "w3c",
}
}
})

bp.plugins:insert({
name = "opentelemetry",
route = {id = bp.routes:insert({
service = service,
hosts = { http_route_ins_host },
}).id},
config = {
traces_endpoint = "http://localhost:8080/v1/traces",
propagation = {
extract = { "b3", "w3c", "jaeger", "ot", "datadog", "aws", "gcp", "instana" },
inject = { "preserve", "instana" },
default_format = "instana",
}
}
})
-- available with new configuration only:
-- no preserve
bp.plugins:insert({
Expand Down Expand Up @@ -511,6 +539,21 @@ describe("propagation tests #" .. strategy ..
assert.equals(trace_id, json.headers["ot-tracer-traceid"])
end)

it("propagates instana headers", function()
local trace_id = gen_trace_id()
local span_id = gen_span_id()
local r = proxy_client:get("/", {
headers = {
["x-instana-t"] = trace_id,
["x-instana-s"] = span_id,
host = http_route_ins_host,
},
})
local body = assert.response(r).has.status(200)
local json = cjson.decode(body)

assert.equals(trace_id, json.headers["x-instana-t"])
end)

describe("propagates datadog tracing headers", function()
it("with datadog headers in client request", function()
Expand Down
Loading