envoy: Enable zipkin tracing (#737)

- Update envoy bootstrap config to protobufs
- Reorganize tracing config to avoid cyclic import
- Push down zipkin config to Envoy
- Update tracing options to provide sample rate
This commit is contained in:
Travis Groth 2020-05-21 11:50:07 -04:00 committed by GitHub
parent 38c1b5ec65
commit 3e17befff7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 434 additions and 120 deletions

View file

@ -10,16 +10,12 @@ import (
prom "github.com/prometheus/client_golang/prometheus"
"go.opencensus.io/stats/view"
"github.com/pomerium/pomerium/internal/envoy"
log "github.com/pomerium/pomerium/internal/log"
"github.com/pomerium/pomerium/internal/urlutil"
)
var envoyURL = envoy.EnvoyAdminURL
// PrometheusHandler creates an exporter that exports stats to Prometheus
// and returns a handler suitable for exporting metrics.
func PrometheusHandler() (http.Handler, error) {
func PrometheusHandler(envoyURL *url.URL) (http.Handler, error) {
if err := registerDefaultViews(); err != nil {
return nil, fmt.Errorf("telemetry/metrics: failed registering views")
}
@ -35,7 +31,7 @@ func PrometheusHandler() (http.Handler, error) {
view.RegisterExporter(exporter)
mux := http.NewServeMux()
envoyMetricsURL, err := urlutil.ParseAndValidateURL(fmt.Sprintf("%s/stats/prometheus", envoyURL))
envoyMetricsURL, err := envoyURL.Parse("/stats/prometheus")
if err != nil {
return nil, fmt.Errorf("telemetry/metrics: invalid proxy URL: %w", err)
}

View file

@ -4,6 +4,7 @@ import (
"io/ioutil"
"net/http"
"net/http/httptest"
"net/url"
"regexp"
"testing"
)
@ -27,8 +28,8 @@ envoy_server_initialization_time_ms_bucket{le="1000"} 1
}
}
func getMetrics(t *testing.T) []byte {
h, err := PrometheusHandler()
func getMetrics(t *testing.T, envoyURL *url.URL) []byte {
h, err := PrometheusHandler(envoyURL)
if err != nil {
t.Fatal(err)
}
@ -48,7 +49,7 @@ func getMetrics(t *testing.T) []byte {
func Test_PrometheusHandler(t *testing.T) {
t.Run("no envoy", func(t *testing.T) {
b := getMetrics(t)
b := getMetrics(t, &url.URL{})
if m, _ := regexp.Match(`(?m)^# HELP .*`, b); !m {
t.Errorf("Metrics endpoint did not contain any help messages: %s", b)
@ -57,8 +58,8 @@ func Test_PrometheusHandler(t *testing.T) {
t.Run("with envoy", func(t *testing.T) {
fakeEnvoyMetricsServer := httptest.NewServer(newEnvoyMetricsHandler())
envoyURL = fakeEnvoyMetricsServer.URL
b := getMetrics(t)
envoyURL, _ := url.Parse(fakeEnvoyMetricsServer.URL)
b := getMetrics(t, envoyURL)
if m, _ := regexp.Match(`(?m)^go_.*`, b); !m {
t.Errorf("Metrics endpoint did not contain internal metrics: %s", b)

View file

@ -10,47 +10,18 @@ import (
zipkinHTTP "github.com/openzipkin/zipkin-go/reporter/http"
"go.opencensus.io/trace"
"github.com/pomerium/pomerium/config"
"github.com/pomerium/pomerium/internal/log"
)
const (
// JaegerTracingProviderName is the name of the tracing provider Jaeger.
JaegerTracingProviderName = "jaeger"
// ZipkinTracingProviderName is the name of the tracing provider Zipkin.
ZipkinTracingProviderName = "zipkin"
)
// TracingOptions contains the configurations settings for a http server.
type TracingOptions struct {
// Shared
Provider string
Service string
Debug bool
// Jaeger
// CollectorEndpoint is the full url to the Jaeger HTTP Thrift collector.
// For example, http://localhost:14268/api/traces
JaegerCollectorEndpoint string `mapstructure:"tracing_jaeger_collector_endpoint"`
// AgentEndpoint instructs exporter to send spans to jaeger-agent at this address.
// For example, localhost:6831.
JaegerAgentEndpoint string `mapstructure:"tracing_jaeger_agent_endpoint"`
// Zipkin
// ZipkinEndpoint configures the zipkin collector URI
// Example: http://zipkin:9411/api/v2/spans
ZipkinEndpoint string `mapstructure:"tracing_zipkin_endpoint"`
}
// RegisterTracing creates a new trace exporter from TracingOptions.
func RegisterTracing(opts *TracingOptions) (trace.Exporter, error) {
func RegisterTracing(opts *config.TracingOptions) (trace.Exporter, error) {
var exporter trace.Exporter
var err error
switch opts.Provider {
case JaegerTracingProviderName:
case config.JaegerTracingProviderName:
exporter, err = registerJaeger(opts)
case ZipkinTracingProviderName:
case config.ZipkinTracingProviderName:
exporter, err = registerZipkin(opts)
default:
return nil, fmt.Errorf("telemetry/trace: provider %s unknown", opts.Provider)
@ -58,10 +29,8 @@ func RegisterTracing(opts *TracingOptions) (trace.Exporter, error) {
if err != nil {
return nil, err
}
if opts.Debug {
log.Debug().Msg("telemetry/trace: debug on, sample everything")
trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()})
}
trace.ApplyConfig(trace.Config{DefaultSampler: trace.ProbabilitySampler(opts.SampleRate)})
log.Debug().Interface("Opts", opts).Msg("telemetry/trace: exporter created")
return exporter, nil
}
@ -71,13 +40,15 @@ func UnregisterTracing(exporter trace.Exporter) {
trace.UnregisterExporter(exporter)
}
func registerJaeger(opts *TracingOptions) (trace.Exporter, error) {
jex, err := jaeger.NewExporter(
jaeger.Options{
AgentEndpoint: opts.JaegerAgentEndpoint,
CollectorEndpoint: opts.JaegerCollectorEndpoint,
ServiceName: opts.Service,
})
func registerJaeger(opts *config.TracingOptions) (trace.Exporter, error) {
jOpts := jaeger.Options{
ServiceName: opts.Service,
AgentEndpoint: opts.JaegerAgentEndpoint,
}
if opts.JaegerCollectorEndpoint != nil {
jOpts.CollectorEndpoint = opts.JaegerCollectorEndpoint.String()
}
jex, err := jaeger.NewExporter(jOpts)
if err != nil {
return nil, err
}
@ -85,13 +56,13 @@ func registerJaeger(opts *TracingOptions) (trace.Exporter, error) {
return jex, nil
}
func registerZipkin(opts *TracingOptions) (trace.Exporter, error) {
func registerZipkin(opts *config.TracingOptions) (trace.Exporter, error) {
localEndpoint, err := zipkin.NewEndpoint(opts.Service, "")
if err != nil {
return nil, fmt.Errorf("telemetry/trace: could not create local endpoint: %w", err)
}
reporter := zipkinHTTP.NewReporter(opts.ZipkinEndpoint)
reporter := zipkinHTTP.NewReporter(opts.ZipkinEndpoint.String())
exporter := ocZipkin.NewExporter(reporter, localEndpoint)
trace.RegisterExporter(exporter)

View file

@ -1,17 +1,23 @@
package trace
import "testing"
import (
"net/url"
"testing"
"github.com/pomerium/pomerium/config"
)
func TestRegisterTracing(t *testing.T) {
tests := []struct {
name string
opts *TracingOptions
opts *config.TracingOptions
wantErr bool
}{
{"jaeger", &TracingOptions{JaegerAgentEndpoint: "localhost:6831", Service: "all", Provider: "jaeger"}, false},
{"jaeger with debug", &TracingOptions{JaegerAgentEndpoint: "localhost:6831", Service: "all", Provider: "jaeger", Debug: true}, false},
{"jaeger no endpoint", &TracingOptions{JaegerAgentEndpoint: "", Service: "all", Provider: "jaeger"}, true},
{"unknown provider", &TracingOptions{JaegerAgentEndpoint: "localhost:0", Service: "all", Provider: "Lucius Cornelius Sulla"}, true},
{"jaeger", &config.TracingOptions{JaegerAgentEndpoint: "localhost:6831", Service: "all", Provider: "jaeger"}, false},
{"jaeger with debug", &config.TracingOptions{JaegerAgentEndpoint: "localhost:6831", Service: "all", Provider: "jaeger", Debug: true}, false},
{"jaeger no endpoint", &config.TracingOptions{JaegerAgentEndpoint: "", Service: "all", Provider: "jaeger"}, true},
{"unknown provider", &config.TracingOptions{JaegerAgentEndpoint: "localhost:0", Service: "all", Provider: "Lucius Cornelius Sulla"}, true},
{"zipkin with debug", &config.TracingOptions{ZipkinEndpoint: &url.URL{Host: "localhost"}, Service: "all", Provider: "zipkin", Debug: true}, false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {