From 6c55fa07336c770e0b5dc71120b8cbfa583f1212 Mon Sep 17 00:00:00 2001 From: Liu Ziming Date: Fri, 23 Aug 2024 15:20:24 +0800 Subject: [PATCH] support mux (#61) * support mux * fix muzzle check --- pkg/rules/mux/mux_data_type.go | 35 +++++++ pkg/rules/mux/mux_otel_instrumenter.go | 121 +++++++++++++++++++++++++ pkg/rules/mux/mux_server_setup.go | 80 ++++++++++++++++ pkg/rules/mux/rule.go | 12 +++ rule_enabler.go | 1 + test/build_test.go | 1 + test/databasesql_tests.go | 1 + test/errors_test.go | 1 + test/flags_test.go | 1 + test/gin_tests.go | 14 +++ test/gorm_tests.go | 14 +++ test/helloworld_test.go | 1 + test/httpclient_test.go | 1 + test/infra.go | 1 + test/integration_test.go | 13 ++- test/logrus_tests.go | 1 + test/mongo_tests.go | 1 + test/mux/v1.3.0/go.mod | 22 +++++ test/mux/v1.3.0/test_mux_basic.go | 52 +++++++++++ test/mux/v1.3.0/test_mux_pattern.go | 54 +++++++++++ test/mux/v1.7.0/go.mod | 22 +++++ test/mux/v1.7.0/test_mux_middleware.go | 63 +++++++++++++ test/mux_tests.go | 49 ++++++++++ test/net_http_tests.go | 1 + test/redis_tests.go | 1 + test/test_main.go | 1 + test/zao_tests.go | 1 + 27 files changed, 562 insertions(+), 3 deletions(-) create mode 100644 pkg/rules/mux/mux_data_type.go create mode 100644 pkg/rules/mux/mux_otel_instrumenter.go create mode 100644 pkg/rules/mux/mux_server_setup.go create mode 100644 pkg/rules/mux/rule.go create mode 100644 test/mux/v1.3.0/go.mod create mode 100644 test/mux/v1.3.0/test_mux_basic.go create mode 100644 test/mux/v1.3.0/test_mux_pattern.go create mode 100644 test/mux/v1.7.0/go.mod create mode 100644 test/mux/v1.7.0/test_mux_middleware.go create mode 100644 test/mux_tests.go diff --git a/pkg/rules/mux/mux_data_type.go b/pkg/rules/mux/mux_data_type.go new file mode 100644 index 00000000..1d81ee4d --- /dev/null +++ b/pkg/rules/mux/mux_data_type.go @@ -0,0 +1,35 @@ +// Copyright (c) 2024 Alibaba Group Holding Ltd. +// +// 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. +//go:build ignore + +package rule + +import ( + "net/http" + "net/url" +) + +type muxHttpRequest struct { + method string + url *url.URL + host string + isTls bool + header http.Header + version string +} + +type muxHttpResponse struct { + statusCode int + header http.Header +} diff --git a/pkg/rules/mux/mux_otel_instrumenter.go b/pkg/rules/mux/mux_otel_instrumenter.go new file mode 100644 index 00000000..fb01c983 --- /dev/null +++ b/pkg/rules/mux/mux_otel_instrumenter.go @@ -0,0 +1,121 @@ +// Copyright (c) 2024 Alibaba Group Holding Ltd. +// +// 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. +//go:build ignore + +package rule + +import ( + "strconv" + + "github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api-semconv/instrumenter/http" + "github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api-semconv/instrumenter/net" + "github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/instrumenter" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/propagation" +) + +type muxHttpServerAttrsGetter struct { +} + +func (n muxHttpServerAttrsGetter) GetRequestMethod(request muxHttpRequest) string { + return request.method +} + +func (n muxHttpServerAttrsGetter) GetHttpRequestHeader(request muxHttpRequest, name string) []string { + return request.header.Values(name) +} + +func (n muxHttpServerAttrsGetter) GetHttpResponseStatusCode(request muxHttpRequest, response muxHttpResponse, err error) int { + return response.statusCode +} + +func (n muxHttpServerAttrsGetter) GetHttpResponseHeader(request muxHttpRequest, response muxHttpResponse, name string) []string { + return response.header.Values(name) +} + +func (n muxHttpServerAttrsGetter) GetErrorType(request muxHttpRequest, response muxHttpResponse, err error) string { + return "" +} + +func (n muxHttpServerAttrsGetter) GetUrlScheme(request muxHttpRequest) string { + return request.url.Scheme +} + +func (n muxHttpServerAttrsGetter) GetUrlPath(request muxHttpRequest) string { + return request.url.Path +} + +func (n muxHttpServerAttrsGetter) GetUrlQuery(request muxHttpRequest) string { + return request.url.RawQuery +} + +func (n muxHttpServerAttrsGetter) GetNetworkType(request muxHttpRequest, response muxHttpResponse) string { + return "ipv4" +} + +func (n muxHttpServerAttrsGetter) GetNetworkTransport(request muxHttpRequest, response muxHttpResponse) string { + return "tcp" +} + +func (n muxHttpServerAttrsGetter) GetNetworkProtocolName(request muxHttpRequest, response muxHttpResponse) string { + if request.isTls == false { + return "http" + } else { + return "https" + } +} + +func (n muxHttpServerAttrsGetter) GetNetworkProtocolVersion(request muxHttpRequest, response muxHttpResponse) string { + return request.version +} + +func (n muxHttpServerAttrsGetter) GetNetworkLocalInetAddress(request muxHttpRequest, response muxHttpResponse) string { + return "" +} + +func (n muxHttpServerAttrsGetter) GetNetworkLocalPort(request muxHttpRequest, response muxHttpResponse) int { + return 0 +} + +func (n muxHttpServerAttrsGetter) GetNetworkPeerInetAddress(request muxHttpRequest, response muxHttpResponse) string { + return request.host +} + +func (n muxHttpServerAttrsGetter) GetNetworkPeerPort(request muxHttpRequest, response muxHttpResponse) int { + port, err := strconv.Atoi(request.url.Port()) + if err != nil { + return 0 + } + return port +} + +func (n muxHttpServerAttrsGetter) GetHttpRoute(request muxHttpRequest) string { + return request.url.Path +} + +func BuildMuxHttpServerOtelInstrumenter() *instrumenter.PropagatingFromUpstreamInstrumenter[muxHttpRequest, muxHttpResponse] { + builder := instrumenter.Builder[muxHttpRequest, muxHttpResponse]{} + serverGetter := muxHttpServerAttrsGetter{} + commonExtractor := http.HttpCommonAttrsExtractor[muxHttpRequest, muxHttpResponse, muxHttpServerAttrsGetter, muxHttpServerAttrsGetter]{HttpGetter: serverGetter, NetGetter: serverGetter, Converter: &http.ServerHttpStatusCodeConverter{}} + networkExtractor := net.NetworkAttrsExtractor[muxHttpRequest, muxHttpResponse, muxHttpServerAttrsGetter]{Getter: serverGetter} + urlExtractor := net.UrlAttrsExtractor[muxHttpRequest, muxHttpResponse, muxHttpServerAttrsGetter]{Getter: serverGetter} + return builder.Init().SetSpanNameExtractor(&http.HttpServerSpanNameExtractor[muxHttpRequest, muxHttpResponse]{Getter: serverGetter}). + SetSpanKindExtractor(&instrumenter.AlwaysServerExtractor[muxHttpRequest]{}). + AddAttributesExtractor(&http.HttpServerAttrsExtractor[muxHttpRequest, muxHttpResponse, muxHttpServerAttrsGetter, muxHttpServerAttrsGetter, muxHttpServerAttrsGetter]{Base: commonExtractor, NetworkExtractor: networkExtractor, UrlExtractor: urlExtractor}).BuildPropagatingFromUpstreamInstrumenter(func(n muxHttpRequest) propagation.TextMapCarrier { + if n.header == nil { + return nil + } + return propagation.HeaderCarrier(n.header) + }, otel.GetTextMapPropagator()) +} diff --git a/pkg/rules/mux/mux_server_setup.go b/pkg/rules/mux/mux_server_setup.go new file mode 100644 index 00000000..af7f42f1 --- /dev/null +++ b/pkg/rules/mux/mux_server_setup.go @@ -0,0 +1,80 @@ +//go:build ignore + +package rule + +import ( + "bufio" + "context" + "fmt" + mux "github.com/gorilla/mux" + "net" + "net/http" + "strconv" +) + +var muxInstrumenter = BuildMuxHttpServerOtelInstrumenter() + +func muxServerOnEnter(call mux.CallContext, router *mux.Router, w http.ResponseWriter, req *http.Request) { + muxRequest := muxHttpRequest{ + method: req.Method, + url: req.URL, + header: req.Header, + version: strconv.Itoa(req.ProtoMajor) + "." + strconv.Itoa(req.ProtoMinor), + host: req.Host, + isTls: req.TLS != nil, + } + ctx := muxInstrumenter.Start(req.Context(), muxRequest) + x := call.GetParam(1).(http.ResponseWriter) + x1 := &muxWriterWrapper{ResponseWriter: x, statusCode: http.StatusOK} + call.SetParam(1, x1) + call.SetParam(2, req.WithContext(ctx)) + call.SetKeyData("ctx", ctx) + call.SetKeyData("request", muxRequest) + return +} + +func muxServerOnExit(call mux.CallContext) { + c := call.GetKeyData("ctx") + if c == nil { + return + } + ctx, ok := c.(context.Context) + if !ok { + return + } + m := call.GetKeyData("request") + if m == nil { + return + } + muxRequest, ok := m.(muxHttpRequest) + if !ok { + return + } + if p, ok := call.GetParam(1).(http.ResponseWriter); ok { + if w1, ok := p.(*muxWriterWrapper); ok { + muxInstrumenter.End(ctx, muxRequest, muxHttpResponse{ + statusCode: w1.statusCode, + }, nil) + } + } + return +} + +type muxWriterWrapper struct { + http.ResponseWriter + statusCode int +} + +func (w *muxWriterWrapper) WriteHeader(statusCode int) { + // cache the status code + w.statusCode = statusCode + + w.ResponseWriter.WriteHeader(statusCode) +} + +func (w *muxWriterWrapper) Hijack() (rwc net.Conn, buf *bufio.ReadWriter, err error) { + if h, ok := w.ResponseWriter.(http.Hijacker); ok { + return h.Hijack() + } + return nil, nil, fmt.Errorf("responseWriter does not implement http.Hijacker") +} diff --git a/pkg/rules/mux/rule.go b/pkg/rules/mux/rule.go new file mode 100644 index 00000000..3c19a176 --- /dev/null +++ b/pkg/rules/mux/rule.go @@ -0,0 +1,12 @@ +package rule + +import ( + "github.com/alibaba/opentelemetry-go-auto-instrumentation/api" +) + +func init() { + api.NewRule("github.com/gorilla/mux", "ServeHTTP", "*Router", "muxServerOnEnter", "muxServerOnExit"). + WithVersion("[1.3.0,1.8.2)"). + WithFileDeps("mux_data_type.go", "mux_otel_instrumenter.go"). + Register() +} diff --git a/rule_enabler.go b/rule_enabler.go index 18c14c8a..98d08740 100644 --- a/rule_enabler.go +++ b/rule_enabler.go @@ -21,6 +21,7 @@ import ( _ "github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/rules/http" _ "github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/rules/logrus" _ "github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/rules/mongo" + _ "github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/rules/mux" _ "github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/rules/otsdk" _ "github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/rules/runtime" _ "github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/rules/test" diff --git a/test/build_test.go b/test/build_test.go index 9ba47378..b92c3201 100644 --- a/test/build_test.go +++ b/test/build_test.go @@ -11,6 +11,7 @@ // 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 test import "testing" diff --git a/test/databasesql_tests.go b/test/databasesql_tests.go index 6e22c79a..ac005a84 100644 --- a/test/databasesql_tests.go +++ b/test/databasesql_tests.go @@ -11,6 +11,7 @@ // 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 test import ( diff --git a/test/errors_test.go b/test/errors_test.go index e380b339..7689c291 100644 --- a/test/errors_test.go +++ b/test/errors_test.go @@ -11,6 +11,7 @@ // 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 test import ( diff --git a/test/flags_test.go b/test/flags_test.go index 897a65f0..5611a79f 100644 --- a/test/flags_test.go +++ b/test/flags_test.go @@ -11,6 +11,7 @@ // 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 test import ( diff --git a/test/gin_tests.go b/test/gin_tests.go index c1085e92..1548b7e0 100644 --- a/test/gin_tests.go +++ b/test/gin_tests.go @@ -1,3 +1,17 @@ +// Copyright (c) 2024 Alibaba Group Holding Ltd. +// +// 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 test import "testing" diff --git a/test/gorm_tests.go b/test/gorm_tests.go index c3e03d55..6dafe4d7 100644 --- a/test/gorm_tests.go +++ b/test/gorm_tests.go @@ -1,3 +1,17 @@ +// Copyright (c) 2024 Alibaba Group Holding Ltd. +// +// 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 test import ( diff --git a/test/helloworld_test.go b/test/helloworld_test.go index 5daf909c..90c095e8 100644 --- a/test/helloworld_test.go +++ b/test/helloworld_test.go @@ -11,6 +11,7 @@ // 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 test import ( diff --git a/test/httpclient_test.go b/test/httpclient_test.go index cb77f4ed..d3da837e 100644 --- a/test/httpclient_test.go +++ b/test/httpclient_test.go @@ -11,6 +11,7 @@ // 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 test import ( diff --git a/test/infra.go b/test/infra.go index 8560d168..10bab782 100644 --- a/test/infra.go +++ b/test/infra.go @@ -11,6 +11,7 @@ // 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 test import ( diff --git a/test/integration_test.go b/test/integration_test.go index a0759b3a..0c6eb118 100644 --- a/test/integration_test.go +++ b/test/integration_test.go @@ -11,19 +11,24 @@ // 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 test import ( _ "github.com/alibaba/opentelemetry-go-auto-instrumentation/test/version" + "os" "testing" ) +const test_plugin_name_key = "TEST_PLUGIN_NAME" + func TestPlugins(t *testing.T) { + testPluginName := os.Getenv(test_plugin_name_key) for _, c := range TestCases { if c == nil { continue } - if c.IsMuzzleCheck || c.IsLatestDepthCheck { + if c.IsMuzzleCheck || c.IsLatestDepthCheck || (testPluginName != "" && c.TestName != testPluginName) { continue } t.Run(c.TestName, func(t *testing.T) { @@ -33,11 +38,12 @@ func TestPlugins(t *testing.T) { } func TestMuzzle(t *testing.T) { + testPluginName := os.Getenv(test_plugin_name_key) for _, c := range TestCases { if c == nil { continue } - if !c.IsMuzzleCheck { + if !c.IsMuzzleCheck || (testPluginName != "" && c.TestName != testPluginName) { continue } t.Run(c.TestName, func(t *testing.T) { @@ -48,10 +54,11 @@ func TestMuzzle(t *testing.T) { func TestLatest(t *testing.T) { for _, c := range TestCases { + testPluginName := os.Getenv(test_plugin_name_key) if c == nil { continue } - if !c.IsLatestDepthCheck { + if !c.IsLatestDepthCheck || (testPluginName != "" && c.TestName != testPluginName) { continue } t.Run(c.TestName, func(t *testing.T) { diff --git a/test/logrus_tests.go b/test/logrus_tests.go index 05dcbbf3..f4c46990 100644 --- a/test/logrus_tests.go +++ b/test/logrus_tests.go @@ -11,6 +11,7 @@ // 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 test import ( diff --git a/test/mongo_tests.go b/test/mongo_tests.go index b77f0435..d31f9a7a 100644 --- a/test/mongo_tests.go +++ b/test/mongo_tests.go @@ -11,6 +11,7 @@ // 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 test import ( diff --git a/test/mux/v1.3.0/go.mod b/test/mux/v1.3.0/go.mod new file mode 100644 index 00000000..d31600b9 --- /dev/null +++ b/test/mux/v1.3.0/go.mod @@ -0,0 +1,22 @@ +module mux/v1.3.0 + +go 1.21.9 + +replace github.com/alibaba/opentelemetry-go-auto-instrumentation => ../../../../opentelemetry-go-auto-instrumentation + +require ( + github.com/alibaba/opentelemetry-go-auto-instrumentation v0.0.0-00010101000000-000000000000 + github.com/gorilla/mux v1.3.0 + go.opentelemetry.io/otel/sdk v1.28.0 +) + +require ( + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/gorilla/context v1.1.2 // indirect + go.opentelemetry.io/otel v1.28.0 // indirect + go.opentelemetry.io/otel/metric v1.28.0 // indirect + go.opentelemetry.io/otel/trace v1.28.0 // indirect + golang.org/x/sys v0.21.0 // indirect +) diff --git a/test/mux/v1.3.0/test_mux_basic.go b/test/mux/v1.3.0/test_mux_basic.go new file mode 100644 index 00000000..4d39fa6b --- /dev/null +++ b/test/mux/v1.3.0/test_mux_basic.go @@ -0,0 +1,52 @@ +// Copyright (c) 2024 Alibaba Group Holding Ltd. +// +// 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 ( + "fmt" + "github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/verifier" + "github.com/gorilla/mux" + "go.opentelemetry.io/otel/sdk/trace/tracetest" + "io/ioutil" + "net/http" + "time" +) + +func setup() { + r := mux.NewRouter() + r.HandleFunc("/test", func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte("hello world")) + }) + http.Handle("/", r) + http.ListenAndServe(":8080", r) +} + +func main() { + go setup() + time.Sleep(5 * time.Second) + client := &http.Client{} + resp, err := client.Get("http://127.0.0.1:8080/test") + defer resp.Body.Close() + if err != nil { + panic(err) + } + body, _ := ioutil.ReadAll(resp.Body) + fmt.Println(string(body)) + verifier.WaitAndAssertTraces(func(stubs []tracetest.SpanStubs) { + verifier.VerifyHttpClientAttributes(stubs[0][0], "GET", "GET", "http://127.0.0.1:8080/test", "http", "1.1", "tcp", "ipv4", "", "127.0.0.1:8080", 200, 0, 8080) + verifier.VerifyHttpServerAttributes(stubs[0][1], "GET /test", "GET", "http", "tcp", "ipv4", "", "127.0.0.1:8080", "Go-http-client/1.1", "", "/test", "", "/test", 200) + verifier.VerifyHttpServerAttributes(stubs[0][2], "GET /test", "GET", "http", "tcp", "ipv4", "", "127.0.0.1:8080", "Go-http-client/1.1", "", "/test", "", "/test", 200) + }, 1) +} diff --git a/test/mux/v1.3.0/test_mux_pattern.go b/test/mux/v1.3.0/test_mux_pattern.go new file mode 100644 index 00000000..f29d1dfb --- /dev/null +++ b/test/mux/v1.3.0/test_mux_pattern.go @@ -0,0 +1,54 @@ +// Copyright (c) 2024 Alibaba Group Holding Ltd. +// +// 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 ( + "fmt" + "github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/verifier" + "github.com/gorilla/mux" + "go.opentelemetry.io/otel/sdk/trace/tracetest" + "io/ioutil" + "net/http" + "time" +) + +func setupPattern() { + r := mux.NewRouter() + s := r.PathPrefix("/test").Subrouter() + s.HandleFunc("/{key}", func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte("hello world")) + }) + http.Handle("/", r) + http.ListenAndServe(":8080", r) +} + +func main() { + go setupPattern() + time.Sleep(5 * time.Second) + client := &http.Client{} + resp, err := client.Get("http://127.0.0.1:8080/test/1") + defer resp.Body.Close() + if err != nil { + panic(err) + } + body, _ := ioutil.ReadAll(resp.Body) + fmt.Println(string(body)) + verifier.WaitAndAssertTraces(func(stubs []tracetest.SpanStubs) { + // TODO: we should update route in mux + verifier.VerifyHttpClientAttributes(stubs[0][0], "GET", "GET", "http://127.0.0.1:8080/test/1", "http", "1.1", "tcp", "ipv4", "", "127.0.0.1:8080", 200, 0, 8080) + verifier.VerifyHttpServerAttributes(stubs[0][1], "GET /test/1", "GET", "http", "tcp", "ipv4", "", "127.0.0.1:8080", "Go-http-client/1.1", "", "/test/1", "", "/test/1", 200) + verifier.VerifyHttpServerAttributes(stubs[0][2], "GET /test/1", "GET", "http", "tcp", "ipv4", "", "127.0.0.1:8080", "Go-http-client/1.1", "", "/test/1", "", "/test/1", 200) + }, 1) +} diff --git a/test/mux/v1.7.0/go.mod b/test/mux/v1.7.0/go.mod new file mode 100644 index 00000000..efa20a7b --- /dev/null +++ b/test/mux/v1.7.0/go.mod @@ -0,0 +1,22 @@ +module mux/v1.7.0 + +go 1.21.9 + +replace github.com/alibaba/opentelemetry-go-auto-instrumentation => ../../../../opentelemetry-go-auto-instrumentation + +require ( + github.com/alibaba/opentelemetry-go-auto-instrumentation v0.0.0-00010101000000-000000000000 + github.com/gorilla/mux v1.7.0 + go.opentelemetry.io/otel/sdk v1.28.0 +) + +require ( + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/gorilla/context v1.1.2 // indirect + go.opentelemetry.io/otel v1.28.0 // indirect + go.opentelemetry.io/otel/metric v1.28.0 // indirect + go.opentelemetry.io/otel/trace v1.28.0 // indirect + golang.org/x/sys v0.21.0 // indirect +) diff --git a/test/mux/v1.7.0/test_mux_middleware.go b/test/mux/v1.7.0/test_mux_middleware.go new file mode 100644 index 00000000..bc396015 --- /dev/null +++ b/test/mux/v1.7.0/test_mux_middleware.go @@ -0,0 +1,63 @@ +// Copyright (c) 2024 Alibaba Group Holding Ltd. +// +// 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 ( + "fmt" + "github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/verifier" + "github.com/gorilla/mux" + "go.opentelemetry.io/otel/sdk/trace/tracetest" + "io/ioutil" + "log" + "net/http" + "time" +) + +func loggingMiddleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Do stuff here + log.Println(r.RequestURI) + // Call the next handler, which can be another middleware in the chain, or the final handler. + next.ServeHTTP(w, r) + }) +} + +func setupMiddleware() { + r := mux.NewRouter() + r.HandleFunc("/test", func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte("hello world")) + }) + r.Use(loggingMiddleware) + http.Handle("/", r) + http.ListenAndServe(":8080", r) +} + +func main() { + go setupMiddleware() + time.Sleep(5 * time.Second) + client := &http.Client{} + resp, err := client.Get("http://127.0.0.1:8080/test") + defer resp.Body.Close() + if err != nil { + panic(err) + } + body, _ := ioutil.ReadAll(resp.Body) + fmt.Println(string(body)) + verifier.WaitAndAssertTraces(func(stubs []tracetest.SpanStubs) { + verifier.VerifyHttpClientAttributes(stubs[0][0], "GET", "GET", "http://127.0.0.1:8080/test", "http", "1.1", "tcp", "ipv4", "", "127.0.0.1:8080", 200, 0, 8080) + verifier.VerifyHttpServerAttributes(stubs[0][1], "GET /test", "GET", "http", "tcp", "ipv4", "", "127.0.0.1:8080", "Go-http-client/1.1", "", "/test", "", "/test", 200) + verifier.VerifyHttpServerAttributes(stubs[0][2], "GET /test", "GET", "http", "tcp", "ipv4", "", "127.0.0.1:8080", "Go-http-client/1.1", "", "/test", "", "/test", 200) + }, 1) +} diff --git a/test/mux_tests.go b/test/mux_tests.go new file mode 100644 index 00000000..92e9ca72 --- /dev/null +++ b/test/mux_tests.go @@ -0,0 +1,49 @@ +// Copyright (c) 2024 Alibaba Group Holding Ltd. +// +// 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 test + +import "testing" + +const mux_dependency_name = "github.com/gorilla/mux" +const mux_module_name = "mux" + +func init() { + TestCases = append(TestCases, + NewGeneralTestCase("mux-basic-test", mux_module_name, "v1.3.0", "", "1.18", "", TestBasicMux), + NewGeneralTestCase("mux-middleware-test", mux_module_name, "v1.3.0", "", "1.18", "", TestMuxMiddleware), + NewGeneralTestCase("mux-pattern-test", mux_module_name, "v1.3.0", "", "1.18", "", TestMuxPattern), + NewMuzzleTestCase("mux-muzzle-test", mux_dependency_name, mux_module_name, "v1.3.0", "v1.6.2", "1.18", "", []string{"test_mux_basic.go"}), + NewMuzzleTestCase("mux-muzzle-test", mux_dependency_name, mux_module_name, "v1.7.0", "", "1.18", "", []string{"test_mux_middleware.go"}), + NewLatestDepthTestCase("mux-latestdepth-test", mux_dependency_name, mux_module_name, "v1.3.0", "", "1.18", "", TestBasicMux), + ) +} + +func TestBasicMux(t *testing.T, env ...string) { + UseApp("mux/v1.3.0") + RunInstrument(t, "-debuglog", "--", "test_mux_basic.go") + RunApp(t, "test_mux_basic", env...) +} + +func TestMuxMiddleware(t *testing.T, env ...string) { + UseApp("mux/v1.7.0") + RunInstrument(t, "-debuglog", "--", "test_mux_middleware.go") + RunApp(t, "test_mux_middleware", env...) +} + +func TestMuxPattern(t *testing.T, env ...string) { + UseApp("mux/v1.3.0") + RunInstrument(t, "-debuglog", "--", "test_mux_pattern.go") + RunApp(t, "test_mux_pattern", env...) +} diff --git a/test/net_http_tests.go b/test/net_http_tests.go index 1e4b5fe9..f8c97ba9 100644 --- a/test/net_http_tests.go +++ b/test/net_http_tests.go @@ -11,6 +11,7 @@ // 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 test import "testing" diff --git a/test/redis_tests.go b/test/redis_tests.go index 0f08b9f1..e8ca3fab 100644 --- a/test/redis_tests.go +++ b/test/redis_tests.go @@ -11,6 +11,7 @@ // 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 test import ( diff --git a/test/test_main.go b/test/test_main.go index 700338fd..c9d8a61f 100644 --- a/test/test_main.go +++ b/test/test_main.go @@ -11,6 +11,7 @@ // 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 test import ( diff --git a/test/zao_tests.go b/test/zao_tests.go index 9bff5785..8a9d9253 100644 --- a/test/zao_tests.go +++ b/test/zao_tests.go @@ -11,6 +11,7 @@ // 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 test import (