blob: 8e19b63ec51daed867d43782781b0c9d94ba0acc [file] [log] [blame]
--
-- 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 Util = require('skywalking.util')
local Span = require('skywalking.span')
local CorrelationContext = require('skywalking.correlation_context')
local CONTEXT_CORRELATION_KEY = 'sw8-correlation'
-------------- 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,
-- -- Created span and still active
-- active_spans,
-- active_count,
-- -- Finished spans
-- finished_spans,
-- }
-- 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
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 = Util.tablepool_fetch()
internal.self_generated_trace_id = true
internal.span_id_seq = 0
internal.active_spans = Util.tablepool_fetch()
internal.active_count = 0
internal.finished_spans = Util.tablepool_fetch()
internal.addRefIfFirst = addRefIfFirst
internal.addActive = addActive
internal.finishSpan = finishSpan
internal.nextSpanID = nextSpanID
return internal
end
local _M = {}
-- local TracingContext = {
-- trace_id,
-- segment_id,
-- service,
-- service_instance,
-- is_noop = false,
-- internal,
-- }
function _M.newNoOP()
return {is_noop = true}
end
function _M.new(serviceName, serviceInstanceName)
if serviceInstanceName == nil or serviceName == nil then
return _M.newNoOP()
end
local tracing_context = Util.tablepool_fetch()
tracing_context.trace_id = Util.newID()
tracing_context.segment_id = tracing_context.trace_id
tracing_context.service = serviceName
tracing_context.service_instance = serviceInstanceName
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 _M.createEntrySpan(tracingContext, operationName, parent, contextCarrier)
if tracingContext.is_noop then
return Span.newNoOP()
end
local correlationData = ''
if contextCarrier then
correlationData = contextCarrier[CONTEXT_CORRELATION_KEY]
end
tracingContext.correlation = CorrelationContext.fromSW8Value(correlationData)
return Span.createEntrySpan(operationName, tracingContext, parent, contextCarrier)
end
-- Delegate to Span.createExitSpan
-- @param contextCarrier could be nil if don't need to inject any context to propagate
function _M.createExitSpan(tracingContext, operationName, parent, peer, contextCarrier, correlation)
if tracingContext.is_noop then
return Span.newNoOP()
end
if contextCarrier then
if correlation then
for name, value in pairs(correlation) do
CorrelationContext.put(tracingContext.correlation, name, value)
end
end
contextCarrier[CONTEXT_CORRELATION_KEY] = CorrelationContext.serialize(tracingContext.correlation)
end
return Span.createExitSpan(operationName, tracingContext, parent, peer, contextCarrier)
end
-- After all active spans finished, this segment will be treated as finished status.
-- Notice, it is different with Java agent, a finished context is still able to recreate new span, and be checked as finished again.
-- This gives the end user more flexibility. Unless it is a real reasonable case, don't call #drainAfterFinished multiple times.
--
-- Return (boolean isSegmentFinished, Segment segment).
-- Segment has value only when the isSegmentFinished is true
-- if isSegmentFinished == false, SpanList = nil
function _M.drainAfterFinished(tracingContext)
if tracingContext.is_noop then
return false, nil
end
if tracingContext.internal.active_count ~= 0 then
return false, nil
else
local segment = Util.tablepool_fetch()
segment.trace_id = tracingContext.trace_id
segment.segment_id = tracingContext.segment_id
segment.service = tracingContext.service
segment.service_instance = tracingContext.service_instance
segment.spans = tracingContext.internal.finished_spans
return true, segment
end
end
return _M