未验证 提交 c6aca516 编写于 作者: wu-sheng's avatar wu-sheng 提交者: GitHub

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's avatar吴晟 Wu Sheng <wu.sheng@foxmail.com>
Co-authored-by: NDaming <zteny@foxmail.com>
上级 6f8e8ad7
......@@ -13,9 +13,10 @@ packages/
/dist/
/docker/snapshot/*.gz
.mvn/wrapper/*.jar
.factorypath
.vscode
.factorypath
.vscode
.checkstyle
.externalToolBuilders
/test/plugin/dist
/test/plugin/workspace
/t/servroot/
......@@ -8,9 +8,9 @@ Apache SkyWalking Nginx Agent
![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 @@ All HTTP 1.1 requests go through Nginx could be collected by this agent.
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 @@ The following APIs are for developers or using this lib out of the Nginx case.
## 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 @@ Have no release yet.
* QQ Group: 392443393(2000/2000, not available), 901167865(available)
# License
Apache 2.0
\ No newline at end of file
Apache 2.0
--
--
-- 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 @@ function Client:registerService(metadata_buffer, backend_http_uri)
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 @@ function Client:registerService(metadata_buffer, backend_http_uri)
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 @@ function Client:registerServiceInstance(metadata_buffer, backend_http_uri)
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 @@ function Client:registerServiceInstance(metadata_buffer, backend_http_uri)
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 @@ function Client:ping(metadata_buffer, backend_http_uri)
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 @@ function Client:reportTraces(metadata_buffer, backend_http_uri)
["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 @@ function Client:reportTraces(metadata_buffer, backend_http_uri)
end
end
return Client
\ No newline at end of file
return Client
--
--
-- 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 @@ function Register:newServiceRegister(unRegisterServiceName)
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 @@ function Register:newServiceInstanceRegister(registeredServiceId, serviceInstUUI
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 @@ function Register:newServiceInstancePingPkg(registeredServiceInstId, serviceInst
return serviceInstancePingPkg
end
return Register
\ No newline at end of file
return _M
......@@ -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
......@@ -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
return o
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,
-- }
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
--
--
-- 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 @@ local cjson = require("cjson")
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 @@ TestSegmentRef = {}
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 @@ TestSegmentRef = {}
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 @@ TestSegmentRef = {}
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() )
--
--
-- 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 SegmentRef = require("segment_ref")
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 @@ function Span:createEntrySpan(operationName, context, parent, contextCarrier)
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 @@ function Span:createExitSpan(operationName, context, parent, peer, contextCarrie
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 @@ function Span:createExitSpan(operationName, context, parent, peer, contextCarrie
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 @@ function Span:createExitSpan(operationName, context, parent, peer, contextCarrie
local parentEndpointName
local parentEndpointId = -1
if firstSpan.is_entry then
parentEndpointName = firstSpan.operation_name
parentEndpointId = 0
......@@ -136,194 +137,185 @@ function Span:createExitSpan(operationName, context, parent, peer, contextCarrie
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
o.operation_name = operationName
o.span_id = context.internal:nextSpanID()
function _M.new(operationName, context, parent)
local span = _M.newNoOP()
span.is_noop = false
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
context.internal:addActive(o)
-- o.start_time = Util.timestamp()
o.refs = {}
o.owner = context
return o
end
span.parent_span_id = parent.span_id
end
function Span:newNoOP()
local o = {}
setmetatable(o, self)
self.__index = self
context.internal.addActive(context.internal, span)
span.refs = {}
span.owner = context
o.is_noop = true
return o
return span
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
--
--
-- 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 @@ local SpanLayer = require("span_layer")
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 @@ TestSpan = {}
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 @@ TestSpan = {}
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 @@ TestSpan = {}
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 @@ TestSpan = {}
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 @@ TestSpan = {}
-- end TestSpan
os.exit( lu.LuaUnit.run() )
\ No newline at end of file
os.exit( lu.LuaUnit.run() )
--
--
-- 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 @@ function Tracer:start(upstream_name)
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 @@ function Tracer:start(upstream_name)
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 @@ function Tracer:start(upstream_name)
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 @@ end
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 @@ function Tracer:prepareForReport()
end
end
return Tracer
\ No newline at end of file
return Tracer
......@@ -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,
}
function TracingContext:new(serviceId, serviceInstID)
local o = {}
setmetatable(o, self)
self.__index = self
-- 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,
-- }
if serviceInstID == nil then
return TracingContext:newNoOP()
-- 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
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 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
function TracingContext:newNoOP()
local o = {}
setmetatable(o, self)
self.__index = self
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
o.is_noop = true
return o
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
-- Delegate to Span:createEntrySpan
-- 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 _M.newNoOP()
end
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
-- 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 @@ end
-- 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
--
--
-- 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 @@ TestTracingContext = {}
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 @@ TestTracingContext = {}
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)
......
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]
......@@ -19,6 +19,7 @@ our $HttpConfig = qq{
run_tests;
__DATA__
=== TEST 1: timestamp
--- http_config eval: $::HttpConfig
--- config
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册