span.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673
  1. // Unless explicitly stated otherwise all files in this repository are licensed
  2. // under the Apache License Version 2.0.
  3. // This product includes software developed at Datadog (https://www.datadoghq.com/).
  4. // Copyright 2016 Datadog, Inc.
  5. //go:generate msgp -unexported -marshal=false -o=span_msgp.go -tests=false
  6. package tracer
  7. import (
  8. "context"
  9. "encoding/base64"
  10. "fmt"
  11. "math"
  12. "os"
  13. "reflect"
  14. "runtime"
  15. "runtime/pprof"
  16. "strconv"
  17. "strings"
  18. "sync"
  19. "sync/atomic"
  20. "time"
  21. "gopkg.in/DataDog/dd-trace-go.v1/ddtrace"
  22. "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/ext"
  23. "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/internal"
  24. "gopkg.in/DataDog/dd-trace-go.v1/internal/globalconfig"
  25. "gopkg.in/DataDog/dd-trace-go.v1/internal/log"
  26. "gopkg.in/DataDog/dd-trace-go.v1/internal/samplernames"
  27. "gopkg.in/DataDog/dd-trace-go.v1/internal/traceprof"
  28. "github.com/DataDog/datadog-agent/pkg/obfuscate"
  29. "github.com/tinylib/msgp/msgp"
  30. "golang.org/x/xerrors"
  31. )
  32. type (
  33. // spanList implements msgp.Encodable on top of a slice of spans.
  34. spanList []*span
  35. // spanLists implements msgp.Decodable on top of a slice of spanList.
  36. // This type is only used in tests.
  37. spanLists []spanList
  38. )
  39. var (
  40. _ ddtrace.Span = (*span)(nil)
  41. _ msgp.Encodable = (*spanList)(nil)
  42. _ msgp.Decodable = (*spanLists)(nil)
  43. )
  44. // errorConfig holds customization options for setting error tags.
  45. type errorConfig struct {
  46. noDebugStack bool
  47. stackFrames uint
  48. stackSkip uint
  49. }
  50. // span represents a computation. Callers must call Finish when a span is
  51. // complete to ensure it's submitted.
  52. type span struct {
  53. sync.RWMutex `msg:"-"` // all fields are protected by this RWMutex
  54. Name string `msg:"name"` // operation name
  55. Service string `msg:"service"` // service name (i.e. "grpc.server", "http.request")
  56. Resource string `msg:"resource"` // resource name (i.e. "/user?id=123", "SELECT * FROM users")
  57. Type string `msg:"type"` // protocol associated with the span (i.e. "web", "db", "cache")
  58. Start int64 `msg:"start"` // span start time expressed in nanoseconds since epoch
  59. Duration int64 `msg:"duration"` // duration of the span expressed in nanoseconds
  60. Meta map[string]string `msg:"meta,omitempty"` // arbitrary map of metadata
  61. Metrics map[string]float64 `msg:"metrics,omitempty"` // arbitrary map of numeric metrics
  62. SpanID uint64 `msg:"span_id"` // identifier of this span
  63. TraceID uint64 `msg:"trace_id"` // identifier of the root span
  64. ParentID uint64 `msg:"parent_id"` // identifier of the span's direct parent
  65. Error int32 `msg:"error"` // error status of the span; 0 means no errors
  66. noDebugStack bool `msg:"-"` // disables debug stack traces
  67. finished bool `msg:"-"` // true if the span has been submitted to a tracer.
  68. context *spanContext `msg:"-"` // span propagation context
  69. pprofCtxActive context.Context `msg:"-"` // contains pprof.WithLabel labels to tell the profiler more about this span
  70. pprofCtxRestore context.Context `msg:"-"` // contains pprof.WithLabel labels of the parent span (if any) that need to be restored when this span finishes
  71. taskEnd func() // ends execution tracer (runtime/trace) task, if started
  72. }
  73. // Context yields the SpanContext for this Span. Note that the return
  74. // value of Context() is still valid after a call to Finish(). This is
  75. // called the span context and it is different from Go's context.
  76. func (s *span) Context() ddtrace.SpanContext { return s.context }
  77. // SetBaggageItem sets a key/value pair as baggage on the span. Baggage items
  78. // are propagated down to descendant spans and injected cross-process. Use with
  79. // care as it adds extra load onto your tracing layer.
  80. func (s *span) SetBaggageItem(key, val string) {
  81. s.context.setBaggageItem(key, val)
  82. }
  83. // BaggageItem gets the value for a baggage item given its key. Returns the
  84. // empty string if the value isn't found in this Span.
  85. func (s *span) BaggageItem(key string) string {
  86. return s.context.baggageItem(key)
  87. }
  88. // SetTag adds a set of key/value metadata to the span.
  89. func (s *span) SetTag(key string, value interface{}) {
  90. s.Lock()
  91. defer s.Unlock()
  92. // We don't lock spans when flushing, so we could have a data race when
  93. // modifying a span as it's being flushed. This protects us against that
  94. // race, since spans are marked `finished` before we flush them.
  95. if s.finished {
  96. return
  97. }
  98. switch key {
  99. case ext.Error:
  100. s.setTagError(value, errorConfig{
  101. noDebugStack: s.noDebugStack,
  102. })
  103. return
  104. }
  105. if v, ok := value.(bool); ok {
  106. s.setTagBool(key, v)
  107. return
  108. }
  109. if v, ok := value.(string); ok {
  110. if key == ext.ResourceName && s.pprofCtxActive != nil && spanResourcePIISafe(s) {
  111. // If the user overrides the resource name for the span,
  112. // update the endpoint label for the runtime profilers.
  113. //
  114. // We don't change s.pprofCtxRestore since that should
  115. // stay as the original parent span context regardless
  116. // of what we change at a lower level.
  117. s.pprofCtxActive = pprof.WithLabels(s.pprofCtxActive, pprof.Labels(traceprof.TraceEndpoint, v))
  118. pprof.SetGoroutineLabels(s.pprofCtxActive)
  119. }
  120. s.setMeta(key, v)
  121. return
  122. }
  123. if v, ok := toFloat64(value); ok {
  124. s.setMetric(key, v)
  125. return
  126. }
  127. if v, ok := value.(fmt.Stringer); ok {
  128. defer func() {
  129. if e := recover(); e != nil {
  130. if v := reflect.ValueOf(value); v.Kind() == reflect.Ptr && v.IsNil() {
  131. // If .String() panics due to a nil receiver, we want to catch this
  132. // and replace the string value with "<nil>", just as Sprintf does.
  133. // Other panics should not be handled.
  134. s.setMeta(key, "<nil>")
  135. return
  136. }
  137. panic(e)
  138. }
  139. }()
  140. s.setMeta(key, v.String())
  141. return
  142. }
  143. // not numeric, not a string, not a fmt.Stringer, not a bool, and not an error
  144. s.setMeta(key, fmt.Sprint(value))
  145. }
  146. // setSamplingPriority locks then span, then updates the sampling priority.
  147. // It also updates the trace's sampling priority.
  148. func (s *span) setSamplingPriority(priority int, sampler samplernames.SamplerName) {
  149. s.Lock()
  150. defer s.Unlock()
  151. s.setSamplingPriorityLocked(priority, sampler)
  152. }
  153. // Root returns the root span of the span's trace. The return value shouldn't be
  154. // nil as long as the root span is valid and not finished.
  155. func (s *span) Root() Span {
  156. return s.root()
  157. }
  158. // root returns the root span of the span's trace. The return value shouldn't be
  159. // nil as long as the root span is valid and not finished.
  160. // As opposed to the public Root method, this one returns the actual span type
  161. // when internal usage requires it (to avoid type assertions from Root's return
  162. // value).
  163. func (s *span) root() *span {
  164. if s == nil || s.context == nil {
  165. return nil
  166. }
  167. if s.context.trace == nil {
  168. return nil
  169. }
  170. return s.context.trace.root
  171. }
  172. // SetUser associates user information to the current trace which the
  173. // provided span belongs to. The options can be used to tune which user
  174. // bit of information gets monitored. In case of distributed traces,
  175. // the user id can be propagated across traces using the WithPropagation() option.
  176. // See https://docs.datadoghq.com/security_platform/application_security/setup_and_configure/?tab=set_user#add-user-information-to-traces
  177. func (s *span) SetUser(id string, opts ...UserMonitoringOption) {
  178. var cfg UserMonitoringConfig
  179. for _, fn := range opts {
  180. fn(&cfg)
  181. }
  182. root := s.root()
  183. trace := root.context.trace
  184. root.Lock()
  185. defer root.Unlock()
  186. if cfg.PropagateID {
  187. // Delete usr.id from the tags since _dd.p.usr.id takes precedence
  188. delete(root.Meta, keyUserID)
  189. idenc := base64.StdEncoding.EncodeToString([]byte(id))
  190. trace.setPropagatingTag(keyPropagatedUserID, idenc)
  191. s.context.updated = true
  192. } else {
  193. // Unset the propagated user ID so that a propagated user ID coming from upstream won't be propagated anymore.
  194. trace.unsetPropagatingTag(keyPropagatedUserID)
  195. if _, ok := trace.propagatingTags[keyPropagatedUserID]; ok {
  196. s.context.updated = true
  197. }
  198. delete(root.Meta, keyPropagatedUserID)
  199. // setMeta is used since the span is already locked
  200. root.setMeta(keyUserID, id)
  201. }
  202. for k, v := range map[string]string{
  203. keyUserEmail: cfg.Email,
  204. keyUserName: cfg.Name,
  205. keyUserScope: cfg.Scope,
  206. keyUserRole: cfg.Role,
  207. keyUserSessionID: cfg.SessionID,
  208. } {
  209. if v != "" {
  210. root.setMeta(k, v)
  211. }
  212. }
  213. }
  214. // setSamplingPriorityLocked updates the sampling priority.
  215. // It also updates the trace's sampling priority.
  216. func (s *span) setSamplingPriorityLocked(priority int, sampler samplernames.SamplerName) {
  217. // We don't lock spans when flushing, so we could have a data race when
  218. // modifying a span as it's being flushed. This protects us against that
  219. // race, since spans are marked `finished` before we flush them.
  220. if s.finished {
  221. return
  222. }
  223. s.setMetric(keySamplingPriority, float64(priority))
  224. s.context.setSamplingPriority(priority, sampler)
  225. }
  226. // setTagError sets the error tag. It accounts for various valid scenarios.
  227. // This method is not safe for concurrent use.
  228. func (s *span) setTagError(value interface{}, cfg errorConfig) {
  229. setError := func(yes bool) {
  230. if yes {
  231. if s.Error == 0 {
  232. // new error
  233. atomic.AddInt32(&s.context.errors, 1)
  234. }
  235. s.Error = 1
  236. } else {
  237. if s.Error > 0 {
  238. // flip from active to inactive
  239. atomic.AddInt32(&s.context.errors, -1)
  240. }
  241. s.Error = 0
  242. }
  243. }
  244. if s.finished {
  245. return
  246. }
  247. switch v := value.(type) {
  248. case bool:
  249. // bool value as per Opentracing spec.
  250. setError(v)
  251. case error:
  252. // if anyone sets an error value as the tag, be nice here
  253. // and provide all the benefits.
  254. setError(true)
  255. s.setMeta(ext.ErrorMsg, v.Error())
  256. s.setMeta(ext.ErrorType, reflect.TypeOf(v).String())
  257. if !cfg.noDebugStack {
  258. s.setMeta(ext.ErrorStack, takeStacktrace(cfg.stackFrames, cfg.stackSkip))
  259. }
  260. switch v.(type) {
  261. case xerrors.Formatter:
  262. s.setMeta(ext.ErrorDetails, fmt.Sprintf("%+v", v))
  263. case fmt.Formatter:
  264. // pkg/errors approach
  265. s.setMeta(ext.ErrorDetails, fmt.Sprintf("%+v", v))
  266. }
  267. case nil:
  268. // no error
  269. setError(false)
  270. default:
  271. // in all other cases, let's assume that setting this tag
  272. // is the result of an error.
  273. setError(true)
  274. }
  275. }
  276. // defaultStackLength specifies the default maximum size of a stack trace.
  277. const defaultStackLength = 32
  278. // takeStacktrace takes a stack trace of maximum n entries, skipping the first skip entries.
  279. // If n is 0, up to 20 entries are retrieved.
  280. func takeStacktrace(n, skip uint) string {
  281. if n == 0 {
  282. n = defaultStackLength
  283. }
  284. var builder strings.Builder
  285. pcs := make([]uintptr, n)
  286. // +2 to exclude runtime.Callers and takeStacktrace
  287. numFrames := runtime.Callers(2+int(skip), pcs)
  288. if numFrames == 0 {
  289. return ""
  290. }
  291. frames := runtime.CallersFrames(pcs[:numFrames])
  292. for i := 0; ; i++ {
  293. frame, more := frames.Next()
  294. if i != 0 {
  295. builder.WriteByte('\n')
  296. }
  297. builder.WriteString(frame.Function)
  298. builder.WriteByte('\n')
  299. builder.WriteByte('\t')
  300. builder.WriteString(frame.File)
  301. builder.WriteByte(':')
  302. builder.WriteString(strconv.Itoa(frame.Line))
  303. if !more {
  304. break
  305. }
  306. }
  307. return builder.String()
  308. }
  309. // setMeta sets a string tag. This method is not safe for concurrent use.
  310. func (s *span) setMeta(key, v string) {
  311. if s.Meta == nil {
  312. s.Meta = make(map[string]string, 1)
  313. }
  314. delete(s.Metrics, key)
  315. switch key {
  316. case ext.SpanName:
  317. s.Name = v
  318. case ext.ServiceName:
  319. s.Service = v
  320. case ext.ResourceName:
  321. s.Resource = v
  322. case ext.SpanType:
  323. s.Type = v
  324. default:
  325. s.Meta[key] = v
  326. }
  327. }
  328. // setTagBool sets a boolean tag on the span.
  329. func (s *span) setTagBool(key string, v bool) {
  330. switch key {
  331. case ext.AnalyticsEvent:
  332. if v {
  333. s.setMetric(ext.EventSampleRate, 1.0)
  334. } else {
  335. s.setMetric(ext.EventSampleRate, 0.0)
  336. }
  337. case ext.ManualDrop:
  338. if v {
  339. s.setSamplingPriorityLocked(ext.PriorityUserReject, samplernames.Manual)
  340. }
  341. case ext.ManualKeep:
  342. if v {
  343. s.setSamplingPriorityLocked(ext.PriorityUserKeep, samplernames.Manual)
  344. }
  345. default:
  346. if v {
  347. s.setMeta(key, "true")
  348. } else {
  349. s.setMeta(key, "false")
  350. }
  351. }
  352. }
  353. // setMetric sets a numeric tag, in our case called a metric. This method
  354. // is not safe for concurrent use.
  355. func (s *span) setMetric(key string, v float64) {
  356. if s.Metrics == nil {
  357. s.Metrics = make(map[string]float64, 1)
  358. }
  359. delete(s.Meta, key)
  360. switch key {
  361. case ext.ManualKeep:
  362. if v == float64(samplernames.AppSec) {
  363. s.setSamplingPriorityLocked(ext.PriorityUserKeep, samplernames.AppSec)
  364. }
  365. case ext.SamplingPriority:
  366. // ext.SamplingPriority is deprecated in favor of ext.ManualKeep and ext.ManualDrop.
  367. // We have it here for backward compatibility.
  368. s.setSamplingPriorityLocked(int(v), samplernames.Manual)
  369. default:
  370. s.Metrics[key] = v
  371. }
  372. }
  373. // Finish closes this Span (but not its children) providing the duration
  374. // of its part of the tracing session.
  375. func (s *span) Finish(opts ...ddtrace.FinishOption) {
  376. t := now()
  377. if len(opts) > 0 {
  378. cfg := ddtrace.FinishConfig{
  379. NoDebugStack: s.noDebugStack,
  380. }
  381. for _, fn := range opts {
  382. fn(&cfg)
  383. }
  384. if !cfg.FinishTime.IsZero() {
  385. t = cfg.FinishTime.UnixNano()
  386. }
  387. if cfg.Error != nil {
  388. s.Lock()
  389. s.setTagError(cfg.Error, errorConfig{
  390. noDebugStack: cfg.NoDebugStack,
  391. stackFrames: cfg.StackFrames,
  392. stackSkip: cfg.SkipStackFrames,
  393. })
  394. s.Unlock()
  395. }
  396. }
  397. if s.taskEnd != nil {
  398. s.taskEnd()
  399. }
  400. s.finish(t)
  401. if s.pprofCtxRestore != nil {
  402. // Restore the labels of the parent span so any CPU samples after this
  403. // point are attributed correctly.
  404. pprof.SetGoroutineLabels(s.pprofCtxRestore)
  405. }
  406. }
  407. // SetOperationName sets or changes the operation name.
  408. func (s *span) SetOperationName(operationName string) {
  409. s.Lock()
  410. defer s.Unlock()
  411. // We don't lock spans when flushing, so we could have a data race when
  412. // modifying a span as it's being flushed. This protects us against that
  413. // race, since spans are marked `finished` before we flush them.
  414. if s.finished {
  415. // already finished
  416. return
  417. }
  418. s.Name = operationName
  419. }
  420. func (s *span) finish(finishTime int64) {
  421. s.Lock()
  422. defer s.Unlock()
  423. // We don't lock spans when flushing, so we could have a data race when
  424. // modifying a span as it's being flushed. This protects us against that
  425. // race, since spans are marked `finished` before we flush them.
  426. if s.finished {
  427. // already finished
  428. return
  429. }
  430. if s.Duration == 0 {
  431. s.Duration = finishTime - s.Start
  432. }
  433. if s.Duration < 0 {
  434. s.Duration = 0
  435. }
  436. s.finished = true
  437. keep := true
  438. if t, ok := internal.GetGlobalTracer().(*tracer); ok {
  439. // we have an active tracer
  440. if t.config.canComputeStats() && shouldComputeStats(s) {
  441. // the agent supports computed stats
  442. select {
  443. case t.stats.In <- newAggregableSpan(s, t.obfuscator):
  444. // ok
  445. default:
  446. log.Error("Stats channel full, disregarding span.")
  447. }
  448. }
  449. if t.config.canDropP0s() {
  450. // the agent supports dropping p0's in the client
  451. keep = shouldKeep(s)
  452. }
  453. }
  454. if keep {
  455. // a single kept span keeps the whole trace.
  456. s.context.trace.keep()
  457. }
  458. s.context.finish()
  459. }
  460. // newAggregableSpan creates a new summary for the span s, within an application
  461. // version version.
  462. func newAggregableSpan(s *span, obfuscator *obfuscate.Obfuscator) *aggregableSpan {
  463. var statusCode uint32
  464. if sc, ok := s.Meta["http.status_code"]; ok && sc != "" {
  465. if c, err := strconv.Atoi(sc); err == nil && c > 0 && c <= math.MaxInt32 {
  466. statusCode = uint32(c)
  467. }
  468. }
  469. key := aggregation{
  470. Name: s.Name,
  471. Resource: obfuscatedResource(obfuscator, s.Type, s.Resource),
  472. Service: s.Service,
  473. Type: s.Type,
  474. Synthetics: strings.HasPrefix(s.Meta[keyOrigin], "synthetics"),
  475. StatusCode: statusCode,
  476. }
  477. return &aggregableSpan{
  478. key: key,
  479. Start: s.Start,
  480. Duration: s.Duration,
  481. TopLevel: s.Metrics[keyTopLevel] == 1,
  482. Error: s.Error,
  483. }
  484. }
  485. // textNonParsable specifies the text that will be assigned to resources for which the resource
  486. // can not be parsed due to an obfuscation error.
  487. const textNonParsable = "Non-parsable SQL query"
  488. // obfuscatedResource returns the obfuscated version of the given resource. It is
  489. // obfuscated using the given obfuscator for the given span type typ.
  490. func obfuscatedResource(o *obfuscate.Obfuscator, typ, resource string) string {
  491. if o == nil {
  492. return resource
  493. }
  494. switch typ {
  495. case "sql", "cassandra":
  496. oq, err := o.ObfuscateSQLString(resource)
  497. if err != nil {
  498. log.Error("Error obfuscating stats group resource %q: %v", resource, err)
  499. return textNonParsable
  500. }
  501. return oq.Query
  502. case "redis":
  503. return o.QuantizeRedisString(resource)
  504. default:
  505. return resource
  506. }
  507. }
  508. // shouldKeep reports whether the trace should be kept.
  509. // a single span being kept implies the whole trace being kept.
  510. func shouldKeep(s *span) bool {
  511. if p, ok := s.context.samplingPriority(); ok && p > 0 {
  512. // positive sampling priorities stay
  513. return true
  514. }
  515. if atomic.LoadInt32(&s.context.errors) > 0 {
  516. // traces with any span containing an error get kept
  517. return true
  518. }
  519. if v, ok := s.Metrics[ext.EventSampleRate]; ok {
  520. return sampledByRate(s.TraceID, v)
  521. }
  522. return false
  523. }
  524. // shouldComputeStats mentions whether this span needs to have stats computed for.
  525. // Warning: callers must guard!
  526. func shouldComputeStats(s *span) bool {
  527. if v, ok := s.Metrics[keyMeasured]; ok && v == 1 {
  528. return true
  529. }
  530. if v, ok := s.Metrics[keyTopLevel]; ok && v == 1 {
  531. return true
  532. }
  533. return false
  534. }
  535. // String returns a human readable representation of the span. Not for
  536. // production, just debugging.
  537. func (s *span) String() string {
  538. s.RLock()
  539. defer s.RUnlock()
  540. lines := []string{
  541. fmt.Sprintf("Name: %s", s.Name),
  542. fmt.Sprintf("Service: %s", s.Service),
  543. fmt.Sprintf("Resource: %s", s.Resource),
  544. fmt.Sprintf("TraceID: %d", s.TraceID),
  545. fmt.Sprintf("SpanID: %d", s.SpanID),
  546. fmt.Sprintf("ParentID: %d", s.ParentID),
  547. fmt.Sprintf("Start: %s", time.Unix(0, s.Start)),
  548. fmt.Sprintf("Duration: %s", time.Duration(s.Duration)),
  549. fmt.Sprintf("Error: %d", s.Error),
  550. fmt.Sprintf("Type: %s", s.Type),
  551. "Tags:",
  552. }
  553. for key, val := range s.Meta {
  554. lines = append(lines, fmt.Sprintf("\t%s:%s", key, val))
  555. }
  556. for key, val := range s.Metrics {
  557. lines = append(lines, fmt.Sprintf("\t%s:%f", key, val))
  558. }
  559. return strings.Join(lines, "\n")
  560. }
  561. // Format implements fmt.Formatter.
  562. func (s *span) Format(f fmt.State, c rune) {
  563. switch c {
  564. case 's':
  565. fmt.Fprint(f, s.String())
  566. case 'v':
  567. if svc := globalconfig.ServiceName(); svc != "" {
  568. fmt.Fprintf(f, "dd.service=%s ", svc)
  569. }
  570. if tr, ok := internal.GetGlobalTracer().(*tracer); ok {
  571. if tr.config.env != "" {
  572. fmt.Fprintf(f, "dd.env=%s ", tr.config.env)
  573. }
  574. if tr.config.version != "" {
  575. fmt.Fprintf(f, "dd.version=%s ", tr.config.version)
  576. }
  577. } else {
  578. if env := os.Getenv("DD_ENV"); env != "" {
  579. fmt.Fprintf(f, "dd.env=%s ", env)
  580. }
  581. if v := os.Getenv("DD_VERSION"); v != "" {
  582. fmt.Fprintf(f, "dd.version=%s ", v)
  583. }
  584. }
  585. fmt.Fprintf(f, `dd.trace_id="%d" dd.span_id="%d"`, s.TraceID, s.SpanID)
  586. default:
  587. fmt.Fprintf(f, "%%!%c(ddtrace.Span=%v)", c, s)
  588. }
  589. }
  590. const (
  591. keySamplingPriority = "_sampling_priority_v1"
  592. keySamplingPriorityRate = "_dd.agent_psr"
  593. keyDecisionMaker = "_dd.p.dm"
  594. keyServiceHash = "_dd.dm.service_hash"
  595. keyOrigin = "_dd.origin"
  596. keyHostname = "_dd.hostname"
  597. keyRulesSamplerAppliedRate = "_dd.rule_psr"
  598. keyRulesSamplerLimiterRate = "_dd.limit_psr"
  599. keyMeasured = "_dd.measured"
  600. // keyTopLevel is the key of top level metric indicating if a span is top level.
  601. // A top level span is a local root (parent span of the local trace) or the first span of each service.
  602. keyTopLevel = "_dd.top_level"
  603. // keyPropagationError holds any error from propagated trace tags (if any)
  604. keyPropagationError = "_dd.propagation_error"
  605. // keySpanSamplingMechanism specifies the sampling mechanism by which an individual span was sampled
  606. keySpanSamplingMechanism = "_dd.span_sampling.mechanism"
  607. // keySingleSpanSamplingRuleRate specifies the configured sampling probability for the single span sampling rule.
  608. keySingleSpanSamplingRuleRate = "_dd.span_sampling.rule_rate"
  609. // keySingleSpanSamplingMPS specifies the configured limit for the single span sampling rule
  610. // that the span matched. If there is no configured limit, then this tag is omitted.
  611. keySingleSpanSamplingMPS = "_dd.span_sampling.max_per_second"
  612. // keyPropagatedUserID holds the propagated user identifier, if user id propagation is enabled.
  613. keyPropagatedUserID = "_dd.p.usr.id"
  614. )
  615. // The following set of tags is used for user monitoring and set through calls to span.SetUser().
  616. const (
  617. keyUserID = "usr.id"
  618. keyUserEmail = "usr.email"
  619. keyUserName = "usr.name"
  620. keyUserRole = "usr.role"
  621. keyUserScope = "usr.scope"
  622. keyUserSessionID = "usr.session_id"
  623. )
  624. const (
  625. // samplingMechanismSingleSpan specifies value reserved to indicate that a span was kept
  626. // on account of a single span sampling rule.
  627. samplingMechanismSingleSpan = 8
  628. )