diff --git a/lib/opentelemetry/trace/exporter/otlp.lua b/lib/opentelemetry/trace/exporter/otlp.lua index 68cac86..fe3b0a0 100644 --- a/lib/opentelemetry/trace/exporter/otlp.lua +++ b/lib/opentelemetry/trace/exporter/otlp.lua @@ -74,7 +74,7 @@ local function call_collector(exporter, pb_encoded_body) return false, res_error or "unknown" end -function _M.export_spans(self, spans) +function _M.encode_spans(self, spans) assert(spans[1]) local body = { @@ -96,12 +96,57 @@ function _M.export_spans(self, spans) } } } + local tracers = {} + local providers = {} + tracers[spans[1].tracer] = 1 + providers[spans[1].tracer.provider] = 1 for _, span in ipairs(spans) do + local rs_idx = providers[span.tracer.provider] + local ils_idx = tracers[span.tracer] + if not rs_idx then + rs_idx = #body.resource_spans + 1 + ils_idx = 1 + providers[span.tracer.provider] = rs_idx + tracers[span.tracer] = ils_idx + table.insert( + body.resource_spans, + { + resource = { + attributes = span.tracer.provider.resource.attrs, + dropped_attributes_count = 0, + }, + instrumentation_library_spans = { + { + instrumentation_library = { + name = span.tracer.il.name, + version = span.tracer.il.version, + }, + spans = {} + }, + }, + }) + elseif not ils_idx then + ils_idx = #body.resource_spans[rs_idx].instrumentation_library_spans + 1 + tracers[span.tracer] = ils_idx + table.insert( + body.resource_spans[rs_idx].instrumentation_library_spans, + { + instrumentation_library = { + name = span.tracer.il.name, + version = span.tracer.il.version, + }, + spans = {} + }) + end table.insert( - body.resource_spans[1].instrumentation_library_spans[1].spans, + body.resource_spans[rs_idx].instrumentation_library_spans[ils_idx].spans, encoder.for_otlp(span)) end - return call_collector(self, pb.encode(body)) + return body +end + +function _M.export_spans(self, spans) + return call_collector(self, pb.encode(self:encode_spans(spans))) end function _M.shutdown(self) diff --git a/spec/trace/exporter/otlp_spec.lua b/spec/trace/exporter/otlp_spec.lua index 7b2f500..20ed8d6 100644 --- a/spec/trace/exporter/otlp_spec.lua +++ b/spec/trace/exporter/otlp_spec.lua @@ -2,8 +2,85 @@ local exporter = require "opentelemetry.trace.exporter.otlp" local client = require "opentelemetry.trace.exporter.http_client" local context = require "opentelemetry.context" local tp = Global.get_tracer_provider() +local tracer_provider_new = require("opentelemetry.trace.tracer_provider").new local tracer = tp:tracer("test") +describe("encode_spans", function() + it("one resource span and one ils for one span", function() + local span + local ctx = context.new() + ctx, span = tracer:start(ctx, "test span") + span:finish() + local cb = exporter.new(nil) + local encoded = cb:encode_spans({span, other_spans}) + -- One resource, one il, one span + assert(#encoded.resource_spans == 1) + local resource = encoded.resource_spans[1] + assert(#resource.instrumentation_library_spans == 1) + assert(#resource.instrumentation_library_spans[1].spans == 1) + end) + + it("one resource span and one ils for multiple span same tracer", function() + local span + local ctx = context.new() + local spans = {} + for i=10,1,-1 do + ctx, span = tracer:start(ctx, "test span" .. i) + span:finish() + table.insert(spans, span) + end + local cb = exporter.new(nil) + local encoded = cb:encode_spans(spans) + -- One resource, one il, 10 spans + assert(#encoded.resource_spans == 1) + local resource = encoded.resource_spans[1] + assert(#resource.instrumentation_library_spans == 1) + assert(#resource.instrumentation_library_spans[1].spans == 10) + end) + + it("one resource span and two ils for spans from distinct tracers", function() + local span + local ctx = context.new() + local spans = {} + ctx, span = tracer:start(ctx, "test span") + span:finish() + table.insert(spans, span) + local other_tracer = tp:tracer("exam") + ctx, other_span = other_tracer:start(ctx, "exam span") + table.insert(spans, other_span) + local cb = exporter.new(nil) + local encoded = cb:encode_spans(spans) + -- One resource, two il, 1 span each + assert(#encoded.resource_spans == 1) + local resource = encoded.resource_spans[1] + assert(#resource.instrumentation_library_spans == 2) + assert(#resource.instrumentation_library_spans[1].spans == 1) + assert(#resource.instrumentation_library_spans[2].spans == 1) + end) + it("distinct trace providers provide distinct resources", function() + local span + local ctx = context.new() + local spans = {} + ctx, span = tracer:start(ctx, "test span") + span:finish() + table.insert(spans, span) + local op = tracer_provider_new(nil, nil) + local other_tracer = op:tracer("exam") + ctx, other_span = other_tracer:start(ctx, "exam span") + table.insert(spans, other_span) + local cb = exporter.new(nil) + local encoded = cb:encode_spans(spans) + -- two resources with one il, 1 span each + assert(#encoded.resource_spans == 2) + local resource = encoded.resource_spans[1] + assert(#resource.instrumentation_library_spans == 1) + assert(#resource.instrumentation_library_spans[1].spans == 1) + resource = encoded.resource_spans[2] + assert(#resource.instrumentation_library_spans == 1) + assert(#resource.instrumentation_library_spans[1].spans == 1) + end) +end) + describe("export_spans", function() it("invokes do_request when there are no failures", function() local span