diff --git a/go.mod b/go.mod index 46251d846..189b52900 100644 --- a/go.mod +++ b/go.mod @@ -64,6 +64,7 @@ require ( github.com/yuin/gopher-lua v1.1.1 go.opencensus.io v0.24.0 go.opentelemetry.io/otel v1.27.0 + go.opentelemetry.io/otel/bridge/opencensus v1.27.0 go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.27.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 diff --git a/go.sum b/go.sum index a10592188..23ca4df22 100644 --- a/go.sum +++ b/go.sum @@ -668,6 +668,8 @@ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= go.opentelemetry.io/otel v1.27.0 h1:9BZoF3yMK/O1AafMiQTVu0YDj5Ea4hPhxCs7sGva+cg= go.opentelemetry.io/otel v1.27.0/go.mod h1:DMpAK8fzYRzs+bi3rS5REupisuqTheUlSZJ1WnZaPAQ= +go.opentelemetry.io/otel/bridge/opencensus v1.27.0 h1:ao9aGGHd+G4YfjBpGs6vbkvt5hoC67STlJA9fCnOAcs= +go.opentelemetry.io/otel/bridge/opencensus v1.27.0/go.mod h1:uRvWtAAXzyVOST0WMPX5JHGBaAvBws+2F8PcC5gMnTk= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.27.0 h1:bFgvUr3/O4PHj3VQcFEuYKvRZJX1SJDQ+11JXuSB3/w= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.27.0/go.mod h1:xJntEd2KL6Qdg5lwp97HMLQDVeAhrYxmzFseAMDPQ8I= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0 h1:R9DE4kQ4k+YtfLI2ULwX82VtNQ2J8yZmA7ZIF/D+7Mc= diff --git a/internal/zero/telemetry/opencensus/opencensus.go b/internal/zero/telemetry/opencensus/opencensus.go new file mode 100644 index 000000000..014a4c7b8 --- /dev/null +++ b/internal/zero/telemetry/opencensus/opencensus.go @@ -0,0 +1,56 @@ +// Package opencensus is a provider of opencensus based telemetry metrics to the zero telemetry system. +package opencensus + +import ( + "context" + "sync/atomic" + + "go.opentelemetry.io/otel/bridge/opencensus" + "go.opentelemetry.io/otel/sdk/metric" + "go.opentelemetry.io/otel/sdk/metric/metricdata" + + "github.com/pomerium/pomerium/internal/sets" +) + +type Producer struct { + producer metric.Producer + filter atomic.Pointer[sets.Hash[string]] +} + +var _ metric.Producer = (*Producer)(nil) + +func New() *Producer { + p := &Producer{ + producer: opencensus.NewMetricProducer(), + } + p.SetFilter(nil) + return p +} + +func (p *Producer) Produce(ctx context.Context) ([]metricdata.ScopeMetrics, error) { + filter := p.filter.Load() + metrics, err := p.producer.Produce(ctx) + if err != nil { + return nil, err + } + var out []metricdata.ScopeMetrics + for _, sm := range metrics { + var m []metricdata.Metrics + for _, metric := range sm.Metrics { + if filter.Has(metric.Name) { + m = append(m, metric) + } + } + if len(m) > 0 { + out = append(out, metricdata.ScopeMetrics{ + Scope: sm.Scope, + Metrics: m, + }) + } + } + return out, nil +} + +func (p *Producer) SetFilter(names []string) { + p.filter.Store(sets.NewHash(names...)) +} diff --git a/internal/zero/telemetry/telemetry.go b/internal/zero/telemetry/telemetry.go index 5bce1f711..5f4d5de75 100644 --- a/internal/zero/telemetry/telemetry.go +++ b/internal/zero/telemetry/telemetry.go @@ -13,6 +13,7 @@ import ( "github.com/pomerium/pomerium/internal/telemetry/prometheus" sdk "github.com/pomerium/pomerium/internal/zero/api" connect_mux "github.com/pomerium/pomerium/internal/zero/connect-mux" + "github.com/pomerium/pomerium/internal/zero/telemetry/opencensus" "github.com/pomerium/pomerium/internal/zero/telemetry/reporter" "github.com/pomerium/pomerium/internal/zero/telemetry/sessions" "github.com/pomerium/pomerium/pkg/grpc/databroker" @@ -26,6 +27,7 @@ type Telemetry struct { envoyMetrics *metricsProducer[*prometheus.Producer] sessionMetrics *metricsProducer[*sessions.Producer] + coreMetrics *metricsProducer[*opencensus.Producer] hasSessionMetricsLease func() bool } @@ -40,10 +42,12 @@ func New( sessionMetricProducer := newMetricsProducer("sessions", buildSessionMetricsProducer(clientProvider)) envoyMetricProducer := newMetricsProducer("envoy", buildEnvoyMetricsProducer(envoyScrapeURL, startTime)) + coreMetricsProducer := newMetricsProducer("core", opencensus.New()) r, err := reporter.New(ctx, api.GetTelemetryConn(), reporter.WithProducer(sessionMetricProducer), reporter.WithProducer(envoyMetricProducer), + reporter.WithProducer(coreMetricsProducer), ) if err != nil { return nil, fmt.Errorf("error creating telemetry metrics reporter: %w", err) @@ -54,6 +58,7 @@ func New( reporter: r, sessionMetrics: sessionMetricProducer, envoyMetrics: envoyMetricProducer, + coreMetrics: coreMetricsProducer, hasSessionMetricsLease: hasSessionMetricsLease, }, nil } @@ -108,6 +113,7 @@ func (srv *Telemetry) handleRequests(ctx context.Context) error { func (srv *Telemetry) handleRequest(ctx context.Context, req *connect.TelemetryRequest) { srv.configureEnvoyMetricsProducer(req.GetEnvoyMetrics()) srv.configureSessionMetricsProducer(req.GetSessionAnalytics()) + srv.configureCoreMetricsProducer(req.GetPomeriumMetrics()) err := srv.reporter.CollectAndExportMetrics(ctx) if err != nil { @@ -144,3 +150,12 @@ func (srv *Telemetry) configureEnvoyMetricsProducer(req *connect.EnvoyMetricsReq ) srv.envoyMetrics.SetEnabled(true) } + +func (srv *Telemetry) configureCoreMetricsProducer(req *connect.PomeriumMetricsRequest) { + if req == nil { + srv.coreMetrics.SetEnabled(false) + return + } + srv.coreMetrics.Producer().SetFilter(req.Metrics) + srv.coreMetrics.SetEnabled(true) +} diff --git a/pkg/zero/connect/connect.pb.go b/pkg/zero/connect/connect.pb.go index bd1b8ea7e..f4b02144a 100644 --- a/pkg/zero/connect/connect.pb.go +++ b/pkg/zero/connect/connect.pb.go @@ -364,7 +364,7 @@ type EnvoyMetricsRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // only include metrics that match the provided labels, and relabel them with the provided labels + // only include metrics that match the provided labels Metrics []string `protobuf:"bytes,1,rep,name=metrics,proto3" json:"metrics,omitempty"` // only include labels that match the provided labels Labels []string `protobuf:"bytes,2,rep,name=labels,proto3" json:"labels,omitempty"` @@ -421,6 +421,9 @@ type PomeriumMetricsRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + + // only include metrics that match the provided labels + Metrics []string `protobuf:"bytes,1,rep,name=metrics,proto3" json:"metrics,omitempty"` } func (x *PomeriumMetricsRequest) Reset() { @@ -455,6 +458,13 @@ func (*PomeriumMetricsRequest) Descriptor() ([]byte, []int) { return file_connect_proto_rawDescGZIP(), []int{7} } +func (x *PomeriumMetricsRequest) GetMetrics() []string { + if x != nil { + return x.Metrics + } + return nil +} + var File_connect_proto protoreflect.FileDescriptor var file_connect_proto_rawDesc = []byte{ @@ -511,17 +521,18 @@ var file_connect_proto_rawDesc = []byte{ 0x0a, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, - 0x22, 0x18, 0x0a, 0x16, 0x50, 0x6f, 0x6d, 0x65, 0x72, 0x69, 0x75, 0x6d, 0x4d, 0x65, 0x74, 0x72, - 0x69, 0x63, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x32, 0x51, 0x0a, 0x07, 0x43, 0x6f, - 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x12, 0x46, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, - 0x62, 0x65, 0x12, 0x1f, 0x2e, 0x70, 0x6f, 0x6d, 0x65, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x7a, 0x65, - 0x72, 0x6f, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x70, 0x6f, 0x6d, 0x65, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x7a, - 0x65, 0x72, 0x6f, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x30, 0x01, 0x42, 0x2f, 0x5a, - 0x2d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x6f, 0x6d, 0x65, - 0x72, 0x69, 0x75, 0x6d, 0x2f, 0x70, 0x6f, 0x6d, 0x65, 0x72, 0x69, 0x75, 0x6d, 0x2f, 0x70, 0x6b, - 0x67, 0x2f, 0x7a, 0x65, 0x72, 0x6f, 0x2f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x22, 0x32, 0x0a, 0x16, 0x50, 0x6f, 0x6d, 0x65, 0x72, 0x69, 0x75, 0x6d, 0x4d, 0x65, 0x74, 0x72, + 0x69, 0x63, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, + 0x74, 0x72, 0x69, 0x63, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x74, + 0x72, 0x69, 0x63, 0x73, 0x32, 0x51, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x12, + 0x46, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x12, 0x1f, 0x2e, 0x70, + 0x6f, 0x6d, 0x65, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x7a, 0x65, 0x72, 0x6f, 0x2e, 0x53, 0x75, 0x62, + 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, + 0x70, 0x6f, 0x6d, 0x65, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x7a, 0x65, 0x72, 0x6f, 0x2e, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x30, 0x01, 0x42, 0x2f, 0x5a, 0x2d, 0x67, 0x69, 0x74, 0x68, 0x75, + 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x6f, 0x6d, 0x65, 0x72, 0x69, 0x75, 0x6d, 0x2f, 0x70, + 0x6f, 0x6d, 0x65, 0x72, 0x69, 0x75, 0x6d, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x7a, 0x65, 0x72, 0x6f, + 0x2f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/pkg/zero/connect/connect.proto b/pkg/zero/connect/connect.proto index 8c5bf6a57..9c53d01fd 100644 --- a/pkg/zero/connect/connect.proto +++ b/pkg/zero/connect/connect.proto @@ -48,14 +48,17 @@ message SessionAnalyticsRequest {} // EnvoyMetricsRequest is used to request current envoy metrics message EnvoyMetricsRequest { - // only include metrics that match the provided labels, and relabel them with the provided labels + // only include metrics that match the provided labels repeated string metrics = 1; // only include labels that match the provided labels repeated string labels = 2; } // PomeriumMetricsRequest is used to request current pomerium metrics -message PomeriumMetricsRequest {} +message PomeriumMetricsRequest { + // only include metrics that match the provided labels + repeated string metrics = 1; +} // Connect service is used to maintain a persistent connection between the // Pomerium Core and Zero Cloud and receive messages from the cloud.