used the nginx lua code style. (#10)
* used the nginx lua code style for tracing context.
* fixed test cases.
* fixed
* fixed test cases
* fixed
* fixed code style of register.
* code style of segment.
* add test cases for segment ref.
* fixed
* fixed bug in TracingContext:drainAfterFinished
Co-authored-by: 吴晟 Wu Sheng <wu.sheng@foxmail.com>
Co-authored-by: Daming <zteny@foxmail.com>
diff --git a/.gitignore b/.gitignore
index 162d14d..e072784 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,9 +13,10 @@
/dist/
/docker/snapshot/*.gz
.mvn/wrapper/*.jar
-.factorypath
-.vscode
+.factorypath
+.vscode
.checkstyle
.externalToolBuilders
/test/plugin/dist
/test/plugin/workspace
+/t/servroot/
diff --git a/README.md b/README.md
index e0ee074..45fe6ed 100644
--- a/README.md
+++ b/README.md
@@ -8,9 +8,9 @@
![CI](https://github.com/apache/skywalking-nginx-lua/workflows/CI/badge.svg?branch=master)
-[**SkyWalking**](https://github.com/apache/skywalking) Nginx Agent provides the native tracing capability for Nginx powered by Nginx LUA module.
+[**SkyWalking**](https://github.com/apache/skywalking) Nginx Agent provides the native tracing capability for Nginx powered by Nginx LUA module.
-This agent follows the SkyWalking tracing and header protocol. It reports tracing data to SkyWalking APM through HTTP protocol.
+This agent follows the SkyWalking tracing and header protocol. It reports tracing data to SkyWalking APM through HTTP protocol.
All HTTP 1.1 requests go through Nginx could be collected by this agent.
# Setup Doc
@@ -18,9 +18,9 @@
http {
lua_package_path "/Path/to/.../skywalking-nginx-lua/lib/skywalking/?.lua;;";
- # Buffer represents the register inform and the queue of the finished segment
+ # Buffer represents the register inform and the queue of the finished segment
lua_shared_dict tracing_buffer 100m;
-
+
# Init is the timer setter and keeper
# Setup an infinite loop timer to do register and trace report.
init_worker_by_lua_block {
@@ -112,13 +112,13 @@
## Tracing APIs at LUA level
**TracingContext** is the entrance API for lua level tracing.
-- `TracingContext:new(serviceId, serviceInstID)`, create an active tracing context.
-- `TracingContext:newNoOP()`, create a no OP tracing context.
-- `TracingContext:drainAfterFinished()`, fetch the segment includes all finished spans.
+- `TracingContext.new(serviceId, serviceInstID)`, create an active tracing context.
+- `TracingContext.newNoOP()`, create a no OP tracing context.
+- `TracingContext.drainAfterFinished()`, fetch the segment includes all finished spans.
Create 2 kinds of span
-- `TracingContext:createEntrySpan(operationName, parent, contextCarrier)`
-- `TracingContext:createExitSpan(operationName, parent, peer, contextCarrier)`
+- `TracingContext.createEntrySpan(operationName, parent, contextCarrier)`
+- `TracingContext.createExitSpan(operationName, parent, peer, contextCarrier)`
# Download
@@ -131,4 +131,4 @@
* QQ Group: 392443393(2000/2000, not available), 901167865(available)
# License
-Apache 2.0
\ No newline at end of file
+Apache 2.0
diff --git a/lib/skywalking/client.lua b/lib/skywalking/client.lua
index 502e198..42b8f7f 100644
--- a/lib/skywalking/client.lua
+++ b/lib/skywalking/client.lua
@@ -1,19 +1,19 @@
---
+--
-- Licensed to the Apache Software Foundation (ASF) under one or more
-- contributor license agreements. See the NOTICE file distributed with
-- this work for additional information regarding copyright ownership.
-- The ASF licenses this file to You under the Apache License, Version 2.0
-- (the "License"); you may not use this file except in compliance with
-- the License. You may obtain a copy of the License at
---
+--
-- http://www.apache.org/licenses/LICENSE-2.0
---
+--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
---
+--
local Client = {}
@@ -78,9 +78,9 @@
local ERR = ngx.ERR
local serviceName = metadata_buffer:get('serviceName')
-
+
local cjson = require('cjson')
- local serviceRegister = require("register"):newServiceRegister(serviceName)
+ local serviceRegister = require("register").newServiceRegister(serviceName)
local serviceRegisterParam = cjson.encode(serviceRegister)
local http = require('resty.http')
@@ -102,7 +102,7 @@
for i, result in ipairs(registerResults)
do
if result.key == serviceName then
- local serviceId = result.value
+ local serviceId = result.value
log(DEBUG, "Service registered, service id = " .. serviceId)
metadata_buffer:set('serviceId', serviceId)
end
@@ -122,9 +122,9 @@
metadata_buffer:set('serviceInstanceUUID', serviceInstName)
local cjson = require('cjson')
- local serviceInstanceRegister = require("register"):newServiceInstanceRegister(
- metadata_buffer:get('serviceId'),
- serviceInstName,
+ local serviceInstanceRegister = require("register").newServiceInstanceRegister(
+ metadata_buffer:get('serviceId'),
+ serviceInstName,
ngx.now() * 1000)
local serviceInstanceRegisterParam = cjson.encode(serviceInstanceRegister)
@@ -146,7 +146,7 @@
for i, result in ipairs(registerResults)
do
if result.key == serviceInstName then
- local serviceId = result.value
+ local serviceId = result.value
log(DEBUG, "Service Instance registered, service instance id = " .. serviceId)
metadata_buffer:set('serviceInstId', serviceId)
end
@@ -166,9 +166,9 @@
local ERR = ngx.ERR
local cjson = require('cjson')
- local pingPkg = require("register"):newServiceInstancePingPkg(
- metadata_buffer:get('serviceInstId'),
- metadata_buffer:get('serviceInstanceUUID'),
+ local pingPkg = require("register").newServiceInstancePingPkg(
+ metadata_buffer:get('serviceInstId'),
+ metadata_buffer:get('serviceInstanceUUID'),
ngx.now() * 1000)
local pingPkgParam = cjson.encode(pingPkg)
@@ -214,7 +214,7 @@
["Content-Type"] = "application/json",
},
})
-
+
if err == nil then
if res.status ~= 200 then
log(ERR, "Segment report fails, response code " .. res.status)
@@ -235,4 +235,4 @@
end
end
-return Client
\ No newline at end of file
+return Client
diff --git a/lib/skywalking/register.lua b/lib/skywalking/register.lua
index 988552f..8223ebc 100644
--- a/lib/skywalking/register.lua
+++ b/lib/skywalking/register.lua
@@ -1,28 +1,28 @@
---
+--
-- Licensed to the Apache Software Foundation (ASF) under one or more
-- contributor license agreements. See the NOTICE file distributed with
-- this work for additional information regarding copyright ownership.
-- The ASF licenses this file to You under the Apache License, Version 2.0
-- (the "License"); you may not use this file except in compliance with
-- the License. You may obtain a copy of the License at
---
+--
-- http://www.apache.org/licenses/LICENSE-2.0
---
+--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
---
+--
-local Register = {}
+local _M = {}
-- Return Services as service register parameter
-function Register:newServiceRegister(unRegisterServiceName)
+function _M.newServiceRegister(unRegisterServiceName)
local serv = {
services = {}
}
-
+
local service = {
serviceName = unRegisterServiceName,
-- Field type is optional, default value is `normal`
@@ -34,11 +34,11 @@
return serv
end
-function Register:newServiceInstanceRegister(registeredServiceId, serviceInstUUID, registerTime)
+function _M.newServiceInstanceRegister(registeredServiceId, serviceInstUUID, registerTime)
local serviceInstances = {
instances = {}
}
-
+
local serviceInstance = {
serviceId = registeredServiceId,
instanceUUID = serviceInstUUID,
@@ -53,7 +53,7 @@
return serviceInstances
end
-function Register:newServiceInstancePingPkg(registeredServiceInstId, serviceInstUUID, updateTime)
+function _M.newServiceInstancePingPkg(registeredServiceInstId, serviceInstUUID, updateTime)
local serviceInstancePingPkg = {
serviceInstanceId = registeredServiceInstId,
time = updateTime,
@@ -63,4 +63,4 @@
return serviceInstancePingPkg
end
-return Register
\ No newline at end of file
+return _M
diff --git a/lib/skywalking/segment.lua b/lib/skywalking/segment.lua
index ea2f33e..7842f2c 100644
--- a/lib/skywalking/segment.lua
+++ b/lib/skywalking/segment.lua
@@ -17,65 +17,49 @@
-- Segment represents a finished tracing context
-- Including all information to send to the SkyWalking OAP server.
-local Util = require('util')
+local Span = require('span')
-local Segment = {
- trace_id,
- segment_id,
- service_id,
- service_inst_id,
- spans,
-}
+local _M = {}
+-- 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 = {
- globalTraceIds,
- traceSegmentId,
- serviceId,
- serviceInstanceId,
- spans,
-}
-
-function Segment:new()
- local o = {}
- setmetatable(o, self)
- self.__index = self
-
- return o
-end
-
-function SegmentProtocol:new()
- local o = {}
- setmetatable(o, self)
- self.__index = self
-
- o.globalTraceIds = {}
-
- return o
-end
+-- local SegmentProtocol = {
+-- globalTraceIds,
+-- traceSegmentId,
+-- serviceId,
+-- serviceInstanceId,
+-- spans,
+-- }
-- Return SegmentProtocol
-function Segment:transform()
- local segmentBuilder = SegmentProtocol:new()
- segmentBuilder.serviceId = self.service_id
- segmentBuilder.globalTraceIds[1] = { idParts = self.trace_id}
- segmentBuilder.traceSegmentId = { idParts = self.segment_id}
- segmentBuilder.serviceId = self.service_id
- segmentBuilder.serviceInstanceId = self.service_inst_id
+function _M.transform(segment)
+ local segmentBuilder = {}
+ segmentBuilder.serviceId = segment.service_id
+ segmentBuilder.globalTraceIds = {}
+ segmentBuilder.globalTraceIds[1] = {idParts = segment.trace_id}
+ segmentBuilder.traceSegmentId = {idParts = segment.segment_id}
+ segmentBuilder.serviceId = segment.service_id
+ segmentBuilder.serviceInstanceId = segment.service_inst_id
segmentBuilder.spans = {}
- if self.spans ~= nil and #self.spans > 0 then
- for i, span in ipairs(self.spans)
- do
- segmentBuilder.spans[#segmentBuilder.spans + 1] = span:transform()
+ if segment.spans ~= nil and #segment.spans > 0 then
+ for i, span in ipairs(segment.spans)
+ do
+ segmentBuilder.spans[#segmentBuilder.spans + 1] = Span.transform(span)
end
end
return segmentBuilder
end
-return Segment
+return _M
diff --git a/lib/skywalking/segment_ref.lua b/lib/skywalking/segment_ref.lua
index 7709e90..7f85167 100644
--- a/lib/skywalking/segment_ref.lua
+++ b/lib/skywalking/segment_ref.lua
@@ -16,142 +16,147 @@
--
local Util = require('util')
local Base64 = require('dependencies/base64')
+local encode_base64 = Base64.encode
+local decode_base64 = Base64.decode
-local SegmentRef = {
- -- There is no multiple-threads scenario in the LUA, no only hard coded as CROSS_PROCESS
- type = 'CROSS_PROCESS',
- trace_id,
- segment_id,
- span_id,
- network_address,
- network_address_id = 0,
- entry_service_instance_id = 0,
- parent_service_instance_id = 0,
- entry_endpoint_name,
- entry_endpoint_id = 0,
- parent_endpoint_name,
- 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)
- self.__index = self
-
- return o
+if Util.is_ngx_lua then
+ encode_base64 = ngx.encode_base64
+ decode_base64 = ngx.decode_base64
end
-function RefProtocol:new()
- local o = {}
- setmetatable(o, self)
- self.__index = self
+local _M = {}
+-- local SegmentRef = {
+-- -- There is no multiple-threads scenario in the LUA, no only hard coded as CROSS_PROCESS
+-- type = 'CROSS_PROCESS',
+-- trace_id,
+-- segment_id,
+-- span_id,
+-- network_address,
+-- network_address_id = 0,
+-- entry_service_instance_id = 0,
+-- parent_service_instance_id = 0,
+-- entry_endpoint_name,
+-- entry_endpoint_id = 0,
+-- parent_endpoint_name,
+-- parent_endpoint_id = 0,
+-- }
- return o
+function _M.new()
+ return {
+ type = 'CROSS_PROCESS',
+ network_address_id = 0,
+ entry_service_instance_id = 0,
+ parent_service_instance_id = 0,
+ entry_endpoint_id = 0,
+ parent_endpoint_id = 0,
+ }
end
-- Deserialize value from the propagated context and initialize the SegmentRef
-function SegmentRef:fromSW6Value(value)
+function _M.fromSW6Value(value)
+ local ref = _M.new()
+
local parts = Util.split(value, '-')
if #parts ~= 9 then
return nil
end
- self.trace_id = Util.formatID(Base64.decode(parts[2]))
- self.segment_id = Util.formatID(Base64.decode(parts[3]))
- self.span_id = tonumber(parts[4])
- self.parent_service_instance_id = tonumber(parts[5])
- self.entry_service_instance_id = tonumber(parts[6])
- local peerStr = Base64.decode(parts[7])
+ ref.trace_id = Util.formatID(decode_base64(parts[2]))
+ ref.segment_id = Util.formatID(decode_base64(parts[3]))
+ ref.span_id = tonumber(parts[4])
+ ref.parent_service_instance_id = tonumber(parts[5])
+ ref.entry_service_instance_id = tonumber(parts[6])
+ local peerStr = decode_base64(parts[7])
if string.sub(peerStr, 1, 1) == '#' then
- self.network_address = string.sub(peerStr, 2)
+ ref.network_address = string.sub(peerStr, 2)
else
- self.network_address_id = tonumber(peerStr)
+ ref.network_address_id = tonumber(peerStr)
end
- local entryEndpointStr = Base64.decode(parts[8])
+ local entryEndpointStr = decode_base64(parts[8])
if string.sub(entryEndpointStr, 1, 1) == '#' then
- self.entry_endpoint_name = string.sub(entryEndpointStr, 2)
+ ref.entry_endpoint_name = string.sub(entryEndpointStr, 2)
else
- self.entry_endpoint_id = tonumber(entryEndpointStr)
+ ref.entry_endpoint_id = tonumber(entryEndpointStr)
end
- local parentEndpointStr = Base64.decode(parts[9])
+ local parentEndpointStr = decode_base64(parts[9])
if string.sub(parentEndpointStr, 1, 1) == '#' then
- self.parent_endpoint_name = string.sub(parentEndpointStr, 2)
+ ref.parent_endpoint_name = string.sub(parentEndpointStr, 2)
else
- self.parent_endpoint_id = tonumber(parentEndpointStr)
+ ref.parent_endpoint_id = tonumber(parentEndpointStr)
end
- return self
+ return ref
end
-- Return string to represent this ref.
-function SegmentRef:serialize()
+function _M.serialize(ref)
local encodedRef = '1'
- encodedRef = encodedRef .. '-' .. Base64.encode(Util.id2String(self.trace_id))
- encodedRef = encodedRef .. '-' .. Base64.encode(Util.id2String(self.segment_id))
- encodedRef = encodedRef .. '-' .. self.span_id
- encodedRef = encodedRef .. '-' .. self.parent_service_instance_id
- encodedRef = encodedRef .. '-' .. self.entry_service_instance_id
+ encodedRef = encodedRef .. '-' .. encode_base64(Util.id2String(ref.trace_id))
+ encodedRef = encodedRef .. '-' .. encode_base64(Util.id2String(ref.segment_id))
+ encodedRef = encodedRef .. '-' .. ref.span_id
+ encodedRef = encodedRef .. '-' .. ref.parent_service_instance_id
+ encodedRef = encodedRef .. '-' .. ref.entry_service_instance_id
local networkAddress
- if self.network_address_id ~= 0 then
- networkAddress = self.network_address_id .. ''
+ if ref.network_address_id ~= 0 then
+ networkAddress = ref.network_address_id .. ''
else
- networkAddress = '#' .. self.network_address
+ networkAddress = '#' .. ref.network_address
end
- encodedRef = encodedRef .. '-' .. Base64.encode(networkAddress)
+ encodedRef = encodedRef .. '-' .. encode_base64(networkAddress)
local entryEndpoint
- if self.entry_endpoint_id ~= 0 then
- entryEndpoint = self.entry_endpoint_id .. ''
+ if ref.entry_endpoint_id ~= 0 then
+ entryEndpoint = ref.entry_endpoint_id .. ''
else
- entryEndpoint = '#' .. self.entry_endpoint_name
+ entryEndpoint = '#' .. ref.entry_endpoint_name
end
- encodedRef = encodedRef .. '-' .. Base64.encode(entryEndpoint)
+ encodedRef = encodedRef .. '-' .. encode_base64(entryEndpoint)
local parentEndpoint
- if self.parent_endpoint_id ~= 0 then
- parentEndpoint = self.parent_endpoint_id .. ''
+ if ref.parent_endpoint_id ~= 0 then
+ parentEndpoint = ref.parent_endpoint_id .. ''
else
- parentEndpoint = '#' .. self.parent_endpoint_name
+ parentEndpoint = '#' .. ref.parent_endpoint_name
end
- encodedRef = encodedRef .. '-' .. Base64.encode(parentEndpoint)
+ encodedRef = encodedRef .. '-' .. encode_base64(parentEndpoint)
return encodedRef
end
+-- 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,
+-- }
-- Return RefProtocol
-function SegmentRef:transform()
- local refBuilder = RefProtocol:new()
- refBuilder.parentTraceSegmentId = {idParts = 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
+function _M.transform(ref)
+ local refBuilder = {}
+ refBuilder.refType = 'CrossProcess'
+ refBuilder.parentTraceSegmentId = {idParts = ref.segment_id }
+ refBuilder.parentSpanId = ref.span_id
+ refBuilder.parentServiceInstanceId = ref.parent_service_instance_id
+ refBuilder.networkAddress = ref.network_address
+ refBuilder.networkAddressId = ref.network_address_id
+ refBuilder.entryServiceInstanceId = ref.entry_service_instance_id
+ refBuilder.entryEndpoint = ref.entry_endpoint_name
+ refBuilder.entryEndpointId = ref.entry_endpoint_id
+ refBuilder.parentEndpoint = ref.parent_endpoint_name
+ refBuilder.parentEndpointId = ref.parent_endpoint_id
return refBuilder
end
-return SegmentRef
+return _M
diff --git a/lib/skywalking/segment_ref_test.lua b/lib/skywalking/segment_ref_test.lua
index 94fc0c0..72c664e 100644
--- a/lib/skywalking/segment_ref_test.lua
+++ b/lib/skywalking/segment_ref_test.lua
@@ -1,19 +1,19 @@
---
+--
-- Licensed to the Apache Software Foundation (ASF) under one or more
-- contributor license agreements. See the NOTICE file distributed with
-- this work for additional information regarding copyright ownership.
-- The ASF licenses this file to You under the Apache License, Version 2.0
-- (the "License"); you may not use this file except in compliance with
-- the License. You may obtain a copy of the License at
---
+--
-- http://www.apache.org/licenses/LICENSE-2.0
---
+--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
---
+--
local lu = require('luaunit')
@@ -23,7 +23,7 @@
TestSegmentRef = {}
-- This test is originally from ContextCarrierV2HeaderTest in the Java agent.
function TestSegmentRef:testFromSW6Value()
- local ref = SegmentRef:new():fromSW6Value('1-My40LjU=-MS4yLjM=-4-1-1-IzEyNy4wLjAuMTo4MDgw-Iy9wb3J0YWw=-MTIz')
+ local ref = SegmentRef.fromSW6Value('1-My40LjU=-MS4yLjM=-4-1-1-IzEyNy4wLjAuMTo4MDgw-Iy9wb3J0YWw=-MTIz')
lu.assertNotNil(ref)
lu.assertEquals(ref.trace_id, {"3", "4", "5"})
lu.assertEquals(ref.segment_id, {"1", "2", "3"})
@@ -37,12 +37,12 @@
lu.assertEquals(ref.parent_endpoint_name, nil)
lu.assertEquals(ref.parent_endpoint_id, 123)
- ref = SegmentRef:new():fromSW6Value('1-My40LjU=-MS')
+ ref = SegmentRef.fromSW6Value('1-My40LjU=-MS')
lu.assertNil(ref)
end
function TestSegmentRef:testSerialize()
- local ref = SegmentRef:new()
+ local ref = SegmentRef.new()
ref.trace_id = {3, 4, 5}
ref.segment_id = {1, 2, 3}
ref.span_id = 4
@@ -52,11 +52,11 @@
ref.entry_endpoint_name = "/portal"
ref.parent_endpoint_id = 123
- lu.assertEquals(ref:serialize(), '1-My40LjU=-MS4yLjM=-4-1-1-IzEyNy4wLjAuMTo4MDgw-Iy9wb3J0YWw=-MTIz')
+ lu.assertEquals(SegmentRef.serialize(ref), '1-My40LjU=-MS4yLjM=-4-1-1-IzEyNy4wLjAuMTo4MDgw-Iy9wb3J0YWw=-MTIz')
end
function TestSegmentRef:testTransform()
- local ref = SegmentRef:new()
+ local ref = SegmentRef.new()
ref.trace_id = {3, 4, 5}
ref.segment_id = {1, 2, 3}
ref.span_id = 4
@@ -66,11 +66,11 @@
ref.entry_endpoint_name = "/portal"
ref.parent_endpoint_id = 123
- local refProtocol = ref:transform()
+ local refProtocol = SegmentRef.transform(ref)
local inJSON = cjson.encode(refProtocol)
lu.assertTrue(string.len(inJSON) > 0)
end
-- end TestSegmentRef
-os.exit( lu.LuaUnit.run() )
\ No newline at end of file
+os.exit( lu.LuaUnit.run() )
diff --git a/lib/skywalking/span.lua b/lib/skywalking/span.lua
index cd5ab4c..6dd30ec 100644
--- a/lib/skywalking/span.lua
+++ b/lib/skywalking/span.lua
@@ -1,19 +1,19 @@
---
+--
-- Licensed to the Apache Software Foundation (ASF) under one or more
-- contributor license agreements. See the NOTICE file distributed with
-- this work for additional information regarding copyright ownership.
-- The ASF licenses this file to You under the Apache License, Version 2.0
-- (the "License"); you may not use this file except in compliance with
-- the License. You may obtain a copy of the License at
---
+--
-- http://www.apache.org/licenses/LICENSE-2.0
---
+--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
---
+--
local spanLayer = require("span_layer")
local Util = require('util')
@@ -21,61 +21,62 @@
local CONTEXT_CARRIER_KEY = 'sw6'
-local Span = {
- span_id,
- parent_span_id,
- operation_name,
- tags,
- logs,
- layer = spanLayer.NONE,
- is_entry = false,
- is_exit = false,
- peer,
- start_time,
- end_time,
- error_occurred = false,
- component_id,
- refs,
- is_noop = false,
- -- owner is a TracingContext reference
- owner,
-}
+local _M = {}
+-- local Span = {
+-- span_id,
+-- parent_span_id,
+-- operation_name,
+-- tags,
+-- logs,
+-- layer = spanLayer.NONE,
+-- is_entry = false,
+-- is_exit = false,
+-- peer,
+-- 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,
-}
+-- 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)
- local span = self:new(operationName, context, parent)
+function _M.createEntrySpan(operationName, context, parent, contextCarrier)
+ local span = _M.new(operationName, context, parent)
span.is_entry = true
if contextCarrier ~= nil then
local propagatedContext = contextCarrier[CONTEXT_CARRIER_KEY]
if propagatedContext ~= nil then
- local ref = SegmentRef:new():fromSW6Value(propagatedContext)
+ local ref = SegmentRef.fromSW6Value(propagatedContext)
if ref ~= nil then
-- 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)
+ context.internal.addRefIfFirst(context.internal, ref)
span.refs[#span.refs + 1] = ref
end
end
@@ -85,14 +86,14 @@
end
-- Create an exit span. Represent the HTTP outgoing request.
-function Span:createExitSpan(operationName, context, parent, peer, contextCarrier)
- local span = self:new(operationName, context, parent)
+function _M.createExitSpan(operationName, context, parent, peer, contextCarrier)
+ local span = _M.new(operationName, context, parent)
span.is_exit = true
span.peer = peer
if contextCarrier ~= nil then
-- if there is contextCarrier container, the Span will inject the value based on the current tracing context
- local injectableRef = SegmentRef:new()
+ local injectableRef = SegmentRef.new()
injectableRef.trace_id = context.trace_id
injectableRef.segment_id = context.segment_id
injectableRef.span_id = span.span_id
@@ -106,8 +107,8 @@
local entryEndpointId = -1
local firstSpan = context.internal.first_span
- if context.internal:hasRef() then
- local firstRef = context.internal:getFirstRef()
+ if context.internal.first_ref then
+ local firstRef = context.internal.first_ref
injectableRef.entry_service_instance_id = firstRef.entry_service_instance_id
entryEndpointName = firstRef.entry_endpoint_name
entryEndpointId = firstRef.entry_endpoint_id
@@ -120,7 +121,7 @@
end
entryServiceInstanceId = context.service_inst_id
end
-
+
injectableRef.entry_service_instance_id = entryServiceInstanceId
injectableRef.parent_service_instance_id = context.service_inst_id
injectableRef.entry_endpoint_name = entryEndpointName
@@ -128,7 +129,7 @@
local parentEndpointName
local parentEndpointId = -1
-
+
if firstSpan.is_entry then
parentEndpointName = firstSpan.operation_name
parentEndpointId = 0
@@ -136,194 +137,185 @@
injectableRef.parent_endpoint_name = parentEndpointName
injectableRef.parent_endpoint_id = parentEndpointId
- contextCarrier[CONTEXT_CARRIER_KEY] = injectableRef:serialize()
+ contextCarrier[CONTEXT_CARRIER_KEY] = SegmentRef.serialize(injectableRef)
end
return span
end
--- Create an local span. Local span is usually not used.
+-- Create an local span. Local span is usually not used.
-- Typically, only one entry span and one exit span in the Nginx tracing segment.
-function Span:createLocalSpan(operationName, context, parent)
- local span = self:new(operationName, context, parent)
+function _M.createLocalSpan(operationName, context, parent)
+ local span = _M.new(operationName, context, parent)
return span
end
-- Create a default span.
-- Usually, this method wouldn't be called by outside directly.
-- Read newEntrySpan, newExitSpan and newLocalSpan for more details
-function Span:new(operationName, context, parent)
- local o = {}
- setmetatable(o, self)
- self.__index = self
+function _M.new(operationName, context, parent)
+ local span = _M.newNoOP()
+ span.is_noop = false
- o.operation_name = operationName
- o.span_id = context.internal:nextSpanID()
-
+ span.operation_name = operationName
+ span.span_id = context.internal.nextSpanID(context.internal)
+
if parent == nil then
-- As the root span, the parent span id is -1
- o.parent_span_id = -1
+ span.parent_span_id = -1
else
- o.parent_span_id = parent.span_id
- end
+ span.parent_span_id = parent.span_id
+ end
- context.internal:addActive(o)
- -- o.start_time = Util.timestamp()
- o.refs = {}
- o.owner = context
+ context.internal.addActive(context.internal, span)
+ span.refs = {}
+ span.owner = context
- return o
+ return span
end
-function Span:newNoOP()
- local o = {}
- setmetatable(o, self)
- self.__index = self
-
- o.is_noop = true
- return o
-end
-
-function SpanProtocol:new()
- local o = {}
- setmetatable(o, self)
- self.__index = self
-
- return o
+function _M.newNoOP()
+ return {
+ layer = spanLayer.NONE,
+ is_entry = false,
+ is_exit = false,
+ error_occurred = false,
+ is_noop = true
+ }
end
---- All belowing are instance methods
-- Set start time explicitly
-function Span:start(startTime)
- if self.is_noop then
- return self
+function _M.start(span, startTime)
+ if span.is_noop then
+ return span
end
- self.start_time = startTime
+ span.start_time = startTime
- return self
+ return span
end
-function Span:finishWithDuration(duration)
- if self.is_noop then
- return self
+function _M.finishWithDuration(span, duration)
+ if span.is_noop then
+ return span
end
- self:finish(self.start_time + duration)
-
- return self
+ _M.finish(span, span.start_time + duration)
+
+ return span
end
-- @param endTime, optional.
-function Span:finish(endTime)
- if self.is_noop then
- return self
+function _M.finish(span, endTime)
+ if span.is_noop then
+ return span
end
if endTime == nil then
- self.end_time = Util.timestamp()
+ span.end_time = Util.timestamp()
else
- self.end_time = endTime
+ span.end_time = endTime
end
- self.owner.internal:finishSpan(self)
+ span.owner.internal.finishSpan(span.owner.internal, span)
- return self
+ return span
end
-function Span:setComponentId(componentId)
- if self.is_noop then
- return self
+function _M.setComponentId(span, componentId)
+ if span.is_noop then
+ return span
end
- self.component_id = componentId
+ span.component_id = componentId
- return self
+ return span
end
-function Span:setLayer(spanLayer)
- if self.is_noop then
- return self
+function _M.setLayer(span, span_layer)
+ if span.is_noop then
+ return span
end
- self.layer = spanLayer
+ span.layer = span_layer
- return self
+ return span
end
-function Span:errorOccurred()
- if self.is_noop then
- return self
+function _M.errorOccurred(span)
+ if span.is_noop then
+ return span
end
- self.error_occurred = true
+ span.error_occurred = true
- return self
+ return span
end
-function Span:tag(tagKey, tagValue)
- if self.is_noop then
- return self
+function _M.tag(span, tagKey, tagValue)
+ if span.is_noop then
+ return span
end
- if self.tags == nil then
- self.tags = {}
+ if span.tags == nil then
+ span.tags = {}
end
local tag = {key = tagKey, value = tagValue}
- self.tags[#self.tags + 1] = tag
+ span.tags[#span.tags + 1] = tag
- return self
+ return span
end
-- @param keyValuePairs, keyValuePairs is a typical {key=value, key1=value1}
-function Span:log(timestamp, keyValuePairs)
- if self.is_noop then
- return self
+function _M.log(span, timestamp, keyValuePairs)
+ if span.is_noop then
+ return span
end
- if self.logs == nil then
- self.logs = {}
+ if span.logs == nil then
+ span.logs = {}
end
local logEntity = {time = timestamp, data = keyValuePairs}
- self.logs[#self.logs + 1] = logEntity
+ span.logs[#span.logs + 1] = logEntity
- return self
+ return span
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
+function _M.transform(span)
+ local spanBuilder = {}
+ spanBuilder.spanId = span.span_id
+ spanBuilder.parentSpanId = span.parent_span_id
+ spanBuilder.startTime = span.start_time
+ spanBuilder.endTime = span.end_time
-- Array of RefProtocol
- if #self.refs > 0 then
+ if #span.refs > 0 then
spanBuilder.refs = {}
- for i, ref in ipairs(self.refs)
- do
- spanBuilder.refs[#spanBuilder.refs + 1] = ref:transform()
+ for i, ref in ipairs(span.refs)
+ do
+ spanBuilder.refs[#spanBuilder.refs + 1] = SegmentRef.transform(ref)
end
end
- spanBuilder.operationName = self.operation_name
- spanBuilder.peer = self.peer
- if self.is_entry then
+ spanBuilder.operationName = span.operation_name
+ spanBuilder.peer = span.peer
+ if span.is_entry then
spanBuilder.spanType = 'Entry'
- elseif self.is_exit then
+ elseif span.is_exit then
spanBuilder.spanType = 'Exit'
else
spanBuilder.spanType = 'Local'
end
- if self.layer ~= spanLayer.NONE then
- spanBuilder.spanLayer = self.layer.name
+ if span.layer ~= spanLayer.NONE then
+ spanBuilder.spanLayer = span.layer.name
end
- spanBuilder.componentId = self.component_id
- spanBuilder.isError = self.error_occurred
+ spanBuilder.componentId = span.component_id
+ spanBuilder.isError = span.error_occurred
- spanBuilder.tags = self.tags
- spanBuilder.logs = self.logs
+ spanBuilder.tags = span.tags
+ spanBuilder.logs = span.logs
return spanBuilder
end
-return Span
+return _M
diff --git a/lib/skywalking/span_test.lua b/lib/skywalking/span_test.lua
index 274f3cc..56e2fd2 100644
--- a/lib/skywalking/span_test.lua
+++ b/lib/skywalking/span_test.lua
@@ -1,19 +1,19 @@
---
+--
-- Licensed to the Apache Software Foundation (ASF) under one or more
-- contributor license agreements. See the NOTICE file distributed with
-- this work for additional information regarding copyright ownership.
-- The ASF licenses this file to You under the Apache License, Version 2.0
-- (the "License"); you may not use this file except in compliance with
-- the License. You may obtain a copy of the License at
---
+--
-- http://www.apache.org/licenses/LICENSE-2.0
---
+--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
---
+--
local lu = require('luaunit')
local TC = require('tracing_context')
@@ -22,10 +22,10 @@
TestSpan = {}
function TestSpan:testNewEntry()
- local context = TC:new(1, 1)
+ local context = TC.new(1, 1)
lu.assertNotNil(context)
- local span1 = Span:createEntrySpan("operation_name", context, nil, nil)
+ local span1 = Span.createEntrySpan("operation_name", context, nil, nil)
lu.assertNotNil(span1)
lu.assertEquals(span1.is_entry, true)
lu.assertEquals(span1.is_exit, false)
@@ -35,13 +35,13 @@
end
function TestSpan:testNewEntryWithContextCarrier()
- local context = TC:new(1, 1)
+ local context = TC.new(1, 1)
lu.assertNotNil(context)
-- Typical header from the SkyWalking Java Agent test case
local header = {sw6='1-My40LjU=-MS4yLjM=-4-1-1-IzEyNy4wLjAuMTo4MDgw-Iy9wb3J0YWw=-MTIz'}
- local span1 = Span:createEntrySpan("operation_name", context, nil, header)
+ local span1 = Span.createEntrySpan("operation_name", context, nil, header)
lu.assertNotNil(span1)
lu.assertEquals(span1.is_entry, true)
lu.assertEquals(span1.is_exit, false)
@@ -66,11 +66,11 @@
end
function TestSpan:testNewExit()
- local context = TC:new(1, 1)
+ local context = TC.new(1, 1)
lu.assertNotNil(context)
local contextCarrier = {}
- local span1 = Span:createExitSpan("operation_name", context, nil, '127.0.0.1:80', contextCarrier)
+ local span1 = Span.createExitSpan("operation_name", context, nil, '127.0.0.1:80', contextCarrier)
lu.assertNotNil(span1)
lu.assertEquals(span1.is_entry, false)
lu.assertEquals(span1.is_exit, true)
@@ -82,44 +82,44 @@
end
function TestSpan:testNew()
- local context = TC:new(1, 1)
+ local context = TC.new(1, 1)
lu.assertNotNil(context)
- local span1 = Span:new("operation_name", context, nil)
+ local span1 = Span.new("operation_name", context, nil)
lu.assertNotNil(span1)
lu.assertEquals(span1.parent_span_id, -1)
lu.assertEquals(span1.span_id, 0)
lu.assertEquals(span1.operation_name, "operation_name")
- local span2 = Span:new("operation_name", context, span1)
+ local span2 = Span.new("operation_name", context, span1)
lu.assertEquals(span2.parent_span_id, 0)
lu.assertEquals(span2.span_id, 1)
lu.assertNil(span2.start_time)
- span2:start(123456)
+ Span.start(span2, 123456)
lu.assertNotNil(span2.start_time)
-- Use new context to check again
- context = TC:new(1, 1)
+ context = TC.new(1, 1)
lu.assertNotNil(context)
- span1 = Span:new("operation_name", context, nil)
+ span1 = Span.new("operation_name", context, nil)
lu.assertNotNil(span1)
lu.assertEquals(span1.parent_span_id, -1)
lu.assertEquals(span1.span_id, 0)
end
function TestSpan:testProperties()
- local context = TC:new(1, 1)
+ 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)
+ local span1 = Span.createEntrySpan("operation_name", context, nil, header)
+ Span.start(span1, 1234567)
lu.assertEquals(span1.start_time, 1234567)
- span1:finish(2222222)
+ Span.finish(span1, 2222222)
lu.assertEquals(span1.end_time, 2222222)
- span1:finishWithDuration(123)
+ Span.finishWithDuration(span1, 123)
lu.assertEquals(span1.end_time, 1234690)
- span1:tag("key1", "value1")
+ Span.tag(span1, "key1", "value1")
lu.assertEquals(span1.tags[1].value, 'value1')
lu.assertEquals(#span1.refs, 1)
@@ -127,16 +127,16 @@
end
function TestSpan:testTransform()
- local context = TC:new(1, 1)
+ 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 span1 = Span.createEntrySpan("operation_name", context, nil, header)
+ Span.start(span1, 1234567)
+ Span.finish(span1, 2222222)
+ Span.tag(span1, "key", "value")
+ Span.log(span1, 123, {logkey="logvalue", logkey1="logvalue2"})
- local spanBuilder = span1:transform()
+ local spanBuilder = Span.transform(span1)
lu.assertEquals(#spanBuilder.refs, 1)
lu.assertNil(spanBuilder.spanLayer)
lu.assertEquals(spanBuilder.spanType, "Entry")
@@ -147,4 +147,4 @@
-- end TestSpan
-os.exit( lu.LuaUnit.run() )
\ No newline at end of file
+os.exit( lu.LuaUnit.run() )
diff --git a/lib/skywalking/tracer.lua b/lib/skywalking/tracer.lua
index 1689d79..f0a1a1e 100644
--- a/lib/skywalking/tracer.lua
+++ b/lib/skywalking/tracer.lua
@@ -1,19 +1,20 @@
---
+--
-- Licensed to the Apache Software Foundation (ASF) under one or more
-- contributor license agreements. See the NOTICE file distributed with
-- this work for additional information regarding copyright ownership.
-- The ASF licenses this file to You under the Apache License, Version 2.0
-- (the "License"); you may not use this file except in compliance with
-- the License. You may obtain a copy of the License at
---
+--
-- http://www.apache.org/licenses/LICENSE-2.0
---
+--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
---
+--
+local Span = require('span')
local Tracer = {}
@@ -27,9 +28,9 @@
local serviceInstId = metadata_buffer:get("serviceInstId")
local serviceId = metadata_buffer:get('serviceId')
if (serviceInstId ~= nil and serviceInstId ~= 0) then
- tracingContext = TC:new(serviceId, serviceInstId)
+ tracingContext = TC.new(serviceId, serviceInstId)
else
- tracingContext = TC:newNoOP()
+ tracingContext = TC.newNoOP()
end
-- Constant pre-defined in SkyWalking main repo
@@ -38,14 +39,14 @@
local contextCarrier = {}
contextCarrier["sw6"] = ngx.req.get_headers()["sw6"]
- local entrySpan = tracingContext:createEntrySpan(ngx.var.uri, nil, contextCarrier)
- entrySpan:start(ngx.now() * 1000)
- entrySpan:setComponentId(nginxComponentId)
- entrySpan:setLayer(Layer.HTTP)
-
- entrySpan:tag('http.method', ngx.req.get_method())
- entrySpan:tag('http.params', ngx.var.scheme .. '://' .. ngx.var.host .. ngx.var.request_uri )
-
+ local entrySpan = TC.createEntrySpan(tracingContext, ngx.var.uri, nil, contextCarrier)
+ Span.start(entrySpan, ngx.now() * 1000)
+ Span.setComponentId(entrySpan, nginxComponentId)
+ Span.setLayer(entrySpan, Layer.HTTP)
+
+ Span.tag(entrySpan, 'http.method', ngx.req.get_method())
+ Span.tag(entrySpan, 'http.params', ngx.var.scheme .. '://' .. ngx.var.host .. ngx.var.request_uri )
+
contextCarrier = {}
-- Use the same URI to represent incoming and forwarding requests
-- Change it if you need.
@@ -53,11 +54,11 @@
local upstreamServerName = upstream_name
------------------------------------------------------
- local exitSpan = tracingContext:createExitSpan(upstreamUri, entrySpan, upstreamServerName, contextCarrier)
- exitSpan:start(ngx.now() * 1000)
- exitSpan:setComponentId(nginxComponentId)
- exitSpan:setLayer(Layer.HTTP)
-
+ local exitSpan = TC.createExitSpan(tracingContext, upstreamUri, entrySpan, upstreamServerName, contextCarrier)
+ Span.start(exitSpan, ngx.now() * 1000)
+ Span.setComponentId(exitSpan, nginxComponentId)
+ Span.setLayer(exitSpan, Layer.HTTP)
+
for name, value in pairs(contextCarrier) do
ngx.req.set_header(name, value)
end
@@ -71,17 +72,19 @@
function Tracer:finish()
-- Finish the exit span when received the first response package from upstream
if ngx.ctx.exitSpan ~= nil then
- ngx.ctx.exitSpan:finish(ngx.now() * 1000)
+ Span.finish(ngx.ctx.exitSpan, ngx.now() * 1000)
ngx.ctx.exitSpan = nil
end
end
function Tracer:prepareForReport()
+ local TC = require('tracing_context')
+ local Segment = require('segment')
if ngx.ctx.entrySpan ~= nil then
- ngx.ctx.entrySpan:finish(ngx.now() * 1000)
- local status, segment = ngx.ctx.tracingContext:drainAfterFinished()
+ Span.finish(ngx.ctx.entrySpan, ngx.now() * 1000)
+ local status, segment = TC.drainAfterFinished(ngx.ctx.tracingContext)
if status then
- local segmentJson = require('cjson').encode(segment:transform())
+ local segmentJson = require('cjson').encode(Segment.transform(segment))
ngx.log(ngx.DEBUG, 'segment = ' .. segmentJson)
local queue = ngx.shared.tracing_buffer
@@ -91,4 +94,4 @@
end
end
-return Tracer
\ No newline at end of file
+return Tracer
diff --git a/lib/skywalking/tracing_context.lua b/lib/skywalking/tracing_context.lua
index 427202e..23ecfb0 100644
--- a/lib/skywalking/tracing_context.lua
+++ b/lib/skywalking/tracing_context.lua
@@ -17,83 +17,129 @@
local Util = require('util')
local Span = require('span')
-local Segment = require('segment')
-
-local TracingContext = {
- trace_id,
- segment_id,
- service_id,
- service_inst_id,
-
- is_noop = false,
-
- internal,
-}
-------------- Internal Object-------------
+local Internal = {}
-- Internal Object hosts the methods for SkyWalking LUA internal APIs only.
-local Internal = {
- self_generated_trace_id,
- -- span id starts from 0
- span_id_seq,
- -- Owner means the Context instance holding this Internal object.
- owner,
- -- The first created span.
- first_span,
- -- The first ref injected in this context
- first_ref,
- -- Created span and still active
- active_spans,
- active_count,
- -- Finished spans
- finished_spans,
-}
+-- local Internal = {
+-- self_generated_trace_id,
+-- -- span id starts from 0
+-- span_id_seq,
+-- -- Owner means the Context instance holding this Internal object.
+-- owner,
+-- -- The first created span.
+-- first_span,
+-- -- The first ref injected in this context
+-- first_ref,
+-- -- Created span and still active
+-- active_spans,
+-- active_count,
+-- -- Finished spans
+-- finished_spans,
+-- }
-function TracingContext:new(serviceId, serviceInstID)
- local o = {}
- setmetatable(o, self)
- self.__index = self
+-- add the segment ref if this is the first ref of this context
+local function addRefIfFirst(internal, ref)
+ if internal.self_generated_trace_id == true then
+ internal.self_generated_trace_id = false
+ internal.owner.trace_id = ref.trace_id
+ internal.first_ref = ref
+ end
+end
+
+local function addActive(internal, span)
+ if internal.first_span == nil then
+ internal.first_span = span
+ end
+
+ -- span id starts at 0, to fit LUA, we need to plus one.
+ internal.active_spans[span.span_id + 1] = span
+ internal.active_count = internal.active_count + 1
+ return internal.owner
+end
+
+local function finishSpan(internal, span)
+ -- span id starts at 0, to fit LUA, we need to plus one.
+ internal.active_spans[span.span_id + 1] = nil
+ internal.active_count = internal.active_count - 1
+ internal.finished_spans[#internal.finished_spans + 1] = span
+
+ return internal.owner
+end
+
+-- Generate the next span ID.
+local function nextSpanID(internal)
+ local nextSpanId = internal.span_id_seq
+ internal.span_id_seq = internal.span_id_seq + 1
+ return nextSpanId
+end
+
+-- Create an internal instance
+function Internal.new()
+ local internal = {}
+
+ internal.self_generated_trace_id = true
+ internal.span_id_seq = 0
+ internal.active_spans = {}
+ internal.active_count = 0
+ internal.finished_spans = {}
+ internal.addRefIfFirst = addRefIfFirst
+ internal.addActive = addActive
+ internal.finishSpan = finishSpan
+ internal.nextSpanID = nextSpanID
+ return internal
+end
+
+
+local _M = {}
+
+-- local TracingContext = {
+-- trace_id,
+-- segment_id,
+-- service_id,
+-- service_inst_id,
+-- is_noop = false,
+-- internal,
+-- }
+
+function _M.newNoOP()
+ return {is_noop = true}
+end
+
+function _M.new(serviceId, serviceInstID)
if serviceInstID == nil then
- return TracingContext:newNoOP()
+ return _M.newNoOP()
end
- 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
- return o
+ local tracing_context = {}
+ tracing_context.trace_id = Util.newID()
+ tracing_context.segment_id = tracing_context.trace_id
+ tracing_context.service_id = serviceId
+ tracing_context.service_inst_id = serviceInstID
+ tracing_context.internal = Internal.new()
+ tracing_context.internal.owner = tracing_context
+ return tracing_context
end
-function TracingContext:newNoOP()
- local o = {}
- setmetatable(o, self)
- self.__index = self
-
- o.is_noop = true
- return o
-end
-
--- Delegate to Span:createEntrySpan
+-- Delegate to Span.createEntrySpan
-- @param contextCarrier could be nil if there is no downstream propagated context
-function TracingContext:createEntrySpan(operationName, parent, contextCarrier)
- if self.is_noop then
- return Span:newNoOP()
+function _M.createEntrySpan(tracingContext, operationName, parent, contextCarrier)
+ if tracingContext.is_noop then
+ return Span.newNoOP()
end
- return Span:createEntrySpan(operationName, self, parent, contextCarrier)
+ return Span.createEntrySpan(operationName, tracingContext, parent, contextCarrier)
end
--- Delegate to Span:createExitSpan
+-- Delegate to Span.createExitSpan
-- @param contextCarrier could be nil if don't need to inject any context to propagate
-function TracingContext:createExitSpan(operationName, parent, peer, contextCarrier)
- if self.is_noop then
- return Span:newNoOP()
+function _M.createExitSpan(tracingContext, operationName, parent, peer, contextCarrier)
+ if tracingContext.is_noop then
+ return Span.newNoOP()
end
- return Span:createExitSpan(operationName, self, parent, peer, contextCarrier)
+ return Span.createExitSpan(operationName, tracingContext, parent, peer, contextCarrier)
end
-- After all active spans finished, this segment will be treated as finished status.
@@ -103,87 +149,22 @@
-- Return (boolean isSegmentFinished, Segment segment).
-- Segment has value only when the isSegmentFinished is true
-- if isSegmentFinished == false, SpanList = nil
-function TracingContext:drainAfterFinished()
- if self.is_noop then
- return true, Segment:new()
+function _M.drainAfterFinished(tracingContext)
+ if tracingContext.is_noop then
+ return false, nil
end
- if self.internal.active_count ~= 0 then
- return false, nil
- elseif #self.internal.finished_spans == 0 then
+ if tracingContext.internal.active_count ~= 0 then
return false, nil
else
- 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
+ local segment = {}
+ segment.trace_id = tracingContext.trace_id
+ segment.segment_id = tracingContext.segment_id
+ segment.service_id = tracingContext.service_id
+ segment.service_inst_id = tracingContext.service_inst_id
+ segment.spans = tracingContext.internal.finished_spans
return true, segment
end
end
--------------- Internal Object-------------
--- Internal Object hosts the methods for SkyWalking LUA internal APIs only.
-
--- Create an internal instance
-function Internal:new()
- local o = {}
- setmetatable(o, self)
- self.__index = self
-
- o.self_generated_trace_id = true
- o.span_id_seq = 0
- o.active_spans = {}
- o.active_count = 0
- o.finished_spans = {}
-
- return o
-end
-
--- add the segment ref if this is the first ref of this context
-function Internal:addRefIfFirst(ref)
- if self.self_generated_trace_id == true then
- self.self_generated_trace_id = false
- self.owner.trace_id = ref.trace_id
- self.first_ref = ref
- end
-end
-
-function Internal:hasRef()
- return first_ref ~= nil
-end
-
-function Internal:getFirstRef()
- return first_ref
-end
-
-function Internal:addActive(span)
- if self.first_span == nil then
- self.first_span = span
- end
-
- -- span id starts at 0, to fit LUA, we need to plus one.
- self.active_spans[span.span_id + 1] = span
- self.active_count = self.active_count + 1
- return self.owner
-end
-
-function Internal:finishSpan(span)
- -- span id starts at 0, to fit LUA, we need to plus one.
- self.active_spans[span.span_id + 1] = nil
- self.active_count = self.active_count - 1
- self.finished_spans[#self.finished_spans + 1] = span
-
- return self.owner
-end
-
--- Generate the next span ID.
-function Internal:nextSpanID()
- local nextSpanId = self.span_id_seq
- self.span_id_seq = self.span_id_seq + 1;
- return nextSpanId
-end
----------------------------------------------
-
-return TracingContext
+return _M
diff --git a/lib/skywalking/tracing_context_test.lua b/lib/skywalking/tracing_context_test.lua
index 2308e94..c5d4420 100644
--- a/lib/skywalking/tracing_context_test.lua
+++ b/lib/skywalking/tracing_context_test.lua
@@ -1,26 +1,28 @@
---
+--
-- Licensed to the Apache Software Foundation (ASF) under one or more
-- contributor license agreements. See the NOTICE file distributed with
-- this work for additional information regarding copyright ownership.
-- The ASF licenses this file to You under the Apache License, Version 2.0
-- (the "License"); you may not use this file except in compliance with
-- the License. You may obtain a copy of the License at
---
+--
-- http://www.apache.org/licenses/LICENSE-2.0
---
+--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
---
+--
local lu = require('luaunit')
local TC = require('tracing_context')
+local Segment = require('segment')
+local Span = require('span')
TestTracingContext = {}
function TestTracingContext:testNew()
- local context = TC:new(1, 1)
+ local context = TC.new(1, 1)
lu.assertNotNil(context)
lu.assertNotNil(context.segment_id[1])
lu.assertNotNil(context.segment_id[2])
@@ -30,24 +32,24 @@
end
function TestTracingContext:testInternal_NextSpanSeqID()
- local context = TC:new(1, 1)
+ local context = TC.new(1, 1)
- lu.assertEquals(context.internal:nextSpanID(), 0)
+ lu.assertEquals(context.internal.nextSpanID(context.internal), 0)
end
function TestTracingContext:testInternal_addActive()
- local context = TC:new(1, 1)
+ local context = TC.new(1, 1)
local mockSpan = {span_id = 0}
- context.internal:addActive(mockSpan)
+ context.internal.addActive(context.internal, mockSpan)
- lu.assertEquals(#(context.internal.active_spans), 1)
+ lu.assertEquals(#context.internal.active_spans, 1)
end
function TestTracingContext:testSpanStack()
- local context = TC:new(1, 1)
- local span1 = context:createEntrySpan('entry_op')
- local span2 = context:createExitSpan("exit_op", span1, "127.0.0.1")
+ local context = TC.new(1, 1)
+ local span1 = TC.createEntrySpan(context, 'entry_op')
+ local span2 = TC.createExitSpan(context, "exit_op", span1, "127.0.0.1")
local activeSpans = context.internal.active_spans
local finishedSpans = context.internal.finished_spans
@@ -56,30 +58,30 @@
lu.assertEquals(span1, activeSpans[1])
lu.assertEquals(span2, activeSpans[2])
- span2:finish()
+ Span.finish(span2)
lu.assertNotNil(span2.end_time)
lu.assertEquals(#(activeSpans), 1)
lu.assertEquals(#(finishedSpans), 1)
- span1:finish()
+ Span.finish(span1)
lu.assertNotNil(span1.end_time)
lu.assertEquals(#(activeSpans), 0)
lu.assertEquals(#(finishedSpans), 2)
- local isSegmentFinished, segment = context:drainAfterFinished()
+ local isSegmentFinished, segment = TC.drainAfterFinished(context)
lu.assertEquals(span2, segment.spans[1])
lu.assertEquals(span1, segment.spans[2])
- local segmentBuilder = segment:transform()
+ local segmentBuilder = Segment.transform(segment)
local JSON = require('cjson').encode(segmentBuilder)
lu.assertTrue(#JSON > 0)
end
function TestTracingContext:testNewNoOP()
- local noopContext = TC:newNoOP()
+ local noopContext = TC.newNoOP()
- local span1 = noopContext:createEntrySpan('entry_op')
- local span2 = noopContext:createExitSpan("exit_op", span1, "127.0.0.1")
+ local span1 = TC.createEntrySpan(noopContext, 'entry_op')
+ local span2 = TC.createExitSpan(noopContext, "exit_op", span1, "127.0.0.1")
lu.assertEquals(true, span1.is_noop)
lu.assertEquals(true, span2.is_noop)
diff --git a/t/segment_ref.t b/t/segment_ref.t
new file mode 100644
index 0000000..8c9f76a
--- /dev/null
+++ b/t/segment_ref.t
@@ -0,0 +1,117 @@
+use Test::Nginx::Socket 'no_plan';
+
+use Cwd qw(cwd);
+my $pwd = cwd();
+
+repeat_each(1);
+no_long_string();
+no_shuffle();
+no_root_location();
+log_level('info');
+
+our $HttpConfig = qq{
+ lua_package_path "$pwd/lib/skywalking/?.lua;;";
+ error_log logs/error.log debug;
+ resolver 114.114.114.114 8.8.8.8 ipv6=off;
+ lua_shared_dict tracing_buffer 100m;
+};
+
+run_tests;
+
+__DATA__
+
+=== TEST 1: fromSW6Value
+--- http_config eval: $::HttpConfig
+--- config
+ location /t {
+ content_by_lua_block {
+ local SegmentRef = require('segment_ref')
+ local ref = SegmentRef.fromSW6Value('1-My40LjU=-MS4yLjM=-4-1-1-IzEyNy4wLjAuMTo4MDgw-Iy9wb3J0YWw=-MTIz')
+ ngx.say(ref.trace_id)
+ ngx.say(ref.segment_id)
+ ngx.say(ref.span_id)
+ ngx.say(ref.parent_service_instance_id)
+ ngx.say(ref.entry_service_instance_id)
+ ngx.say(ref.network_address)
+ ngx.say(ref.network_address_id)
+ ngx.say(ref.entry_endpoint_name)
+ ngx.say(ref.entry_endpoint_id)
+ ngx.say(ref.parent_endpoint_name)
+ ngx.say(ref.parent_endpoint_id)
+ }
+ }
+--- request
+GET /t
+--- response_body
+345
+123
+4
+1
+1
+127.0.0.1:8080
+0
+/portal
+0
+nil
+123
+--- no_error_log
+[error]
+
+
+
+=== TEST 2: Serialize
+--- http_config eval: $::HttpConfig
+--- config
+ location /t {
+ content_by_lua_block {
+ local SegmentRef = require('segment_ref')
+ 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
+ ngx.say(SegmentRef.serialize(ref))
+ }
+ }
+--- request
+GET /t
+--- response_body
+1-My40LjU=-MS4yLjM=-4-1-1-IzEyNy4wLjAuMTo4MDgw-Iy9wb3J0YWw=-MTIz
+--- no_error_log
+[error]
+
+
+
+=== TEST 3: Transform
+--- http_config eval: $::HttpConfig
+--- config
+ location /t {
+ content_by_lua_block {
+ local SegmentRef = require('segment_ref')
+ local cjson = require("cjson")
+
+ 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 = SegmentRef.transform(ref)
+ local inJSON = cjson.encode(refProtocol)
+ ngx.say(string.len(inJSON) > 0)
+ }
+ }
+--- request
+GET /t
+--- response_body
+true
+--- no_error_log
+[error]
diff --git a/t/util.t b/t/util.t
index 53f6094..e526e4f 100644
--- a/t/util.t
+++ b/t/util.t
@@ -19,6 +19,7 @@
run_tests;
__DATA__
+
=== TEST 1: timestamp
--- http_config eval: $::HttpConfig
--- config