Build part of the transform, prepare to push into segment cache.
diff --git a/README.md b/README.md
index c1c163c..caba6c9 100644
--- a/README.md
+++ b/README.md
@@ -20,6 +20,7 @@
- LuaRocks
The following libs are required in runtime or test cases, please use `LuaRocks` to install them.
+- lua-cjson. NOTICE, some platforms such as MacOS 10.15 may have issue with the latest release of this lib, consider to install an old release.(`luarocks install lua-cjson 2.1.0-1`)
- luaunit
# APIs
diff --git a/examples/nginx.conf b/examples/nginx.conf
index 84feefc..7829c58 100644
--- a/examples/nginx.conf
+++ b/examples/nginx.conf
@@ -43,11 +43,12 @@
local metadata_buffer = ngx.shared.metadata_buffer
-- Mock the service instance id
+ metadata_buffer['serviceId'] = 1
metadata_buffer['serviceInstId'] = 1
local tracingContext
if metadata_buffer['serviceInstId'] ~= nil then
- tracingContext = TC:new(metadata_buffer['serviceInstId'])
+ tracingContext = TC:new(metadata_buffer['serviceId'], metadata_buffer['serviceInstId'])
else
tracingContext = TC:newNoOP()
end
@@ -91,7 +92,14 @@
if ngx.ctx.entrySpan ~= nil then
ngx.ctx.entrySpan:finish()
local status, segment = ngx.ctx.tracingContext:drainAfterFinished()
- ngx.log(ngx.ERR, 'span exist? ' .. segment.spans[1].start_time)
+ if status then
+ local segmentJson = segment:transform()
+ ngx.log(ngx.DEBUG, 'segment = ' .. segmentJson)
+
+ local queue = ngx.shared.segment_buffer
+ local length = queue:lpush('segment', "abc")
+
+ end
end
}
}
diff --git a/lib/skywalking/segment.lua b/lib/skywalking/segment.lua
index 3b64229..3249c24 100644
--- a/lib/skywalking/segment.lua
+++ b/lib/skywalking/segment.lua
@@ -18,13 +18,26 @@
-- Segment represents a finished tracing context
-- Including all information to send to the SkyWalking OAP server.
+local cjson = require("cjson")
+
local Segment = {
trace_id,
segment_id,
+ service_id,
service_inst_id,
spans,
}
+-- Due to nesting relationship inside Segment/Span/TracingContext at the runtime,
+-- SegmentProtocol is created to prepare JSON format serialization.
+-- Following SkyWalking official trace protocol v2
+-- https://github.com/apache/skywalking-data-collect-protocol/blob/master/language-agent-v2/trace.proto
+local SegmentProtocol = {
+ serviceId,
+ serviceInstanceId,
+ spans,
+}
+
function Segment:new()
local o = {}
setmetatable(o, self)
@@ -33,4 +46,9 @@
return o
end
+-- Transform the segment object to the
+function Segment:transform()
+ return cjson.encode(self)
+end
+
return Segment
\ No newline at end of file
diff --git a/lib/skywalking/segment_ref.lua b/lib/skywalking/segment_ref.lua
index 7e801eb..93a33bd 100644
--- a/lib/skywalking/segment_ref.lua
+++ b/lib/skywalking/segment_ref.lua
@@ -34,6 +34,25 @@
parent_endpoint_id = 0,
}
+-- Due to nesting relationship inside Segment/Span/TracingContext at the runtime,
+-- RefProtocol is created to prepare JSON format serialization.
+-- Following SkyWalking official trace protocol v2
+-- https://github.com/apache/skywalking-data-collect-protocol/blob/master/language-agent-v2/trace.proto
+local RefProtocol = {
+ -- Constant in LUA, no cross-thread
+ refType = 'CrossProcess',
+ parentTraceSegmentId,
+ parentSpanId,
+ parentServiceInstanceId,
+ networkAddress,
+ networkAddressId,
+ entryServiceInstanceId,
+ entryEndpoint,
+ entryEndpointId,
+ parentEndpoint,
+ parentEndpointId,
+}
+
function SegmentRef:new()
local o = {}
setmetatable(o, self)
@@ -42,6 +61,14 @@
return o
end
+function RefProtocol:new()
+ local o = {}
+ setmetatable(o, self)
+ self.__index = self
+
+ return o
+end
+
-- Deserialize value from the propagated context and initialize the SegmentRef
function SegmentRef:fromSW6Value(value)
local parts = Util: split(value, '-')
@@ -112,4 +139,20 @@
return encodedRef
end
+-- Return RefProtocol
+function SegmentRef:transform()
+ local refBuilder = RefProtocol:new()
+ refBuilder.parentTraceSegmentId = Util:id2String(self.segment_id)
+ refBuilder.parentSpanId = self.span_id
+ refBuilder.parentServiceInstanceId = self.parent_service_instance_id
+ refBuilder.networkAddress = self.network_address
+ refBuilder.networkAddressId = self.network_address_id
+ refBuilder.entryServiceInstanceId = self.entry_service_instance_id
+ refBuilder.entryEndpoint = self.entry_endpoint_name
+ refBuilder.entryEndpointId = self.entry_endpoint_id
+ refBuilder.parentEndpoint = self.parent_endpoint_name
+ refBuilder.parentEndpointId = self.parent_endpoint_id
+ return refBuilder
+end
+
return SegmentRef
diff --git a/lib/skywalking/segment_ref_test.lua b/lib/skywalking/segment_ref_test.lua
index a076f61..1e854c6 100644
--- a/lib/skywalking/segment_ref_test.lua
+++ b/lib/skywalking/segment_ref_test.lua
@@ -18,6 +18,7 @@
local lu = require('luaunit')
local SegmentRef = require('segment_ref')
+local cjson = require("cjson")
TestSegmentRef = {}
-- This test is originally from ContextCarrierV2HeaderTest in the Java agent.
@@ -53,6 +54,22 @@
lu.assertEquals(ref:serialize(), '1-My40LjU=-MS4yLjM=-4-1-1-IzEyNy4wLjAuMTo4MDgw-Iy9wb3J0YWw=-MTIz')
end
+
+ function TestSegmentRef:testTransform()
+ local ref = SegmentRef:new()
+ ref.trace_id = {3, 4, 5}
+ ref.segment_id = {1, 2, 3}
+ ref.span_id = 4
+ ref.entry_service_instance_id = 1
+ ref.parent_service_instance_id = 1
+ ref.network_address = "127.0.0.1:8080"
+ ref.entry_endpoint_name = "/portal"
+ ref.parent_endpoint_id = 123
+
+ local refProtocol = ref:transform()
+ local inJSON = cjson.encode(refProtocol)
+ lu.assertTrue(string.len(inJSON) > 0)
+ end
-- end TestSegmentRef
diff --git a/lib/skywalking/span.lua b/lib/skywalking/span.lua
index deffd50..3fafd01 100644
--- a/lib/skywalking/span.lua
+++ b/lib/skywalking/span.lua
@@ -34,12 +34,34 @@
start_time,
end_time,
error_occurred = false,
+ component_id,
refs,
is_noop = false,
-- owner is a TracingContext reference
owner,
}
+-- Due to nesting relationship inside Segment/Span/TracingContext at the runtime,
+-- SpanProtocol is created to prepare JSON format serialization.
+-- Following SkyWalking official trace protocol v2
+-- https://github.com/apache/skywalking-data-collect-protocol/blob/master/language-agent-v2/trace.proto
+local SpanProtocol = {
+ spanId,
+ parentSpanId,
+ startTime,
+ endTime,
+ -- Array of RefProtocol
+ refs,
+ operationName,
+ peer,
+ spanType,
+ spanLayer,
+ componentId,
+ isError,
+ tags,
+ logs,
+}
+
-- Create an entry span. Represent the HTTP incoming request.
-- @param contextCarrier, HTTP request header, which could carry the `sw6` context
function Span:createEntrySpan(operationName, context, parent, contextCarrier)
@@ -54,7 +76,7 @@
-- If current trace id is generated by the context, in LUA case, mostly are yes
-- use the ref trace id to override it, in order to keep trace id consistently same.
context.internal:addRefIfFirst(ref)
- table.insert(span.refs, ref)
+ span.refs[#span.refs + 1] = ref
end
end
end
@@ -149,6 +171,8 @@
o.start_time = Util.timestamp()
o.refs = {}
o.owner = context
+ o.tags = {}
+ o.logs = {}
return o
end
@@ -162,6 +186,14 @@
return o
end
+function SpanProtocol:new()
+ local o = {}
+ setmetatable(o, self)
+ self.__index = self
+
+ return o
+end
+
---- All belowing are instance methods
-- Set start time explicitly
@@ -201,4 +233,81 @@
return self
end
+function Span:setComponentId(componentId)
+ if self.is_noop then
+ return self
+ end
+ self.component_id = componentId
+
+ return self
+end
+
+function Span:errorOccurred()
+ if self.is_noop then
+ return self
+ end
+ self.error_occurred = true
+
+ return self
+end
+
+function Span:tag(key, value)
+ if self.is_noop then
+ return self
+ end
+
+ self.tags[#self.tags + 1] = { key=value }
+
+ return self
+end
+
+-- @param keyValuePairs, keyValuePairs is a typical {key=value, key1=value1}
+function Span:log(timestamp, keyValuePairs)
+ if self.is_noop then
+ return self
+ end
+
+ local logEntity = {time = timestamp, data = keyValuePairs}
+ self.logs[#self.logs + 1] = logEntity
+
+ return self
+end
+
+-- Return SpanProtocol
+function Span:transform()
+ local spanBuilder = SpanProtocol:new()
+ spanBuilder.spanId = self.span_id
+ spanBuilder.parentSpanId = self.parent_span_id
+ spanBuilder.startTime = self.start_time
+ spanBuilder.endTime = self.end_time
+ -- Array of RefProtocol
+ if #self.refs > 0 then
+ spanBuilder.refs = {}
+ for i, ref in ipairs(self.refs)
+ do
+ spanBuilder.refs[#spanBuilder.refs + 1] = ref:transform()
+ end
+ end
+
+ spanBuilder.operationName = self.operation_name
+ spanBuilder.peer = self.peer
+ if self.is_entry then
+ spanBuilder.spanType = 'Entry'
+ elseif self.is_exit then
+ spanBuilder.spanType = 'Exit'
+ else
+ spanBuilder.spanType = 'Local'
+ end
+ if self.layer ~= spanLayer.NONE then
+ spanBuilder.spanLayer = self.span_layer.name
+ end
+ spanBuilder.componentId = self.component_id
+ spanBuilder.isError = self.error_occurred
+
+ spanBuilder.tags = self.tags
+ spanBuilder.logs = self.logs
+
+ return spanBuilder
+end
+
return Span
diff --git a/lib/skywalking/span_test.lua b/lib/skywalking/span_test.lua
index d005d44..e685142 100644
--- a/lib/skywalking/span_test.lua
+++ b/lib/skywalking/span_test.lua
@@ -22,7 +22,7 @@
TestSpan = {}
function TestSpan:testNewEntry()
- local context = TC:new(1)
+ local context = TC:new(1, 1)
lu.assertNotNil(context)
local span1 = Span:createEntrySpan("operation_name", context, nil, nil)
@@ -35,7 +35,7 @@
end
function TestSpan:testNewEntryWithContextCarrier()
- local context = TC:new(1)
+ local context = TC:new(1, 1)
lu.assertNotNil(context)
-- Typical header from the SkyWalking Java Agent test case
@@ -66,7 +66,7 @@
end
function TestSpan:testNewExit()
- local context = TC:new(1)
+ local context = TC:new(1, 1)
lu.assertNotNil(context)
local contextCarrier = {}
@@ -82,7 +82,7 @@
end
function TestSpan:testNew()
- local context = TC:new(1)
+ local context = TC:new(1, 1)
lu.assertNotNil(context)
local span1 = Span:new("operation_name", context, nil)
@@ -96,7 +96,7 @@
lu.assertNotNil(span2.start_time)
-- Use new context to check again
- context = TC:new(1)
+ context = TC:new(1, 1)
lu.assertNotNil(context)
span1 = Span:new("operation_name", context, nil)
@@ -106,15 +106,41 @@
end
function TestSpan:testProperties()
- local context = TC:new(1)
+ local context = TC:new(1, 1)
- local span1 = Span:new("operation_name", context, nil)
+ local header = {sw6='1-My40LjU=-MS4yLjM=-4-1-1-IzEyNy4wLjAuMTo4MDgw-Iy9wb3J0YWw=-MTIz'}
+ local span1 = Span:createEntrySpan("operation_name", context, nil, header)
span1:start(1234567)
lu.assertEquals(span1.start_time, 1234567)
span1:finish(2222222)
lu.assertEquals(span1.end_time, 2222222)
span1:finishWithDuration(123)
lu.assertEquals(span1.end_time, 1234690)
+
+ span1:tag("key", "value")
+ lu.assertEquals(span1.tags[1], {key='value'})
+
+ lu.assertEquals(#span1.refs, 1)
+ lu.assertEquals(span1.refs[1].network_address, '127.0.0.1:8080')
+ end
+
+ function TestSpan:testTransform()
+ local context = TC:new(1, 1)
+
+ local header = {sw6='1-My40LjU=-MS4yLjM=-4-1-1-IzEyNy4wLjAuMTo4MDgw-Iy9wb3J0YWw=-MTIz'}
+ local span1 = Span:createEntrySpan("operation_name", context, nil, header)
+ span1:start(1234567)
+ span1:finish(2222222)
+ span1:tag("key", "value")
+ span1:log(123, {logkey="logvalue", logkey1="logvalue2"})
+
+ local spanBuilder = span1:transform()
+ lu.assertEquals(#spanBuilder.refs, 1)
+ lu.assertNil(spanBuilder.spanLayer)
+ lu.assertEquals(#spanBuilder.spanType, "Entry")
+ lu.assertEquals(#spanBuilder.logs, 1)
+ lu.assertEquals(spanBuilder.logs[1].data["logkey"], "logvalue")
+ lu.assertEquals(spanBuilder.logs[1].data["logkey1"], "logvalue2")
end
-- end TestSpan
diff --git a/lib/skywalking/tracing_context.lua b/lib/skywalking/tracing_context.lua
index 52ff9b8..78976b7 100644
--- a/lib/skywalking/tracing_context.lua
+++ b/lib/skywalking/tracing_context.lua
@@ -22,6 +22,7 @@
local TracingContext = {
trace_id,
segment_id,
+ service_id,
service_inst_id,
is_noop = false,
@@ -48,7 +49,7 @@
finished_spans,
}
-function TracingContext:new(serviceInstID)
+function TracingContext:new(serviceId, serviceInstID)
local o = {}
setmetatable(o, self)
self.__index = self
@@ -59,6 +60,7 @@
o.trace_id = Util:newID()
o.segment_id = o.trace_id
+ o.service_id = serviceId
o.service_inst_id = serviceInstID
o.internal = Internal:new()
o.internal.owner = o
@@ -112,6 +114,7 @@
local segment = Segment:new()
segment.trace_id = self.trace_id
segment.segment_id = self.segment_id
+ segment.service_id = self.service_id
segment.service_inst_id = self.service_inst_id
segment.spans = self.internal.finished_spans
return true, segment
diff --git a/lib/skywalking/tracing_context_test.lua b/lib/skywalking/tracing_context_test.lua
index 50f127f..63b47ad 100644
--- a/lib/skywalking/tracing_context_test.lua
+++ b/lib/skywalking/tracing_context_test.lua
@@ -20,7 +20,7 @@
TestTracingContext = {}
function TestTracingContext:testNew()
- local context = TC:new(1)
+ local context = TC:new(1, 1)
lu.assertNotNil(context)
lu.assertNotNil(context.segment_id[1])
lu.assertNotNil(context.segment_id[2])
@@ -30,13 +30,13 @@
end
function TestTracingContext:testInternal_NextSpanSeqID()
- local context = TC:new(1)
+ local context = TC:new(1, 1)
lu.assertEquals(context.internal:nextSpanID(), 0)
end
function TestTracingContext:testInternal_addActive()
- local context = TC:new(1)
+ local context = TC:new(1, 1)
local mockSpan = {span_id = 0}
context.internal:addActive(mockSpan)
@@ -45,7 +45,7 @@
end
function TestTracingContext:testSpanStack()
- local context = TC:new(1)
+ local context = TC:new(1, 1)
local span1 = context:createEntrySpan('entry_op')
local span2 = context:createExitSpan("exit_op", span1, "127.0.0.1")