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 }