@@ -17,12 +17,14 @@ import (
1717 "net/http"
1818 "os"
1919 "os/exec"
20+ "runtime"
2021 "runtime/pprof"
2122 "strconv"
2223 "syscall"
2324 "time"
2425 "unsafe"
2526
27+ "github.com/DataDog/dd-trace-go/v2/ddtrace/tracer"
2628 manager "github.com/DataDog/ebpf-manager"
2729 "github.com/syndtr/gocapability/capability"
2830 "github.com/vishvananda/netlink"
5557 goSpanSpanID string
5658 goSpanLocalRootSpanID string
5759 goSpanFilePath string
60+ ddtraceSpanTest bool
61+ ddtraceSpanFilePath string
5862)
5963
6064//go:embed ebpf_probe.o
@@ -340,6 +344,89 @@ func RunGoSpanTest(spanID, localRootSpanID, filePath string) error {
340344 return nil
341345}
342346
347+ // RunDDTraceSpanTest uses dd-trace-go to create a real span, which sets pprof
348+ // labels automatically via the profiler code hotspots integration. This tests
349+ // the full dd-trace-go → pprof labels → eBPF Go labels reader pipeline.
350+ func RunDDTraceSpanTest (filePath string ) error {
351+ // Create and seal a tracer-info memfd with tracer_language="go".
352+ type TracerMeta struct {
353+ SchemaVersion uint8 `msgpack:"schema_version"`
354+ TracerLanguage string `msgpack:"tracer_language"`
355+ TracerVersion string `msgpack:"tracer_version"`
356+ Hostname string `msgpack:"hostname"`
357+ ServiceName string `msgpack:"service_name"`
358+ }
359+ meta := TracerMeta {
360+ SchemaVersion : 2 ,
361+ TracerLanguage : "go" ,
362+ TracerVersion : "0.0.1-test" ,
363+ Hostname : "test" ,
364+ ServiceName : "ddtrace-test" ,
365+ }
366+ data , err := msgpack .Marshal (& meta )
367+ if err != nil {
368+ return fmt .Errorf ("msgpack marshal: %w" , err )
369+ }
370+
371+ fd , err := unix .MemfdCreate ("datadog-tracer-info-ddtrace0" , unix .MFD_ALLOW_SEALING )
372+ if err != nil {
373+ return fmt .Errorf ("memfd_create: %w" , err )
374+ }
375+ defer unix .Close (fd )
376+
377+ if _ , err := unix .Write (fd , data ); err != nil {
378+ return fmt .Errorf ("memfd write: %w" , err )
379+ }
380+ const fAddSeals = 1033
381+ const fSealWrite = 0x0008
382+ const fSealShrink = 0x0002
383+ const fSealGrow = 0x0004
384+ if _ , _ , errno := syscall .Syscall (syscall .SYS_FCNTL , uintptr (fd ), fAddSeals , fSealWrite | fSealShrink | fSealGrow ); errno != 0 {
385+ return fmt .Errorf ("memfd seal: %w" , errno )
386+ }
387+
388+ // Wait for the agent to process the memfd seal event and populate the BPF map.
389+ time .Sleep (500 * time .Millisecond )
390+
391+ // Start dd-trace-go with:
392+ // - WithTestDefaults: uses a dummy transport (no real agent needed)
393+ // - WithProfilerCodeHotspots: enables "span id" and "local root span id" pprof labels
394+ // - WithService: set a service name
395+ tracer .Start (
396+ tracer .WithTestDefaults (nil ),
397+ tracer .WithProfilerCodeHotspots (true ),
398+ tracer .WithService ("ddtrace-test" ),
399+ tracer .WithLogStartup (false ),
400+ )
401+ defer tracer .Stop ()
402+
403+ // Create a span. dd-trace-go will automatically set pprof labels
404+ // "span id" and "local root span id" on the current goroutine.
405+ span , ctx := tracer .StartSpanFromContext (context .Background (), "test.operation" )
406+
407+ // Print the span ID and local root span ID so the test can parse and verify them.
408+ spanID := span .Context ().SpanID ()
409+ localRootSpanID := span .Root ().Context ().SpanID ()
410+ fmt .Printf ("ddtrace_span_id=%d\n " , spanID )
411+ fmt .Printf ("ddtrace_local_root_span_id=%d\n " , localRootSpanID )
412+
413+ _ = ctx
414+ runtime .LockOSThread ()
415+ defer runtime .UnlockOSThread ()
416+
417+ // Trigger the file open that the CWS rule is watching.
418+ f , err := os .Create (filePath )
419+ if err != nil {
420+ span .Finish ()
421+ return fmt .Errorf ("create file: %w" , err )
422+ }
423+ f .Close ()
424+ os .Remove (filePath )
425+
426+ span .Finish ()
427+ return nil
428+ }
429+
343430func main () {
344431 flag .BoolVar (& bpfLoad , "load-bpf" , false , "load the eBPF programs" )
345432 flag .BoolVar (& bpfClone , "clone-bpf" , false , "clone maps" )
@@ -360,6 +447,8 @@ func main() {
360447 flag .StringVar (& goSpanSpanID , "go-span-span-id" , "" , "span ID for the Go span test (decimal string)" )
361448 flag .StringVar (& goSpanLocalRootSpanID , "go-span-local-root-span-id" , "" , "local root span ID for the Go span test (decimal string)" )
362449 flag .StringVar (& goSpanFilePath , "go-span-file-path" , "" , "file path to open for the Go span test" )
450+ flag .BoolVar (& ddtraceSpanTest , "ddtrace-span-test" , false , "when set, runs the dd-trace-go span test" )
451+ flag .StringVar (& ddtraceSpanFilePath , "ddtrace-span-file-path" , "" , "file path to open for the dd-trace-go span test" )
363452
364453 flag .Parse ()
365454
@@ -426,4 +515,10 @@ func main() {
426515 panic (err )
427516 }
428517 }
518+
519+ if ddtraceSpanTest {
520+ if err := RunDDTraceSpanTest (ddtraceSpanFilePath ); err != nil {
521+ panic (err )
522+ }
523+ }
429524}
0 commit comments