From 3b0f2ff8ca05b08c42ead2bc2be5396a0ce6e284 Mon Sep 17 00:00:00 2001 From: Mike Goldsmth Date: Wed, 26 Apr 2023 13:28:31 +0100 Subject: [PATCH 01/20] add gin instrumentation --- Makefile | 3 +- .../github.com/gin-gonic/gin/bpf/probe.bpf.c | 110 +++++++++ .../bpf/github.com/gin-gonic/gin/probe.go | 217 ++++++++++++++++++ pkg/instrumentors/manager.go | 2 + test/e2e/gin/Dockerfile | 4 + test/e2e/gin/go.mod | 3 + test/e2e/gin/main.go | 36 +++ test/e2e/gin/traces.json | 74 ++++++ 8 files changed, 448 insertions(+), 1 deletion(-) create mode 100644 pkg/instrumentors/bpf/github.com/gin-gonic/gin/bpf/probe.bpf.c create mode 100644 pkg/instrumentors/bpf/github.com/gin-gonic/gin/probe.go create mode 100644 test/e2e/gin/Dockerfile create mode 100644 test/e2e/gin/go.mod create mode 100644 test/e2e/gin/main.go create mode 100644 test/e2e/gin/traces.json diff --git a/Makefile b/Makefile index dfec3a943..6279a7a4f 100644 --- a/Makefile +++ b/Makefile @@ -63,9 +63,10 @@ verify-licenses: | $(GOLICENSES) exit 1; \ fi; \ -.PHONY: fixture-nethttp fixture-gorillamux +.PHONY: fixture-nethttp fixture-gorillamux fixture-gin fixture-nethttp: fixtures/nethttp fixture-gorillamux: fixtures/gorillamux +fixture-gorillamux: fixtures/gin fixtures/%: LIBRARY=$* fixtures/%: IMG=otel-go-instrumentation $(MAKE) docker-build 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 new file mode 100644 index 000000000..1aa23b75d --- /dev/null +++ b/pkg/instrumentors/bpf/github.com/gin-gonic/gin/bpf/probe.bpf.c @@ -0,0 +1,110 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "arguments.h" +#include "span_context.h" +#include "go_context.h" + +char __license[] SEC("license") = "Dual MIT/GPL"; + +#define PATH_MAX_LEN 100 +#define METHOD_MAX_LEN 6 // Longer method: DELETE +#define MAX_CONCURRENT 50 + +struct http_request_t +{ + u64 start_time; + u64 end_time; + char method[METHOD_MAX_LEN]; + char path[PATH_MAX_LEN]; + struct span_context sc; +}; + +// map key: pointer to the goroutine that handles the request +struct +{ + __uint(type, BPF_MAP_TYPE_HASH); + __type(key, void *); + __type(value, struct http_request_t); + __uint(max_entries, MAX_CONCURRENT); +} context_to_http_events SEC(".maps"); + +struct +{ + __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); +} events SEC(".maps"); + +// Injected in init +volatile const u64 method_ptr_pos; +volatile const u64 url_ptr_pos; +volatile const u64 path_ptr_pos; + +// This instrumentation attaches uprobe to the following function: +// func (engine *Engine) ServeHTTP(w http.ResponseWriter, r *http.Request) +SEC("uprobe/GinEngine_ServeHTTP") +int uprobe_GinEngine_ServeHTTP(struct pt_regs *ctx) +{ + u64 request_pos = 4; + struct http_request_t httpReq = {}; + httpReq.start_time = bpf_ktime_get_ns(); + + // Get request struct + void *req_ptr = get_argument(ctx, request_pos); + + // Get method from request + void *method_ptr = 0; + bpf_probe_read(&method_ptr, sizeof(method_ptr), (void *)(req_ptr + method_ptr_pos)); + u64 method_len = 0; + bpf_probe_read(&method_len, sizeof(method_len), (void *)(req_ptr + (method_ptr_pos + 8))); + u64 method_size = sizeof(httpReq.method); + method_size = method_size < method_len ? method_size : method_len; + bpf_probe_read(&httpReq.method, method_size, method_ptr); + + // get path from Request.URL + void *url_ptr = 0; + bpf_probe_read(&url_ptr, sizeof(url_ptr), (void *)(req_ptr + url_ptr_pos)); + void *path_ptr = 0; + bpf_probe_read(&path_ptr, sizeof(path_ptr), (void *)(url_ptr + path_ptr_pos)); + u64 path_len = 0; + bpf_probe_read(&path_len, sizeof(path_len), (void *)(url_ptr + (path_ptr_pos + 8))); + u64 path_size = sizeof(httpReq.path); + path_size = path_size < path_len ? path_size : path_len; + bpf_probe_read(&httpReq.path, path_size, path_ptr); + + // Get goroutine pointer + void *goroutine = get_goroutine_address(ctx); + + // Write event + httpReq.sc = generate_span_context(); + bpf_map_update_elem(&context_to_http_events, &goroutine, &httpReq, 0); + long res = bpf_map_update_elem(&spans_in_progress, &goroutine, &httpReq.sc, 0); + return 0; +} + +SEC("uprobe/GinEngine_ServeHTTP") +int uprobe_GinEngine_ServeHTTP_Returns(struct pt_regs *ctx) +{ + u64 request_pos = 4; + void *req_ptr = get_argument(ctx, request_pos); + void *goroutine = get_goroutine_address(ctx); + + 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(); + bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &httpReq, sizeof(httpReq)); + bpf_map_delete_elem(&context_to_http_events, &goroutine); + bpf_map_delete_elem(&spans_in_progress, &goroutine); + return 0; +} \ No newline at end of file diff --git a/pkg/instrumentors/bpf/github.com/gin-gonic/gin/probe.go b/pkg/instrumentors/bpf/github.com/gin-gonic/gin/probe.go new file mode 100644 index 000000000..c89517f13 --- /dev/null +++ b/pkg/instrumentors/bpf/github.com/gin-gonic/gin/probe.go @@ -0,0 +1,217 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package server + +import ( + "bytes" + "encoding/binary" + "errors" + "os" + + "go.opentelemetry.io/auto/pkg/instrumentors/bpffs" + + "github.com/cilium/ebpf" + "github.com/cilium/ebpf/link" + "github.com/cilium/ebpf/perf" + "go.opentelemetry.io/auto/pkg/inject" + "go.opentelemetry.io/auto/pkg/instrumentors/context" + "go.opentelemetry.io/auto/pkg/instrumentors/events" + "go.opentelemetry.io/auto/pkg/log" + "go.opentelemetry.io/otel/attribute" + semconv "go.opentelemetry.io/otel/semconv/v1.7.0" + "go.opentelemetry.io/otel/trace" + "golang.org/x/sys/unix" +) + +//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -target bpfel -cc clang -cflags $CFLAGS bpf ./bpf/probe.bpf.c + +type HttpEvent struct { + StartTime uint64 + EndTime uint64 + Method [6]byte + Path [100]byte + SpanContext context.EbpfSpanContext +} + +type httpServerInstrumentor struct { + bpfObjects *bpfObjects + uprobes []link.Link + returnProbs []link.Link + eventsReader *perf.Reader +} + +func New() *httpServerInstrumentor { + return &httpServerInstrumentor{} +} + +func (h *httpServerInstrumentor) LibraryName() string { + return "github.com/gin-gonic/gin" +} + +func (h *httpServerInstrumentor) FuncNames() []string { + return []string{"github.com/gin-gonic/gin.(*Engine).ServeHTTP"} +} + +func (h *httpServerInstrumentor) Load(ctx *context.InstrumentorContext) error { + spec, err := ctx.Injector.Inject(loadBpf, "go", ctx.TargetDetails.GoVersion.Original(), []*inject.InjectStructField{ + { + VarName: "method_ptr_pos", + StructName: "net/http.Request", + Field: "Method", + }, + { + VarName: "url_ptr_pos", + StructName: "net/http.Request", + Field: "URL", + }, + { + VarName: "path_ptr_pos", + StructName: "net/url.URL", + Field: "Path", + }, + }, false) + + if err != nil { + return err + } + + h.bpfObjects = &bpfObjects{} + err = spec.LoadAndAssign(h.bpfObjects, &ebpf.CollectionOptions{ + Maps: ebpf.MapOptions{ + PinPath: bpffs.BpfFsPath, + }, + }) + if err != nil { + return err + } + + for _, funcName := range h.FuncNames() { + h.registerProbes(ctx, funcName) + } + + rd, err := perf.NewReader(h.bpfObjects.Events, os.Getpagesize()) + if err != nil { + return err + } + h.eventsReader = rd + + return nil +} + +func (h *httpServerInstrumentor) registerProbes(ctx *context.InstrumentorContext, funcName string) { + logger := log.Logger.WithName("gin-gonic/gin-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 offsets. Skipping") + return + } + + up, err := ctx.Executable.Uprobe("", h.bpfObjects.UprobeGinEngineServeHTTP, &link.UprobeOptions{ + Address: offset, + }) + if err != nil { + logger.V(1).Info("could not insert start uprobe. Skipping", + "error", err.Error()) + return + } + + h.uprobes = append(h.uprobes, up) + + for _, ret := range retOffsets { + retProbe, err := ctx.Executable.Uprobe("", h.bpfObjects.UprobeGinEngineServeHTTP_Returns, &link.UprobeOptions{ + Address: ret, + }) + if err != nil { + logger.Error(err, "could not insert return uprobe. Skipping") + return + } + h.returnProbs = append(h.returnProbs, retProbe) + } +} + +func (h *httpServerInstrumentor) Run(eventsChan chan<- *events.Event) { + logger := log.Logger.WithName("gin-gonic/gin-instrumentor") + var event HttpEvent + for { + record, err := h.eventsReader.Read() + if err != nil { + if errors.Is(err, perf.ErrClosed) { + return + } + logger.Error(err, "error reading from perf reader") + continue + } + + if record.LostSamples != 0 { + logger.V(0).Info("perf event ring buffer full", "dropped", record.LostSamples) + continue + } + + if err := binary.Read(bytes.NewBuffer(record.RawSample), binary.LittleEndian, &event); err != nil { + logger.Error(err, "error parsing perf event") + continue + } + + eventsChan <- h.convertEvent(&event) + } +} + +func (h *httpServerInstrumentor) convertEvent(e *HttpEvent) *events.Event { + method := unix.ByteSliceToString(e.Method[:]) + path := unix.ByteSliceToString(e.Path[:]) + + sc := trace.NewSpanContext(trace.SpanContextConfig{ + TraceID: e.SpanContext.TraceID, + SpanID: e.SpanContext.SpanID, + TraceFlags: trace.FlagsSampled, + }) + + return &events.Event{ + Library: h.LibraryName(), + Name: path, + Kind: trace.SpanKindServer, + StartTime: int64(e.StartTime), + EndTime: int64(e.EndTime), + SpanContext: &sc, + Attributes: []attribute.KeyValue{ + semconv.HTTPMethodKey.String(method), + semconv.HTTPTargetKey.String(path), + }, + } +} + +func (h *httpServerInstrumentor) Close() { + log.Logger.V(0).Info("closing gin-gonic/gin instrumentor") + if h.eventsReader != nil { + h.eventsReader.Close() + } + + for _, r := range h.uprobes { + r.Close() + } + + for _, r := range h.returnProbs { + r.Close() + } + + if h.bpfObjects != nil { + h.bpfObjects.Close() + } +} diff --git a/pkg/instrumentors/manager.go b/pkg/instrumentors/manager.go index 8b0bc9f0c..587a46ed9 100644 --- a/pkg/instrumentors/manager.go +++ b/pkg/instrumentors/manager.go @@ -18,6 +18,7 @@ import ( "fmt" "go.opentelemetry.io/auto/pkg/instrumentors/allocator" + ginMux "go.opentelemetry.io/auto/pkg/instrumentors/bpf/github.com/gin-gonic/gin" gorillaMux "go.opentelemetry.io/auto/pkg/instrumentors/bpf/github.com/gorilla/mux" "go.opentelemetry.io/auto/pkg/instrumentors/bpf/google/golang/org/grpc" grpcServer "go.opentelemetry.io/auto/pkg/instrumentors/bpf/google/golang/org/grpc/server" @@ -101,6 +102,7 @@ func registerInstrumentors(m *instrumentorsManager) error { grpcServer.New(), httpServer.New(), gorillaMux.New(), + ginMux.New(), } for _, i := range insts { diff --git a/test/e2e/gin/Dockerfile b/test/e2e/gin/Dockerfile new file mode 100644 index 000000000..646ec7a43 --- /dev/null +++ b/test/e2e/gin/Dockerfile @@ -0,0 +1,4 @@ +FROM golang:1.20 +WORKDIR /sample-app +COPY . . +RUN go build -o main diff --git a/test/e2e/gin/go.mod b/test/e2e/gin/go.mod new file mode 100644 index 000000000..5aba1a349 --- /dev/null +++ b/test/e2e/gin/go.mod @@ -0,0 +1,3 @@ +module go.opentelemetry.io/auto/test/e2e/nethttp + +go 1.20 diff --git a/test/e2e/gin/main.go b/test/e2e/gin/main.go new file mode 100644 index 000000000..4deca4a1b --- /dev/null +++ b/test/e2e/gin/main.go @@ -0,0 +1,36 @@ +package main + +import ( + "fmt" + "io/ioutil" + "log" + "net/http" + "time" +) + +func hello(w http.ResponseWriter, req *http.Request) { + fmt.Fprintf(w, "hello\n") +} + +func main() { + http.HandleFunc("/hello", hello) + go http.ListenAndServe(":8080", nil) + + // give time for auto-instrumentation to start up + time.Sleep(5 * time.Second) + + resp, err := http.Get("http://localhost:8080/hello") + if err != nil { + log.Fatal(err) + } + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + log.Fatal(err) + } + + log.Printf("Body: %s\n", string(body)) + _ = resp.Body.Close() + + // give time for auto-instrumentation to report signal + time.Sleep(5 * time.Second) +} diff --git a/test/e2e/gin/traces.json b/test/e2e/gin/traces.json new file mode 100644 index 000000000..a9c250222 --- /dev/null +++ b/test/e2e/gin/traces.json @@ -0,0 +1,74 @@ +{ + "resourceSpans": [ + { + "resource": { + "attributes": [ + { + "key": "service.name", + "value": { + "stringValue": "sample-app" + } + }, + { + "key": "telemetry.sdk.language", + "value": { + "stringValue": "go" + } + } + ] + }, + "scopeSpans": [ + { + "scope": { + "name": "gin-gonic/gin" + }, + "spans": [ + { + "attributes": [ + { + "key": "http.method", + "value": { + "stringValue": "GET" + } + }, + { + "key": "http.target", + "value": { + "stringValue": "/hello" + } + } + ], + "kind": 2, + "name": "/hello", + "parentSpanId": "", + "spanId": "xxxxx", + "status": {}, + "traceId": "xxxxx" + }, + { + "attributes": [ + { + "key": "http.method", + "value": { + "stringValue": "" + } + }, + { + "key": "http.target", + "value": { + "stringValue": "" + } + } + ], + "kind": 2, + "parentSpanId": "", + "spanId": "", + "status": {}, + "traceId": "" + } + ] + } + ] + } + ] +} \ No newline at end of file From 0819563b22f388f9508401c4cb4232ddeb51f195 Mon Sep 17 00:00:00 2001 From: Mike Goldsmth Date: Wed, 26 Apr 2023 13:32:27 +0100 Subject: [PATCH 02/20] fix gin makefile fixture name --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 6279a7a4f..5ac00edd5 100644 --- a/Makefile +++ b/Makefile @@ -66,7 +66,7 @@ verify-licenses: | $(GOLICENSES) .PHONY: fixture-nethttp fixture-gorillamux fixture-gin fixture-nethttp: fixtures/nethttp fixture-gorillamux: fixtures/gorillamux -fixture-gorillamux: fixtures/gin +fixture-gin: fixtures/gin fixtures/%: LIBRARY=$* fixtures/%: IMG=otel-go-instrumentation $(MAKE) docker-build From 989d460fcd6a0910db7750260280f16652dc0d4c Mon Sep 17 00:00:00 2001 From: Mike Goldsmth Date: Wed, 26 Apr 2023 13:34:34 +0100 Subject: [PATCH 03/20] add gin to e2e workflow library set --- .github/workflows/kind.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/kind.yml b/.github/workflows/kind.yml index f12ae3b07..deb603e3a 100644 --- a/.github/workflows/kind.yml +++ b/.github/workflows/kind.yml @@ -10,10 +10,10 @@ on: jobs: kubernetes-test: - strategy: + strategy: matrix: k8s-version: ["v1.26.0"] - library: ["gorillamux", "nethttp"] + library: ["gorillamux", "nethttp", "gin"] runs-on: ubuntu-latest steps: - name: Checkout Repo From 6e38dc979cb4fabd48575c797c81e5266a06b90d Mon Sep 17 00:00:00 2001 From: Mike Goldsmth Date: Wed, 26 Apr 2023 13:40:01 +0100 Subject: [PATCH 04/20] actually use gin in test app --- test/e2e/gin/go.mod | 28 +++++++++++++++ test/e2e/gin/go.sum | 81 ++++++++++++++++++++++++++++++++++++++++++++ test/e2e/gin/main.go | 7 ++-- 3 files changed, 114 insertions(+), 2 deletions(-) create mode 100644 test/e2e/gin/go.sum diff --git a/test/e2e/gin/go.mod b/test/e2e/gin/go.mod index 5aba1a349..838ad0866 100644 --- a/test/e2e/gin/go.mod +++ b/test/e2e/gin/go.mod @@ -1,3 +1,31 @@ module go.opentelemetry.io/auto/test/e2e/nethttp go 1.20 + +require github.com/gin-gonic/gin v1.9.0 + +require ( + github.com/bytedance/sonic v1.8.0 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.11.2 // indirect + github.com/goccy/go-json v0.10.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.0.9 // indirect + github.com/leodido/go-urn v1.2.1 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/pelletier/go-toml/v2 v2.0.6 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.9 // indirect + golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect + golang.org/x/crypto v0.5.0 // indirect + golang.org/x/net v0.7.0 // indirect + golang.org/x/sys v0.5.0 // indirect + golang.org/x/text v0.7.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/test/e2e/gin/go.sum b/test/e2e/gin/go.sum new file mode 100644 index 000000000..bfad1c04d --- /dev/null +++ b/test/e2e/gin/go.sum @@ -0,0 +1,81 @@ +github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= +github.com/bytedance/sonic v1.8.0 h1:ea0Xadu+sHlu7x5O3gKhRpQ1IKiMrSiHttPF0ybECuA= +github.com/bytedance/sonic v1.8.0/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= +github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.9.0 h1:OjyFBKICoexlu99ctXNR2gg+c5pKrKMuyjgARg9qeY8= +github.com/gin-gonic/gin v1.9.0/go.mod h1:W1Me9+hsUSyj3CePGrd1/QrKJMSJ1Tu/0hFEH89961k= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU= +github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s= +github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= +github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= +github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.9 h1:rmenucSohSTiyL09Y+l2OCk+FrMxGMzho2+tjr5ticU= +github.com/ugorji/go/codec v1.2.9/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE= +golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= +golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/test/e2e/gin/main.go b/test/e2e/gin/main.go index 4deca4a1b..c5d4c581e 100644 --- a/test/e2e/gin/main.go +++ b/test/e2e/gin/main.go @@ -6,6 +6,8 @@ import ( "log" "net/http" "time" + + "github.com/gin-gonic/gin" ) func hello(w http.ResponseWriter, req *http.Request) { @@ -13,8 +15,9 @@ func hello(w http.ResponseWriter, req *http.Request) { } func main() { - http.HandleFunc("/hello", hello) - go http.ListenAndServe(":8080", nil) + r := gin.Default() + r.Get("/hello", hello) + go r.run(); // give time for auto-instrumentation to start up time.Sleep(5 * time.Second) From d96b053db3ef6ae26ff9f345cd8bdaa8fda8fd14 Mon Sep 17 00:00:00 2001 From: Mike Goldsmth Date: Wed, 26 Apr 2023 14:08:02 +0100 Subject: [PATCH 05/20] update gin test app --- test/e2e/gin/main.go | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/test/e2e/gin/main.go b/test/e2e/gin/main.go index c5d4c581e..66309ceed 100644 --- a/test/e2e/gin/main.go +++ b/test/e2e/gin/main.go @@ -1,7 +1,6 @@ package main import ( - "fmt" "io/ioutil" "log" "net/http" @@ -10,14 +9,12 @@ import ( "github.com/gin-gonic/gin" ) -func hello(w http.ResponseWriter, req *http.Request) { - fmt.Fprintf(w, "hello\n") -} - func main() { r := gin.Default() - r.Get("/hello", hello) - go r.run(); + r.GET("/hello", func(c *gin.Context) { + c.String(http.StatusOK, "hello\n") + }) + go r.Run(); // give time for auto-instrumentation to start up time.Sleep(5 * time.Second) From 88a840867b8d7172f7753af67066381ccd054a05 Mon Sep 17 00:00:00 2001 From: Mike Goldsmth Date: Wed, 26 Apr 2023 14:17:14 +0100 Subject: [PATCH 06/20] update expected trace json --- test/e2e/gin/traces.json | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/test/e2e/gin/traces.json b/test/e2e/gin/traces.json index a9c250222..219b27a02 100644 --- a/test/e2e/gin/traces.json +++ b/test/e2e/gin/traces.json @@ -20,7 +20,7 @@ "scopeSpans": [ { "scope": { - "name": "gin-gonic/gin" + "name": "github.com/gin-gonic/gin" }, "spans": [ { @@ -44,27 +44,6 @@ "spanId": "xxxxx", "status": {}, "traceId": "xxxxx" - }, - { - "attributes": [ - { - "key": "http.method", - "value": { - "stringValue": "" - } - }, - { - "key": "http.target", - "value": { - "stringValue": "" - } - } - ], - "kind": 2, - "parentSpanId": "", - "spanId": "", - "status": {}, - "traceId": "" } ] } From e46cc1f31a69881abb5a9bb7ca07ceddecb77ed8 Mon Sep 17 00:00:00 2001 From: Mike Goldsmth Date: Wed, 26 Apr 2023 14:30:45 +0100 Subject: [PATCH 07/20] add new line to gin trace --- test/e2e/gin/traces.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/gin/traces.json b/test/e2e/gin/traces.json index 219b27a02..e13828d74 100644 --- a/test/e2e/gin/traces.json +++ b/test/e2e/gin/traces.json @@ -50,4 +50,4 @@ ] } ] -} \ No newline at end of file +} From 555f8d4ea777d7f4c190948edc38580bb6760da2 Mon Sep 17 00:00:00 2001 From: Mike Goldsmth Date: Wed, 26 Apr 2023 15:07:29 +0100 Subject: [PATCH 08/20] add changelog entry --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 772efb445..49d0bbfc4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ OpenTelemetry Go Automatic Instrumentation adheres to [Semantic Versioning](http ## [Unreleased] +### Added + +- Add [gin-gonic/gin](https://github.com/gin-gonic/gin) instrumentation. ([#100](https://github.com/open-telemetry/opentelemetry-go-instrumentation/pull/100)) + ## [v0.1.0-alpha] - 2023-04-17 This is the first release of OpenTelemetry Go Automatic Instrumentation. From d4bdf9015280e199433c5147efa06bde636ce5f7 Mon Sep 17 00:00:00 2001 From: Mike Goldsmth Date: Wed, 26 Apr 2023 15:38:17 +0100 Subject: [PATCH 09/20] use unique path to indicate instrumentation --- test/e2e/gin/main.go | 2 +- test/e2e/gin/traces.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/e2e/gin/main.go b/test/e2e/gin/main.go index 66309ceed..29ebb0202 100644 --- a/test/e2e/gin/main.go +++ b/test/e2e/gin/main.go @@ -11,7 +11,7 @@ import ( func main() { r := gin.Default() - r.GET("/hello", func(c *gin.Context) { + r.GET("/hello-gin", func(c *gin.Context) { c.String(http.StatusOK, "hello\n") }) go r.Run(); diff --git a/test/e2e/gin/traces.json b/test/e2e/gin/traces.json index e13828d74..5832be918 100644 --- a/test/e2e/gin/traces.json +++ b/test/e2e/gin/traces.json @@ -34,12 +34,12 @@ { "key": "http.target", "value": { - "stringValue": "/hello" + "stringValue": "/hello-gin" } } ], "kind": 2, - "name": "/hello", + "name": "/hello-gin", "parentSpanId": "", "spanId": "xxxxx", "status": {}, From 92104db28ebe2b70c76b05c7259672b8f58bfb82 Mon Sep 17 00:00:00 2001 From: Mike Goldsmth Date: Wed, 26 Apr 2023 17:31:22 +0100 Subject: [PATCH 10/20] fix http call path --- test/e2e/gin/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/gin/main.go b/test/e2e/gin/main.go index 29ebb0202..a6346197c 100644 --- a/test/e2e/gin/main.go +++ b/test/e2e/gin/main.go @@ -19,7 +19,7 @@ func main() { // give time for auto-instrumentation to start up time.Sleep(5 * time.Second) - resp, err := http.Get("http://localhost:8080/hello") + resp, err := http.Get("http://localhost:8080/hello-gin") if err != nil { log.Fatal(err) } From dd21b2b97d615a0214cfbc59e846a4a583a420ea Mon Sep 17 00:00:00 2001 From: Mike Goldsmth Date: Wed, 26 Apr 2023 17:37:18 +0100 Subject: [PATCH 11/20] update probe formatting to match other probes --- .../bpf/github.com/gin-gonic/gin/bpf/probe.bpf.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) 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 1aa23b75d..9ee1fe7b6 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 @@ -22,8 +22,7 @@ char __license[] SEC("license") = "Dual MIT/GPL"; #define METHOD_MAX_LEN 6 // Longer method: DELETE #define MAX_CONCURRENT 50 -struct http_request_t -{ +struct http_request_t { u64 start_time; u64 end_time; char method[METHOD_MAX_LEN]; @@ -32,16 +31,14 @@ struct http_request_t }; // map key: pointer to the goroutine that handles the request -struct -{ +struct { __uint(type, BPF_MAP_TYPE_HASH); __type(key, void *); __type(value, struct http_request_t); __uint(max_entries, MAX_CONCURRENT); } context_to_http_events SEC(".maps"); -struct -{ +struct { __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); } events SEC(".maps"); @@ -53,8 +50,7 @@ volatile const u64 path_ptr_pos; // This instrumentation attaches uprobe to the following function: // func (engine *Engine) ServeHTTP(w http.ResponseWriter, r *http.Request) SEC("uprobe/GinEngine_ServeHTTP") -int uprobe_GinEngine_ServeHTTP(struct pt_regs *ctx) -{ +int uprobe_GinEngine_ServeHTTP(struct pt_regs *ctx) { u64 request_pos = 4; struct http_request_t httpReq = {}; httpReq.start_time = bpf_ktime_get_ns(); @@ -93,8 +89,7 @@ int uprobe_GinEngine_ServeHTTP(struct pt_regs *ctx) } SEC("uprobe/GinEngine_ServeHTTP") -int uprobe_GinEngine_ServeHTTP_Returns(struct pt_regs *ctx) -{ +int uprobe_GinEngine_ServeHTTP_Returns(struct pt_regs *ctx) { u64 request_pos = 4; void *req_ptr = get_argument(ctx, request_pos); void *goroutine = get_goroutine_address(ctx); From b1f985f9e8e13beee378f612047a9c7c2b446270 Mon Sep 17 00:00:00 2001 From: Mike Goldsmith Date: Thu, 27 Apr 2023 15:03:16 +0100 Subject: [PATCH 12/20] Update test/e2e/gin/go module name Co-authored-by: Tyler Yahn --- test/e2e/gin/go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/gin/go.mod b/test/e2e/gin/go.mod index 838ad0866..343b1da55 100644 --- a/test/e2e/gin/go.mod +++ b/test/e2e/gin/go.mod @@ -1,4 +1,4 @@ -module go.opentelemetry.io/auto/test/e2e/nethttp +module go.opentelemetry.io/auto/test/e2e/gin go 1.20 From 563a4e5dbe1c11a1f923ce587e0bc1d3b197bf71 Mon Sep 17 00:00:00 2001 From: Mike Goldsmth Date: Thu, 27 Apr 2023 15:07:57 +0100 Subject: [PATCH 13/20] update probe go package name Co-authored-by: Tyler Yahn --- pkg/instrumentors/bpf/github.com/gin-gonic/gin/probe.go | 2 +- pkg/instrumentors/manager.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) 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 c89517f13..cde32e9b7 100644 --- a/pkg/instrumentors/bpf/github.com/gin-gonic/gin/probe.go +++ b/pkg/instrumentors/bpf/github.com/gin-gonic/gin/probe.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package server +package gin import ( "bytes" diff --git a/pkg/instrumentors/manager.go b/pkg/instrumentors/manager.go index 587a46ed9..a4b00b55f 100644 --- a/pkg/instrumentors/manager.go +++ b/pkg/instrumentors/manager.go @@ -18,7 +18,7 @@ import ( "fmt" "go.opentelemetry.io/auto/pkg/instrumentors/allocator" - ginMux "go.opentelemetry.io/auto/pkg/instrumentors/bpf/github.com/gin-gonic/gin" + "go.opentelemetry.io/auto/pkg/instrumentors/bpf/github.com/gin-gonic/gin" gorillaMux "go.opentelemetry.io/auto/pkg/instrumentors/bpf/github.com/gorilla/mux" "go.opentelemetry.io/auto/pkg/instrumentors/bpf/google/golang/org/grpc" grpcServer "go.opentelemetry.io/auto/pkg/instrumentors/bpf/google/golang/org/grpc/server" @@ -102,7 +102,7 @@ func registerInstrumentors(m *instrumentorsManager) error { grpcServer.New(), httpServer.New(), gorillaMux.New(), - ginMux.New(), + gin.New(), } for _, i := range insts { From 99cac2ee7310eb9be4957378e2abc56b1d5ebb9f Mon Sep 17 00:00:00 2001 From: Mike Goldsmth Date: Thu, 27 Apr 2023 16:03:11 +0100 Subject: [PATCH 14/20] add license file to gin e2e test --- test/e2e/gin/main.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/e2e/gin/main.go b/test/e2e/gin/main.go index a6346197c..ee4b2f6ab 100644 --- a/test/e2e/gin/main.go +++ b/test/e2e/gin/main.go @@ -1,3 +1,17 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package main import ( From e0ead59122e8dc452300d7300b97e70d764aec4d Mon Sep 17 00:00:00 2001 From: Mike Goldsmth Date: Thu, 27 Apr 2023 19:23:12 +0100 Subject: [PATCH 15/20] use updated bpffs variable names --- pkg/instrumentors/bpf/github.com/gin-gonic/gin/probe.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 cde32e9b7..b74a75a67 100644 --- a/pkg/instrumentors/bpf/github.com/gin-gonic/gin/probe.go +++ b/pkg/instrumentors/bpf/github.com/gin-gonic/gin/probe.go @@ -42,7 +42,7 @@ type HttpEvent struct { EndTime uint64 Method [6]byte Path [100]byte - SpanContext context.EbpfSpanContext + SpanContext context.EBPFSpanContext } type httpServerInstrumentor struct { @@ -90,7 +90,7 @@ func (h *httpServerInstrumentor) Load(ctx *context.InstrumentorContext) error { h.bpfObjects = &bpfObjects{} err = spec.LoadAndAssign(h.bpfObjects, &ebpf.CollectionOptions{ Maps: ebpf.MapOptions{ - PinPath: bpffs.BpfFsPath, + PinPath: bpffs.BPFFsPath, }, }) if err != nil { From fa999bd9b65c41d0e6513eacfa092749b6396375 Mon Sep 17 00:00:00 2001 From: Mike Goldsmth Date: Thu, 27 Apr 2023 19:39:13 +0100 Subject: [PATCH 16/20] update probe to apply linter rules --- .../bpf/github.com/gin-gonic/gin/probe.go | 34 ++++++++++++------- 1 file changed, 22 insertions(+), 12 deletions(-) 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 b74a75a67..d91fe0a99 100644 --- a/pkg/instrumentors/bpf/github.com/gin-gonic/gin/probe.go +++ b/pkg/instrumentors/bpf/github.com/gin-gonic/gin/probe.go @@ -37,7 +37,9 @@ import ( //go:generate go run github.com/cilium/ebpf/cmd/bpf2go -target bpfel -cc clang -cflags $CFLAGS bpf ./bpf/probe.bpf.c -type HttpEvent struct { +// Event represents an event in the gin-gonic/gin server during an HTTP +// request-response. +type Event struct { StartTime uint64 EndTime uint64 Method [6]byte @@ -45,26 +47,32 @@ type HttpEvent struct { SpanContext context.EBPFSpanContext } -type httpServerInstrumentor struct { +// Instrumentor is the gin-gonic/gin instrumentor. +type Instrumentor struct { bpfObjects *bpfObjects uprobes []link.Link returnProbs []link.Link eventsReader *perf.Reader } -func New() *httpServerInstrumentor { - return &httpServerInstrumentor{} +// New returns a new [Instrumentor]. +func New() *Instrumentor { + return &Instrumentor{} } -func (h *httpServerInstrumentor) LibraryName() string { +// LibraryName returns the gorilla/mux package import path. +func (h *Instrumentor) LibraryName() string { return "github.com/gin-gonic/gin" } -func (h *httpServerInstrumentor) FuncNames() []string { +// FuncNames returns the function names from "github.com/gin-gonic/gin" that are +// instrumented. +func (h *Instrumentor) FuncNames() []string { return []string{"github.com/gin-gonic/gin.(*Engine).ServeHTTP"} } -func (h *httpServerInstrumentor) Load(ctx *context.InstrumentorContext) error { +// Load loads all instrumentation offsets. +func (h *Instrumentor) Load(ctx *context.InstrumentorContext) error { spec, err := ctx.Injector.Inject(loadBpf, "go", ctx.TargetDetails.GoVersion.Original(), []*inject.InjectStructField{ { VarName: "method_ptr_pos", @@ -110,7 +118,7 @@ func (h *httpServerInstrumentor) Load(ctx *context.InstrumentorContext) error { return nil } -func (h *httpServerInstrumentor) registerProbes(ctx *context.InstrumentorContext, funcName string) { +func (h *Instrumentor) registerProbes(ctx *context.InstrumentorContext, funcName string) { logger := log.Logger.WithName("gin-gonic/gin-instrumentor").WithValues("function", funcName) offset, err := ctx.TargetDetails.GetFunctionOffset(funcName) if err != nil { @@ -146,9 +154,10 @@ func (h *httpServerInstrumentor) registerProbes(ctx *context.InstrumentorContext } } -func (h *httpServerInstrumentor) Run(eventsChan chan<- *events.Event) { +// Run runs the events processing loop. +func (h *Instrumentor) Run(eventsChan chan<- *events.Event) { logger := log.Logger.WithName("gin-gonic/gin-instrumentor") - var event HttpEvent + var event Event for { record, err := h.eventsReader.Read() if err != nil { @@ -173,7 +182,7 @@ func (h *httpServerInstrumentor) Run(eventsChan chan<- *events.Event) { } } -func (h *httpServerInstrumentor) convertEvent(e *HttpEvent) *events.Event { +func (h *Instrumentor) convertEvent(e *Event) *events.Event { method := unix.ByteSliceToString(e.Method[:]) path := unix.ByteSliceToString(e.Path[:]) @@ -197,7 +206,8 @@ func (h *httpServerInstrumentor) convertEvent(e *HttpEvent) *events.Event { } } -func (h *httpServerInstrumentor) Close() { +// Close stops the Instrumentor. +func (h *Instrumentor) Close() { log.Logger.V(0).Info("closing gin-gonic/gin instrumentor") if h.eventsReader != nil { h.eventsReader.Close() From 691965500cebf7c3e881b607918d511ad3d24ce7 Mon Sep 17 00:00:00 2001 From: Mike Goldsmth Date: Thu, 27 Apr 2023 20:06:29 +0100 Subject: [PATCH 17/20] redact resource attr version and update e2e json --- .github/workflows/kind.yml | 2 +- test/e2e/gin/traces.json | 6 ++++++ test/e2e/gorillamux/traces.json | 2 +- test/e2e/nethttp/traces.json | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/kind.yml b/.github/workflows/kind.yml index deb603e3a..8f6ed54e5 100644 --- a/.github/workflows/kind.yml +++ b/.github/workflows/kind.yml @@ -69,7 +69,7 @@ jobs: - name: copy telemetry trace output run: | kubectl cp -c filecp default/test-opentelemetry-collector-0:tmp/trace.json ./test/e2e/${{ matrix.library }}/traces.json.tmp - jq 'del(.resourceSpans[].scopeSpans[].spans[].endTimeUnixNano, .resourceSpans[].scopeSpans[].spans[].startTimeUnixNano) | .resourceSpans[].scopeSpans[].spans[].spanId|= (if . != "" then "xxxxx" else . end) | .resourceSpans[].scopeSpans[].spans[].traceId|= (if . != "" then "xxxxx" else . end) | .resourceSpans[].scopeSpans|=sort_by(.scope.name)' ./test/e2e/${{ matrix.library }}/traces.json.tmp | jq --sort-keys . > ./test/e2e/${{ matrix.library }}/traces.json + jq 'del(.resourceSpans[].scopeSpans[].spans[].endTimeUnixNano, .resourceSpans[].scopeSpans[].spans[].startTimeUnixNano) | .resourceSpans[].resource.attributes[].telemetry.auto.version|= (if . != "" then "xxxxx" else . end) | .resourceSpans[].scopeSpans[].spans[].spanId|= (if . != "" then "xxxxx" else . end) | .resourceSpans[].scopeSpans[].spans[].traceId|= (if . != "" then "xxxxx" else . end) | .resourceSpans[].scopeSpans|=sort_by(.scope.name)' ./test/e2e/${{ matrix.library }}/traces.json.tmp | jq --sort-keys . > ./test/e2e/${{ matrix.library }}/traces.json rm ./test/e2e/${{ matrix.library }}/traces.json.tmp - name: verify output run: | diff --git a/test/e2e/gin/traces.json b/test/e2e/gin/traces.json index 5832be918..49576c281 100644 --- a/test/e2e/gin/traces.json +++ b/test/e2e/gin/traces.json @@ -9,6 +9,12 @@ "stringValue": "sample-app" } }, + { + "key": "telemetry.auto.version", + "value": { + "stringValue": "xxxxx" + } + }, { "key": "telemetry.sdk.language", "value": { diff --git a/test/e2e/gorillamux/traces.json b/test/e2e/gorillamux/traces.json index ba6adfbc6..150081161 100644 --- a/test/e2e/gorillamux/traces.json +++ b/test/e2e/gorillamux/traces.json @@ -12,7 +12,7 @@ { "key": "telemetry.auto.version", "value": { - "stringValue": "v0.1.0-alpha" + "stringValue": "xxxxx" } }, { diff --git a/test/e2e/nethttp/traces.json b/test/e2e/nethttp/traces.json index a11b52ea0..10ad47857 100644 --- a/test/e2e/nethttp/traces.json +++ b/test/e2e/nethttp/traces.json @@ -12,7 +12,7 @@ { "key": "telemetry.auto.version", "value": { - "stringValue": "v0.1.0-alpha" + "stringValue": "xxxxx" } }, { From 96bd025cc56bf1c066283700e7281d55c77e7a59 Mon Sep 17 00:00:00 2001 From: Mike Goldsmith Date: Thu, 27 Apr 2023 20:12:34 +0100 Subject: [PATCH 18/20] Update LibraryName comment Co-authored-by: Tyler Yahn --- pkg/instrumentors/bpf/github.com/gin-gonic/gin/probe.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 d91fe0a99..347190ff9 100644 --- a/pkg/instrumentors/bpf/github.com/gin-gonic/gin/probe.go +++ b/pkg/instrumentors/bpf/github.com/gin-gonic/gin/probe.go @@ -60,7 +60,7 @@ func New() *Instrumentor { return &Instrumentor{} } -// LibraryName returns the gorilla/mux package import path. +// LibraryName returns the gin-gonic/gin package import path. func (h *Instrumentor) LibraryName() string { return "github.com/gin-gonic/gin" } From 81a709a34ee973589d185059734729d04d436c02 Mon Sep 17 00:00:00 2001 From: Mike Goldsmth Date: Thu, 27 Apr 2023 20:27:38 +0100 Subject: [PATCH 19/20] redact telemtry.sdk.auto field in makefile fixture tests too --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 75c19e356..cdbd8cd76 100644 --- a/Makefile +++ b/Makefile @@ -113,7 +113,7 @@ fixtures/%: kubectl -n default create -f .github/workflows/e2e/k8s/sample-job.yml kubectl wait --for=condition=Complete --timeout=60s job/sample-job kubectl cp -c filecp default/test-opentelemetry-collector-0:tmp/trace.json ./test/e2e/$(LIBRARY)/traces.json.tmp - jq 'del(.resourceSpans[].scopeSpans[].spans[].endTimeUnixNano, .resourceSpans[].scopeSpans[].spans[].startTimeUnixNano) | .resourceSpans[].scopeSpans[].spans[].spanId|= (if . != "" then "xxxxx" else . end) | .resourceSpans[].scopeSpans[].spans[].traceId|= (if . != "" then "xxxxx" else . end) | .resourceSpans[].scopeSpans|=sort_by(.scope.name)' ./test/e2e/$(LIBRARY)/traces.json.tmp | jq --sort-keys . > ./test/e2e/$(LIBRARY)/traces.json + jq 'del(.resourceSpans[].scopeSpans[].spans[].endTimeUnixNano, .resourceSpans[].scopeSpans[].spans[].startTimeUnixNano) | .resourceSpans[].resource.attributes[].telemetry.auto.version|= (if . != "" then "xxxxx" else . end) .resourceSpans[].scopeSpans[].spans[].spanId|= (if . != "" then "xxxxx" else . end) | .resourceSpans[].scopeSpans[].spans[].traceId|= (if . != "" then "xxxxx" else . end) | .resourceSpans[].scopeSpans|=sort_by(.scope.name)' ./test/e2e/$(LIBRARY)/traces.json.tmp | jq --sort-keys . > ./test/e2e/$(LIBRARY)/traces.json rm ./test/e2e/$(LIBRARY)/traces.json.tmp kind delete cluster From ed3a42b76ed3ff47e276dcab47d46e7334d8db24 Mon Sep 17 00:00:00 2001 From: Mike Goldsmth Date: Thu, 27 Apr 2023 20:48:59 +0100 Subject: [PATCH 20/20] revert jq to redact version from resource attrs --- .github/workflows/kind.yml | 2 +- Makefile | 2 +- test/e2e/gin/traces.json | 2 +- test/e2e/gorillamux/traces.json | 2 +- test/e2e/nethttp/traces.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/kind.yml b/.github/workflows/kind.yml index 8f6ed54e5..deb603e3a 100644 --- a/.github/workflows/kind.yml +++ b/.github/workflows/kind.yml @@ -69,7 +69,7 @@ jobs: - name: copy telemetry trace output run: | kubectl cp -c filecp default/test-opentelemetry-collector-0:tmp/trace.json ./test/e2e/${{ matrix.library }}/traces.json.tmp - jq 'del(.resourceSpans[].scopeSpans[].spans[].endTimeUnixNano, .resourceSpans[].scopeSpans[].spans[].startTimeUnixNano) | .resourceSpans[].resource.attributes[].telemetry.auto.version|= (if . != "" then "xxxxx" else . end) | .resourceSpans[].scopeSpans[].spans[].spanId|= (if . != "" then "xxxxx" else . end) | .resourceSpans[].scopeSpans[].spans[].traceId|= (if . != "" then "xxxxx" else . end) | .resourceSpans[].scopeSpans|=sort_by(.scope.name)' ./test/e2e/${{ matrix.library }}/traces.json.tmp | jq --sort-keys . > ./test/e2e/${{ matrix.library }}/traces.json + jq 'del(.resourceSpans[].scopeSpans[].spans[].endTimeUnixNano, .resourceSpans[].scopeSpans[].spans[].startTimeUnixNano) | .resourceSpans[].scopeSpans[].spans[].spanId|= (if . != "" then "xxxxx" else . end) | .resourceSpans[].scopeSpans[].spans[].traceId|= (if . != "" then "xxxxx" else . end) | .resourceSpans[].scopeSpans|=sort_by(.scope.name)' ./test/e2e/${{ matrix.library }}/traces.json.tmp | jq --sort-keys . > ./test/e2e/${{ matrix.library }}/traces.json rm ./test/e2e/${{ matrix.library }}/traces.json.tmp - name: verify output run: | diff --git a/Makefile b/Makefile index cdbd8cd76..75c19e356 100644 --- a/Makefile +++ b/Makefile @@ -113,7 +113,7 @@ fixtures/%: kubectl -n default create -f .github/workflows/e2e/k8s/sample-job.yml kubectl wait --for=condition=Complete --timeout=60s job/sample-job kubectl cp -c filecp default/test-opentelemetry-collector-0:tmp/trace.json ./test/e2e/$(LIBRARY)/traces.json.tmp - jq 'del(.resourceSpans[].scopeSpans[].spans[].endTimeUnixNano, .resourceSpans[].scopeSpans[].spans[].startTimeUnixNano) | .resourceSpans[].resource.attributes[].telemetry.auto.version|= (if . != "" then "xxxxx" else . end) .resourceSpans[].scopeSpans[].spans[].spanId|= (if . != "" then "xxxxx" else . end) | .resourceSpans[].scopeSpans[].spans[].traceId|= (if . != "" then "xxxxx" else . end) | .resourceSpans[].scopeSpans|=sort_by(.scope.name)' ./test/e2e/$(LIBRARY)/traces.json.tmp | jq --sort-keys . > ./test/e2e/$(LIBRARY)/traces.json + jq 'del(.resourceSpans[].scopeSpans[].spans[].endTimeUnixNano, .resourceSpans[].scopeSpans[].spans[].startTimeUnixNano) | .resourceSpans[].scopeSpans[].spans[].spanId|= (if . != "" then "xxxxx" else . end) | .resourceSpans[].scopeSpans[].spans[].traceId|= (if . != "" then "xxxxx" else . end) | .resourceSpans[].scopeSpans|=sort_by(.scope.name)' ./test/e2e/$(LIBRARY)/traces.json.tmp | jq --sort-keys . > ./test/e2e/$(LIBRARY)/traces.json rm ./test/e2e/$(LIBRARY)/traces.json.tmp kind delete cluster diff --git a/test/e2e/gin/traces.json b/test/e2e/gin/traces.json index 49576c281..7d93f8b7d 100644 --- a/test/e2e/gin/traces.json +++ b/test/e2e/gin/traces.json @@ -12,7 +12,7 @@ { "key": "telemetry.auto.version", "value": { - "stringValue": "xxxxx" + "stringValue": "v0.1.0-alpha" } }, { diff --git a/test/e2e/gorillamux/traces.json b/test/e2e/gorillamux/traces.json index 150081161..ba6adfbc6 100644 --- a/test/e2e/gorillamux/traces.json +++ b/test/e2e/gorillamux/traces.json @@ -12,7 +12,7 @@ { "key": "telemetry.auto.version", "value": { - "stringValue": "xxxxx" + "stringValue": "v0.1.0-alpha" } }, { diff --git a/test/e2e/nethttp/traces.json b/test/e2e/nethttp/traces.json index 10ad47857..a11b52ea0 100644 --- a/test/e2e/nethttp/traces.json +++ b/test/e2e/nethttp/traces.json @@ -12,7 +12,7 @@ { "key": "telemetry.auto.version", "value": { - "stringValue": "xxxxx" + "stringValue": "v0.1.0-alpha" } }, {