Merge pull request #220 from travisgroth/feature/http-metrics-v2

HTTP metrics improvements
This commit is contained in:
Bobby DeSimone 2019-07-11 23:39:44 -07:00 committed by GitHub
commit 51e15daffd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 139 additions and 129 deletions

View file

@ -14,6 +14,11 @@
- GRPC version upgraded to v1.22 [GH-219] - GRPC version upgraded to v1.22 [GH-219]
- HTTP Metrics Implementation [GH-220]
- Support HTTP request sizes on client and server side of proxy
- Improved HTTP metrics implementation internals
- The HTTP method label is now `http_method`, and HTTP status label is now `http_status`
## v0.1.0 ## v0.1.0
### NEW ### NEW

View file

@ -168,9 +168,11 @@ Name | Type | Description
:------------------------------ | :-------- | :-------------------------------------------- :------------------------------ | :-------- | :--------------------------------------------
http_server_requests_total | Counter | Total HTTP server requests handled by service http_server_requests_total | Counter | Total HTTP server requests handled by service
http_server_response_size_bytes | Histogram | HTTP server response size by service http_server_response_size_bytes | Histogram | HTTP server response size by service
http_server_request_size_bytes | Histogram | HTTP server request size by service
http_server_request_duration_ms | Histogram | HTTP server request duration by service http_server_request_duration_ms | Histogram | HTTP server request duration by service
http_client_requests_total | Counter | Total HTTP client requests made by service http_client_requests_total | Counter | Total HTTP client requests made by service
http_client_response_size_bytes | Histogram | HTTP client response size by service http_client_response_size_bytes | Histogram | HTTP client response size by service
http_client_request_size_bytes | Histogram | HTTP client request size by service
http_client_request_duration_ms | Histogram | HTTP client request duration by service http_client_request_duration_ms | Histogram | HTTP client request duration by service
grpc_client_requests_total | Counter | Total GRPC client requests made by service grpc_client_requests_total | Counter | Total GRPC client requests made by service
grpc_client_response_size_bytes | Histogram | GRPC client response size by service grpc_client_response_size_bytes | Histogram | GRPC client response size by service

View file

@ -18,7 +18,7 @@ func testDataRetrieval(v *view.View, t *testing.T, want string) {
t.Fatalf("%s: failed to retrieve data line %s", name, err) t.Fatalf("%s: failed to retrieve data line %s", name, err)
} }
if len(data) != 1 { if len(data) != 1 {
t.Errorf("%s: received too many data rows: %d", name, len(data)) t.Fatalf("%s: received incorrect number of data rows: %d", name, len(data))
} }
if !strings.HasPrefix(data[0].String(), want) { if !strings.HasPrefix(data[0].String(), want) {

View file

@ -1,99 +1,105 @@
package metrics // import "github.com/pomerium/pomerium/internal/metrics" package metrics // import "github.com/pomerium/pomerium/internal/metrics"
import ( import (
"context"
"net/http" "net/http"
"strconv"
"time" "go.opencensus.io/plugin/ochttp"
"github.com/pomerium/pomerium/internal/log" "github.com/pomerium/pomerium/internal/log"
"github.com/pomerium/pomerium/internal/middleware/responsewriter"
"github.com/pomerium/pomerium/internal/tripper" "github.com/pomerium/pomerium/internal/tripper"
"go.opencensus.io/stats"
"go.opencensus.io/stats/view" "go.opencensus.io/stats/view"
"go.opencensus.io/tag" "go.opencensus.io/tag"
) )
var ( var (
httpServerRequestCount = stats.Int64("http_server_requests_total", "Total HTTP Requests", "1") httpSizeDistribution = view.Distribution(
httpServerResponseSize = stats.Int64("http_server_response_size_bytes", "HTTP Server Response Size in bytes", "bytes") 1, 256, 512, 1024, 2048, 8192, 16384, 32768, 65536, 131072, 262144, 524288,
httpServerRequestDuration = stats.Int64("http_server_request_duration_ms", "HTTP Request duration in ms", "ms") 1048576, 2097152, 4194304, 8388608,
)
httpClientRequestCount = stats.Int64("http_client_requests_total", "Total HTTP Client Requests", "1") httpLatencyDistrubtion = view.Distribution(
httpClientResponseSize = stats.Int64("http_client_response_size_bytes", "HTTP Client Response Size in bytes", "bytes") 1, 2, 5, 7, 10, 25, 500, 750,
httpClientRequestDuration = stats.Int64("http_client_request_duration_ms", "HTTP Client Request duration in ms", "ms") 100, 250, 500, 750,
1000, 2500, 5000, 7500,
10000, 25000, 50000, 75000,
100000,
)
// httpClientRequestCount = stats.Int64("http_client_requests_total", "Total HTTP Client Requests", "1")
// httpClientResponseSize = stats.Int64("http_client_response_size_bytes", "HTTP Client Response Size in bytes", "bytes")
// httpClientRequestDuration = stats.Int64("http_client_request_duration_ms", "HTTP Client Request duration in ms", "ms")
// HTTPServerRequestCountView is an OpenCensus View that tracks HTTP server requests by pomerium service, host, method and status // HTTPServerRequestCountView is an OpenCensus View that tracks HTTP server requests by pomerium service, host, method and status
HTTPServerRequestCountView = &view.View{ HTTPServerRequestCountView = &view.View{
Name: httpServerRequestCount.Name(), Name: "http_server_requests_total",
Measure: httpServerRequestCount, Measure: ochttp.ServerLatency,
Description: httpServerRequestCount.Description(), Description: "Total HTTP Requests",
TagKeys: []tag.Key{keyService, keyHost, keyMethod, keyStatus}, TagKeys: []tag.Key{keyService, keyHost, keyHTTPMethod, ochttp.StatusCode},
Aggregation: view.Count(), Aggregation: view.Count(),
} }
// HTTPServerRequestDurationView is an OpenCensus view that tracks HTTP server request duration by pomerium service, host, method and status // HTTPServerRequestDurationView is an OpenCensus view that tracks HTTP server request duration by pomerium service, host, method and status
HTTPServerRequestDurationView = &view.View{ HTTPServerRequestDurationView = &view.View{
Name: httpServerRequestDuration.Name(), Name: "http_server_request_duration_ms",
Measure: httpServerRequestDuration, Measure: ochttp.ServerLatency,
Description: httpServerRequestDuration.Description(), Description: "HTTP Request duration in ms",
TagKeys: []tag.Key{keyService, keyHost, keyMethod, keyStatus}, TagKeys: []tag.Key{keyService, keyHost, keyHTTPMethod, ochttp.StatusCode},
Aggregation: view.Distribution( Aggregation: httpLatencyDistrubtion,
1, 2, 5, 7, 10, 25, 500, 750,
100, 250, 500, 750,
1000, 2500, 5000, 7500,
10000, 25000, 50000, 75000,
100000,
),
} }
// HTTPServerRequestSizeView is an OpenCensus view that tracks HTTP server request duration by pomerium service, host, method and status // HTTPServerRequestSizeView is an OpenCensus view that tracks HTTP server request size by pomerium service, host and method
HTTPServerRequestSizeView = &view.View{ HTTPServerRequestSizeView = &view.View{
Name: httpServerResponseSize.Name(), Name: "http_server_request_size_bytes",
Measure: httpServerResponseSize, Measure: ochttp.ServerRequestBytes,
Description: httpServerResponseSize.Description(), Description: "HTTP Server Request Size in bytes",
TagKeys: []tag.Key{keyService, keyHost, keyMethod, keyStatus}, TagKeys: []tag.Key{keyService, keyHost, keyHTTPMethod},
Aggregation: view.Distribution( Aggregation: httpSizeDistribution,
1, 256, 512, 1024, 2048, 8192, 16384, 32768, 65536, 131072, 262144, 524288,
1048576, 2097152, 4194304, 8388608,
),
} }
// HTTPClientRequestCountView is an OpenCensus View that tracks HTTP client requests by pomerium service, host, method and status // HTTPServerResponseSizeView is an OpenCensus view that tracks HTTP server response size by pomerium service, host, method and status
HTTPServerResponseSizeView = &view.View{
Name: "http_server_response_size_bytes",
Measure: ochttp.ServerResponseBytes,
Description: "HTTP Server Response Size in bytes",
TagKeys: []tag.Key{keyService, keyHost, keyHTTPMethod, ochttp.StatusCode},
Aggregation: httpSizeDistribution,
}
// HTTPClientRequestCountView is an OpenCensus View that tracks HTTP client requests by pomerium service, destination, host, method and status
HTTPClientRequestCountView = &view.View{ HTTPClientRequestCountView = &view.View{
Name: httpClientRequestCount.Name(), Name: "http_client_requests_total",
Measure: httpClientRequestCount, Measure: ochttp.ClientLatency,
Description: httpClientRequestCount.Description(), Description: "Total HTTP Client Requests",
TagKeys: []tag.Key{keyService, keyHost, keyMethod, keyStatus}, TagKeys: []tag.Key{keyService, keyHost, keyHTTPMethod, ochttp.StatusCode, keyDestination},
Aggregation: view.Count(), Aggregation: view.Count(),
} }
// HTTPClientRequestDurationView is an OpenCensus view that tracks HTTP client request duration by pomerium service, host, method and status // HTTPClientRequestDurationView is an OpenCensus view that tracks HTTP client request duration by pomerium service, destination, host, method and status
HTTPClientRequestDurationView = &view.View{ HTTPClientRequestDurationView = &view.View{
Name: httpClientRequestDuration.Name(), Name: "http_client_request_duration_ms",
Measure: httpClientRequestDuration, Measure: ochttp.ClientRoundtripLatency,
Description: httpClientRequestDuration.Description(), Description: "HTTP Client Request duration in ms",
TagKeys: []tag.Key{keyService, keyHost, keyMethod, keyStatus}, TagKeys: []tag.Key{keyService, keyHost, keyHTTPMethod, ochttp.StatusCode, keyDestination},
Aggregation: view.Distribution( Aggregation: httpLatencyDistrubtion,
1, 2, 5, 7, 10, 25, 500, 750,
100, 250, 500, 750,
1000, 2500, 5000, 7500,
10000, 25000, 50000, 75000,
100000,
),
} }
// HTTPClientResponseSizeView is an OpenCensus view that tracks HTTP client response size by pomerium service, host, method and status // HTTPClientResponseSizeView is an OpenCensus view that tracks HTTP client response size by pomerium service, destination, host, method and status
HTTPClientResponseSizeView = &view.View{ HTTPClientResponseSizeView = &view.View{
Name: httpClientResponseSize.Name(), Name: "http_client_response_size_bytes",
Measure: httpClientResponseSize, Measure: ochttp.ClientReceivedBytes,
Description: httpClientResponseSize.Description(), Description: "HTTP Client Response Size in bytes",
TagKeys: []tag.Key{keyService, keyHost, keyMethod, keyStatus}, TagKeys: []tag.Key{keyService, keyHost, keyHTTPMethod, ochttp.StatusCode, keyDestination},
Aggregation: view.Distribution( Aggregation: httpSizeDistribution,
1, 256, 512, 1024, 2048, 8192, 16384, 32768, 65536, 131072, 262144, 524288, }
1048576, 2097152, 4194304, 8388608,
), // HTTPClientRequestSizeView is an OpenCensus view that tracks HTTP client request size by pomerium service, destination, host and method
HTTPClientRequestSizeView = &view.View{
Name: "http_client_response_size_bytes",
Measure: ochttp.ClientSentBytes,
Description: "HTTP Client Response Size in bytes",
TagKeys: []tag.Key{keyService, keyHost, keyHTTPMethod, keyDestination},
Aggregation: httpSizeDistribution,
} }
) )
@ -102,61 +108,44 @@ func HTTPMetricsHandler(service string) func(next http.Handler) http.Handler {
return func(next http.Handler) http.Handler { return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
startTime := time.Now()
m := responsewriter.NewWrapResponseWriter(w, 1)
next.ServeHTTP(m, r)
ctx, tagErr := tag.New( ctx, tagErr := tag.New(
context.Background(), r.Context(),
tag.Insert(keyService, service), tag.Insert(keyService, service),
tag.Insert(keyHost, r.Host), tag.Insert(keyHost, r.Host),
tag.Insert(keyMethod, r.Method), tag.Insert(keyHTTPMethod, r.Method),
tag.Insert(keyStatus, strconv.Itoa(m.Status())),
) )
if tagErr != nil { if tagErr != nil {
log.Warn().Err(tagErr).Str("context", "HTTPMetricsHandler").Msg("Failed to create metrics context tag") log.Warn().Err(tagErr).Str("context", "HTTPMetricsHandler").Msg("internal/metrics: Failed to create metrics context tag")
} else { next.ServeHTTP(w, r)
stats.Record(ctx, return
httpServerRequestCount.M(1),
httpServerRequestDuration.M(time.Since(startTime).Nanoseconds()/int64(time.Millisecond)),
httpServerResponseSize.M(int64(m.BytesWritten())),
)
} }
ocHandler := ochttp.Handler{Handler: next}
ocHandler.ServeHTTP(w, r.WithContext(ctx))
}) })
} }
} }
// HTTPMetricsRoundTripper creates a metrics tracking tripper for outbound HTTP Requests // HTTPMetricsRoundTripper creates a metrics tracking tripper for outbound HTTP Requests
func HTTPMetricsRoundTripper(service string) func(next http.RoundTripper) http.RoundTripper { func HTTPMetricsRoundTripper(service string, destination string) func(next http.RoundTripper) http.RoundTripper {
return func(next http.RoundTripper) http.RoundTripper { return func(next http.RoundTripper) http.RoundTripper {
return tripper.RoundTripperFunc(func(r *http.Request) (*http.Response, error) { return tripper.RoundTripperFunc(func(r *http.Request) (*http.Response, error) {
startTime := time.Now()
resp, err := next.RoundTrip(r) ctx, tagErr := tag.New(
r.Context(),
tag.Insert(keyService, service),
tag.Insert(keyHost, r.Host),
tag.Insert(keyHTTPMethod, r.Method),
tag.Insert(keyDestination, destination),
)
if resp != nil && err == nil { if tagErr != nil {
ctx, tagErr := tag.New( log.Warn().Err(tagErr).Str("context", "HTTPMetricsRoundTripper").Msg("internal/metrics: Failed to create context tag")
context.Background(), return next.RoundTrip(r)
tag.Insert(keyService, service),
tag.Insert(keyHost, r.Host),
tag.Insert(keyMethod, r.Method),
tag.Insert(keyStatus, strconv.Itoa(resp.StatusCode)),
)
if tagErr != nil {
log.Warn().Err(tagErr).Str("context", "HTTPMetricsRoundTripper").Msg("Failed to create context tag")
} else {
stats.Record(ctx,
httpClientRequestCount.M(1),
httpClientRequestDuration.M(time.Since(startTime).Nanoseconds()/int64(time.Millisecond)),
httpClientResponseSize.M(resp.ContentLength),
)
}
} }
return resp, err
ocTransport := ochttp.Transport{Base: next}
return ocTransport.RoundTrip(r.WithContext(ctx))
}) })
} }
} }

View file

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"errors" "errors"
"fmt" "fmt"
"io/ioutil"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"testing" "testing"
@ -32,6 +33,7 @@ func Test_HTTPMetricsHandler(t *testing.T) {
name string name string
url string url string
verb string verb string
wanthttpServerRequestSize string
wanthttpServerResponseSize string wanthttpServerResponseSize string
wanthttpServerRequestDuration string wanthttpServerRequestDuration string
wanthttpServerRequestCount string wanthttpServerRequestCount string
@ -40,37 +42,41 @@ func Test_HTTPMetricsHandler(t *testing.T) {
name: "good get", name: "good get",
url: "http://test.local/good", url: "http://test.local/good",
verb: "GET", verb: "GET",
wanthttpServerResponseSize: "{ { {host test.local}{method GET}{service test_service}{status 200} }&{1 5 5 5 0 [0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]", wanthttpServerRequestSize: "{ { {host test.local}{http_method GET}{service test_service} }&{1 0 5e-324 0 0 [1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]",
wanthttpServerRequestDuration: "{ { {host test.local}{method GET}{service test_service}{status 200} }&{1", wanthttpServerResponseSize: "{ { {host test.local}{http.status 200}{http_method GET}{service test_service} }&{1 5 5 5 0 [0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]",
wanthttpServerRequestCount: "{ { {host test.local}{method GET}{service test_service}{status 200} }&{1", wanthttpServerRequestDuration: "{ { {host test.local}{http.status 200}{http_method GET}{service test_service} }&{1",
wanthttpServerRequestCount: "{ { {host test.local}{http.status 200}{http_method GET}{service test_service} }&{1",
}, },
{ {
name: "good post", name: "good post",
url: "http://test.local/good", url: "http://test.local/good",
verb: "POST", verb: "POST",
wanthttpServerResponseSize: "{ { {host test.local}{method POST}{service test_service}{status 200} }&{1 5 5 5 0 [0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]", wanthttpServerRequestSize: "{ { {host test.local}{http_method POST}{service test_service} }&{1 0 5e-324 0 0 [1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]",
wanthttpServerRequestDuration: "{ { {host test.local}{method POST}{service test_service}{status 200} }&{1", wanthttpServerResponseSize: "{ { {host test.local}{http.status 200}{http_method POST}{service test_service} }&{1 5 5 5 0 [0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]",
wanthttpServerRequestCount: "{ { {host test.local}{method POST}{service test_service}{status 200} }&{1", wanthttpServerRequestDuration: "{ { {host test.local}{http.status 200}{http_method POST}{service test_service} }&{1",
wanthttpServerRequestCount: "{ { {host test.local}{http.status 200}{http_method POST}{service test_service} }&{1",
}, },
{ {
name: "bad post", name: "bad post",
url: "http://test.local/bad", url: "http://test.local/bad",
verb: "POST", verb: "POST",
wanthttpServerResponseSize: "{ { {host test.local}{method POST}{service test_service}{status 404} }&{1 19 19 19 0 [0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]", wanthttpServerRequestSize: "{ { {host test.local}{http_method POST}{service test_service} }&{1 0 5e-324 0 0 [1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]",
wanthttpServerRequestDuration: "{ { {host test.local}{method POST}{service test_service}{status 404} }&{1", wanthttpServerResponseSize: "{ { {host test.local}{http.status 404}{http_method POST}{service test_service} }&{1 19 19 19 0 [0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]",
wanthttpServerRequestCount: "{ { {host test.local}{method POST}{service test_service}{status 404} }&{1", wanthttpServerRequestDuration: "{ { {host test.local}{http.status 404}{http_method POST}{service test_service} }&{1",
wanthttpServerRequestCount: "{ { {host test.local}{http.status 404}{http_method POST}{service test_service} }&{1",
}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
view.Unregister(HTTPServerRequestCountView, HTTPServerRequestDurationView, HTTPServerRequestSizeView) view.Unregister(HTTPServerRequestCountView, HTTPServerRequestDurationView, HTTPServerRequestSizeView, HTTPServerResponseSizeView)
view.Register(HTTPServerRequestCountView, HTTPServerRequestDurationView, HTTPServerRequestSizeView) view.Register(HTTPServerRequestCountView, HTTPServerRequestDurationView, HTTPServerRequestSizeView, HTTPServerResponseSizeView)
req := httptest.NewRequest(tt.verb, tt.url, new(bytes.Buffer)) req := httptest.NewRequest(tt.verb, tt.url, new(bytes.Buffer))
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
chainHandler.ServeHTTP(rec, req) chainHandler.ServeHTTP(rec, req)
testDataRetrieval(HTTPServerRequestSizeView, t, tt.wanthttpServerResponseSize) testDataRetrieval(HTTPServerRequestSizeView, t, tt.wanthttpServerRequestSize)
testDataRetrieval(HTTPServerResponseSizeView, t, tt.wanthttpServerResponseSize)
testDataRetrieval(HTTPServerRequestDurationView, t, tt.wanthttpServerRequestDuration) testDataRetrieval(HTTPServerRequestDurationView, t, tt.wanthttpServerRequestDuration)
testDataRetrieval(HTTPServerRequestCountView, t, tt.wanthttpServerRequestCount) testDataRetrieval(HTTPServerRequestCountView, t, tt.wanthttpServerRequestCount)
}) })
@ -98,7 +104,7 @@ func newFailingTestTransport() http.RoundTripper {
} }
func Test_HTTPMetricsRoundTripper(t *testing.T) { func Test_HTTPMetricsRoundTripper(t *testing.T) {
chain := tripper.NewChain(HTTPMetricsRoundTripper("test_service")) chain := tripper.NewChain(HTTPMetricsRoundTripper("test_service", "test_destination"))
rt := chain.Then(newTestTransport()) rt := chain.Then(newTestTransport())
client := http.Client{Transport: rt} client := http.Client{Transport: rt}
@ -106,6 +112,7 @@ func Test_HTTPMetricsRoundTripper(t *testing.T) {
name string name string
url string url string
verb string verb string
wanthttpClientRequestSize string
wanthttpClientResponseSize string wanthttpClientResponseSize string
wanthttpClientRequestDuration string wanthttpClientRequestDuration string
wanthttpClientRequestCount string wanthttpClientRequestCount string
@ -114,36 +121,42 @@ func Test_HTTPMetricsRoundTripper(t *testing.T) {
name: "good get", name: "good get",
url: "http://test.local/good", url: "http://test.local/good",
verb: "GET", verb: "GET",
wanthttpClientResponseSize: "{ { {host test.local}{method GET}{service test_service}{status 200} }&{1 5 5 5 0 [0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]", wanthttpClientRequestSize: "{ { {destination test_destination}{host test.local}{http.status 200}{http_method GET}{service test_service} }&{1 5 5 5 0 [0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]",
wanthttpClientRequestDuration: "{ { {host test.local}{method GET}{service test_service}{status 200} }&{1", wanthttpClientResponseSize: "{ { {destination test_destination}{host test.local}{http.status 200}{http_method GET}{service test_service} }&{1 5 5 5 0 [0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]",
wanthttpClientRequestCount: "{ { {host test.local}{method GET}{service test_service}{status 200} }&{1", wanthttpClientRequestDuration: "{ { {destination test_destination}{host test.local}{http.status 200}{http_method GET}{service test_service} }&{1",
wanthttpClientRequestCount: "{ { {destination test_destination}{host test.local}{http.status 200}{http_method GET}{service test_service} }&{1",
}, },
{ {
name: "good post", name: "good post",
url: "http://test.local/good", url: "http://test.local/good",
verb: "POST", verb: "POST",
wanthttpClientResponseSize: "{ { {host test.local}{method POST}{service test_service}{status 200} }&{1 5 5 5 0 [0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]", wanthttpClientRequestSize: "{ { {destination test_destination}{host test.local}{http.status 200}{http_method POST}{service test_service} }&{1 5 5 5 0 [0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]",
wanthttpClientRequestDuration: "{ { {host test.local}{method POST}{service test_service}{status 200} }&{1", wanthttpClientResponseSize: "{ { {destination test_destination}{host test.local}{http.status 200}{http_method POST}{service test_service} }&{1 5 5 5 0 [0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]",
wanthttpClientRequestCount: "{ { {host test.local}{method POST}{service test_service}{status 200} }&{1", wanthttpClientRequestDuration: "{ { {destination test_destination}{host test.local}{http.status 200}{http_method POST}{service test_service} }&{1",
wanthttpClientRequestCount: "{ { {destination test_destination}{host test.local}{http.status 200}{http_method POST}{service test_service} }&{1",
}, },
{ {
name: "bad post", name: "bad post",
url: "http://test.local/bad", url: "http://test.local/bad",
verb: "POST", verb: "POST",
wanthttpClientResponseSize: "{ { {host test.local}{method POST}{service test_service}{status 404} }&{1 19 19 19 0 [0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]", wanthttpClientRequestSize: "{ { {destination test_destination}{host test.local}{http.status 404}{http_method POST}{service test_service} }&{1 19 19 19 0 [0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]",
wanthttpClientRequestDuration: "{ { {host test.local}{method POST}{service test_service}{status 404} }&{1", wanthttpClientResponseSize: "{ { {destination test_destination}{host test.local}{http.status 404}{http_method POST}{service test_service} }&{1 19 19 19 0 [0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]",
wanthttpClientRequestCount: "{ { {host test.local}{method POST}{service test_service}{status 404} }&{1", wanthttpClientRequestDuration: "{ { {destination test_destination}{host test.local}{http.status 404}{http_method POST}{service test_service} }&{1",
wanthttpClientRequestCount: "{ { {destination test_destination}{host test.local}{http.status 404}{http_method POST}{service test_service} }&{1",
}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
view.Unregister(HTTPClientRequestCountView, HTTPClientRequestDurationView, HTTPClientResponseSizeView) view.Unregister(HTTPClientRequestCountView, HTTPClientRequestDurationView, HTTPClientResponseSizeView, HTTPClientRequestSizeView)
view.Register(HTTPClientRequestCountView, HTTPClientRequestDurationView, HTTPClientResponseSizeView) view.Register(HTTPClientRequestCountView, HTTPClientRequestDurationView, HTTPClientResponseSizeView, HTTPClientRequestSizeView)
req, _ := http.NewRequest(tt.verb, tt.url, new(bytes.Buffer)) req, _ := http.NewRequest(tt.verb, tt.url, new(bytes.Buffer))
resp, err := client.Do(req) resp, err := client.Do(req)
// must be done to record()
ioutil.ReadAll(resp.Body)
t.Logf("response: %#v, %#v", resp, err) t.Logf("response: %#v, %#v\n\n", resp, err)
testDataRetrieval(HTTPClientRequestSizeView, t, tt.wanthttpClientRequestSize)
testDataRetrieval(HTTPClientResponseSizeView, t, tt.wanthttpClientResponseSize) testDataRetrieval(HTTPClientResponseSizeView, t, tt.wanthttpClientResponseSize)
testDataRetrieval(HTTPClientRequestDurationView, t, tt.wanthttpClientRequestDuration) testDataRetrieval(HTTPClientRequestDurationView, t, tt.wanthttpClientRequestDuration)
testDataRetrieval(HTTPClientRequestCountView, t, tt.wanthttpClientRequestCount) testDataRetrieval(HTTPClientRequestCountView, t, tt.wanthttpClientRequestCount)

View file

@ -5,10 +5,11 @@ import (
) )
var ( var (
keyMethod tag.Key = tag.MustNewKey("method") keyHTTPMethod tag.Key = tag.MustNewKey("http_method")
keyStatus tag.Key = tag.MustNewKey("status") keyStatus tag.Key = tag.MustNewKey("status")
keyService tag.Key = tag.MustNewKey("service") keyService tag.Key = tag.MustNewKey("service")
keyGRPCService tag.Key = tag.MustNewKey("grpc_service") keyGRPCService tag.Key = tag.MustNewKey("grpc_service")
keyGRPCMethod tag.Key = tag.MustNewKey("grpc_method") keyGRPCMethod tag.Key = tag.MustNewKey("grpc_method")
keyHost tag.Key = tag.MustNewKey("host") keyHost tag.Key = tag.MustNewKey("host")
keyDestination tag.Key = tag.MustNewKey("destination")
) )

View file

@ -9,7 +9,7 @@ var (
// HTTPClientViews contains opencensus views for HTTP Client metrics // HTTPClientViews contains opencensus views for HTTP Client metrics
HTTPClientViews = []*view.View{HTTPClientRequestCountView, HTTPClientRequestDurationView, HTTPClientResponseSizeView} HTTPClientViews = []*view.View{HTTPClientRequestCountView, HTTPClientRequestDurationView, HTTPClientResponseSizeView}
// HTTPServerViews contains opencensus views for HTTP Server metrics // HTTPServerViews contains opencensus views for HTTP Server metrics
HTTPServerViews = []*view.View{HTTPServerRequestCountView, HTTPServerRequestDurationView, HTTPServerRequestSizeView} HTTPServerViews = []*view.View{HTTPServerRequestCountView, HTTPServerRequestDurationView, HTTPServerRequestSizeView, HTTPServerResponseSizeView}
// GRPCClientViews contains opencensus views for GRPC Client metrics // GRPCClientViews contains opencensus views for GRPC Client metrics
GRPCClientViews = []*view.View{GRPCClientRequestCountView, GRPCClientRequestDurationView, GRPCClientResponseSizeView, GRPCClientRequestSizeView} GRPCClientViews = []*view.View{GRPCClientRequestCountView, GRPCClientRequestDurationView, GRPCClientResponseSizeView, GRPCClientRequestSizeView}
// GRPCServerViews contains opencensus views for GRPC Server metrics // GRPCServerViews contains opencensus views for GRPC Server metrics

View file

@ -200,7 +200,7 @@ func (p *Proxy) UpdatePolicies(opts *config.Options) error {
// https://github.com/golang/go/issues/26013#issuecomment-399481302 // https://github.com/golang/go/issues/26013#issuecomment-399481302
transport := *(http.DefaultTransport.(*http.Transport)) transport := *(http.DefaultTransport.(*http.Transport))
c := tripper.NewChain() c := tripper.NewChain()
c = c.Append(metrics.HTTPMetricsRoundTripper("proxy")) c = c.Append(metrics.HTTPMetricsRoundTripper("proxy", policy.Destination.Host))
if policy.TLSSkipVerify { if policy.TLSSkipVerify {
transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
} }