diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d543869e..b6a7b3718 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ OpenTelemetry Go Automatic Instrumentation adheres to [Semantic Versioning](http ### Fixed - Fix gRPC instrumentation memory access issue on newer kernels. ([#150](https://github.com/open-telemetry/opentelemetry-go-instrumentation/pull/150)) +- Fix missing spans in gorillamux instrumentation. ([#86](https://github.com/open-telemetry/opentelemetry-go-instrumentation/pull/86)) ### Changed diff --git a/pkg/instrumentors/bpf/github.com/gin-gonic/gin/bpf/probe.bpf.c b/pkg/instrumentors/bpf/github.com/gin-gonic/gin/bpf/probe.bpf.c index 0c595e789..a068fe450 100644 --- a/pkg/instrumentors/bpf/github.com/gin-gonic/gin/bpf/probe.bpf.c +++ b/pkg/instrumentors/bpf/github.com/gin-gonic/gin/bpf/probe.bpf.c @@ -19,7 +19,7 @@ char __license[] SEC("license") = "Dual MIT/GPL"; #define PATH_MAX_LEN 100 -#define METHOD_MAX_LEN 6 // Longer method: DELETE +#define METHOD_MAX_LEN 7 #define MAX_CONCURRENT 50 struct http_request_t { diff --git a/pkg/instrumentors/bpf/github.com/gin-gonic/gin/bpf_bpfel_arm64.go b/pkg/instrumentors/bpf/github.com/gin-gonic/gin/bpf_bpfel_arm64.go index be4cd2a39..3532cd519 100644 --- a/pkg/instrumentors/bpf/github.com/gin-gonic/gin/bpf_bpfel_arm64.go +++ b/pkg/instrumentors/bpf/github.com/gin-gonic/gin/bpf_bpfel_arm64.go @@ -16,10 +16,10 @@ import ( type bpfHttpRequestT struct { StartTime uint64 EndTime uint64 - Method [6]int8 + Method [7]int8 Path [100]int8 Sc bpfSpanContext - _ [6]byte + _ [5]byte } type bpfSpanContext struct { diff --git a/pkg/instrumentors/bpf/github.com/gin-gonic/gin/bpf_bpfel_x86.go b/pkg/instrumentors/bpf/github.com/gin-gonic/gin/bpf_bpfel_x86.go index d57a435b0..787c38522 100644 --- a/pkg/instrumentors/bpf/github.com/gin-gonic/gin/bpf_bpfel_x86.go +++ b/pkg/instrumentors/bpf/github.com/gin-gonic/gin/bpf_bpfel_x86.go @@ -16,10 +16,10 @@ import ( type bpfHttpRequestT struct { StartTime uint64 EndTime uint64 - Method [6]int8 + Method [7]int8 Path [100]int8 Sc bpfSpanContext - _ [6]byte + _ [5]byte } type bpfSpanContext struct { diff --git a/pkg/instrumentors/bpf/github.com/gin-gonic/gin/probe.go b/pkg/instrumentors/bpf/github.com/gin-gonic/gin/probe.go index 6ca555950..9be30b8f7 100644 --- a/pkg/instrumentors/bpf/github.com/gin-gonic/gin/probe.go +++ b/pkg/instrumentors/bpf/github.com/gin-gonic/gin/probe.go @@ -46,7 +46,7 @@ import ( type Event struct { StartTime uint64 EndTime uint64 - Method [6]byte + Method [7]byte Path [100]byte SpanContext context.EBPFSpanContext } diff --git a/pkg/instrumentors/bpf/github.com/gorilla/mux/bpf/probe.bpf.c b/pkg/instrumentors/bpf/github.com/gorilla/mux/bpf/probe.bpf.c index f4a1d4c16..e20865fe9 100644 --- a/pkg/instrumentors/bpf/github.com/gorilla/mux/bpf/probe.bpf.c +++ b/pkg/instrumentors/bpf/github.com/gorilla/mux/bpf/probe.bpf.c @@ -19,7 +19,7 @@ char __license[] SEC("license") = "Dual MIT/GPL"; #define PATH_MAX_LEN 100 -#define METHOD_MAX_LEN 6 // Longer method: DELETE +#define METHOD_MAX_LEN 7 #define MAX_CONCURRENT 50 struct http_request_t { @@ -91,8 +91,11 @@ int uprobe_GorillaMux_ServeHTTP(struct pt_regs *ctx) { SEC("uprobe/GorillaMux_ServeHTTP") int uprobe_GorillaMux_ServeHTTP_Returns(struct pt_regs *ctx) { + u64 request_pos = 4; void *goroutine = get_goroutine_address(ctx, ctx_ptr_pos); - void *httpReq_ptr = bpf_map_lookup_elem(&context_to_http_events, &goroutine); + void* req_ptr = get_argument(ctx, request_pos); + + void* httpReq_ptr = bpf_map_lookup_elem(&context_to_http_events, &goroutine); struct http_request_t httpReq = {}; bpf_probe_read(&httpReq, sizeof(httpReq), httpReq_ptr); httpReq.end_time = bpf_ktime_get_ns(); diff --git a/pkg/instrumentors/bpf/github.com/gorilla/mux/bpf_bpfel_arm64.go b/pkg/instrumentors/bpf/github.com/gorilla/mux/bpf_bpfel_arm64.go index 3d8c80d1d..e64f9a790 100644 --- a/pkg/instrumentors/bpf/github.com/gorilla/mux/bpf_bpfel_arm64.go +++ b/pkg/instrumentors/bpf/github.com/gorilla/mux/bpf_bpfel_arm64.go @@ -16,10 +16,10 @@ import ( type bpfHttpRequestT struct { StartTime uint64 EndTime uint64 - Method [6]int8 + Method [7]int8 Path [100]int8 Sc bpfSpanContext - _ [6]byte + _ [5]byte } type bpfSpanContext struct { diff --git a/pkg/instrumentors/bpf/github.com/gorilla/mux/bpf_bpfel_x86.go b/pkg/instrumentors/bpf/github.com/gorilla/mux/bpf_bpfel_x86.go index 50f832a31..2af10aa70 100644 --- a/pkg/instrumentors/bpf/github.com/gorilla/mux/bpf_bpfel_x86.go +++ b/pkg/instrumentors/bpf/github.com/gorilla/mux/bpf_bpfel_x86.go @@ -16,10 +16,10 @@ import ( type bpfHttpRequestT struct { StartTime uint64 EndTime uint64 - Method [6]int8 + Method [7]int8 Path [100]int8 Sc bpfSpanContext - _ [6]byte + _ [5]byte } type bpfSpanContext struct { diff --git a/pkg/instrumentors/bpf/github.com/gorilla/mux/probe.go b/pkg/instrumentors/bpf/github.com/gorilla/mux/probe.go index 8f09cf16e..e9f3f953d 100644 --- a/pkg/instrumentors/bpf/github.com/gorilla/mux/probe.go +++ b/pkg/instrumentors/bpf/github.com/gorilla/mux/probe.go @@ -45,7 +45,7 @@ import ( type Event struct { StartTime uint64 EndTime uint64 - Method [100]byte + Method [7]byte Path [100]byte SpanContext context.EBPFSpanContext } @@ -53,7 +53,7 @@ type Event struct { // Instrumentor is the gorilla/mux instrumentor. type Instrumentor struct { bpfObjects *bpfObjects - uprobe link.Link + uprobes []link.Link returnProbs []link.Link eventsReader *perf.Reader } @@ -113,41 +113,51 @@ func (g *Instrumentor) Load(ctx *context.InstrumentorContext) error { return err } - offset, err := ctx.TargetDetails.GetFunctionOffset(g.FuncNames()[0]) + for _, funcName := range g.FuncNames() { + g.registerProbes(ctx, funcName) + } + rd, err := perf.NewReader(g.bpfObjects.Events, os.Getpagesize()) if err != nil { return err } + g.eventsReader = rd + + return nil +} + +func (g *Instrumentor) registerProbes(ctx *context.InstrumentorContext, funcName string) { + logger := log.Logger.WithName("gorilla/mux-instrumentor").WithValues("function", funcName) + offset, err := ctx.TargetDetails.GetFunctionOffset(funcName) + if err != nil { + logger.Error(err, "could not find function start offset. Skipping") + return + } + retOffsets, err := ctx.TargetDetails.GetFunctionReturns(funcName) + if err != nil { + logger.Error(err, "could not find function end offset. Skipping") + return + } up, err := ctx.Executable.Uprobe("", g.bpfObjects.UprobeGorillaMuxServeHTTP, &link.UprobeOptions{ Address: offset, }) if err != nil { - return err + logger.Error(err, "could not insert start uprobe. Skipping") + return } - g.uprobe = up - retOffsets, err := ctx.TargetDetails.GetFunctionReturns(g.FuncNames()[0]) - if err != nil { - return err - } + g.uprobes = append(g.uprobes, up) for _, ret := range retOffsets { retProbe, err := ctx.Executable.Uprobe("", g.bpfObjects.UprobeGorillaMuxServeHTTP_Returns, &link.UprobeOptions{ Address: ret, }) if err != nil { - return err + logger.Error(err, "could not insert return uprobe. Skipping") + return } g.returnProbs = append(g.returnProbs, retProbe) } - - rd, err := perf.NewReader(g.bpfObjects.Events, os.Getpagesize()) - if err != nil { - return err - } - g.eventsReader = rd - - return nil } // Run runs the events processing loop. @@ -210,8 +220,8 @@ func (g *Instrumentor) Close() { g.eventsReader.Close() } - if g.uprobe != nil { - g.uprobe.Close() + for _, r := range g.uprobes { + r.Close() } for _, r := range g.returnProbs { diff --git a/pkg/instrumentors/bpf/net/http/server/bpf/probe.bpf.c b/pkg/instrumentors/bpf/net/http/server/bpf/probe.bpf.c index bb724666b..bde32a61b 100644 --- a/pkg/instrumentors/bpf/net/http/server/bpf/probe.bpf.c +++ b/pkg/instrumentors/bpf/net/http/server/bpf/probe.bpf.c @@ -19,7 +19,7 @@ char __license[] SEC("license") = "Dual MIT/GPL"; #define PATH_MAX_LEN 100 -#define METHOD_MAX_LEN 6 // Longer method: DELETE +#define METHOD_MAX_LEN 7 #define MAX_CONCURRENT 50 struct http_request_t diff --git a/pkg/instrumentors/bpf/net/http/server/bpf_bpfel_arm64.go b/pkg/instrumentors/bpf/net/http/server/bpf_bpfel_arm64.go index 8b017c446..8d06beb63 100644 --- a/pkg/instrumentors/bpf/net/http/server/bpf_bpfel_arm64.go +++ b/pkg/instrumentors/bpf/net/http/server/bpf_bpfel_arm64.go @@ -16,10 +16,10 @@ import ( type bpfHttpRequestT struct { StartTime uint64 EndTime uint64 - Method [6]int8 + Method [7]int8 Path [100]int8 Sc bpfSpanContext - _ [6]byte + _ [5]byte } type bpfSpanContext struct { diff --git a/pkg/instrumentors/bpf/net/http/server/bpf_bpfel_x86.go b/pkg/instrumentors/bpf/net/http/server/bpf_bpfel_x86.go index 8d70f5d5e..d6cb3da28 100644 --- a/pkg/instrumentors/bpf/net/http/server/bpf_bpfel_x86.go +++ b/pkg/instrumentors/bpf/net/http/server/bpf_bpfel_x86.go @@ -16,10 +16,10 @@ import ( type bpfHttpRequestT struct { StartTime uint64 EndTime uint64 - Method [6]int8 + Method [7]int8 Path [100]int8 Sc bpfSpanContext - _ [6]byte + _ [5]byte } type bpfSpanContext struct { diff --git a/pkg/instrumentors/bpf/net/http/server/probe.go b/pkg/instrumentors/bpf/net/http/server/probe.go index 6daafc4f2..78cbce87b 100644 --- a/pkg/instrumentors/bpf/net/http/server/probe.go +++ b/pkg/instrumentors/bpf/net/http/server/probe.go @@ -45,7 +45,7 @@ import ( type Event struct { StartTime uint64 EndTime uint64 - Method [6]byte + Method [7]byte Path [100]byte SpanContext context.EBPFSpanContext } diff --git a/test/e2e/gorillamux/traces.json b/test/e2e/gorillamux/traces.json index d7d5b45a7..26027ede2 100644 --- a/test/e2e/gorillamux/traces.json +++ b/test/e2e/gorillamux/traces.json @@ -24,6 +24,35 @@ ] }, "scopeSpans": [ + { + "scope": { + "name": "github.com/gorilla/mux" + }, + "spans": [ + { + "attributes": [ + { + "key": "http.method", + "value": { + "stringValue": "GET" + } + }, + { + "key": "http.target", + "value": { + "stringValue": "/users/foo" + } + } + ], + "kind": 2, + "name": "GET /users/foo", + "parentSpanId": "", + "spanId": "xxxxx", + "status": {}, + "traceId": "xxxxx" + } + ] + }, { "scope": { "name": "net/http"