module/apmot/wrapper.go (127 lines of code) (raw):
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. 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 apmot // import "go.elastic.co/apm/module/apmot/v2"
import (
"context"
opentracing "github.com/opentracing/opentracing-go"
"github.com/opentracing/opentracing-go/log"
"go.elastic.co/apm/v2"
)
func init() {
// We override the apm context functions so that transactions
// and spans started with the native API are wrapped and made
// available as OpenTracing spans.
apm.OverrideContextWithSpan = contextWithSpan
apm.OverrideContextWithTransaction = contextWithTransaction
apm.OverrideSpanFromContext = spanFromContext
apm.OverrideTransactionFromContext = transactionFromContext
}
func contextWithSpan(ctx context.Context, apmSpan *apm.Span) context.Context {
return opentracing.ContextWithSpan(ctx, apmSpanWrapper{
spanContext: apmSpanWrapperContext{
span: apmSpan,
transaction: transactionFromContext(ctx),
},
})
}
func contextWithTransaction(ctx context.Context, apmTransaction *apm.Transaction) context.Context {
return opentracing.ContextWithSpan(ctx, apmTransactionWrapper{
spanContext: apmTransactionWrapperContext{
transaction: apmTransaction,
},
})
}
func spanFromContext(ctx context.Context) *apm.Span {
otSpan, _ := opentracing.SpanFromContext(ctx).(interface {
Span() *apm.Span
})
if otSpan == nil {
return nil
}
return otSpan.Span()
}
func transactionFromContext(ctx context.Context) *apm.Transaction {
otSpan := opentracing.SpanFromContext(ctx)
if otSpan == nil {
return nil
}
if apmSpanContext, ok := otSpan.Context().(interface {
Transaction() *apm.Transaction
}); ok {
return apmSpanContext.Transaction()
}
return nil
}
// apmSpanWrapperContext is an opentracing.SpanContext that wraps
// an apm.Span and apm.Transaction.
type apmSpanWrapperContext struct {
span *apm.Span
transaction *apm.Transaction
}
// TraceContext returns ctx.span.TraceContext(). This is used to set the
// parent trace context for spans created through the OpenTracing API.
func (ctx apmSpanWrapperContext) TraceContext() apm.TraceContext {
return ctx.span.TraceContext()
}
// Transaction returns ctx.transaction. This is used to obtain the transaction
// to use for creating spans through the OpenTracing API.
func (ctx apmSpanWrapperContext) Transaction() *apm.Transaction {
return ctx.transaction
}
// ForeachBaggageItem is a no-op; we do not support baggage propagation.
func (apmSpanWrapperContext) ForeachBaggageItem(handler func(k, v string) bool) {}
// apmSpanWrapper is an opentracing.Span that wraps an apmSpanWrapperContext.
type apmSpanWrapper struct {
apmBaseWrapper
spanContext apmSpanWrapperContext
}
// Span returns s.spanContext.span. This is used by spanFromContext.
func (s apmSpanWrapper) Span() *apm.Span {
return s.spanContext.span
}
// SetOperationName sets or changes the operation name.
func (s apmSpanWrapper) SetOperationName(operationName string) opentracing.Span {
return s
}
// SetTag adds or changes a tag.
func (s apmSpanWrapper) SetTag(key string, value interface{}) opentracing.Span {
return s
}
// Context returns the span's current context.
//
// It is valid to call Context after calling Finish or FinishWithOptions.
// The resulting context is also valid after the span is finished.
func (s apmSpanWrapper) Context() opentracing.SpanContext {
return s.spanContext
}
// BaggageItem returns the empty string; we do not support baggage.
func (apmSpanWrapper) BaggageItem(key string) string {
return ""
}
// SetBaggageItem is a no-op; we do not support baggage.
func (s apmSpanWrapper) SetBaggageItem(key, val string) opentracing.Span {
// We do not support baggage.
return s
}
// apmTransactionWrapperContext is an opentracing.SpanContext that wraps
// an apm.Transaction.
type apmTransactionWrapperContext struct {
transaction *apm.Transaction
}
// TraceContext returns ctx.transaction.TraceContext(). This is used to set the
// parent trace context for spans created through the OpenTracing API.
func (ctx apmTransactionWrapperContext) TraceContext() apm.TraceContext {
return ctx.transaction.TraceContext()
}
// Transaction returns ctx.transaction. This is used to obtain the transaction
// to use for creating spans through the OpenTracing API.
func (ctx apmTransactionWrapperContext) Transaction() *apm.Transaction {
return ctx.transaction
}
// ForeachBaggageItem is a no-op; we do not support baggage propagation.
func (apmTransactionWrapperContext) ForeachBaggageItem(handler func(k, v string) bool) {}
// apmTransactionWrapper is an opentracing.Span that wraps an apmTransactionWrapperContext.
type apmTransactionWrapper struct {
apmBaseWrapper
spanContext apmTransactionWrapperContext
}
// SetOperationName sets or changes the operation name.
func (s apmTransactionWrapper) SetOperationName(operationName string) opentracing.Span {
return s
}
// SetTag adds or changes a tag.
func (s apmTransactionWrapper) SetTag(key string, value interface{}) opentracing.Span {
return s
}
// Context returns the span's current context.
//
// It is valid to call Context after calling Finish or FinishWithOptions.
// The resulting context is also valid after the span is finished.
func (s apmTransactionWrapper) Context() opentracing.SpanContext {
return s.spanContext
}
// BaggageItem returns the empty string; we do not support baggage.
func (apmTransactionWrapper) BaggageItem(key string) string {
return ""
}
// SetBaggageItem is a no-op; we do not support baggage.
func (s apmTransactionWrapper) SetBaggageItem(key, val string) opentracing.Span {
// We do not support baggage.
return s
}
type apmBaseWrapper struct{}
// Tracer returns the Tracer that created this span.
func (apmBaseWrapper) Tracer() opentracing.Tracer {
return opentracing.NoopTracer{}
}
// Finish ends the span; this (or FinishWithOptions) must be the last method
// call on the span, except for calls to Context which may be called at any
// time.
func (apmBaseWrapper) Finish() {}
// FinishWithOptions is like Finish, but provides explicit control over the
// end timestamp and log data.
func (apmBaseWrapper) FinishWithOptions(opentracing.FinishOptions) {}
// LogKV is a no-op for APM wrapper spans.
func (apmBaseWrapper) LogKV(keyValues ...interface{}) {
// No-op.
}
// LogFields is a no-op for APM wrapper spans.
func (apmBaseWrapper) LogFields(fields ...log.Field) {
// No-op.
}
// LogEvent is deprecated, and is a no-op.
func (apmBaseWrapper) LogEvent(event string) {
// Deprecated, no-op.
}
// LogEventWithPayload is deprecated, and is a no-op.
func (apmBaseWrapper) LogEventWithPayload(event string, payload interface{}) {
// Deprecated, no-op.
}
// Log is deprecated, and is a no-op.
func (apmBaseWrapper) Log(ld opentracing.LogData) {
// Deprecated, no-op.
}