storage/postgres: pgx client tracing (#5438)

* fix testcontainers docker client using the global tracer provider

* storage/postgres: pgx client tracing

* skip postgres test on macos
This commit is contained in:
Joe Kralicky 2025-01-28 17:10:09 -05:00 committed by GitHub
parent 332d3dc334
commit b5f58997bd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 100 additions and 12 deletions

7
go.mod
View file

@ -19,6 +19,7 @@ require (
github.com/docker/docker v27.4.1+incompatible
github.com/envoyproxy/go-control-plane/envoy v1.32.3
github.com/envoyproxy/protoc-gen-validate v1.1.0
github.com/exaring/otelpgx v0.8.0
github.com/go-chi/chi/v5 v5.2.0
github.com/go-jose/go-jose/v3 v3.0.3
github.com/google/btree v1.1.3
@ -70,16 +71,16 @@ require (
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.57.0
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0
go.opentelemetry.io/contrib/propagators/autoprop v0.57.0
go.opentelemetry.io/otel v1.33.0
go.opentelemetry.io/otel v1.34.0
go.opentelemetry.io/otel/bridge/opencensus v1.32.0
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.32.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.32.0
go.opentelemetry.io/otel/metric v1.33.0
go.opentelemetry.io/otel/metric v1.34.0
go.opentelemetry.io/otel/sdk v1.33.0
go.opentelemetry.io/otel/sdk/metric v1.32.0
go.opentelemetry.io/otel/trace v1.33.0
go.opentelemetry.io/otel/trace v1.34.0
go.opentelemetry.io/proto/otlp v1.4.0
go.uber.org/automaxprocs v1.6.0
go.uber.org/mock v0.5.0

14
go.sum
View file

@ -208,6 +208,8 @@ github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJP
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/envoyproxy/protoc-gen-validate v1.1.0 h1:tntQDh69XqOCOZsDz0lVJQez/2L6Uu2PdjCQwWCJ3bM=
github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4=
github.com/exaring/otelpgx v0.8.0 h1:uqoDIW9qKkyz479z2cGrmJ8OJypydyEA+xwey4ukvNo=
github.com/exaring/otelpgx v0.8.0/go.mod h1:ANkRZDfgfmN6yJS1xKMkshbnsHO8at5sYwtVEYOX8hc=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
@ -708,8 +710,8 @@ go.opentelemetry.io/contrib/propagators/jaeger v1.32.0 h1:K/fOyTMD6GELKTIJBaJ9k3
go.opentelemetry.io/contrib/propagators/jaeger v1.32.0/go.mod h1:ISE6hda//MTWvtngG7p4et3OCngsrTVfl7c6DjN17f8=
go.opentelemetry.io/contrib/propagators/ot v1.32.0 h1:Poy02A4wOZubHyd2hpHPDgZW+rn6EIq0vCwTZJ6Lmu8=
go.opentelemetry.io/contrib/propagators/ot v1.32.0/go.mod h1:cbhaURV+VR3NIMarzDYZU1RDEkXG1fNd1WMP1XCcGkY=
go.opentelemetry.io/otel v1.33.0 h1:/FerN9bax5LoK51X/sI0SVYrjSE0/yUL7DpxW4K3FWw=
go.opentelemetry.io/otel v1.33.0/go.mod h1:SUUkR6csvUQl+yjReHu5uM3EtVV7MBm5FHKRlNx4I8I=
go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY=
go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI=
go.opentelemetry.io/otel/bridge/opencensus v1.32.0 h1:OVbbFgPG60UolI8ZUs+Z75NnKiO0C9QltXBrqUDImS0=
go.opentelemetry.io/otel/bridge/opencensus v1.32.0/go.mod h1:J5SEiJNu6zzqpcA6+AVpxUKzxNocUMsefgHRpS8zdW8=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.32.0 h1:j7ZSD+5yn+lo3sGV69nW04rRR0jhYnBwjuX3r0HvnK0=
@ -722,14 +724,14 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.32.0 h1:cMyu9
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.32.0/go.mod h1:6Am3rn7P9TVVeXYG+wtcGE7IE1tsQ+bP3AuWcKt/gOI=
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.29.0 h1:WDdP9acbMYjbKIyJUhTvtzj601sVJOqgWdUxSdR/Ysc=
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.29.0/go.mod h1:BLbf7zbNIONBLPwvFnwNHGj4zge8uTCM/UPIVW1Mq2I=
go.opentelemetry.io/otel/metric v1.33.0 h1:r+JOocAyeRVXD8lZpjdQjzMadVZp2M4WmQ+5WtEnklQ=
go.opentelemetry.io/otel/metric v1.33.0/go.mod h1:L9+Fyctbp6HFTddIxClbQkjtubW6O9QS3Ann/M82u6M=
go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ=
go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE=
go.opentelemetry.io/otel/sdk v1.33.0 h1:iax7M131HuAm9QkZotNHEfstof92xM+N8sr3uHXc2IM=
go.opentelemetry.io/otel/sdk v1.33.0/go.mod h1:A1Q5oi7/9XaMlIWzPSxLRWOI8nG3FnzHJNbiENQuihM=
go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiyYCU9snn1CU=
go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ=
go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s=
go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck=
go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k=
go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE=
go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg=
go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY=
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=

View file

@ -470,7 +470,7 @@ func (srv *Server) newBackendLocked(ctx context.Context) (storage.Backend, error
// NB: the context passed to postgres.New here is a separate context scoped
// to the lifetime of the server itself. 'ctx' may be a short-lived request
// context, since the backend is lazy-initialized.
return postgres.New(srv.backendCtx, srv.cfg.storageConnectionString), nil
return postgres.New(srv.backendCtx, srv.cfg.storageConnectionString, postgres.WithTracerProvider(srv.tracerProvider)), nil
default:
return nil, fmt.Errorf("unsupported storage type: %s", srv.cfg.storageType)
}

View file

@ -9,6 +9,7 @@ import (
"time"
"github.com/cenkalti/backoff/v4"
"github.com/exaring/otelpgx"
"github.com/jackc/pgx/v5/pgxpool"
"google.golang.org/protobuf/types/known/fieldmaskpb"
"google.golang.org/protobuf/types/known/timestamppb"
@ -353,6 +354,11 @@ func (backend *Backend) init(ctx context.Context) (serverVersion uint64, pool *p
return serverVersion, nil, err
}
if backend.cfg.tracerProvider != nil {
config.ConnConfig.Tracer = otelpgx.NewTracer(
otelpgx.WithTracerProvider(backend.cfg.tracerProvider))
}
pool, err = pgxpool.NewWithConfig(context.Background(), config)
if err != nil {
return serverVersion, nil, err

View file

@ -2,6 +2,8 @@ package postgres
import (
"time"
oteltrace "go.opentelemetry.io/otel/trace"
)
const (
@ -10,8 +12,9 @@ const (
)
type config struct {
expiry time.Duration
registryTTL time.Duration
expiry time.Duration
registryTTL time.Duration
tracerProvider oteltrace.TracerProvider
}
// Option customizes a Backend.
@ -31,6 +34,12 @@ func WithRegistryTTL(ttl time.Duration) Option {
}
}
func WithTracerProvider(tracerProvider oteltrace.TracerProvider) Option {
return func(cfg *config) {
cfg.tracerProvider = tracerProvider
}
}
func getConfig(options ...Option) *config {
cfg := new(config)
WithExpiry(defaultExpiry)(cfg)

View file

@ -0,0 +1,70 @@
package postgres_test
import (
"context"
"io"
"net/http"
"os"
"runtime"
"testing"
"github.com/pomerium/pomerium/config"
"github.com/pomerium/pomerium/internal/testenv"
"github.com/pomerium/pomerium/internal/testenv/scenarios"
"github.com/pomerium/pomerium/internal/testenv/snippets"
"github.com/pomerium/pomerium/internal/testenv/upstreams"
"github.com/pomerium/pomerium/internal/testutil"
"github.com/pomerium/pomerium/internal/testutil/tracetest"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestQueryTracing(t *testing.T) {
if os.Getenv("GITHUB_ACTION") != "" && runtime.GOOS == "darwin" {
t.Skip("Github action can not run docker on MacOS")
}
testutil.WithTestPostgres(t, func(dsn string) {
receiver := scenarios.NewOTLPTraceReceiver()
env := testenv.New(t, testenv.WithTraceDebugFlags(testenv.StandardTraceDebugFlags), testenv.WithTraceClient(receiver.NewGRPCClient()))
env.Add(receiver)
env.Add(testenv.ModifierFunc(func(_ context.Context, cfg *config.Config) {
cfg.Options.DataBrokerStorageType = config.StoragePostgresName
cfg.Options.DataBrokerStorageConnectionString = dsn
}))
up := upstreams.HTTP(nil, upstreams.WithDisplayName("Upstream"))
up.Handle("/foo", func(w http.ResponseWriter, _ *http.Request) {
w.Write([]byte("OK"))
})
env.Add(scenarios.NewIDP([]*scenarios.User{{Email: "user@example.com"}}))
route := up.Route().
From(env.SubdomainURL("postgres-test")).
PPL(`{"allow":{"and":["email":{"is":"user@example.com"}]}}`)
env.AddUpstream(up)
env.Start()
snippets.WaitStartupComplete(env)
resp, err := up.Get(route, upstreams.AuthenticateAs("user@example.com"), upstreams.Path("/foo"))
assert.NoError(t, err)
io.ReadAll(resp.Body)
resp.Body.Close()
env.Stop()
results := tracetest.NewTraceResults(receiver.FlushResourceSpans())
traces, exists := results.GetTraces().ByParticipant["Data Broker"]
require.True(t, exists)
require.Len(t, traces, 1)
var found bool
for _, span := range traces[0].Spans {
if span.Scope.GetName() == "github.com/exaring/otelpgx" {
found = true
break
}
}
assert.True(t, found, "no spans with otelpgx scope found")
})
}