@@ -2,6 +2,7 @@ package tracing
2
2
3
3
import (
4
4
"context"
5
+ "encoding/json"
5
6
"errors"
6
7
"net/http"
7
8
"net/http/httptest"
@@ -15,17 +16,26 @@ import (
15
16
16
17
func TestTracing_UnmarshalCaddyfile (t * testing.T ) {
17
18
tests := []struct {
18
- name string
19
- spanName string
20
- d * caddyfile.Dispenser
21
- wantErr bool
19
+ name string
20
+ spanName string
21
+ spanAttributes map [string ]string
22
+ d * caddyfile.Dispenser
23
+ wantErr bool
22
24
}{
23
25
{
24
26
name : "Full config" ,
25
27
spanName : "my-span" ,
28
+ spanAttributes : map [string ]string {
29
+ "attr1" : "value1" ,
30
+ "attr2" : "value2" ,
31
+ },
26
32
d : caddyfile .NewTestDispenser (`
27
33
tracing {
28
34
span my-span
35
+ span_attributes {
36
+ attr1 value1
37
+ attr2 value2
38
+ }
29
39
}` ),
30
40
wantErr : false ,
31
41
},
@@ -42,6 +52,21 @@ tracing {
42
52
name : "Empty config" ,
43
53
d : caddyfile .NewTestDispenser (`
44
54
tracing {
55
+ }` ),
56
+ wantErr : false ,
57
+ },
58
+ {
59
+ name : "Only span attributes" ,
60
+ spanAttributes : map [string ]string {
61
+ "service.name" : "my-service" ,
62
+ "service.version" : "1.0.0" ,
63
+ },
64
+ d : caddyfile .NewTestDispenser (`
65
+ tracing {
66
+ span_attributes {
67
+ service.name my-service
68
+ service.version 1.0.0
69
+ }
45
70
}` ),
46
71
wantErr : false ,
47
72
},
@@ -56,6 +81,20 @@ tracing {
56
81
if ot .SpanName != tt .spanName {
57
82
t .Errorf ("UnmarshalCaddyfile() SpanName = %v, want SpanName %v" , ot .SpanName , tt .spanName )
58
83
}
84
+
85
+ if len (tt .spanAttributes ) > 0 {
86
+ if ot .SpanAttributes == nil {
87
+ t .Errorf ("UnmarshalCaddyfile() SpanAttributes is nil, expected %v" , tt .spanAttributes )
88
+ } else {
89
+ for key , expectedValue := range tt .spanAttributes {
90
+ if actualValue , exists := ot .SpanAttributes [key ]; ! exists {
91
+ t .Errorf ("UnmarshalCaddyfile() SpanAttributes missing key %v" , key )
92
+ } else if actualValue != expectedValue {
93
+ t .Errorf ("UnmarshalCaddyfile() SpanAttributes[%v] = %v, want %v" , key , actualValue , expectedValue )
94
+ }
95
+ }
96
+ }
97
+ }
59
98
})
60
99
}
61
100
}
@@ -79,6 +118,26 @@ func TestTracing_UnmarshalCaddyfile_Error(t *testing.T) {
79
118
d : caddyfile .NewTestDispenser (`
80
119
tracing {
81
120
span
121
+ }` ),
122
+ wantErr : true ,
123
+ },
124
+ {
125
+ name : "Span attributes missing value" ,
126
+ d : caddyfile .NewTestDispenser (`
127
+ tracing {
128
+ span_attributes {
129
+ key
130
+ }
131
+ }` ),
132
+ wantErr : true ,
133
+ },
134
+ {
135
+ name : "Span attributes too many arguments" ,
136
+ d : caddyfile .NewTestDispenser (`
137
+ tracing {
138
+ span_attributes {
139
+ key value extra
140
+ }
82
141
}` ),
83
142
wantErr : true ,
84
143
},
@@ -181,6 +240,100 @@ func TestTracing_ServeHTTP_Next_Error(t *testing.T) {
181
240
}
182
241
}
183
242
243
+ func TestTracing_ServeHTTP_With_SpanAttributes (t * testing.T ) {
244
+ ot := & Tracing {
245
+ SpanName : "mySpan" ,
246
+ SpanAttributes : map [string ]string {
247
+ "service.name" : "test-service" ,
248
+ "service.version" : "1.0.0" ,
249
+ "custom.attr" : "test-value" ,
250
+ },
251
+ }
252
+
253
+ req := createRequestWithContext ("GET" , "https://example.com/foo" )
254
+ w := httptest .NewRecorder ()
255
+
256
+ var handler caddyhttp.HandlerFunc = func (writer http.ResponseWriter , request * http.Request ) error {
257
+ traceparent := request .Header .Get ("Traceparent" )
258
+ if traceparent == "" || strings .HasPrefix (traceparent , "00-00000000000000000000000000000000-0000000000000000" ) {
259
+ t .Errorf ("Invalid traceparent: %v" , traceparent )
260
+ }
261
+
262
+ return nil
263
+ }
264
+
265
+ ctx , cancel := caddy .NewContext (caddy.Context {Context : context .Background ()})
266
+ defer cancel ()
267
+
268
+ if err := ot .Provision (ctx ); err != nil {
269
+ t .Errorf ("Provision error: %v" , err )
270
+ t .FailNow ()
271
+ }
272
+
273
+ if err := ot .ServeHTTP (w , req , handler ); err != nil {
274
+ t .Errorf ("ServeHTTP error: %v" , err )
275
+ }
276
+
277
+ // Verify span attributes were configured
278
+ if ot .otel .spanAttributes == nil {
279
+ t .Error ("Expected span attributes to be set on otel wrapper" )
280
+ }
281
+
282
+ expectedAttrs := map [string ]string {
283
+ "service.name" : "test-service" ,
284
+ "service.version" : "1.0.0" ,
285
+ "custom.attr" : "test-value" ,
286
+ }
287
+
288
+ for key , expectedValue := range expectedAttrs {
289
+ if actualValue , exists := ot .otel .spanAttributes [key ]; ! exists {
290
+ t .Errorf ("Expected span attribute %s to exist" , key )
291
+ } else if actualValue != expectedValue {
292
+ t .Errorf ("Expected span attribute %s = %s, got %s" , key , expectedValue , actualValue )
293
+ }
294
+ }
295
+ }
296
+
297
+ func TestTracing_JSON_Configuration (t * testing.T ) {
298
+ // Test that our struct correctly marshals to and from JSON
299
+ original := & Tracing {
300
+ SpanName : "test-span" ,
301
+ SpanAttributes : map [string ]string {
302
+ "service.name" : "test-service" ,
303
+ "service.version" : "1.0.0" ,
304
+ "env" : "test" ,
305
+ },
306
+ }
307
+
308
+ jsonData , err := json .Marshal (original )
309
+ if err != nil {
310
+ t .Fatalf ("Failed to marshal to JSON: %v" , err )
311
+ }
312
+
313
+ var unmarshaled Tracing
314
+ if err := json .Unmarshal (jsonData , & unmarshaled ); err != nil {
315
+ t .Fatalf ("Failed to unmarshal from JSON: %v" , err )
316
+ }
317
+
318
+ if unmarshaled .SpanName != original .SpanName {
319
+ t .Errorf ("Expected SpanName %s, got %s" , original .SpanName , unmarshaled .SpanName )
320
+ }
321
+
322
+ if len (unmarshaled .SpanAttributes ) != len (original .SpanAttributes ) {
323
+ t .Errorf ("Expected %d span attributes, got %d" , len (original .SpanAttributes ), len (unmarshaled .SpanAttributes ))
324
+ }
325
+
326
+ for key , expectedValue := range original .SpanAttributes {
327
+ if actualValue , exists := unmarshaled .SpanAttributes [key ]; ! exists {
328
+ t .Errorf ("Expected span attribute %s to exist" , key )
329
+ } else if actualValue != expectedValue {
330
+ t .Errorf ("Expected span attribute %s = %s, got %s" , key , expectedValue , actualValue )
331
+ }
332
+ }
333
+
334
+ t .Logf ("JSON representation: %s" , string (jsonData ))
335
+ }
336
+
184
337
func createRequestWithContext (method string , url string ) * http.Request {
185
338
r , _ := http .NewRequest (method , url , nil )
186
339
repl := caddy .NewReplacer ()
0 commit comments