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:
parent
1c9aab619d
commit
03cd779f0e
@ -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)
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -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 (
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user