blob: 292a1cf8f318b8c65de56a743e32d75de3956730 [file] [log] [blame]
Girish Kumar46d7c3a2020-05-18 12:06:33 +00001/*
Joey Armstrong9cdee9f2024-01-03 04:56:14 -05002 * Copyright 2018-2024 Open Networking Foundation (ONF) and the ONF Contributors
Girish Kumar46d7c3a2020-05-18 12:06:33 +00003
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17// File contains utility functions to support Open Tracing in conjunction with
18// Enhanced Logging based on context propagation
19
20package log
21
22import (
23 "context"
24 "errors"
Girish Kumare9d35bb2020-08-18 06:47:59 +000025 "fmt"
Girish Kumar46d7c3a2020-05-18 12:06:33 +000026 "io"
27 "os"
Girish Kumar131ef8f2020-06-10 14:50:42 +000028 "strings"
Girish Kumare9d35bb2020-08-18 06:47:59 +000029 "sync"
Abhay Kumar40252eb2025-10-13 13:25:53 +000030
31 "github.com/opentracing/opentracing-go"
32 jtracing "github.com/uber/jaeger-client-go"
33 jcfg "github.com/uber/jaeger-client-go/config"
Girish Kumar46d7c3a2020-05-18 12:06:33 +000034)
35
Girish Kumar131ef8f2020-06-10 14:50:42 +000036const (
37 RootSpanNameKey = "op-name"
38)
39
Girish Kumare9d35bb2020-08-18 06:47:59 +000040// Global Settings governing the Log Correlation and Tracing features. Should only
41// be updated through the exposed public methods
42type LogFeaturesManager struct {
43 isTracePublishingEnabled bool
44 isLogCorrelationEnabled bool
45 componentName string // Name of component extracted from ENV variable
46 activeTraceAgentAddress string
47 lock sync.Mutex
48}
Girish Kumar131ef8f2020-06-10 14:50:42 +000049
Girish Kumare9d35bb2020-08-18 06:47:59 +000050var globalLFM *LogFeaturesManager = &LogFeaturesManager{}
51
52func GetGlobalLFM() *LogFeaturesManager {
53 return globalLFM
54}
55
56// A Wrapper to utilize currently Active Tracer instance. The middleware library being used for generating
57// Spans for GRPC API calls does not support dynamically setting the Active Tracer similar to the SetGlobalTracer method
58// provided by OpenTracing API
59type ActiveTracerProxy struct {
60}
61
62func (atw ActiveTracerProxy) StartSpan(operationName string, opts ...opentracing.StartSpanOption) opentracing.Span {
63 return opentracing.GlobalTracer().StartSpan(operationName, opts...)
64}
65
66func (atw ActiveTracerProxy) Inject(sm opentracing.SpanContext, format interface{}, carrier interface{}) error {
67 return opentracing.GlobalTracer().Inject(sm, format, carrier)
68}
69
70func (atw ActiveTracerProxy) Extract(format interface{}, carrier interface{}) (opentracing.SpanContext, error) {
71 return opentracing.GlobalTracer().Extract(format, carrier)
72}
Girish Kumar131ef8f2020-06-10 14:50:42 +000073
74// Jaeger complaint Logger instance to redirect logs to Default Logger
75type traceLogger struct {
76 logger *clogger
77}
78
79func (tl traceLogger) Error(msg string) {
80 tl.logger.Error(context.Background(), msg)
81}
82
83func (tl traceLogger) Infof(msg string, args ...interface{}) {
84 // Tracing logs should be performed only at Debug Verbosity
85 tl.logger.Debugf(context.Background(), msg, args...)
86}
87
Girish Kumare9d35bb2020-08-18 06:47:59 +000088// Wrapper to handle correct Closer call at the time of Process Termination
89type traceCloser struct {
90}
91
92func (c traceCloser) Close() error {
93 currentActiveTracer := opentracing.GlobalTracer()
94 if currentActiveTracer != nil {
95 if jTracer, ok := currentActiveTracer.(*jtracing.Tracer); ok {
96 jTracer.Close()
97 }
Girish Kumar131ef8f2020-06-10 14:50:42 +000098 }
99
Girish Kumare9d35bb2020-08-18 06:47:59 +0000100 return nil
101}
Girish Kumar131ef8f2020-06-10 14:50:42 +0000102
Girish Kumare9d35bb2020-08-18 06:47:59 +0000103// Method to Initialize Jaeger based Tracing client based on initial status of Tracing Publish and Log Correlation
104func (lfm *LogFeaturesManager) InitTracingAndLogCorrelation(tracePublishEnabled bool, traceAgentAddress string, logCorrelationEnabled bool) (io.Closer, error) {
105 lfm.componentName = os.Getenv("COMPONENT_NAME")
106 if lfm.componentName == "" {
Abhay Kumar40252eb2025-10-13 13:25:53 +0000107 return nil, errors.New("unable to retrieve PoD Component Name from Runtime env")
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000108 }
109
Girish Kumare9d35bb2020-08-18 06:47:59 +0000110 lfm.lock.Lock()
111 defer lfm.lock.Unlock()
112
113 // Use NoopTracer when both Tracing Publishing and Log Correlation are disabled
114 if !tracePublishEnabled && !logCorrelationEnabled {
115 logger.Info(context.Background(), "Skipping Global Tracer initialization as both Trace publish and Log correlation are configured as disabled")
116 lfm.isTracePublishingEnabled = false
117 lfm.isLogCorrelationEnabled = false
118 opentracing.SetGlobalTracer(opentracing.NoopTracer{})
119 return traceCloser{}, nil
120 }
121
122 tracer, _, err := lfm.constructJaegerTracer(tracePublishEnabled, traceAgentAddress, true)
123 if err != nil {
124 return nil, err
125 }
126
127 // Initialize variables representing Active Status
128 opentracing.SetGlobalTracer(tracer)
129 lfm.isTracePublishingEnabled = tracePublishEnabled
130 lfm.activeTraceAgentAddress = traceAgentAddress
131 lfm.isLogCorrelationEnabled = logCorrelationEnabled
132 return traceCloser{}, nil
133}
134
135// Method to replace Active Tracer along with graceful closer of previous tracer
136func (lfm *LogFeaturesManager) replaceActiveTracer(tracer opentracing.Tracer) {
137 currentActiveTracer := opentracing.GlobalTracer()
138 opentracing.SetGlobalTracer(tracer)
139
140 if currentActiveTracer != nil {
141 if jTracer, ok := currentActiveTracer.(*jtracing.Tracer); ok {
142 jTracer.Close()
143 }
144 }
145}
146
147func (lfm *LogFeaturesManager) GetLogCorrelationStatus() bool {
148 lfm.lock.Lock()
149 defer lfm.lock.Unlock()
150
151 return lfm.isLogCorrelationEnabled
152}
153
154func (lfm *LogFeaturesManager) SetLogCorrelationStatus(isEnabled bool) {
155 lfm.lock.Lock()
156 defer lfm.lock.Unlock()
157
158 if isEnabled == lfm.isLogCorrelationEnabled {
Girish Kumar503cce62020-08-24 16:34:39 +0000159 logger.Debugf(context.Background(), "Ignoring Log Correlation Set operation with value %t; current Status same as desired", isEnabled)
Girish Kumare9d35bb2020-08-18 06:47:59 +0000160 return
161 }
162
163 if isEnabled {
164 // Construct new Tracer instance if Log Correlation has been enabled and current active tracer is a NoopTracer instance.
165 // Continue using the earlier tracer instance in case of any error
166 if _, ok := opentracing.GlobalTracer().(opentracing.NoopTracer); ok {
167 tracer, _, err := lfm.constructJaegerTracer(lfm.isTracePublishingEnabled, lfm.activeTraceAgentAddress, false)
168 if err != nil {
Girish Kumar503cce62020-08-24 16:34:39 +0000169 logger.Warnf(context.Background(), "Log Correlation Enable operation failed with error: %s", err.Error())
Girish Kumare9d35bb2020-08-18 06:47:59 +0000170 return
171 }
172
173 lfm.replaceActiveTracer(tracer)
174 }
175
176 lfm.isLogCorrelationEnabled = true
Girish Kumar503cce62020-08-24 16:34:39 +0000177 logger.Info(context.Background(), "Log Correlation has been enabled")
Girish Kumare9d35bb2020-08-18 06:47:59 +0000178
179 } else {
180 // Switch to NoopTracer when Log Correlation has been disabled and Tracing Publish is already disabled
181 if _, ok := opentracing.GlobalTracer().(opentracing.NoopTracer); !ok && !lfm.isTracePublishingEnabled {
182 lfm.replaceActiveTracer(opentracing.NoopTracer{})
183 }
184
185 lfm.isLogCorrelationEnabled = false
Girish Kumar503cce62020-08-24 16:34:39 +0000186 logger.Info(context.Background(), "Log Correlation has been disabled")
Girish Kumare9d35bb2020-08-18 06:47:59 +0000187 }
188}
189
190func (lfm *LogFeaturesManager) GetTracePublishingStatus() bool {
191 lfm.lock.Lock()
192 defer lfm.lock.Unlock()
193
194 return lfm.isTracePublishingEnabled
195}
196
197func (lfm *LogFeaturesManager) SetTracePublishingStatus(isEnabled bool) {
198 lfm.lock.Lock()
199 defer lfm.lock.Unlock()
200
201 if isEnabled == lfm.isTracePublishingEnabled {
Girish Kumar503cce62020-08-24 16:34:39 +0000202 logger.Debugf(context.Background(), "Ignoring Trace Publishing Set operation with value %t; current Status same as desired", isEnabled)
Girish Kumare9d35bb2020-08-18 06:47:59 +0000203 return
204 }
205
206 if isEnabled {
207 // Construct new Tracer instance if Tracing Publish has been enabled (even if a Jaeger instance is already active)
208 // This is needed to ensure that a fresh lookup of Jaeger Agent address is performed again while performing
209 // Disable-Enable of Tracing
210 tracer, _, err := lfm.constructJaegerTracer(isEnabled, lfm.activeTraceAgentAddress, false)
211 if err != nil {
Girish Kumar503cce62020-08-24 16:34:39 +0000212 logger.Warnf(context.Background(), "Trace Publishing Enable operation failed with error: %s", err.Error())
Girish Kumare9d35bb2020-08-18 06:47:59 +0000213 return
214 }
215 lfm.replaceActiveTracer(tracer)
216
217 lfm.isTracePublishingEnabled = true
Girish Kumar503cce62020-08-24 16:34:39 +0000218 logger.Info(context.Background(), "Tracing Publishing has been enabled")
Girish Kumare9d35bb2020-08-18 06:47:59 +0000219 } else {
220 // Switch to NoopTracer when Tracing Publish has been disabled and Log Correlation is already disabled
221 if !lfm.isLogCorrelationEnabled {
222 lfm.replaceActiveTracer(opentracing.NoopTracer{})
223 } else {
224 // Else construct a new Jaeger Instance with publishing disabled
225 tracer, _, err := lfm.constructJaegerTracer(isEnabled, lfm.activeTraceAgentAddress, false)
226 if err != nil {
Girish Kumar503cce62020-08-24 16:34:39 +0000227 logger.Warnf(context.Background(), "Trace Publishing Disable operation failed with error: %s", err.Error())
Girish Kumare9d35bb2020-08-18 06:47:59 +0000228 return
229 }
230 lfm.replaceActiveTracer(tracer)
231 }
232
233 lfm.isTracePublishingEnabled = false
Girish Kumar503cce62020-08-24 16:34:39 +0000234 logger.Info(context.Background(), "Tracing Publishing has been disabled")
Girish Kumare9d35bb2020-08-18 06:47:59 +0000235 }
236}
237
238// Method to contruct a new Jaeger Tracer instance based on given Trace Agent address and Publish status.
239// The last attribute indicates whether to use Loopback IP for creating Jaeger Client when the DNS lookup
240// of supplied Trace Agent address has failed. It is fine to fallback during the initialization step, but
241// not later (when enabling/disabling the status dynamically)
242func (lfm *LogFeaturesManager) constructJaegerTracer(tracePublishEnabled bool, traceAgentAddress string, fallbackToLoopbackAllowed bool) (opentracing.Tracer, io.Closer, error) {
243 cfg := jcfg.Configuration{ServiceName: lfm.componentName}
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000244
Girish Kumar131ef8f2020-06-10 14:50:42 +0000245 var err error
246 var jReporterConfig jcfg.ReporterConfig
247 var jReporterCfgOption jtracing.Reporter
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000248
Girish Kumare9d35bb2020-08-18 06:47:59 +0000249 logger.Info(context.Background(), "Constructing new Jaeger Tracer instance")
Girish Kumar131ef8f2020-06-10 14:50:42 +0000250
Girish Kumare9d35bb2020-08-18 06:47:59 +0000251 // Attempt Trace Agent Address first; will fallback to Loopback IP if it fails
252 jReporterConfig = jcfg.ReporterConfig{LocalAgentHostPort: traceAgentAddress, LogSpans: true}
Girish Kumar503cce62020-08-24 16:34:39 +0000253 jReporterCfgOption, err = jReporterConfig.NewReporter(lfm.componentName, jtracing.NewNullMetrics(), traceLogger{logger: logger.(*clogger)})
Girish Kumare9d35bb2020-08-18 06:47:59 +0000254
255 if err != nil {
256 if !fallbackToLoopbackAllowed {
257 return nil, nil, errors.New("Reporter Creation for given Trace Agent address " + traceAgentAddress + " failed with error : " + err.Error())
Girish Kumar131ef8f2020-06-10 14:50:42 +0000258 }
Girish Kumar131ef8f2020-06-10 14:50:42 +0000259
Girish Kumare9d35bb2020-08-18 06:47:59 +0000260 logger.Infow(context.Background(), "Unable to create Reporter with given Trace Agent address",
261 Fields{"error": err, "address": traceAgentAddress})
262 // The Reporter initialization may fail due to Invalid Agent address or non-existent Agent (DNS lookup failure).
263 // It is essential for Tracer Instance to still start for correct Span propagation needed for log correlation.
264 // Thus, falback to use loopback IP for Reporter initialization before throwing back any error
265 tracePublishEnabled = false
266
Girish Kumar131ef8f2020-06-10 14:50:42 +0000267 jReporterConfig.LocalAgentHostPort = "127.0.0.1:6831"
Girish Kumare9d35bb2020-08-18 06:47:59 +0000268 jReporterCfgOption, err = jReporterConfig.NewReporter(lfm.componentName, jtracing.NewNullMetrics(), traceLogger{logger: logger.(*clogger)})
Girish Kumar131ef8f2020-06-10 14:50:42 +0000269 if err != nil {
Girish Kumare9d35bb2020-08-18 06:47:59 +0000270 return nil, nil, errors.New("Failed to initialize Jaeger Tracing due to Reporter creation error : " + err.Error())
Girish Kumar131ef8f2020-06-10 14:50:42 +0000271 }
272 }
273
274 // To start with, we are using Constant Sampling type
275 samplerParam := 0 // 0: Do not publish span, 1: Publish
276 if tracePublishEnabled {
277 samplerParam = 1
278 }
279 jSamplerConfig := jcfg.SamplerConfig{Type: "const", Param: float64(samplerParam)}
Girish Kumare9d35bb2020-08-18 06:47:59 +0000280 jSamplerCfgOption, err := jSamplerConfig.NewSampler(lfm.componentName, jtracing.NewNullMetrics())
Girish Kumar131ef8f2020-06-10 14:50:42 +0000281 if err != nil {
Girish Kumare9d35bb2020-08-18 06:47:59 +0000282 return nil, nil, errors.New("Unable to create Sampler : " + err.Error())
Girish Kumar131ef8f2020-06-10 14:50:42 +0000283 }
284
Girish Kumare9d35bb2020-08-18 06:47:59 +0000285 return cfg.NewTracer(jcfg.Reporter(jReporterCfgOption), jcfg.Sampler(jSamplerCfgOption))
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000286}
287
Girish Kumar446274f2020-07-22 03:17:28 +0000288func TerminateTracing(c io.Closer) {
289 err := c.Close()
290 if err != nil {
Girish Kumar950f21e2020-08-19 17:42:29 +0000291 logger.Error(context.Background(), "error-while-closing-jaeger-tracer", Fields{"err": err})
Girish Kumar446274f2020-07-22 03:17:28 +0000292 }
293}
294
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000295// Extracts details of Execution Context as log fields from the Tracing Span injected into the
296// context instance. Following log fields are extracted:
297// 1. Operation Name : key as 'op-name' and value as Span operation name
298// 2. Operation Id : key as 'op-id' and value as 64 bit Span Id in hex digits string
299//
300// Additionally, any tags present in Span are also extracted to use as log fields e.g. device-id.
301//
302// If no Span is found associated with context, blank slice is returned without any log fields
Girish Kumar503cce62020-08-24 16:34:39 +0000303func (lfm *LogFeaturesManager) ExtractContextAttributes(ctx context.Context) []interface{} {
304 if !lfm.isLogCorrelationEnabled {
Girish Kumar131ef8f2020-06-10 14:50:42 +0000305 return make([]interface{}, 0)
306 }
307
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000308 attrMap := make(map[string]interface{})
309
310 if ctx != nil {
311 if span := opentracing.SpanFromContext(ctx); span != nil {
312 if jspan, ok := span.(*jtracing.Span); ok {
Girish Kumar131ef8f2020-06-10 14:50:42 +0000313 // Add Log fields for operation identified by Root Level Span (Trace)
Girish Kumare9d35bb2020-08-18 06:47:59 +0000314 opId := fmt.Sprintf("%016x", jspan.SpanContext().TraceID().Low) // Using Sprintf to avoid removal of leading 0s
Girish Kumar131ef8f2020-06-10 14:50:42 +0000315 opName := jspan.BaggageItem(RootSpanNameKey)
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000316
Girish Kumare9d35bb2020-08-18 06:47:59 +0000317 taskId := fmt.Sprintf("%016x", uint64(jspan.SpanContext().SpanID())) // Using Sprintf to avoid removal of leading 0s
Girish Kumar131ef8f2020-06-10 14:50:42 +0000318 taskName := jspan.OperationName()
319
320 if opName == "" {
321 span.SetBaggageItem(RootSpanNameKey, taskName)
322 opName = taskName
323 }
324
325 attrMap["op-id"] = opId
326 attrMap["op-name"] = opName
327
328 // Add Log fields for task identified by Current Span, if it is different
329 // than operation
330 if taskId != opId {
331 attrMap["task-id"] = taskId
332 attrMap["task-name"] = taskName
333 }
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000334
335 for k, v := range jspan.Tags() {
Girish Kumar131ef8f2020-06-10 14:50:42 +0000336 // Ignore the special tags added by Jaeger, middleware (sampler.type, span.*) present in the span
337 if strings.HasPrefix(k, "sampler.") || strings.HasPrefix(k, "span.") || k == "component" {
338 continue
339 }
340
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000341 attrMap[k] = v
342 }
Girish Kumar74240652020-07-10 11:54:28 +0000343
344 processBaggageItems := func(k, v string) bool {
345 if k != "rpc-span-name" {
346 attrMap[k] = v
347 }
348 return true
349 }
350
351 jspan.SpanContext().ForeachBaggageItem(processBaggageItems)
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000352 }
353 }
354 }
355
356 return serializeMap(attrMap)
357}
358
Girish Kumar131ef8f2020-06-10 14:50:42 +0000359// Method to inject additional log fields into Span e.g. device-id
360func EnrichSpan(ctx context.Context, keyAndValues ...Fields) {
361 span := opentracing.SpanFromContext(ctx)
362 if span != nil {
Girish Kumar74240652020-07-10 11:54:28 +0000363 if jspan, ok := span.(*jtracing.Span); ok {
364 // Inject as a BaggageItem when the Span is the Root Span so that it propagates
365 // across the components along with Root Span (called as Trace)
366 // Else, inject as a Tag so that it is attached to the Child Task
367 isRootSpan := false
368 if jspan.SpanContext().TraceID().String() == jspan.SpanContext().SpanID().String() {
369 isRootSpan = true
370 }
371
372 for _, field := range keyAndValues {
373 for k, v := range field {
374 if isRootSpan {
375 span.SetBaggageItem(k, v.(string))
376 } else {
377 span.SetTag(k, v)
378 }
379 }
Girish Kumar131ef8f2020-06-10 14:50:42 +0000380 }
381 }
382 }
383}
384
385// Method to inject Error into the Span in event of any operation failure
386func MarkSpanError(ctx context.Context, err error) {
387 span := opentracing.SpanFromContext(ctx)
Girish Kumare9d35bb2020-08-18 06:47:59 +0000388 if span != nil {
389 span.SetTag("error", true)
390 span.SetTag("err", err)
391 }
Girish Kumar131ef8f2020-06-10 14:50:42 +0000392}
393
394// Creates a Child Span from Parent Span embedded in passed context. Should be used before starting a new major
395// operation in Synchronous or Asynchronous mode (go routine), such as following:
396// 1. Start of all implemented External API methods unless using a interceptor for auto-injection of Span (Server side impl)
397// 2. Just before calling an Third-Party lib which is invoking a External API (etcd, kafka)
398// 3. In start of a Go Routine responsible for performing a major task involving significant duration
399// 4. Any method which is suspected to be time consuming...
400func CreateChildSpan(ctx context.Context, taskName string, keyAndValues ...Fields) (opentracing.Span, context.Context) {
Girish Kumare9d35bb2020-08-18 06:47:59 +0000401 if !GetGlobalLFM().GetLogCorrelationStatus() && !GetGlobalLFM().GetTracePublishingStatus() {
Girish Kumar131ef8f2020-06-10 14:50:42 +0000402 return opentracing.NoopTracer{}.StartSpan(taskName), ctx
403 }
404
405 parentSpan := opentracing.SpanFromContext(ctx)
406 childSpan, newCtx := opentracing.StartSpanFromContext(ctx, taskName)
407
408 if parentSpan == nil || parentSpan.BaggageItem(RootSpanNameKey) == "" {
409 childSpan.SetBaggageItem(RootSpanNameKey, taskName)
410 }
411
412 EnrichSpan(newCtx, keyAndValues...)
413 return childSpan, newCtx
414}
415
416// Creates a Async Child Span with Follows-From relationship from Parent Span embedded in passed context.
417// Should be used only in scenarios when
418// a) There is dis-continuation in execution and thus result of Child span does not affect the Parent flow at all
419// b) The execution of Child Span is guaranteed to start after the completion of Parent Span
420// In case of any confusion, use CreateChildSpan method
421// Some situations where this method would be suitable includes Kafka Async RPC call, Propagation of Event across
422// a channel etc.
423func CreateAsyncSpan(ctx context.Context, taskName string, keyAndValues ...Fields) (opentracing.Span, context.Context) {
Girish Kumare9d35bb2020-08-18 06:47:59 +0000424 if !GetGlobalLFM().GetLogCorrelationStatus() && !GetGlobalLFM().GetTracePublishingStatus() {
Girish Kumar131ef8f2020-06-10 14:50:42 +0000425 return opentracing.NoopTracer{}.StartSpan(taskName), ctx
426 }
427
428 var asyncSpan opentracing.Span
429 var newCtx context.Context
430
431 parentSpan := opentracing.SpanFromContext(ctx)
432
433 // We should always be creating Aysnc span from a Valid parent span. If not, create a Child span instead
434 if parentSpan == nil {
Girish Kumar950f21e2020-08-19 17:42:29 +0000435 logger.Warn(context.Background(), "Async span must be created with a Valid parent span only")
Girish Kumar131ef8f2020-06-10 14:50:42 +0000436 asyncSpan, newCtx = opentracing.StartSpanFromContext(ctx, taskName)
437 } else {
438 // Use Background context as the base for Follows-from case; else new span is getting both Child and FollowsFrom relationship
439 asyncSpan, newCtx = opentracing.StartSpanFromContext(context.Background(), taskName, opentracing.FollowsFrom(parentSpan.Context()))
440 }
441
442 if parentSpan == nil || parentSpan.BaggageItem(RootSpanNameKey) == "" {
443 asyncSpan.SetBaggageItem(RootSpanNameKey, taskName)
444 }
445
446 EnrichSpan(newCtx, keyAndValues...)
447 return asyncSpan, newCtx
448}
449
450// Extracts the span from Source context and injects into the supplied Target context.
451// This should be used in situations wherein we are calling a time-sensitive operation (etcd update) and hence
452// had a context.Background() used earlier to avoid any cancellation/timeout of operation by passed context.
453// This will allow propagation of span with a different base context (and not the original context)
454func WithSpanFromContext(targetCtx, sourceCtx context.Context) context.Context {
455 span := opentracing.SpanFromContext(sourceCtx)
456 return opentracing.ContextWithSpan(targetCtx, span)
457}
458
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000459// Utility method to convert log Fields into array of interfaces expected by zap logger methods
460func serializeMap(fields Fields) []interface{} {
461 data := make([]interface{}, len(fields)*2)
462 i := 0
463 for k, v := range fields {
464 data[i] = k
465 data[i+1] = v
466 i = i + 2
467 }
468 return data
469}