Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
aos
GitHub Repository: aos/grafana-agent
Path: blob/main/pkg/traces/automaticloggingprocessor/automaticloggingprocessor_test.go
4095 views
1
package automaticloggingprocessor
2
3
import (
4
"context"
5
"testing"
6
"time"
7
8
"github.com/grafana/agent/pkg/logs"
9
"github.com/grafana/agent/pkg/util"
10
"github.com/prometheus/common/model"
11
"github.com/stretchr/testify/assert"
12
"github.com/stretchr/testify/require"
13
"go.opentelemetry.io/collector/component/componenttest"
14
"go.opentelemetry.io/collector/pdata/pcommon"
15
"go.opentelemetry.io/collector/pdata/ptrace"
16
"gopkg.in/yaml.v3"
17
)
18
19
func TestSpanKeyVals(t *testing.T) {
20
tests := []struct {
21
spanName string
22
spanAttrs map[string]interface{}
23
spanStart time.Time
24
spanEnd time.Time
25
cfg AutomaticLoggingConfig
26
expected []interface{}
27
}{
28
{
29
expected: []interface{}{
30
"span", "",
31
"dur", "0ns",
32
"status", ptrace.StatusCode(1),
33
},
34
},
35
{
36
spanName: "test",
37
expected: []interface{}{
38
"span", "test",
39
"dur", "0ns",
40
"status", ptrace.StatusCode(1),
41
},
42
},
43
{
44
expected: []interface{}{
45
"span", "",
46
"dur", "0ns",
47
"status", ptrace.StatusCode(1),
48
},
49
},
50
{
51
spanStart: time.Unix(0, 0),
52
spanEnd: time.Unix(0, 10),
53
expected: []interface{}{
54
"span", "",
55
"dur", "10ns",
56
"status", ptrace.StatusCode(1),
57
},
58
},
59
{
60
spanStart: time.Unix(0, 10),
61
spanEnd: time.Unix(0, 100),
62
expected: []interface{}{
63
"span", "",
64
"dur", "90ns",
65
"status", ptrace.StatusCode(1),
66
},
67
},
68
{
69
spanAttrs: map[string]interface{}{
70
"xstr": "test",
71
},
72
expected: []interface{}{
73
"span", "",
74
"dur", "0ns",
75
"status", ptrace.StatusCode(1),
76
},
77
},
78
{
79
spanAttrs: map[string]interface{}{
80
"xstr": "test",
81
},
82
cfg: AutomaticLoggingConfig{
83
SpanAttributes: []string{"xstr"},
84
},
85
expected: []interface{}{
86
"span", "",
87
"dur", "0ns",
88
"status", ptrace.StatusCode(1),
89
"xstr", "test",
90
},
91
},
92
{
93
cfg: AutomaticLoggingConfig{
94
Overrides: OverrideConfig{
95
SpanNameKey: "a",
96
DurationKey: "c",
97
StatusKey: "d",
98
},
99
},
100
expected: []interface{}{
101
"a", "",
102
"c", "0ns",
103
"d", ptrace.StatusCode(1),
104
},
105
},
106
}
107
108
for _, tc := range tests {
109
tc.cfg.Backend = BackendStdout
110
tc.cfg.Spans = true
111
p, err := newTraceProcessor(&automaticLoggingProcessor{}, &tc.cfg)
112
require.NoError(t, err)
113
114
span := ptrace.NewSpan()
115
span.SetName(tc.spanName)
116
span.Attributes().FromRaw(tc.spanAttrs)
117
span.SetStartTimestamp(pcommon.NewTimestampFromTime(tc.spanStart))
118
span.SetEndTimestamp(pcommon.NewTimestampFromTime(tc.spanEnd))
119
span.Status().SetCode(ptrace.StatusCodeOk)
120
121
actual := p.(*automaticLoggingProcessor).spanKeyVals(span)
122
assert.Equal(t, tc.expected, actual)
123
}
124
}
125
126
func TestProcessKeyVals(t *testing.T) {
127
tests := []struct {
128
processAttrs map[string]interface{}
129
svc string
130
cfg AutomaticLoggingConfig
131
expected []interface{}
132
}{
133
{
134
expected: []interface{}{
135
"svc", "",
136
},
137
},
138
{
139
processAttrs: map[string]interface{}{
140
"xstr": "test",
141
},
142
expected: []interface{}{
143
"svc", "",
144
},
145
},
146
{
147
processAttrs: map[string]interface{}{
148
"xstr": "test",
149
},
150
cfg: AutomaticLoggingConfig{
151
ProcessAttributes: []string{"xstr"},
152
},
153
expected: []interface{}{
154
"svc", "",
155
"xstr", "test",
156
},
157
},
158
}
159
160
for _, tc := range tests {
161
tc.cfg.Backend = BackendStdout
162
tc.cfg.Spans = true
163
p, err := newTraceProcessor(&automaticLoggingProcessor{}, &tc.cfg)
164
require.NoError(t, err)
165
166
process := pcommon.NewResource()
167
process.Attributes().Sort().FromRaw(tc.processAttrs)
168
169
actual := p.(*automaticLoggingProcessor).processKeyVals(process, tc.svc)
170
assert.Equal(t, tc.expected, actual)
171
}
172
}
173
174
func TestBadConfigs(t *testing.T) {
175
tests := []struct {
176
cfg *AutomaticLoggingConfig
177
}{
178
{
179
cfg: &AutomaticLoggingConfig{},
180
},
181
{
182
cfg: &AutomaticLoggingConfig{
183
Backend: "blarg",
184
Spans: true,
185
},
186
},
187
{
188
cfg: &AutomaticLoggingConfig{
189
Backend: "logs",
190
},
191
},
192
{
193
cfg: &AutomaticLoggingConfig{
194
Backend: "loki",
195
},
196
},
197
{
198
cfg: &AutomaticLoggingConfig{
199
Backend: "stdout",
200
},
201
},
202
}
203
204
for _, tc := range tests {
205
p, err := newTraceProcessor(&automaticLoggingProcessor{}, tc.cfg)
206
require.Error(t, err)
207
require.Nil(t, p)
208
}
209
}
210
211
func TestLogToStdoutSet(t *testing.T) {
212
cfg := &AutomaticLoggingConfig{
213
Backend: BackendStdout,
214
Spans: true,
215
}
216
217
p, err := newTraceProcessor(&automaticLoggingProcessor{}, cfg)
218
require.NoError(t, err)
219
require.True(t, p.(*automaticLoggingProcessor).logToStdout)
220
221
err = p.Start(context.Background(), componenttest.NewNopHost())
222
require.NoError(t, err)
223
224
cfg = &AutomaticLoggingConfig{
225
Backend: BackendLogs,
226
Spans: true,
227
}
228
229
p, err = newTraceProcessor(&automaticLoggingProcessor{}, cfg)
230
require.NoError(t, err)
231
require.False(t, p.(*automaticLoggingProcessor).logToStdout)
232
}
233
234
func TestDefaults(t *testing.T) {
235
cfg := &AutomaticLoggingConfig{
236
Spans: true,
237
}
238
239
p, err := newTraceProcessor(&automaticLoggingProcessor{}, cfg)
240
require.NoError(t, err)
241
require.Equal(t, BackendStdout, p.(*automaticLoggingProcessor).cfg.Backend)
242
require.Equal(t, defaultTimeout, p.(*automaticLoggingProcessor).cfg.Timeout)
243
require.True(t, p.(*automaticLoggingProcessor).logToStdout)
244
245
require.Equal(t, defaultLogsTag, p.(*automaticLoggingProcessor).cfg.Overrides.LogsTag)
246
require.Equal(t, defaultServiceKey, p.(*automaticLoggingProcessor).cfg.Overrides.ServiceKey)
247
require.Equal(t, defaultSpanNameKey, p.(*automaticLoggingProcessor).cfg.Overrides.SpanNameKey)
248
require.Equal(t, defaultStatusKey, p.(*automaticLoggingProcessor).cfg.Overrides.StatusKey)
249
require.Equal(t, defaultDurationKey, p.(*automaticLoggingProcessor).cfg.Overrides.DurationKey)
250
require.Equal(t, defaultTraceIDKey, p.(*automaticLoggingProcessor).cfg.Overrides.TraceIDKey)
251
}
252
253
func TestLokiNameMigration(t *testing.T) {
254
logsConfig := &logs.Config{
255
Configs: []*logs.InstanceConfig{{Name: "default"}},
256
}
257
258
input := util.Untab(`
259
backend: loki
260
loki_name: default
261
overrides:
262
loki_tag: traces
263
`)
264
expect := util.Untab(`
265
backend: logs_instance
266
logs_instance_name: default
267
overrides:
268
logs_instance_tag: traces
269
`)
270
271
var cfg AutomaticLoggingConfig
272
require.NoError(t, yaml.Unmarshal([]byte(input), &cfg))
273
require.NoError(t, cfg.Validate(logsConfig))
274
275
bb, err := yaml.Marshal(cfg)
276
require.NoError(t, err)
277
require.YAMLEq(t, expect, string(bb))
278
}
279
280
func TestLabels(t *testing.T) {
281
tests := []struct {
282
name string
283
labels []string
284
keyValues []interface{}
285
expectedLabels model.LabelSet
286
}{
287
{
288
name: "happy case",
289
labels: []string{"loki", "svc"},
290
keyValues: []interface{}{"loki", "loki", "svc", "gateway", "duration", "1s"},
291
expectedLabels: map[model.LabelName]model.LabelValue{
292
"loki": "loki",
293
"svc": "gateway",
294
},
295
},
296
{
297
name: "happy case with dots",
298
labels: []string{"loki", "service.name"},
299
keyValues: []interface{}{"loki", "loki", "service.name", "gateway", "duration", "1s"},
300
expectedLabels: map[model.LabelName]model.LabelValue{
301
"loki": "loki",
302
"service_name": "gateway",
303
},
304
},
305
{
306
name: "no labels",
307
labels: []string{},
308
keyValues: []interface{}{"loki", "loki", "svc", "gateway", "duration", "1s"},
309
expectedLabels: map[model.LabelName]model.LabelValue{},
310
},
311
{
312
name: "label not present in keyValues",
313
labels: []string{"loki", "svc"},
314
keyValues: []interface{}{"loki", "loki", "duration", "1s"},
315
expectedLabels: map[model.LabelName]model.LabelValue{
316
"loki": "loki",
317
},
318
},
319
{
320
name: "label value is not type string",
321
labels: []string{"loki"},
322
keyValues: []interface{}{"loki", 42, "duration", "1s"},
323
expectedLabels: map[model.LabelName]model.LabelValue{
324
"loki": "42",
325
},
326
},
327
{
328
name: "stringifies value if possible",
329
labels: []string{"status"},
330
keyValues: []interface{}{"status", ptrace.StatusCode(1)},
331
expectedLabels: map[model.LabelName]model.LabelValue{
332
"status": model.LabelValue(ptrace.StatusCode(1).String()),
333
},
334
},
335
{
336
name: "no keyValues",
337
labels: []string{"status"},
338
keyValues: []interface{}{},
339
expectedLabels: map[model.LabelName]model.LabelValue{},
340
},
341
}
342
343
for _, tc := range tests {
344
t.Run(tc.name, func(t *testing.T) {
345
cfg := &AutomaticLoggingConfig{
346
Spans: true,
347
Labels: tc.labels,
348
}
349
p, err := newTraceProcessor(&automaticLoggingProcessor{}, cfg)
350
require.NoError(t, err)
351
352
ls := p.(*automaticLoggingProcessor).spanLabels(tc.keyValues)
353
assert.Equal(t, tc.expectedLabels, ls)
354
})
355
}
356
}
357
358