Skip to content

Commit c7d6af3

Browse files
committed
add test for net http
1 parent 625ae34 commit c7d6af3

11 files changed

+229
-15
lines changed

pkg/rules/http/client_setup.go

+8-3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ func clientOnEnter(call http.CallContext, t *http.Transport, req *http.Request)
1616
url: *req.URL,
1717
header: req.Header,
1818
version: strconv.Itoa(req.ProtoMajor) + "." + strconv.Itoa(req.ProtoMinor),
19+
host: req.Host,
20+
isTls: req.TLS != nil,
1921
})
2022
req = req.WithContext(ctx)
2123
call.SetParam(1, req)
@@ -33,9 +35,12 @@ func clientOnExit(call http.CallContext, res *http.Response, err error) {
3335
ctx := data["ctx"].(context.Context)
3436
if res != nil {
3537
netHttpClientInstrumenter.End(ctx, netHttpRequest{
36-
method: res.Request.Method,
37-
url: *res.Request.URL,
38-
header: res.Request.Header,
38+
method: res.Request.Method,
39+
url: *res.Request.URL,
40+
header: res.Request.Header,
41+
version: strconv.Itoa(res.Request.ProtoMajor) + "." + strconv.Itoa(res.Request.ProtoMinor),
42+
host: res.Request.Host,
43+
isTls: res.Request.TLS != nil,
3944
}, netHttpResponse{
4045
statusCode: res.StatusCode,
4146
header: res.Header,

pkg/rules/http/net_http_data_type.go

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import (
1010
type netHttpRequest struct {
1111
method string
1212
url url.URL
13+
host string
14+
isTls bool
1315
header http.Header
1416
version string
1517
}

pkg/rules/http/net_http_otel_instrumenter.go

+13-5
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,11 @@ func (n netHttpClientAttrsGetter) GetNetworkTransport(request netHttpRequest, re
4343
}
4444

4545
func (n netHttpClientAttrsGetter) GetNetworkProtocolName(request netHttpRequest, response netHttpResponse) string {
46-
return request.url.Scheme
46+
if request.isTls == false {
47+
return "http"
48+
} else {
49+
return "https"
50+
}
4751
}
4852

4953
func (n netHttpClientAttrsGetter) GetNetworkProtocolVersion(request netHttpRequest, response netHttpResponse) string {
@@ -59,7 +63,7 @@ func (n netHttpClientAttrsGetter) GetNetworkLocalPort(request netHttpRequest, re
5963
}
6064

6165
func (n netHttpClientAttrsGetter) GetNetworkPeerInetAddress(request netHttpRequest, response netHttpResponse) string {
62-
return request.url.Host
66+
return request.host
6367
}
6468

6569
func (n netHttpClientAttrsGetter) GetNetworkPeerPort(request netHttpRequest, response netHttpResponse) int {
@@ -75,7 +79,7 @@ func (n netHttpClientAttrsGetter) GetUrlFull(request netHttpRequest) string {
7579
}
7680

7781
func (n netHttpClientAttrsGetter) GetServerAddress(request netHttpRequest) string {
78-
return request.url.Host
82+
return request.host
7983
}
8084

8185
type netHttpServerAttrsGetter struct {
@@ -122,7 +126,11 @@ func (n netHttpServerAttrsGetter) GetNetworkTransport(request netHttpRequest, re
122126
}
123127

124128
func (n netHttpServerAttrsGetter) GetNetworkProtocolName(request netHttpRequest, response netHttpResponse) string {
125-
return request.url.Scheme
129+
if request.isTls == false {
130+
return "http"
131+
} else {
132+
return "https"
133+
}
126134
}
127135

128136
func (n netHttpServerAttrsGetter) GetNetworkProtocolVersion(request netHttpRequest, response netHttpResponse) string {
@@ -138,7 +146,7 @@ func (n netHttpServerAttrsGetter) GetNetworkLocalPort(request netHttpRequest, re
138146
}
139147

140148
func (n netHttpServerAttrsGetter) GetNetworkPeerInetAddress(request netHttpRequest, response netHttpResponse) string {
141-
return request.url.Host
149+
return request.host
142150
}
143151

144152
func (n netHttpServerAttrsGetter) GetNetworkPeerPort(request netHttpRequest, response netHttpResponse) int {

pkg/rules/http/server_setup.go

+16-6
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,29 @@ import (
88
"fmt"
99
"net"
1010
"net/http"
11+
"strconv"
1112
)
1213

1314
var netHttpServerInstrumenter = BuildNetHttpServerOtelInstrumenter()
1415

1516
func serverOnEnter(call http.CallContext, _ interface{}, w http.ResponseWriter, r *http.Request) {
16-
ctx := netHttpServerInstrumenter.Start(r.Context(), netHttpRequest{
17-
method: r.Method,
18-
url: *r.URL,
19-
header: r.Header,
20-
})
17+
request := netHttpRequest{
18+
method: r.Method,
19+
url: *r.URL,
20+
header: r.Header,
21+
version: strconv.Itoa(r.ProtoMajor) + "." + strconv.Itoa(r.ProtoMinor),
22+
host: r.Host,
23+
isTls: r.TLS != nil,
24+
}
25+
ctx := netHttpServerInstrumenter.Start(r.Context(), request)
2126
if x, ok := call.GetParam(1).(http.ResponseWriter); ok {
2227
x1 := &writerWrapper{ResponseWriter: x, statusCode: http.StatusOK}
2328
call.SetParam(1, x1)
2429
}
2530
call.SetParam(2, r.WithContext(ctx))
2631
data := make(map[string]interface{}, 1)
2732
data["ctx"] = ctx
33+
data["request"] = request
2834
call.SetData(data)
2935
return
3036
}
@@ -35,9 +41,13 @@ func serverOnExit(call http.CallContext) {
3541
return
3642
}
3743
ctx := data["ctx"].(context.Context)
44+
request, ok := data["request"].(netHttpRequest)
45+
if !ok {
46+
return
47+
}
3848
if p, ok := call.GetParam(1).(http.ResponseWriter); ok {
3949
if w1, ok := p.(*writerWrapper); ok {
40-
netHttpServerInstrumenter.End(ctx, netHttpRequest{}, netHttpResponse{
50+
netHttpServerInstrumenter.End(ctx, request, netHttpResponse{
4151
statusCode: w1.statusCode,
4252
}, nil)
4353
}

pkg/verifier/verifier.go

+35
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,38 @@ func VerifyDbAttributes(span tracetest.SpanStub, name, dbName, system, user, con
2525
actualOperation := GetAttribute(span.Attributes, "db.operation").AsString()
2626
Assert(actualOperation == operation, "Except client db name to be %s, got %s", operation, actualOperation)
2727
}
28+
29+
func VerifyHttpClientAttributes(span tracetest.SpanStub, name, method, fullUrl, protocolName, protocolVersion, networkTransport, networkType, localAddr, peerAddr string, statusCode, localPort, peerPort int64) {
30+
Assert(span.SpanKind == trace.SpanKindClient, "Expect to be client span, got %d", span.SpanKind)
31+
Assert(span.Name == name, "Except client span name to be %s, got %s", name, span.Name)
32+
Assert(GetAttribute(span.Attributes, "http.request.method").AsString() == method, "Except method to be %s, got %s", method, GetAttribute(span.Attributes, "http.request.method").AsString())
33+
Assert(GetAttribute(span.Attributes, "url.full").AsString() == fullUrl, "Except full url to be %s, got %s", fullUrl, GetAttribute(span.Attributes, "url.full").AsString())
34+
Assert(GetAttribute(span.Attributes, "network.protocol.name").AsString() == protocolName, "Except protocol name to be %s, got %s", protocolName, GetAttribute(span.Attributes, "network.protocol.name").AsString())
35+
Assert(GetAttribute(span.Attributes, "network.protocol.version").AsString() == protocolVersion, "Except protocol version to be %s, got %s", protocolVersion, GetAttribute(span.Attributes, "network.protocol.version").AsString())
36+
Assert(GetAttribute(span.Attributes, "network.transport").AsString() == networkTransport, "Except network transport to be %s, got %s", networkTransport, GetAttribute(span.Attributes, "network.transport").AsString())
37+
Assert(GetAttribute(span.Attributes, "network.type").AsString() == networkType, "Except network type to be %s, got %s", networkType, GetAttribute(span.Attributes, "network.type").AsString())
38+
Assert(GetAttribute(span.Attributes, "network.local.address").AsString() == localAddr, "Except local addr to be %s, got %s", localAddr, GetAttribute(span.Attributes, "network.local.address").AsString())
39+
Assert(GetAttribute(span.Attributes, "network.peer.address").AsString() == peerAddr, "Except peer addr to be %s, got %s", peerAddr, GetAttribute(span.Attributes, "network.peer.address").AsString())
40+
Assert(GetAttribute(span.Attributes, "http.response.status_code").AsInt64() == statusCode, "Except status code to be %d, got %d", statusCode, GetAttribute(span.Attributes, "http.response.status_code").AsInt64())
41+
Assert(GetAttribute(span.Attributes, "network.peer.port").AsInt64() == peerPort, "Except peer port to be %d, got %d", peerPort, GetAttribute(span.Attributes, "network.peer.port").AsInt64())
42+
if localPort > 0 {
43+
Assert(GetAttribute(span.Attributes, "network.local.port").AsInt64() == localPort, "Except local port to be %d, got %d", localAddr, GetAttribute(span.Attributes, "network.local.port").AsInt64())
44+
}
45+
}
46+
47+
func VerifyHttpServerAttributes(span tracetest.SpanStub, name, method, protocolName, networkTransport, networkType, localAddr, peerAddr, agent, scheme, path, query, route string, statusCode int64) {
48+
Assert(span.SpanKind == trace.SpanKindServer, "Expect to be client span, got %d", span.SpanKind)
49+
Assert(span.Name == name, "Except client span name to be %s, got %s", name, span.Name)
50+
Assert(GetAttribute(span.Attributes, "http.request.method").AsString() == method, "Except method to be %s, got %s", method, GetAttribute(span.Attributes, "http.request.method").AsString())
51+
Assert(GetAttribute(span.Attributes, "network.protocol.name").AsString() == protocolName, "Except protocol name to be %s, got %s", protocolName, GetAttribute(span.Attributes, "network.protocol.name").AsString())
52+
Assert(GetAttribute(span.Attributes, "network.transport").AsString() == networkTransport, "Except network transport to be %s, got %s", networkTransport, GetAttribute(span.Attributes, "network.transport").AsString())
53+
Assert(GetAttribute(span.Attributes, "network.type").AsString() == networkType, "Except network type to be %s, got %s", networkType, GetAttribute(span.Attributes, "network.type").AsString())
54+
Assert(GetAttribute(span.Attributes, "network.local.address").AsString() == localAddr, "Except local addr to be %s, got %s", localAddr, GetAttribute(span.Attributes, "network.local.address").AsString())
55+
Assert(GetAttribute(span.Attributes, "network.peer.address").AsString() == peerAddr, "Except peer addr to be %s, got %s", peerAddr, GetAttribute(span.Attributes, "network.peer.address").AsString())
56+
Assert(GetAttribute(span.Attributes, "user_agent.original").AsString() == agent, "Except user agent to be %s, got %s", agent, GetAttribute(span.Attributes, "user_agent.original").AsString())
57+
Assert(GetAttribute(span.Attributes, "url.scheme").AsString() == scheme, "Except url scheme to be %s, got %s", scheme, GetAttribute(span.Attributes, "url.scheme").AsString())
58+
Assert(GetAttribute(span.Attributes, "url.path").AsString() == path, "Except url path to be %s, got %s", path, GetAttribute(span.Attributes, "url.path").AsString())
59+
Assert(GetAttribute(span.Attributes, "url.query").AsString() == query, "Except url query to be %s, got %s", query, GetAttribute(span.Attributes, "url.query").AsString())
60+
Assert(GetAttribute(span.Attributes, "http.route").AsString() == route, "Except http route to be %s, got %s", route, GetAttribute(span.Attributes, "http.route").AsString())
61+
Assert(GetAttribute(span.Attributes, "http.response.status_code").AsInt64() == statusCode, "Except status code to be %d, got %d", statusCode, GetAttribute(span.Attributes, "http.response.status_code").AsInt64())
62+
}

rule_enabler.go

+4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
package main
22

33
import (
4+
_ "go.opentelemetry.io/otel"
5+
_ "go.opentelemetry.io/otel/baggage"
6+
_ "go.opentelemetry.io/otel/sdk/trace"
7+
48
_ "github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/rules/databasesql"
59
_ "github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/rules/goredis"
610
_ "github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/rules/http"

test/integration_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77

88
func TestPlugins(t *testing.T) {
99
for _, c := range TestCases {
10-
if c == nil || c.TestName != "redis-9.0.5-universal-test" {
10+
if c == nil {
1111
continue
1212
}
1313
if c.IsMuzzleCheck || c.IsLatestDepthCheck {

test/net_http_tests.go

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package test
2+
3+
import "testing"
4+
5+
func init() {
6+
TestCases = append(TestCases,
7+
NewGeneralTestCase("nethttp-basic-test", "", "databasesql", "", "", "1.18", "", TestBasicNetHttp),
8+
)
9+
}
10+
11+
func TestBasicNetHttp(t *testing.T, env ...string) {
12+
UseApp("nethttp")
13+
RunInstrument(t, "-debuglog", "--", "test_http.go", "http_server.go")
14+
RunApp(t, "test_http", env...)
15+
}

test/nethttp/go.mod

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
module nethttp
2+
3+
go 1.21
4+
5+
replace github.com/alibaba/opentelemetry-go-auto-instrumentation => ../../../opentelemetry-go-auto-instrumentation
6+
7+
require (
8+
github.com/alibaba/opentelemetry-go-auto-instrumentation v0.0.0-00010101000000-000000000000
9+
go.opentelemetry.io/otel/sdk v1.28.0
10+
)
11+
12+
require (
13+
github.com/go-logr/logr v1.4.2 // indirect
14+
github.com/go-logr/stdr v1.2.2 // indirect
15+
github.com/google/uuid v1.6.0 // indirect
16+
go.opentelemetry.io/otel v1.28.0 // indirect
17+
go.opentelemetry.io/otel/metric v1.28.0 // indirect
18+
go.opentelemetry.io/otel/trace v1.28.0 // indirect
19+
golang.org/x/sys v0.21.0 // indirect
20+
)

test/nethttp/http_server.go

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package main
2+
3+
import (
4+
"io"
5+
"log"
6+
"net/http"
7+
"strconv"
8+
)
9+
10+
func redirectHandler(w http.ResponseWriter, r *http.Request) {
11+
resp, err := http.Get("http://127.0.0.1:" + strconv.Itoa(port) + "/b")
12+
if err != nil {
13+
log.Printf("request provider error: %v", err)
14+
w.WriteHeader(http.StatusInternalServerError)
15+
return
16+
}
17+
defer resp.Body.Close()
18+
_, err = io.ReadAll(resp.Body)
19+
if err != nil {
20+
log.Print(err)
21+
w.WriteHeader(http.StatusInternalServerError)
22+
return
23+
}
24+
_, _ = w.Write([]byte("success"))
25+
}
26+
27+
func helloHandler(w http.ResponseWriter, r *http.Request) {
28+
w.WriteHeader(http.StatusOK)
29+
_, _ = w.Write([]byte("success"))
30+
}

test/nethttp/test_http.go

+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package main
2+
3+
import (
4+
"bytes"
5+
"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/verifier"
6+
"go.opentelemetry.io/otel/sdk/trace/tracetest"
7+
"log"
8+
"net/http"
9+
"strconv"
10+
"time"
11+
)
12+
13+
var port int
14+
15+
func setupBasicHttp() {
16+
http.HandleFunc("/a", redirectHandler)
17+
http.HandleFunc("/b", helloHandler)
18+
var err error
19+
port, err = verifier.GetFreePort()
20+
if err != nil {
21+
panic(err)
22+
}
23+
err = http.ListenAndServe(":"+strconv.Itoa(port), nil)
24+
if err != nil {
25+
panic(err)
26+
}
27+
}
28+
29+
func main() {
30+
go setupBasicHttp()
31+
time.Sleep(1 * time.Second)
32+
_, err := http.Get("http://127.0.0.1:" + strconv.Itoa(port) + "/a")
33+
if err != nil {
34+
panic(err)
35+
}
36+
jsonData := []byte(`{"key1": "value1", "key2": "value2"}`)
37+
req, err := http.NewRequest("POST", "http://127.0.0.1:"+strconv.Itoa(port)+"/a", bytes.NewBuffer(jsonData))
38+
if err != nil {
39+
panic(err)
40+
}
41+
req.Header.Set("Content-Type", "application/json")
42+
client := http.Client{}
43+
resp, err := client.Do(req)
44+
if err != nil {
45+
panic(err)
46+
}
47+
defer resp.Body.Close()
48+
time.Sleep(1 * time.Second)
49+
verifier.WaitAndAssertTraces(func(stubs []tracetest.SpanStubs) {
50+
verifier.VerifyHttpClientAttributes(stubs[0][0], "GET", "GET", "http://127.0.0.1:"+strconv.Itoa(port)+"/a", "http", "1.1", "tcp", "ipv4", "", "127.0.0.1:"+strconv.Itoa(port), 200, 0, int64(port))
51+
verifier.VerifyHttpServerAttributes(stubs[0][1], "GET /a", "GET", "http", "tcp", "ipv4", "", "127.0.0.1:"+strconv.Itoa(port), "Go-http-client/1.1", "", "/a", "", "/a", 200)
52+
verifier.VerifyHttpClientAttributes(stubs[0][2], "GET", "GET", "http://127.0.0.1:"+strconv.Itoa(port)+"/b", "http", "1.1", "tcp", "ipv4", "", "127.0.0.1:"+strconv.Itoa(port), 200, 0, int64(port))
53+
verifier.VerifyHttpServerAttributes(stubs[0][3], "GET /b", "GET", "http", "tcp", "ipv4", "", "127.0.0.1:"+strconv.Itoa(port), "Go-http-client/1.1", "", "/b", "", "/b", 200)
54+
if stubs[0][1].Parent.TraceID().String() != stubs[0][0].SpanContext.TraceID().String() {
55+
log.Fatal("span 1 should be child of span 0")
56+
}
57+
if stubs[0][2].Parent.TraceID().String() != stubs[0][1].SpanContext.TraceID().String() {
58+
log.Fatal("span 2 should be child of span 1")
59+
}
60+
if stubs[0][3].Parent.TraceID().String() != stubs[0][2].SpanContext.TraceID().String() {
61+
log.Fatal("span 3 should be child of span 2")
62+
}
63+
for i, _ := range stubs[1] {
64+
span := stubs[1][i]
65+
println(span.Name)
66+
for _, attr := range span.Attributes {
67+
log.Printf("%v %v", attr.Key, attr.Value)
68+
}
69+
println()
70+
}
71+
verifier.VerifyHttpClientAttributes(stubs[1][0], "POST", "POST", "http://127.0.0.1:"+strconv.Itoa(port)+"/a", "http", "1.1", "tcp", "ipv4", "", "127.0.0.1:"+strconv.Itoa(port), 200, 0, int64(port))
72+
verifier.VerifyHttpServerAttributes(stubs[1][1], "POST /a", "POST", "http", "tcp", "ipv4", "", "127.0.0.1:"+strconv.Itoa(port), "Go-http-client/1.1", "", "/a", "", "/a", 200)
73+
verifier.VerifyHttpClientAttributes(stubs[1][2], "GET", "GET", "http://127.0.0.1:"+strconv.Itoa(port)+"/b", "http", "1.1", "tcp", "ipv4", "", "127.0.0.1:"+strconv.Itoa(port), 200, 0, int64(port))
74+
verifier.VerifyHttpServerAttributes(stubs[1][3], "GET /b", "GET", "http", "tcp", "ipv4", "", "127.0.0.1:"+strconv.Itoa(port), "Go-http-client/1.1", "", "/b", "", "/b", 200)
75+
if stubs[1][1].Parent.TraceID().String() != stubs[1][0].SpanContext.TraceID().String() {
76+
log.Fatal("span 1 should be child of span 0")
77+
}
78+
if stubs[1][2].Parent.TraceID().String() != stubs[1][1].SpanContext.TraceID().String() {
79+
log.Fatal("span 2 should be child of span 1")
80+
}
81+
if stubs[1][3].Parent.TraceID().String() != stubs[1][2].SpanContext.TraceID().String() {
82+
log.Fatal("span 3 should be child of span 2")
83+
}
84+
})
85+
}

0 commit comments

Comments
 (0)