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