blob: 590fa94a4f3485ef99820f34c6a8b9bd9644638a [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 tracing
import (
"github.com/apache/skywalking-go/plugins/core/operator"
)
var (
errParameter = operator.NewError("parameter are nil")
)
// CreateEntrySpan creates a new entry span.
// operationName is the name of the span.
// extractor is the extractor to extract the context from the carrier.
// opts is the options to create the span.
func CreateEntrySpan(operationName string, extractor Extractor, opts ...SpanOption) (s Span, err error) {
if operationName == "" || extractor == nil {
return nil, errParameter
}
op := operator.GetOperator()
if op == nil {
return &NoopSpan{}, nil
}
span, err := op.Tracing().(operator.TracingOperator).CreateEntrySpan(operationName, extractorWrapper(extractor), copyOptsAsInterface(opts)...)
if err != nil {
return nil, err
}
return newSpanAdapter(span.(AdaptSpan)), nil
}
// CreateLocalSpan creates a new local span.
// operationName is the name of the span.
// opts is the options to create the span.
func CreateLocalSpan(operationName string, opts ...SpanOption) (s Span, err error) {
if operationName == "" {
return nil, errParameter
}
op := operator.GetOperator()
if op == nil {
return &NoopSpan{}, nil
}
span, err := op.Tracing().(operator.TracingOperator).CreateLocalSpan(operationName, copyOptsAsInterface(opts)...)
if err != nil {
return nil, err
}
return newSpanAdapter(span.(AdaptSpan)), nil
}
// CreateExitSpan creates a new exit span.
// operationName is the name of the span.
// peer is the peer address of the span.
// injector is the injector to inject the context into the carrier.
// opts is the options to create the span.
func CreateExitSpan(operationName, peer string, injector Injector, opts ...SpanOption) (s Span, err error) {
if operationName == "" || peer == "" || injector == nil {
return nil, errParameter
}
op := operator.GetOperator()
if op == nil {
return &NoopSpan{}, nil
}
span, err := op.Tracing().(operator.TracingOperator).CreateExitSpan(operationName, peer, injectorWrapper(injector), copyOptsAsInterface(opts)...)
if err != nil {
return nil, err
}
return newSpanAdapter(span.(AdaptSpan)), nil
}
// ActiveSpan returns the current active span, it can be got the current span in the current goroutine.
// If the current goroutine is not in the context of the span, it will return nil.
// If get the span from other goroutine, it can only get information but cannot be operated.
func ActiveSpan() Span {
op := operator.GetOperator()
if op == nil {
return nil
}
if span, ok := op.Tracing().(operator.TracingOperator).ActiveSpan().(AdaptSpan); ok {
return newSpanAdapter(span)
}
return nil
}
// GetRuntimeContextValue returns the value of the key in the runtime context, which is current goroutine.
// The value can also read from the goroutine which is created by the current goroutine
func GetRuntimeContextValue(key string) interface{} {
op := operator.GetOperator()
if op == nil {
return nil
}
return op.Tracing().(operator.TracingOperator).GetRuntimeContextValue(key)
}
// SetRuntimeContextValue sets the value of the key in the runtime context.
func SetRuntimeContextValue(key string, val interface{}) {
op := operator.GetOperator()
if op != nil {
op.Tracing().(operator.TracingOperator).SetRuntimeContextValue(key, val)
}
}
// DebugStack returns the stack of the current goroutine, for getting details when plugin broken.
func DebugStack() []byte {
op := operator.GetOperator()
if op == nil {
return nil
}
return op.DebugStack()
}
func copyOptsAsInterface(opts []SpanOption) []interface{} {
optsVal := make([]interface{}, len(opts))
for i := range opts {
optsVal[i] = opts[i]
}
return optsVal
}
type extractorWrapperImpl struct {
extractor Extractor
}
func (e *extractorWrapperImpl) Fun() func(headerKey string) (string, error) {
return e.extractor
}
func extractorWrapper(extractor Extractor) *extractorWrapperImpl {
return &extractorWrapperImpl{extractor: extractor}
}
type injectorWrapperImpl struct {
injector Injector
}
func (i *injectorWrapperImpl) Fun() func(headerKey, headerValue string) error {
return i.injector
}
func injectorWrapper(injector Injector) *injectorWrapperImpl {
return &injectorWrapperImpl{injector: injector}
}
var noopSpanTraceOrSegmentID = "N/A"
type NoopSpan struct {
}
func (n *NoopSpan) TraceID() string {
return noopSpanTraceOrSegmentID
}
func (n *NoopSpan) TraceSegmentID() string {
return noopSpanTraceOrSegmentID
}
func (n *NoopSpan) SpanID() int32 {
return -1
}
func (n *NoopSpan) SetOperationName(string) {
}
func (n *NoopSpan) SetPeer(string) {
}
func (n *NoopSpan) SetSpanLayer(SpanLayer) {
}
func (n *NoopSpan) SetComponent(int32) {
}
func (n *NoopSpan) Tag(Tag, string) {
}
func (n *NoopSpan) Log(...string) {
}
func (n *NoopSpan) Error(...string) {
}
func (n *NoopSpan) End() {
}