1
0
mirror of https://github.com/open-telemetry/opentelemetry-go.git synced 2025-01-28 03:57:09 +02:00

Add http content size semantic conventions (#905)

* Add http content size to standard package

Signed-off-by: Sam Xie <xsambundy@gmail.com>

* Include `http.request_content_length` in HTTP request basic attributes

Signed-off-by: Sam Xie <xsambundy@gmail.com>

* Add test for api.standard package

Signed-off-by: Sam Xie <xsambundy@gmail.com>

* Update CHANGELOG

Signed-off-by: Sam Xie <xsambundy@gmail.com>

* Fix http content size naming

Signed-off-by: Sam Xie <xsambundy@gmail.com>

Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com>
This commit is contained in:
Sam Xie 2020-07-09 01:39:15 +08:00 committed by GitHub
parent 1c9aab619d
commit 03cd779f0e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 238 additions and 20 deletions

View File

@ -17,6 +17,8 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- Add `peer.service` semantic attribute. (#898)
- Add database-specific semantic attributes. (#899)
- Add semantic convention for `faas.coldstart` and `container.id`. (#909)
- Add http content size semantic conventions. (#905)
- Include `http.request_content_length` in HTTP request basic attributes. (#905)
### Changed
@ -51,6 +53,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- Ensure span status is not set to `Unknown` when no HTTP status code is provided as it is assumed to be `200 OK`. (#908)
- Ensure `httptrace.clientTracer` closes `http.headers` span. (#912)
- Prometheus exporter will not apply stale updates or forget inactive metrics. (#903)
- Add test for api.standard `HTTPClientAttributesFromHTTPRequest`. (#905)
- Bump github.com/golangci/golangci-lint from 1.27.0 to 1.28.1 in /tools. (#901, #913)
- Update otel-colector example to use the v0.5.0 collector. (#915)

View File

@ -177,6 +177,9 @@ func httpBasicAttributesFromHTTPRequest(request *http.Request) []kv.KeyValue {
if flavor != "" {
attrs = append(attrs, HTTPFlavorKey.String(flavor))
}
if request.ContentLength > 0 {
attrs = append(attrs, HTTPRequestContentLengthKey.Int64(request.ContentLength))
}
return attrs
}

View File

@ -420,14 +420,15 @@ func TestHTTPServerAttributesFromHTTPRequest(t *testing.T) {
serverName string
route string
method string
requestURI string
proto string
remoteAddr string
host string
url *url.URL
header http.Header
tls tlsOption
method string
requestURI string
proto string
remoteAddr string
host string
url *url.URL
header http.Header
tls tlsOption
contentLength int64
expected []otelkv.KeyValue
}
@ -658,9 +659,22 @@ func TestHTTPServerAttributesFromHTTPRequest(t *testing.T) {
otelkv.String("http.client_ip", "1.2.3.4"),
},
},
{
name: "with content length",
method: "GET",
requestURI: "/user/123",
contentLength: 100,
expected: []otelkv.KeyValue{
otelkv.String("http.method", "GET"),
otelkv.String("http.target", "/user/123"),
otelkv.String("http.scheme", "http"),
otelkv.Int64("http.request_content_length", 100),
},
},
}
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 := HTTPServerAttributesFromHTTPRequest(tc.serverName, tc.route, r)
assertElementsMatch(t, tc.expected, got, "testcase %d - %s", idx, tc.name)
}
@ -775,3 +789,184 @@ func kvStr(kvs []otelkv.KeyValue) string {
sb.WriteRune(']')
return sb.String()
}
func TestHTTPClientAttributesFromHTTPRequest(t *testing.T) {
testCases := []struct {
name string
method string
requestURI string
proto string
remoteAddr string
host string
url *url.URL
header http.Header
tls tlsOption
contentLength int64
expected []otelkv.KeyValue
}{
{
name: "stripped",
method: "GET",
requestURI: "/user/123",
proto: "HTTP/1.0",
remoteAddr: "",
host: "",
url: &url.URL{
Path: "/user/123",
},
header: nil,
tls: noTLS,
expected: []otelkv.KeyValue{
otelkv.String("http.method", "GET"),
otelkv.String("http.url", "/user/123"),
otelkv.String("http.scheme", "http"),
otelkv.String("http.flavor", "1.0"),
},
},
{
name: "with tls",
method: "GET",
requestURI: "/user/123",
proto: "HTTP/1.0",
remoteAddr: "",
host: "",
url: &url.URL{
Path: "/user/123",
},
header: nil,
tls: withTLS,
expected: []otelkv.KeyValue{
otelkv.String("http.method", "GET"),
otelkv.String("http.url", "/user/123"),
otelkv.String("http.scheme", "https"),
otelkv.String("http.flavor", "1.0"),
},
},
{
name: "with host",
method: "GET",
requestURI: "/user/123",
proto: "HTTP/1.0",
remoteAddr: "",
host: "example.com",
url: &url.URL{
Path: "/user/123",
},
header: nil,
tls: withTLS,
expected: []otelkv.KeyValue{
otelkv.String("http.method", "GET"),
otelkv.String("http.url", "/user/123"),
otelkv.String("http.scheme", "https"),
otelkv.String("http.flavor", "1.0"),
otelkv.String("http.host", "example.com"),
},
},
{
name: "with user agent",
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: []otelkv.KeyValue{
otelkv.String("http.method", "GET"),
otelkv.String("http.url", "/user/123"),
otelkv.String("http.scheme", "https"),
otelkv.String("http.flavor", "1.0"),
otelkv.String("http.host", "example.com"),
otelkv.String("http.user_agent", "foodownloader"),
},
},
{
name: "with http 1.1",
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"},
},
tls: withTLS,
expected: []otelkv.KeyValue{
otelkv.String("http.method", "GET"),
otelkv.String("http.url", "/user/123"),
otelkv.String("http.scheme", "https"),
otelkv.String("http.flavor", "1.1"),
otelkv.String("http.host", "example.com"),
otelkv.String("http.user_agent", "foodownloader"),
},
},
{
name: "with http 2",
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"},
},
tls: withTLS,
expected: []otelkv.KeyValue{
otelkv.String("http.method", "GET"),
otelkv.String("http.url", "/user/123"),
otelkv.String("http.scheme", "https"),
otelkv.String("http.flavor", "2"),
otelkv.String("http.host", "example.com"),
otelkv.String("http.user_agent", "foodownloader"),
},
},
{
name: "with content length",
method: "GET",
url: &url.URL{
Path: "/user/123",
},
contentLength: 100,
expected: []otelkv.KeyValue{
otelkv.String("http.method", "GET"),
otelkv.String("http.url", "/user/123"),
otelkv.String("http.scheme", "http"),
otelkv.Int64("http.request_content_length", 100),
},
},
{
name: "with empty method (fallback to GET)",
method: "",
url: &url.URL{
Path: "/user/123",
},
expected: []otelkv.KeyValue{
otelkv.String("http.method", "GET"),
otelkv.String("http.url", "/user/123"),
otelkv.String("http.scheme", "http"),
},
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
r := testRequest(tc.method, tc.requestURI, tc.proto, tc.remoteAddr, tc.host, tc.url, tc.header, tc.tls)
r.ContentLength = tc.contentLength
got := HTTPClientAttributesFromHTTPRequest(r)
assert.ElementsMatch(t, tc.expected, got)
})
}
}

View File

@ -111,6 +111,20 @@ const (
// The IP address of the original client behind all proxies, if known
// (e.g. from X-Forwarded-For).
HTTPClientIPKey = kv.Key("http.client_ip")
// The size of the request payload body in bytes.
HTTPRequestContentLengthKey = kv.Key("http.request_content_length")
// The size of the uncompressed request payload body after transport decoding.
// Not set if transport encoding not used.
HTTPRequestContentLengthUncompressedKey = kv.Key("http.request_content_length_uncompressed")
// The size of the response payload body in bytes.
HTTPResponseContentLengthKey = kv.Key("http.response_content_length")
// The size of the uncompressed response payload body after transport decoding.
// Not set if transport encoding not used.
HTTPResponseContentLengthUncompressedKey = kv.Key("http.response_content_length_uncompressed")
)
var (

View File

@ -87,23 +87,24 @@ func TestRoundtrip(t *testing.T) {
address := ts.Listener.Addr()
hp := strings.Split(address.String(), ":")
expectedAttrs = map[kv.Key]string{
standard.HTTPFlavorKey: "1.1",
standard.HTTPHostKey: address.String(),
standard.HTTPMethodKey: "GET",
standard.HTTPSchemeKey: "http",
standard.HTTPTargetKey: "/",
standard.HTTPUserAgentKey: "Go-http-client/1.1",
standard.NetHostIPKey: hp[0],
standard.NetHostPortKey: hp[1],
standard.NetPeerIPKey: "127.0.0.1",
standard.NetTransportKey: "IP.TCP",
standard.HTTPFlavorKey: "1.1",
standard.HTTPHostKey: address.String(),
standard.HTTPMethodKey: "GET",
standard.HTTPSchemeKey: "http",
standard.HTTPTargetKey: "/",
standard.HTTPUserAgentKey: "Go-http-client/1.1",
standard.HTTPRequestContentLengthKey: "3",
standard.NetHostIPKey: hp[0],
standard.NetHostPortKey: hp[1],
standard.NetPeerIPKey: "127.0.0.1",
standard.NetTransportKey: "IP.TCP",
}
client := ts.Client()
err := tr.WithSpan(context.Background(), "test",
func(ctx context.Context) error {
ctx = correlation.ContextWithMap(ctx, correlation.NewMap(correlation.MapUpdate{SingleKV: kv.Key("foo").String("bar")}))
req, _ := http.NewRequest("GET", ts.URL, nil)
req, _ := http.NewRequest("GET", ts.URL, strings.NewReader("foo"))
httptrace.Inject(ctx, req)
res, err := client.Do(req)

View File

@ -19,6 +19,7 @@ import (
"io/ioutil"
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/stretchr/testify/assert"
@ -56,7 +57,7 @@ func TestHandlerBasics(t *testing.T) {
WithMeter(meter),
)
r, err := http.NewRequest(http.MethodGet, "http://localhost/", nil)
r, err := http.NewRequest(http.MethodGet, "http://localhost/", strings.NewReader("foo"))
if err != nil {
t.Fatal(err)
}
@ -71,6 +72,7 @@ func TestHandlerBasics(t *testing.T) {
standard.HTTPSchemeHTTP,
standard.HTTPHostKey.String(r.Host),
standard.HTTPFlavorKey.String(fmt.Sprintf("1.%d", r.ProtoMinor)),
standard.HTTPRequestContentLengthKey.Int64(3),
}
assertMetricLabels(t, labelsToVerify, meterimpl.MeasurementBatches)