github.com/waldiirawan/apm-agent-go/v2@v2.2.2/gocontext.go (about)

     1  // Licensed to Elasticsearch B.V. under one or more contributor
     2  // license agreements. See the NOTICE file distributed with
     3  // this work for additional information regarding copyright
     4  // ownership. Elasticsearch B.V. licenses this file to you under
     5  // the Apache License, Version 2.0 (the "License"); you may
     6  // not use this file except in compliance with the License.
     7  // You may obtain a copy of the License at
     8  //
     9  //     http://www.apache.org/licenses/LICENSE-2.0
    10  //
    11  // Unless required by applicable law or agreed to in writing,
    12  // software distributed under the License is distributed on an
    13  // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    14  // KIND, either express or implied.  See the License for the
    15  // specific language governing permissions and limitations
    16  // under the License.
    17  
    18  package apm // import "github.com/waldiirawan/apm-agent-go/v2"
    19  
    20  import (
    21  	"context"
    22  )
    23  
    24  // ContextWithSpan returns a copy of parent in which the given span
    25  // is stored, associated with the key ContextSpanKey.
    26  func ContextWithSpan(parent context.Context, s *Span) context.Context {
    27  	return OverrideContextWithSpan(parent, s)
    28  }
    29  
    30  // ContextWithTransaction returns a copy of parent in which the given
    31  // transaction is stored, associated with the key ContextTransactionKey.
    32  func ContextWithTransaction(parent context.Context, t *Transaction) context.Context {
    33  	return OverrideContextWithTransaction(parent, t)
    34  }
    35  
    36  // ContextWithBodyCapturer returns a copy of parent in which the given
    37  // body capturer is stored, associated with the key bodyCapturerKey.
    38  func ContextWithBodyCapturer(parent context.Context, bc *BodyCapturer) context.Context {
    39  	return OverrideContextWithBodyCapturer(parent, bc)
    40  }
    41  
    42  // SpanFromContext returns the current Span in context, if any. The span must
    43  // have been added to the context previously using ContextWithSpan, or the
    44  // top-level StartSpan function.
    45  func SpanFromContext(ctx context.Context) *Span {
    46  	return OverrideSpanFromContext(ctx)
    47  }
    48  
    49  // TransactionFromContext returns the current Transaction in context, if any.
    50  // The transaction must have been added to the context previously using
    51  // ContextWithTransaction.
    52  func TransactionFromContext(ctx context.Context) *Transaction {
    53  	return OverrideTransactionFromContext(ctx)
    54  }
    55  
    56  // BodyCapturerFromContext returns the BodyCapturer in context, if any.
    57  // The body capturer must have been added to the context previously using
    58  // ContextWithBodyCapturer.
    59  func BodyCapturerFromContext(ctx context.Context) *BodyCapturer {
    60  	return OverrideBodyCapturerFromContext(ctx)
    61  }
    62  
    63  // DetachedContext returns a new context detached from the lifetime
    64  // of ctx, but which still returns the values of ctx.
    65  //
    66  // DetachedContext can be used to maintain the trace context required
    67  // to correlate events, but where the operation is "fire-and-forget",
    68  // and should not be affected by the deadline or cancellation of ctx.
    69  func DetachedContext(ctx context.Context) context.Context {
    70  	return &detachedContext{Context: context.Background(), orig: ctx}
    71  }
    72  
    73  type detachedContext struct {
    74  	context.Context
    75  	orig context.Context
    76  }
    77  
    78  // Value returns c.orig.Value(key).
    79  func (c *detachedContext) Value(key interface{}) interface{} {
    80  	return c.orig.Value(key)
    81  }
    82  
    83  // StartSpan is equivalent to calling StartSpanOptions with a zero SpanOptions struct.
    84  func StartSpan(ctx context.Context, name, spanType string) (*Span, context.Context) {
    85  	return StartSpanOptions(ctx, name, spanType, SpanOptions{})
    86  }
    87  
    88  // StartSpanOptions starts and returns a new Span within the sampled transaction
    89  // and parent span in the context, if any. If the span isn't dropped, it will be
    90  // stored in the resulting context.
    91  //
    92  // If opts.Parent is non-zero, its value will be used in preference to any parent
    93  // span in ctx.
    94  //
    95  // StartSpanOptions always returns a non-nil Span. Its End method must be called
    96  // when the span completes.
    97  func StartSpanOptions(ctx context.Context, name, spanType string, opts SpanOptions) (*Span, context.Context) {
    98  	var span *Span
    99  	if opts.parent = SpanFromContext(ctx); opts.parent != nil {
   100  		if opts.parent.tx == nil && opts.parent.tracer != nil {
   101  			span = opts.parent.tracer.StartSpan(name, spanType, opts.parent.transactionID, opts)
   102  		} else {
   103  			span = opts.parent.tx.StartSpanOptions(name, spanType, opts)
   104  		}
   105  	} else {
   106  		tx := TransactionFromContext(ctx)
   107  		span = tx.StartSpanOptions(name, spanType, opts)
   108  	}
   109  	if !span.Dropped() {
   110  		ctx = ContextWithSpan(ctx, span)
   111  	}
   112  	return span, ctx
   113  }
   114  
   115  // CaptureError returns a new Error related to the sampled transaction
   116  // and span present in the context, if any, and sets its exception info
   117  // from err. The Error.Handled field will be set to true, and a stacktrace
   118  // set either from err, or from the caller.
   119  //
   120  // If the provided error is nil, then CaptureError will also return nil;
   121  // otherwise a non-nil Error will always be returned. If there is no
   122  // transaction or span in the context, then the returned Error's Send
   123  // method will have no effect.
   124  func CaptureError(ctx context.Context, err error) *Error {
   125  	if err == nil {
   126  		return nil
   127  	}
   128  	if span := SpanFromContext(ctx); span != nil {
   129  		if span.tracer == nil {
   130  			return &Error{cause: err, err: err.Error()}
   131  		}
   132  		e := span.tracer.NewError(err)
   133  		e.Handled = true
   134  		e.SetSpan(span)
   135  		return e
   136  	} else if tx := TransactionFromContext(ctx); tx != nil {
   137  		if tx.tracer == nil {
   138  			return &Error{cause: err, err: err.Error()}
   139  		}
   140  		e := tx.tracer.NewError(err)
   141  		e.Handled = true
   142  		bc := BodyCapturerFromContext(ctx)
   143  		if bc != nil {
   144  			e.Context.SetHTTPRequest(bc.request)
   145  			e.Context.SetHTTPRequestBody(bc)
   146  		}
   147  		e.SetTransaction(tx)
   148  		return e
   149  	} else {
   150  		return &Error{cause: err, err: err.Error()}
   151  	}
   152  }
   153  
   154  var (
   155  	// OverrideContextWithSpan returns a copy of parent in which the given
   156  	// span is stored, associated with the key ContextSpanKey.
   157  	//
   158  	// OverrideContextWithSpan is a variable to allow other packages, such
   159  	// as apmot, to replace it at package init time.
   160  	OverrideContextWithSpan = defaultContextWithSpan
   161  
   162  	// OverrideContextWithTransaction returns a copy of parent in which the
   163  	// given transaction is stored, associated with the key
   164  	// ContextTransactionKey.
   165  	//
   166  	// ContextWithTransaction is a variable to allow other packages, such as
   167  	// apmot, to replace it at package init time.
   168  	OverrideContextWithTransaction = defaultContextWithTransaction
   169  
   170  	// OverrideContextWithBodyCapturer returns a copy of parent in which the
   171  	// given body capturer is stored, associated with the key
   172  	// bodyCapturerKey.
   173  	//
   174  	// OverrideContextWithBodyCapturer is a variable to allow other packages,
   175  	// such as apmot, to replace it at package init time.
   176  	OverrideContextWithBodyCapturer = defaultContextWithBodyCapturer
   177  
   178  	// OverrideSpanFromContext returns the current Span in context, if any.
   179  	// The span must have been added to the context previously using
   180  	// ContextWithSpan, or the top-level StartSpan function.
   181  	//
   182  	// SpanFromContext is a variable to allow other packages, such as apmot,
   183  	// to replace it at package init time.
   184  	OverrideSpanFromContext = defaultSpanFromContext
   185  
   186  	// OverrideTransactionFromContext returns the current Transaction in
   187  	// context, if any. The transaction must have been added to the context
   188  	// previously using ContextWithTransaction.
   189  	//
   190  	// OverrideTransactionFromContext is a variable to allow other packages,
   191  	// such as apmot, to replace it at package init time.
   192  	OverrideTransactionFromContext = defaultTransactionFromContext
   193  
   194  	// OverrideBodyCapturerFromContext returns the BodyCapturer in context,
   195  	// if any. The body capturer must have been added to the context
   196  	// previously using ContextWithBodyCapturer.
   197  	//
   198  	// OverrideBodyCapturerFromContext is a variable to allow other
   199  	// packages, such as apmot, to replace it at package init time.
   200  	OverrideBodyCapturerFromContext = defaultBodyCapturerFromContext
   201  )
   202  
   203  type spanKey struct{}
   204  type transactionKey struct{}
   205  type bodyCapturerKey struct{}
   206  
   207  // defaultContextWithSpan is the default value for ContextWithSpan.
   208  func defaultContextWithSpan(ctx context.Context, span *Span) context.Context {
   209  	return context.WithValue(ctx, spanKey{}, span)
   210  }
   211  
   212  // defaultContextWithTransaction is the default value for ContextWithTransaction.
   213  func defaultContextWithTransaction(ctx context.Context, tx *Transaction) context.Context {
   214  	return context.WithValue(ctx, transactionKey{}, tx)
   215  }
   216  
   217  // defaultContextWithBodyCapturer is the default value for ContextWithBodyCapturer.
   218  func defaultContextWithBodyCapturer(ctx context.Context, bc *BodyCapturer) context.Context {
   219  	return context.WithValue(ctx, bodyCapturerKey{}, bc)
   220  }
   221  
   222  // defaultSpanFromContext is the default value for SpanFromContext.
   223  func defaultSpanFromContext(ctx context.Context) *Span {
   224  	span, _ := ctx.Value(spanKey{}).(*Span)
   225  	return span
   226  }
   227  
   228  // defaultTransactionFromContext is the default value for TransactionFromContext.
   229  func defaultTransactionFromContext(ctx context.Context) *Transaction {
   230  	tx, _ := ctx.Value(transactionKey{}).(*Transaction)
   231  	return tx
   232  }
   233  
   234  // defaultBodyCapturerFromContext is the default value for BodyCapturerFromContext.
   235  func defaultBodyCapturerFromContext(ctx context.Context) *BodyCapturer {
   236  	bc, _ := ctx.Value(bodyCapturerKey{}).(*BodyCapturer)
   237  	return bc
   238  }