blob: 0c4d5e5ba3ab2013e9f45e6c1e9f3c8477f244a5 [file] [log] [blame]
// Licensed to 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. Apache Software Foundation (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.
package core
import (
"math"
"sync"
"time"
"github.com/apache/skywalking-go/plugins/core/reporter"
commonv3 "skywalking.apache.org/repo/goapi/collect/common/v3"
agentv3 "skywalking.apache.org/repo/goapi/collect/language/agent/v3"
)
type DefaultSpan struct {
Refs []reporter.SpanContext
tracer *Tracer
StartTime time.Time
EndTime time.Time
OperationName string
Peer string
Layer agentv3.SpanLayer
ComponentID int32
Tags []*commonv3.KeyStringValuePair
Logs []*agentv3.Log
IsError bool
SpanType SpanType
Parent TracingSpan
InAsyncMode bool
AsyncModeFinished bool
AsyncOpLocker *sync.Mutex
}
func NewDefaultSpan(tracer *Tracer, parent TracingSpan) *DefaultSpan {
return &DefaultSpan{
tracer: tracer,
StartTime: time.Now(),
SpanType: SpanTypeLocal,
Parent: parent,
}
}
// For TracingSpan
func (ds *DefaultSpan) SetOperationName(name string) {
if ds.InAsyncMode {
ds.AsyncOpLocker.Lock()
defer ds.AsyncOpLocker.Unlock()
}
ds.OperationName = name
}
func (ds *DefaultSpan) GetOperationName() string {
return ds.OperationName
}
func (ds *DefaultSpan) SetPeer(peer string) {
if ds.InAsyncMode {
ds.AsyncOpLocker.Lock()
defer ds.AsyncOpLocker.Unlock()
}
ds.Peer = peer
}
func (ds *DefaultSpan) GetPeer() string {
return ds.Peer
}
func (ds *DefaultSpan) SetSpanLayer(layer int32) {
if ds.InAsyncMode {
ds.AsyncOpLocker.Lock()
defer ds.AsyncOpLocker.Unlock()
}
ds.Layer = agentv3.SpanLayer(layer)
}
func (ds *DefaultSpan) GetSpanLayer() agentv3.SpanLayer {
return ds.Layer
}
func (ds *DefaultSpan) SetComponent(componentID int32) {
if ds.InAsyncMode {
ds.AsyncOpLocker.Lock()
defer ds.AsyncOpLocker.Unlock()
}
ds.ComponentID = componentID
}
func (ds *DefaultSpan) GetComponent() int32 {
return ds.ComponentID
}
func (ds *DefaultSpan) Tag(key, value string) {
if ds.InAsyncMode {
ds.AsyncOpLocker.Lock()
defer ds.AsyncOpLocker.Unlock()
}
for _, tag := range ds.Tags {
if tag.Key == key {
tag.Value = value
return
}
}
ds.Tags = append(ds.Tags, &commonv3.KeyStringValuePair{Key: key, Value: value})
}
func (ds *DefaultSpan) Log(ll ...string) {
if ds.InAsyncMode {
ds.AsyncOpLocker.Lock()
defer ds.AsyncOpLocker.Unlock()
}
data := make([]*commonv3.KeyStringValuePair, 0, int32(math.Ceil(float64(len(ll))/2.0)))
var kvp *commonv3.KeyStringValuePair
for i, l := range ll {
if i%2 == 0 {
kvp = &commonv3.KeyStringValuePair{}
data = append(data, kvp)
kvp.Key = l
} else if kvp != nil {
kvp.Value = l
}
}
ds.Logs = append(ds.Logs, &agentv3.Log{Time: Millisecond(time.Now()), Data: data})
}
func (ds *DefaultSpan) Error(ll ...string) {
if ds.InAsyncMode {
ds.AsyncOpLocker.Lock()
defer ds.AsyncOpLocker.Unlock()
}
ds.IsError = true
ds.Log(ll...)
}
func (ds *DefaultSpan) End(changeParent bool) {
ds.EndTime = time.Now()
if changeParent {
if ctx := getTracingContext(); ctx != nil {
ctx.SaveActiveSpan(ds.Parent)
}
}
}
func (ds *DefaultSpan) IsEntry() bool {
return ds.SpanType == SpanTypeEntry
}
func (ds *DefaultSpan) IsExit() bool {
return ds.SpanType == SpanTypeExit
}
func (ds *DefaultSpan) IsValid() bool {
return ds.EndTime.IsZero()
}
func (ds *DefaultSpan) ParentSpan() TracingSpan {
return ds.Parent
}
func (ds *DefaultSpan) PrepareAsync() {
if ds.InAsyncMode {
panic("already in async mode")
}
ds.InAsyncMode = true
ds.AsyncModeFinished = false
ds.AsyncOpLocker = &sync.Mutex{}
}
func (ds *DefaultSpan) AsyncFinish() {
if !ds.InAsyncMode {
panic("not in async mode")
}
if ds.AsyncModeFinished {
panic("already finished async")
}
ds.AsyncModeFinished = true
ds.AsyncOpLocker = nil
}