Skip to content

Commit

Permalink
Add http.method attribute to http server metric (#3018)
Browse files Browse the repository at this point in the history
* Add http.method attribute to http server metric

Signed-off-by: Ziqi Zhao <zhaoziqi9146@gmail.com>

* fix lint

Signed-off-by: Ziqi Zhao <zhaoziqi9146@gmail.com>

* fix lint

Signed-off-by: Ziqi Zhao <zhaoziqi9146@gmail.com>

* fix for reviews

Signed-off-by: Ziqi Zhao <zhaoziqi9146@gmail.com>

* add changelog entry

Signed-off-by: Ziqi Zhao <zhaoziqi9146@gmail.com>
  • Loading branch information
fatsheep9146 committed Jul 19, 2022
1 parent 5568a30 commit 096a162
Show file tree
Hide file tree
Showing 3 changed files with 292 additions and 7 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -14,6 +14,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
The package contains semantic conventions from the `v1.12.0` version of the OpenTelemetry specification. (#3010)
- Add the `go.opentelemetry.io/otel/semconv/v1.11.0` package.
The package contains semantic conventions from the `v1.11.0` version of the OpenTelemetry specification. (#3009)
- Add http.method attribute to http server metric. (#3018)

## [1.8.0/0.31.0] - 2022-07-08

Expand Down
13 changes: 6 additions & 7 deletions semconv/internal/http.go
Expand Up @@ -147,12 +147,6 @@ func (sc *SemanticConventions) EndUserAttributesFromHTTPRequest(request *http.Re
func (sc *SemanticConventions) HTTPClientAttributesFromHTTPRequest(request *http.Request) []attribute.KeyValue {
attrs := []attribute.KeyValue{}

if request.Method != "" {
attrs = append(attrs, sc.HTTPMethodKey.String(request.Method))
} else {
attrs = append(attrs, sc.HTTPMethodKey.String(http.MethodGet))
}

// remove any username/password info that may be in the URL
// before adding it to the attributes
userinfo := request.URL.User
Expand Down Expand Up @@ -204,6 +198,12 @@ func (sc *SemanticConventions) httpBasicAttributesFromHTTPRequest(request *http.
attrs = append(attrs, sc.HTTPFlavorKey.String(flavor))
}

if request.Method != "" {
attrs = append(attrs, sc.HTTPMethodKey.String(request.Method))
} else {
attrs = append(attrs, sc.HTTPMethodKey.String(http.MethodGet))
}

return attrs
}

Expand All @@ -223,7 +223,6 @@ func (sc *SemanticConventions) HTTPServerMetricAttributesFromHTTPRequest(serverN
// supported.
func (sc *SemanticConventions) HTTPServerAttributesFromHTTPRequest(serverName, route string, request *http.Request) []attribute.KeyValue {
attrs := []attribute.KeyValue{
sc.HTTPMethodKey.String(request.Method),
sc.HTTPTargetKey.String(request.RequestURI),
}

Expand Down
285 changes: 285 additions & 0 deletions semconv/internal/http_test.go
Expand Up @@ -1236,3 +1236,288 @@ func TestHTTPClientAttributesFromHTTPRequest(t *testing.T) {
})
}
}

func TestHTTPServerMetricAttributesFromHTTPRequest(t *testing.T) {
type testcase struct {
name string
serverName string
method string
requestURI string
proto string
remoteAddr string
host string
url *url.URL
header http.Header
tls tlsOption
contentLength int64
expected []attribute.KeyValue
}
testcases := []testcase{
{
name: "stripped",
serverName: "",
method: "GET",
requestURI: "/user/123",
proto: "HTTP/1.0",
remoteAddr: "",
host: "",
url: &url.URL{
Path: "/user/123",
},
header: nil,
tls: noTLS,
expected: []attribute.KeyValue{
attribute.String("http.method", "GET"),
attribute.String("http.scheme", "http"),
attribute.String("http.flavor", "1.0"),
},
},
{
name: "with server name",
serverName: "my-server-name",
method: "GET",
requestURI: "/user/123",
proto: "HTTP/1.0",
remoteAddr: "",
host: "",
url: &url.URL{
Path: "/user/123",
},
header: nil,
tls: noTLS,
expected: []attribute.KeyValue{
attribute.String("http.method", "GET"),
attribute.String("http.scheme", "http"),
attribute.String("http.flavor", "1.0"),
attribute.String("http.server_name", "my-server-name"),
},
},
{
name: "with tls",
serverName: "my-server-name",
method: "GET",
requestURI: "/user/123",
proto: "HTTP/1.0",
remoteAddr: "",
host: "",
url: &url.URL{
Path: "/user/123",
},
header: nil,
tls: withTLS,
expected: []attribute.KeyValue{
attribute.String("http.method", "GET"),
attribute.String("http.scheme", "https"),
attribute.String("http.flavor", "1.0"),
attribute.String("http.server_name", "my-server-name"),
},
},
{
name: "with route",
serverName: "my-server-name",
method: "GET",
requestURI: "/user/123",
proto: "HTTP/1.0",
remoteAddr: "",
host: "",
url: &url.URL{
Path: "/user/123",
},
header: nil,
tls: withTLS,
expected: []attribute.KeyValue{
attribute.String("http.method", "GET"),
attribute.String("http.scheme", "https"),
attribute.String("http.flavor", "1.0"),
attribute.String("http.server_name", "my-server-name"),
},
},
{
name: "with host",
serverName: "my-server-name",
method: "GET",
requestURI: "/user/123",
proto: "HTTP/1.0",
remoteAddr: "",
host: "example.com",
url: &url.URL{
Path: "/user/123",
},
header: nil,
tls: withTLS,
expected: []attribute.KeyValue{
attribute.String("http.method", "GET"),
attribute.String("http.scheme", "https"),
attribute.String("http.flavor", "1.0"),
attribute.String("http.server_name", "my-server-name"),
attribute.String("http.host", "example.com"),
},
},
{
name: "with host fallback",
serverName: "my-server-name",
method: "GET",
requestURI: "/user/123",
proto: "HTTP/1.0",
remoteAddr: "",
host: "",
url: &url.URL{
Host: "example.com",
Path: "/user/123",
},
header: nil,
tls: withTLS,
expected: []attribute.KeyValue{
attribute.String("http.method", "GET"),
attribute.String("http.scheme", "https"),
attribute.String("http.flavor", "1.0"),
attribute.String("http.server_name", "my-server-name"),
attribute.String("http.host", "example.com"),
},
},
{
name: "with user agent",
serverName: "my-server-name",
method: "GET",
requestURI: "/user/123",
proto: "HTTP/1.0",
remoteAddr: "",
host: "example.com",
url: &url.URL{
Path: "/user/123",
},
header: http.Header{
"User-Agent": []string{"foodownloader"},
},
tls: withTLS,
expected: []attribute.KeyValue{
attribute.String("http.method", "GET"),
attribute.String("http.scheme", "https"),
attribute.String("http.flavor", "1.0"),
attribute.String("http.server_name", "my-server-name"),
attribute.String("http.host", "example.com"),
},
},
{
name: "with proxy info",
serverName: "my-server-name",
method: "GET",
requestURI: "/user/123",
proto: "HTTP/1.0",
remoteAddr: "",
host: "example.com",
url: &url.URL{
Path: "/user/123",
},
header: http.Header{
"User-Agent": []string{"foodownloader"},
"X-Forwarded-For": []string{"203.0.113.195, 70.41.3.18, 150.172.238.178"},
},
tls: withTLS,
expected: []attribute.KeyValue{
attribute.String("http.method", "GET"),
attribute.String("http.scheme", "https"),
attribute.String("http.flavor", "1.0"),
attribute.String("http.server_name", "my-server-name"),
attribute.String("http.host", "example.com"),
},
},
{
name: "with http 1.1",
serverName: "my-server-name",
method: "GET",
requestURI: "/user/123",
proto: "HTTP/1.1",
remoteAddr: "",
host: "example.com",
url: &url.URL{
Path: "/user/123",
},
header: http.Header{
"User-Agent": []string{"foodownloader"},
"X-Forwarded-For": []string{"1.2.3.4"},
},
tls: withTLS,
expected: []attribute.KeyValue{
attribute.String("http.method", "GET"),
attribute.String("http.scheme", "https"),
attribute.String("http.flavor", "1.1"),
attribute.String("http.server_name", "my-server-name"),
attribute.String("http.host", "example.com"),
},
},
{
name: "with http 2",
serverName: "my-server-name",
method: "GET",
requestURI: "/user/123",
proto: "HTTP/2.0",
remoteAddr: "",
host: "example.com",
url: &url.URL{
Path: "/user/123",
},
header: http.Header{
"User-Agent": []string{"foodownloader"},
"X-Forwarded-For": []string{"1.2.3.4"},
},
tls: withTLS,
expected: []attribute.KeyValue{
attribute.String("http.method", "GET"),
attribute.String("http.scheme", "https"),
attribute.String("http.flavor", "2"),
attribute.String("http.server_name", "my-server-name"),
attribute.String("http.host", "example.com"),
},
},
}
for idx, tc := range testcases {
r := testRequest(tc.method, tc.requestURI, tc.proto, tc.remoteAddr, tc.host, tc.url, tc.header, tc.tls)
r.ContentLength = tc.contentLength
got := sc.HTTPServerMetricAttributesFromHTTPRequest(tc.serverName, r)
assertElementsMatch(t, tc.expected, got, "testcase %d - %s", idx, tc.name)
}
}

func TestHttpBasicAttributesFromHTTPRequest(t *testing.T) {
type testcase struct {
name string
method string
requestURI string
proto string
remoteAddr string
host string
url *url.URL
header http.Header
tls tlsOption
contentLength int64
expected []attribute.KeyValue
}
testcases := []testcase{
{
name: "stripped",
method: "GET",
requestURI: "/user/123",
proto: "HTTP/1.0",
remoteAddr: "",
host: "example.com",
url: &url.URL{
Path: "/user/123",
},
header: nil,
tls: noTLS,
expected: []attribute.KeyValue{
attribute.String("http.method", "GET"),
attribute.String("http.scheme", "http"),
attribute.String("http.flavor", "1.0"),
attribute.String("http.host", "example.com"),
},
},
}
for idx, tc := range testcases {
r := testRequest(tc.method, tc.requestURI, tc.proto, tc.remoteAddr, tc.host, tc.url, tc.header, tc.tls)
r.ContentLength = tc.contentLength
got := sc.httpBasicAttributesFromHTTPRequest(r)
assertElementsMatch(t, tc.expected, got, "testcase %d - %s", idx, tc.name)
}
}

0 comments on commit 096a162

Please sign in to comment.