This repository was archived by the owner on Aug 30, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 31
/
Copy pathagent_test.go
236 lines (200 loc) · 6.42 KB
/
agent_test.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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
package main
import (
"context"
"fmt"
"net/http"
"regexp"
"runtime"
"strings"
"testing"
"time"
log "github.com/cihub/seelog"
"github.com/DataDog/datadog-trace-agent/config"
"github.com/DataDog/datadog-trace-agent/info"
"github.com/DataDog/datadog-trace-agent/model"
"github.com/DataDog/datadog-trace-agent/obfuscate"
"github.com/DataDog/datadog-trace-agent/testutil"
"github.com/stretchr/testify/assert"
)
func TestWatchdog(t *testing.T) {
if testing.Short() {
return
}
conf := config.New()
conf.APIKey = "apikey_2"
conf.MaxMemory = 1e7
conf.WatchdogInterval = time.Millisecond
// save the global mux aside, we don't want to break other tests
defaultMux := http.DefaultServeMux
http.DefaultServeMux = http.NewServeMux()
ctx, cancelFunc := context.WithCancel(context.Background())
agent := NewAgent(ctx, conf)
defer func() {
cancelFunc()
// We need to manually close the receiver as the Run() func
// should have been broken and interrupted by the watchdog panic
agent.Receiver.Stop()
http.DefaultServeMux = defaultMux
}()
var killed bool
defer func() {
if r := recover(); r != nil {
killed = true
switch v := r.(type) {
case string:
if strings.HasPrefix(v, "exceeded max memory") {
t.Logf("watchdog worked, trapped the right error: %s", v)
runtime.GC() // make sure we clean up after allocating all this
return
}
}
t.Fatalf("unexpected error: %v", r)
}
}()
// allocating a lot of memory
buf := make([]byte, 2*int64(conf.MaxMemory))
buf[0] = 1
buf[len(buf)-1] = 1
// override the default die, else our test would stop, use a plain panic() instead
oldDie := dieFunc
defer func() { dieFunc = oldDie }()
dieFunc = func(format string, args ...interface{}) {
panic(fmt.Sprintf(format, args...))
}
// after some time, the watchdog should kill this
agent.Run()
// without this. runtime could be smart and free memory before we Run()
buf[0] = 2
buf[len(buf)-1] = 2
assert.True(t, killed)
}
// Test to make sure that the joined effort of the quantizer and truncator, in that order, produce the
// desired string
func TestFormatTrace(t *testing.T) {
assert := assert.New(t)
resource := "SELECT name FROM people WHERE age = 42"
rep := strings.Repeat(" AND age = 42", 5000)
resource = resource + rep
testTrace := model.Trace{
&model.Span{
Resource: resource,
Type: "sql",
},
}
result := formatTrace(testTrace)[0]
assert.Equal(5000, len(result.Resource))
assert.NotEqual("Non-parsable SQL query", result.Resource)
assert.NotContains(result.Resource, "42")
assert.Contains(result.Resource, "SELECT name FROM people WHERE age = ?")
assert.Equal(5003, len(result.Meta["sql.query"])) // Ellipsis added in quantizer
assert.NotEqual("Non-parsable SQL query", result.Meta["sql.query"])
assert.NotContains(result.Meta["sql.query"], "42")
assert.Contains(result.Meta["sql.query"], "SELECT name FROM people WHERE age = ?")
}
func TestProcess(t *testing.T) {
t.Run("Replacer", func(t *testing.T) {
// Ensures that for "sql" type spans:
// • obfuscator runs before replacer
// • obfuscator obfuscates both resource and "sql.query" tag
// • resulting resource is obfuscated with replacements applied
// • resulting "sql.query" tag is obfuscated with no replacements applied
cfg := config.New()
cfg.APIKey = "test"
cfg.ReplaceTags = []*config.ReplaceRule{{
Name: "resource.name",
Re: regexp.MustCompile("AND.*"),
Repl: "...",
}}
ctx, cancel := context.WithCancel(context.Background())
agent := NewAgent(ctx, cfg)
defer cancel()
now := time.Now()
span := &model.Span{
Resource: "SELECT name FROM people WHERE age = 42 AND extra = 55",
Type: "sql",
Start: now.Add(-time.Second).UnixNano(),
Duration: (500 * time.Millisecond).Nanoseconds(),
}
agent.Process(model.Trace{span})
assert := assert.New(t)
assert.Equal("SELECT name FROM people WHERE age = ? ...", span.Resource)
assert.Equal("SELECT name FROM people WHERE age = ? AND extra = ?", span.Meta["sql.query"])
})
t.Run("Blacklister", func(t *testing.T) {
cfg := config.New()
cfg.APIKey = "test"
cfg.Ignore["resource"] = []string{"^INSERT.*"}
ctx, cancel := context.WithCancel(context.Background())
agent := NewAgent(ctx, cfg)
defer cancel()
now := time.Now()
spanValid := &model.Span{
Resource: "SELECT name FROM people WHERE age = 42 AND extra = 55",
Type: "sql",
Start: now.Add(-time.Second).UnixNano(),
Duration: (500 * time.Millisecond).Nanoseconds(),
}
spanInvalid := &model.Span{
Resource: "INSERT INTO db VALUES (1, 2, 3)",
Type: "sql",
Start: now.Add(-time.Second).UnixNano(),
Duration: (500 * time.Millisecond).Nanoseconds(),
}
stats := agent.Receiver.stats.GetTagStats(info.Tags{})
assert := assert.New(t)
agent.Process(model.Trace{spanValid})
assert.EqualValues(0, stats.TracesFiltered)
agent.Process(model.Trace{spanInvalid})
assert.EqualValues(1, stats.TracesFiltered)
})
}
func BenchmarkAgentTraceProcessing(b *testing.B) {
c := config.New()
c.APIKey = "test"
runTraceProcessingBenchmark(b, c)
}
func BenchmarkAgentTraceProcessingWithFiltering(b *testing.B) {
c := config.New()
c.APIKey = "test"
c.Ignore["resource"] = []string{"[0-9]{3}", "foobar", "G.T [a-z]+", "[^123]+_baz"}
runTraceProcessingBenchmark(b, c)
}
// worst case scenario: spans are tested against multiple rules without any match.
// this means we won't compesate the overhead of filtering by dropping traces
func BenchmarkAgentTraceProcessingWithWorstCaseFiltering(b *testing.B) {
c := config.New()
c.APIKey = "test"
c.Ignore["resource"] = []string{"[0-9]{3}", "foobar", "aaaaa?aaaa", "[^123]+_baz"}
runTraceProcessingBenchmark(b, c)
}
func runTraceProcessingBenchmark(b *testing.B, c *config.AgentConfig) {
ctx, cancelFunc := context.WithCancel(context.Background())
defer cancelFunc()
agent := NewAgent(ctx, c)
log.UseLogger(log.Disabled)
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
agent.Process(testutil.RandomTrace(10, 8))
}
}
func BenchmarkWatchdog(b *testing.B) {
conf := config.New()
conf.APIKey = "apikey_2"
ctx, cancelFunc := context.WithCancel(context.Background())
defer cancelFunc()
agent := NewAgent(ctx, conf)
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
agent.watchdog()
}
}
// Mimicks behaviour of agent Process function
func formatTrace(t model.Trace) model.Trace {
for _, span := range t {
obfuscate.NewObfuscator(nil).Obfuscate(span)
span.Truncate()
}
return t
}