mirror of
https://github.com/pomerium/pomerium.git
synced 2025-05-02 03:46:29 +02:00
Merge pull request #220 from travisgroth/feature/http-metrics-v2
HTTP metrics improvements
This commit is contained in:
commit
51e15daffd
8 changed files with 139 additions and 129 deletions
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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")
|
||||||
)
|
)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue