@@ -19,6 +19,7 @@ import (
19
19
"go.opentelemetry.io/collector/consumer"
20
20
"go.opentelemetry.io/collector/consumer/consumertest"
21
21
"go.opentelemetry.io/collector/exporter"
22
+ "go.opentelemetry.io/collector/featuregate"
22
23
"go.opentelemetry.io/collector/pdata/pcommon"
23
24
"go.opentelemetry.io/collector/pdata/pmetric"
24
25
"go.opentelemetry.io/collector/pdata/ptrace"
@@ -63,69 +64,145 @@ func TestConnectorShutdown(t *testing.T) {
63
64
}
64
65
65
66
func TestConnectorConsume (t * testing.T ) {
66
- t .Run ("test common case" , func (t * testing.T ) {
67
- // Prepare
68
- cfg := & Config {
69
- Dimensions : []string {"some-attribute" , "non-existing-attribute" },
70
- Store : StoreConfig {MaxItems : 10 },
71
- }
72
-
73
- set := componenttest .NewNopTelemetrySettings ()
74
- set .Logger = zaptest .NewLogger (t )
75
- conn , err := newConnector (set , cfg , newMockMetricsExporter ())
76
- require .NoError (t , err )
77
- assert .NoError (t , conn .Start (context .Background (), componenttest .NewNopHost ()))
78
-
79
- // Test & verify
80
- td := buildSampleTrace (t , "val" )
81
- // The assertion is part of verifyHappyCaseMetrics func.
82
- assert .NoError (t , conn .ConsumeTraces (context .Background (), td ))
83
-
84
- // Force collection
85
- conn .store .Expire ()
86
- md , err := conn .buildMetrics ()
87
- assert .NoError (t , err )
88
- verifyHappyCaseMetrics (t , md )
89
-
90
- // Shutdown the connector
91
- assert .NoError (t , conn .Shutdown (context .Background ()))
92
- })
93
- t .Run ("test fix failed label not work" , func (t * testing.T ) {
94
- cfg := & Config {
95
- Store : StoreConfig {MaxItems : 10 },
96
- }
97
- set := componenttest .NewNopTelemetrySettings ()
98
- set .Logger = zaptest .NewLogger (t )
99
- conn , err := newConnector (set , cfg , newMockMetricsExporter ())
100
- require .NoError (t , err )
101
-
102
- assert .NoError (t , conn .Start (context .Background (), componenttest .NewNopHost ()))
103
- defer require .NoError (t , conn .Shutdown (context .Background ()))
104
-
105
- // this trace simulate two services' trace: foo, bar
106
- // foo called bar three times, two success, one failed
107
- td , err := golden .ReadTraces ("testdata/failed-label-not-work-simple-trace.yaml" )
108
- assert .NoError (t , err )
109
- assert .NoError (t , conn .ConsumeTraces (context .Background (), td ))
110
-
111
- // Force collection
112
- conn .store .Expire ()
113
- actualMetrics , err := conn .buildMetrics ()
114
- assert .NoError (t , err )
115
-
116
- // Verify
117
- expectedMetrics , err := golden .ReadMetrics ("testdata/failed-label-not-work-expect-metrics.yaml" )
118
- assert .NoError (t , err )
119
-
120
- err = pmetrictest .CompareMetrics (expectedMetrics , actualMetrics ,
121
- pmetrictest .IgnoreMetricsOrder (),
122
- pmetrictest .IgnoreMetricDataPointsOrder (),
123
- pmetrictest .IgnoreStartTimestamp (),
124
- pmetrictest .IgnoreTimestamp (),
125
- pmetrictest .IgnoreDatapointAttributesOrder (),
126
- )
127
- require .NoError (t , err )
128
- })
67
+ for _ , tc := range []struct {
68
+ name string
69
+ cfg * Config
70
+ gates []* featuregate.Gate
71
+ sampleTraces ptrace.Traces
72
+ verifyMetrics func (t * testing.T , md pmetric.Metrics )
73
+ }{
74
+ {
75
+ name : "complete traces with client and server span" ,
76
+ cfg : & Config {
77
+ Dimensions : []string {"some-attribute" , "non-existing-attribute" },
78
+ Store : StoreConfig {
79
+ MaxItems : 10 ,
80
+ TTL : time .Nanosecond ,
81
+ },
82
+ },
83
+ sampleTraces : buildSampleTrace (t , "val" ),
84
+ verifyMetrics : verifyHappyCaseMetrics ,
85
+ },
86
+ {
87
+ name : "test fix failed label not work" ,
88
+ cfg : & Config {
89
+ Store : StoreConfig {
90
+ MaxItems : 10 ,
91
+ TTL : time .Nanosecond ,
92
+ },
93
+ },
94
+ sampleTraces : getGoldenTraces (t , "testdata/failed-label-not-work-simple-trace.yaml" ),
95
+ verifyMetrics : func (t * testing.T , actualMetrics pmetric.Metrics ) {
96
+ expectedMetrics , err := golden .ReadMetrics ("testdata/failed-label-not-work-expect-metrics.yaml" )
97
+ assert .NoError (t , err )
98
+
99
+ err = pmetrictest .CompareMetrics (expectedMetrics , actualMetrics ,
100
+ pmetrictest .IgnoreMetricsOrder (),
101
+ pmetrictest .IgnoreMetricDataPointsOrder (),
102
+ pmetrictest .IgnoreStartTimestamp (),
103
+ pmetrictest .IgnoreTimestamp (),
104
+ pmetrictest .IgnoreDatapointAttributesOrder (),
105
+ )
106
+ require .NoError (t , err )
107
+ },
108
+ },
109
+ {
110
+ name : "incomplete traces with virtual server span" ,
111
+ cfg : & Config {
112
+ Dimensions : []string {"some-attribute" , "non-existing-attribute" },
113
+ Store : StoreConfig {
114
+ MaxItems : 10 ,
115
+ TTL : time .Nanosecond ,
116
+ },
117
+ },
118
+ sampleTraces : incompleteClientTraces (),
119
+ verifyMetrics : func (t * testing.T , md pmetric.Metrics ) {
120
+ v , ok := md .ResourceMetrics ().At (0 ).ScopeMetrics ().At (0 ).Metrics ().At (0 ).Sum ().DataPoints ().At (0 ).Attributes ().Get ("server" )
121
+ assert .True (t , ok )
122
+ assert .Equal (t , "AuthTokenCache" , v .Str ())
123
+ },
124
+ },
125
+ {
126
+ name : "incomplete traces with virtual client span" ,
127
+ cfg : & Config {
128
+ Dimensions : []string {"some-attribute" , "non-existing-attribute" },
129
+ Store : StoreConfig {
130
+ MaxItems : 10 ,
131
+ TTL : time .Nanosecond ,
132
+ },
133
+ },
134
+ sampleTraces : incompleteServerTraces (false ),
135
+ verifyMetrics : func (t * testing.T , md pmetric.Metrics ) {
136
+ v , ok := md .ResourceMetrics ().At (0 ).ScopeMetrics ().At (0 ).Metrics ().At (0 ).Sum ().DataPoints ().At (0 ).Attributes ().Get ("client" )
137
+ assert .True (t , ok )
138
+ assert .Equal (t , "user" , v .Str ())
139
+ },
140
+ },
141
+ {
142
+ name : "incomplete traces with client span lost" ,
143
+ cfg : & Config {
144
+ Dimensions : []string {"some-attribute" , "non-existing-attribute" },
145
+ Store : StoreConfig {
146
+ MaxItems : 10 ,
147
+ TTL : time .Nanosecond ,
148
+ },
149
+ },
150
+ sampleTraces : incompleteServerTraces (true ),
151
+ verifyMetrics : func (t * testing.T , md pmetric.Metrics ) {
152
+ assert .Equal (t , 0 , md .MetricCount ())
153
+ },
154
+ },
155
+ {
156
+ name : "complete traces with legacy latency metrics" ,
157
+ cfg : & Config {
158
+ Dimensions : []string {"some-attribute" , "non-existing-attribute" },
159
+ Store : StoreConfig {
160
+ MaxItems : 10 ,
161
+ TTL : time .Nanosecond ,
162
+ },
163
+ },
164
+ sampleTraces : buildSampleTrace (t , "val" ),
165
+ gates : []* featuregate.Gate {legacyLatencyUnitMsFeatureGate },
166
+ verifyMetrics : verifyHappyCaseMetricsWithDuration (1000 ),
167
+ },
168
+ } {
169
+ t .Run (tc .name , func (t * testing.T ) {
170
+ // Set feature gates
171
+ for _ , gate := range tc .gates {
172
+ require .NoError (t , featuregate .GlobalRegistry ().Set (gate .ID (), true ))
173
+ }
174
+
175
+ // Prepare
176
+ set := componenttest .NewNopTelemetrySettings ()
177
+ set .Logger = zaptest .NewLogger (t )
178
+ conn , err := newConnector (set , tc .cfg , newMockMetricsExporter ())
179
+ require .NoError (t , err )
180
+ assert .NoError (t , conn .Start (context .Background (), componenttest .NewNopHost ()))
181
+
182
+ // Send spans to the connector
183
+ assert .NoError (t , conn .ConsumeTraces (context .Background (), tc .sampleTraces ))
184
+
185
+ // Force collection
186
+ conn .store .Expire ()
187
+ md , err := conn .buildMetrics ()
188
+ assert .NoError (t , err )
189
+ tc .verifyMetrics (t , md )
190
+
191
+ // Shutdown the connector
192
+ assert .NoError (t , conn .Shutdown (context .Background ()))
193
+
194
+ // Unset feature gates
195
+ for _ , gate := range tc .gates {
196
+ require .NoError (t , featuregate .GlobalRegistry ().Set (gate .ID (), false ))
197
+ }
198
+ })
199
+ }
200
+ }
201
+
202
+ func getGoldenTraces (t * testing.T , file string ) ptrace.Traces {
203
+ td , err := golden .ReadTraces (file )
204
+ assert .NoError (t , err )
205
+ return td
129
206
}
130
207
131
208
func verifyHappyCaseMetrics (t * testing.T , md pmetric.Metrics ) {
@@ -245,6 +322,53 @@ func buildSampleTrace(t *testing.T, attrValue string) ptrace.Traces {
245
322
return traces
246
323
}
247
324
325
+ func incompleteClientTraces () ptrace.Traces {
326
+ tStart := time .Date (2022 , 1 , 2 , 3 , 4 , 5 , 6 , time .UTC )
327
+ tEnd := time .Date (2022 , 1 , 2 , 3 , 4 , 6 , 6 , time .UTC )
328
+
329
+ traces := ptrace .NewTraces ()
330
+
331
+ resourceSpans := traces .ResourceSpans ().AppendEmpty ()
332
+ resourceSpans .Resource ().Attributes ().PutStr (semconv .AttributeServiceName , "some-client-service" )
333
+
334
+ scopeSpans := resourceSpans .ScopeSpans ().AppendEmpty ()
335
+ anotherTraceID := pcommon .TraceID ([16 ]byte {1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 16 })
336
+ anotherClientSpanID := pcommon .SpanID ([8 ]byte {1 , 2 , 3 , 4 , 4 , 3 , 2 , 1 })
337
+ clientSpanNoServerSpan := scopeSpans .Spans ().AppendEmpty ()
338
+ clientSpanNoServerSpan .SetName ("client span" )
339
+ clientSpanNoServerSpan .SetSpanID (anotherClientSpanID )
340
+ clientSpanNoServerSpan .SetTraceID (anotherTraceID )
341
+ clientSpanNoServerSpan .SetKind (ptrace .SpanKindClient )
342
+ clientSpanNoServerSpan .SetStartTimestamp (pcommon .NewTimestampFromTime (tStart ))
343
+ clientSpanNoServerSpan .SetEndTimestamp (pcommon .NewTimestampFromTime (tEnd ))
344
+ clientSpanNoServerSpan .Attributes ().PutStr (semconv .AttributePeerService , "AuthTokenCache" ) // Attribute selected as dimension for metrics
345
+
346
+ return traces
347
+ }
348
+
349
+ func incompleteServerTraces (withParentSpan bool ) ptrace.Traces {
350
+ tStart := time .Date (2022 , 1 , 2 , 3 , 4 , 5 , 6 , time .UTC )
351
+ tEnd := time .Date (2022 , 1 , 2 , 3 , 4 , 6 , 6 , time .UTC )
352
+
353
+ traces := ptrace .NewTraces ()
354
+
355
+ resourceSpans := traces .ResourceSpans ().AppendEmpty ()
356
+ resourceSpans .Resource ().Attributes ().PutStr (semconv .AttributeServiceName , "some-server-service" )
357
+ scopeSpans := resourceSpans .ScopeSpans ().AppendEmpty ()
358
+ anotherTraceID := pcommon .TraceID ([16 ]byte {1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 8 , 7 , 6 , 5 , 4 , 3 , 2 , 1 })
359
+ serverSpanNoClientSpan := scopeSpans .Spans ().AppendEmpty ()
360
+ serverSpanNoClientSpan .SetName ("server span" )
361
+ serverSpanNoClientSpan .SetSpanID ([8 ]byte {0x19 , 0x20 , 0x21 , 0x22 , 0x23 , 0x24 , 0x25 , 0x26 })
362
+ if withParentSpan {
363
+ serverSpanNoClientSpan .SetParentSpanID ([8 ]byte {0x27 , 0x28 , 0x29 , 0x30 , 0x31 , 0x32 , 0x33 , 0x34 })
364
+ }
365
+ serverSpanNoClientSpan .SetTraceID (anotherTraceID )
366
+ serverSpanNoClientSpan .SetKind (ptrace .SpanKindServer )
367
+ serverSpanNoClientSpan .SetStartTimestamp (pcommon .NewTimestampFromTime (tStart ))
368
+ serverSpanNoClientSpan .SetEndTimestamp (pcommon .NewTimestampFromTime (tEnd ))
369
+ return traces
370
+ }
371
+
248
372
var _ exporter.Metrics = (* mockMetricsExporter )(nil )
249
373
250
374
func newMockMetricsExporter () * mockMetricsExporter {
0 commit comments