/
inferred_span.go
138 lines (120 loc) · 4.15 KB
/
inferred_span.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2022-present Datadog, Inc.
package inferredspan
import (
"crypto/rand"
"math"
"math/big"
"os"
"strings"
"time"
"github.com/DataDog/datadog-agent/pkg/config"
configUtils "github.com/DataDog/datadog-agent/pkg/config/utils"
pb "github.com/DataDog/datadog-agent/pkg/proto/pbgo/trace"
"github.com/DataDog/datadog-agent/pkg/serverless/random"
"github.com/DataDog/datadog-agent/pkg/serverless/tags"
"github.com/DataDog/datadog-agent/pkg/util/log"
)
const (
// tagInferredSpanTagSource is the key to the meta tag
// that lets us know whether this span should inherit its tags.
// Expected options are "lambda" and "self"
tagInferredSpanTagSource = "_inferred_span.tag_source"
// additional function specific tag keys to ignore
functionVersionTagKey = "function_version"
coldStartTagKey = "cold_start"
)
// InferredSpan contains the pb.Span and Async information
// of the inferredSpan for the current invocation
type InferredSpan struct {
Span *pb.Span
IsAsync bool
// CurrentInvocationStartTime is the start time of the
// current invocation not he inferred span. It is used
// for async function calls to calculate the duration.
CurrentInvocationStartTime time.Time
}
var functionTagsToIgnore = []string{
tags.FunctionARNKey,
tags.FunctionNameKey,
tags.ExecutedVersionKey,
tags.EnvKey,
tags.VersionKey,
tags.ServiceKey,
tags.RuntimeKey,
tags.MemorySizeKey,
tags.ArchitectureKey,
functionVersionTagKey,
coldStartTagKey,
}
// CheckIsInferredSpan determines if a span belongs to a managed service or not
// _inferred_span.tag_source = "self" => managed service span
// _inferred_span.tag_source = "lambda" or missing => lambda related span
func CheckIsInferredSpan(span *pb.Span) bool {
return strings.Compare(span.Meta[tagInferredSpanTagSource], "self") == 0
}
// FilterFunctionTags filters out DD tags & function specific tags
func FilterFunctionTags(input map[string]string) map[string]string {
if input == nil {
return nil
}
output := make(map[string]string)
for k, v := range input {
output[k] = v
}
// filter out DD_TAGS & DD_EXTRA_TAGS
ddTags := configUtils.GetConfiguredTags(config.Datadog, false)
for _, tag := range ddTags {
tagParts := strings.SplitN(tag, ":", 2)
if len(tagParts) != 2 {
log.Warnf("Cannot split tag %s", tag)
continue
}
tagKey := tagParts[0]
delete(output, tagKey)
}
// filter out function specific tags
for _, tagKey := range functionTagsToIgnore {
delete(output, tagKey)
}
return output
}
// GenerateSpanId creates a secure random span id in specific scenarios, otherwise return a pseudo random id
//
//nolint:revive // TODO(SERV) Fix revive linter
func GenerateSpanId() uint64 {
isSnapStart := os.Getenv(tags.InitType) == tags.SnapStartValue
if isSnapStart {
max := new(big.Int).SetUint64(math.MaxUint64)
if randId, err := rand.Int(rand.Reader, max); err != nil {
log.Debugf("Failed to generate a secure random span id: %v", err)
} else {
return randId.Uint64()
}
}
return random.Random.Uint64()
}
// GenerateInferredSpan declares and initializes a new inferred span with a
// SpanID
func (inferredSpan *InferredSpan) GenerateInferredSpan(startTime time.Time) {
inferredSpan.CurrentInvocationStartTime = startTime
inferredSpan.Span = &pb.Span{
SpanID: GenerateSpanId(),
}
log.Debugf("Generated new Inferred span: %+v", inferredSpan)
}
// IsInferredSpansEnabled is used to determine if we need to
// generate and enrich inferred spans for a particular invocation
func IsInferredSpansEnabled() bool {
return config.Datadog.GetBool("serverless.trace_enabled") && config.Datadog.GetBool("serverless.trace_managed_services")
}
// AddTagToInferredSpan is used to add new tags to the inferred span in
// inferredSpan.Span.Meta[]. Should be used before completing an inferred span.
func (inferredSpan *InferredSpan) AddTagToInferredSpan(key string, value string) {
if inferredSpan.Span.Meta == nil {
inferredSpan.Span.Meta = make(map[string]string)
}
inferredSpan.Span.Meta[key] = value
}