Skip to content

Commit 28bac6a

Browse files
feat: Introduce connect traces (#624)
## This PR Partially address issue #620 Introduce connect interceptor[1] to add distributed tracing support for flagd. With interceptor and sdk tracing, we can get out of the box distributed tracing. Consider following screens, ![image](https://user-images.githubusercontent.com/8186721/232918928-c4c75290-d1fd-4021-9435-d5e079084bc7.png) ![image](https://user-images.githubusercontent.com/8186721/232918838-0dbb488b-e7df-4c42-9bd1-960879291541.png) note - follow up pr is ready at https://github.com/open-feature/go-sdk-contrib [1] - https://connect.build/docs/go/observability/ --------- Signed-off-by: Kavindu Dodanduwa <kavindudodanduwa@gmail.com>
1 parent 2dd59f8 commit 28bac6a

File tree

11 files changed

+176
-143
lines changed

11 files changed

+176
-143
lines changed

core/go.mod

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ require (
77
buf.build/gen/go/open-feature/flagd/grpc/go v1.3.0-20230317150644-afd1cc2ef580.1
88
buf.build/gen/go/open-feature/flagd/protocolbuffers/go v1.29.1-20230317150644-afd1cc2ef580.1
99
github.com/bufbuild/connect-go v1.7.0
10+
github.com/bufbuild/connect-opentelemetry-go v0.1.0
1011
github.com/diegoholiveira/jsonlogic/v3 v3.2.7
1112
github.com/fsnotify/fsnotify v1.6.0
1213
github.com/golang/mock v1.6.0
@@ -41,6 +42,8 @@ require (
4142
)
4243

4344
require (
45+
github.com/Masterminds/goutils v1.1.1 // indirect
46+
github.com/Masterminds/semver v1.5.0 // indirect
4447
github.com/beorn7/perks v1.0.1 // indirect
4548
github.com/cenkalti/backoff/v4 v4.2.0 // indirect
4649
github.com/cespare/xxhash/v2 v2.2.0 // indirect
@@ -53,6 +56,7 @@ require (
5356
github.com/go-openapi/jsonpointer v0.19.6 // indirect
5457
github.com/go-openapi/jsonreference v0.20.2 // indirect
5558
github.com/go-openapi/swag v0.22.3 // indirect
59+
github.com/go-task/slim-sprig v2.20.0+incompatible // indirect
5660
github.com/gogo/protobuf v1.3.2 // indirect
5761
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
5862
github.com/golang/protobuf v1.5.3 // indirect
@@ -61,11 +65,11 @@ require (
6165
github.com/google/gofuzz v1.2.0 // indirect
6266
github.com/google/uuid v1.3.0 // indirect
6367
github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3 // indirect
68+
github.com/huandu/xstrings v1.4.0 // indirect
6469
github.com/imdario/mergo v0.3.13 // indirect
6570
github.com/josharian/intern v1.0.0 // indirect
6671
github.com/json-iterator/go v1.1.12 // indirect
6772
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
68-
github.com/kr/pretty v0.3.1 // indirect
6973
github.com/mailru/easyjson v0.7.7 // indirect
7074
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
7175
github.com/mitchellh/copystructure v1.2.0 // indirect
@@ -78,6 +82,7 @@ require (
7882
github.com/prometheus/client_model v0.3.0 // indirect
7983
github.com/prometheus/common v0.42.0 // indirect
8084
github.com/prometheus/procfs v0.9.0 // indirect
85+
github.com/rogpeppe/go-internal v1.9.0 // indirect
8186
github.com/spf13/pflag v1.0.5 // indirect
8287
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
8388
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
@@ -91,6 +96,7 @@ require (
9196
golang.org/x/term v0.7.0 // indirect
9297
golang.org/x/text v0.9.0 // indirect
9398
golang.org/x/time v0.3.0 // indirect
99+
golang.org/x/tools v0.7.0 // indirect
94100
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
95101
google.golang.org/appengine v1.6.7 // indirect
96102
google.golang.org/genproto v0.0.0-20230221151758-ace64dc21148 // indirect

core/go.sum

Lines changed: 17 additions & 37 deletions
Large diffs are not rendered by default.

core/pkg/runtime/from_config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ func FromConfig(logger *logger.Logger, version string, config Config) (*Runtime,
134134
CertPath: config.ServiceCertPath,
135135
SocketPath: config.ServiceSocketPath,
136136
CORS: config.CORS,
137+
Options: telemetry.BuildConnectOptions(telCfg),
137138
},
138139
SyncImpl: iSyncs,
139140
}, nil

core/pkg/service/flag-evaluation/connect_service.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ func (s *ConnectService) setupServer(svcConf service.Configuration) (net.Listene
116116
s.eventingConfiguration,
117117
s.metrics,
118118
)
119-
path, handler := schemaConnectV1.NewServiceHandler(fes)
119+
path, handler := schemaConnectV1.NewServiceHandler(fes, svcConf.Options...)
120120
mux.Handle(path, handler)
121121

122122
s.serverMtx.Lock()

core/pkg/service/iservice.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package service
22

33
import (
44
"context"
5+
6+
"github.com/bufbuild/connect-go"
57
)
68

79
type NotificationType string
@@ -28,6 +30,7 @@ type Configuration struct {
2830
KeyPath string
2931
SocketPath string
3032
CORS []string
33+
Options []connect.HandlerOption
3134
}
3235

3336
/*

core/pkg/telemetry/builder.go

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ import (
55
"fmt"
66
"time"
77

8+
"github.com/bufbuild/connect-go"
9+
otelconnect "github.com/bufbuild/connect-opentelemetry-go"
10+
11+
"go.opentelemetry.io/otel/propagation"
12+
813
"github.com/open-feature/flagd/core/pkg/logger"
914
"go.opentelemetry.io/otel"
1015
"go.opentelemetry.io/otel/sdk/trace"
@@ -50,14 +55,14 @@ func BuildMetricsRecorder(
5055
return NewOTelRecorder(mReader, rsc, svcName), nil
5156
}
5257

53-
// BuildTraceProvider build and register the trace provider for the caller runtime. This method attempt to register
54-
// a global TracerProvider backed by batch SpanProcessor.Config. CollectorTarget can be used to provide the grpc
55-
// collector target. Providing empty target results in skipping provider registration. This results in tracers having
56-
// NoopTracerProvider performing no action
58+
// BuildTraceProvider build and register the trace provider and propagator for the caller runtime. This method
59+
// attempt to register a global TracerProvider backed by batch SpanProcessor.Config. CollectorTarget can be used to
60+
// provide the grpc collector target. Providing empty target results in skipping provider & propagator registration.
61+
// This results in tracers having NoopTracerProvider and propagator having No-Op TextMapPropagator performing no action
5762
func BuildTraceProvider(ctx context.Context, logger *logger.Logger, svc string, svcVersion string, cfg Config) error {
5863
if cfg.CollectorTarget == "" {
5964
logger.Warn("skipping trace provider setup as collector target is not set." +
60-
" Traces will use NoopTracerProvider provider")
65+
" Traces will use NoopTracerProvider provider and propagator will use no-Op TextMapPropagator")
6166
return nil
6267
}
6368

@@ -77,10 +82,24 @@ func BuildTraceProvider(ctx context.Context, logger *logger.Logger, svc string,
7782
trace.WithResource(res))
7883

7984
otel.SetTracerProvider(provider)
80-
85+
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))
8186
return nil
8287
}
8388

89+
// BuildConnectOptions is a helper to build connect options based on telemetry configurations
90+
func BuildConnectOptions(cfg Config) []connect.HandlerOption {
91+
options := []connect.HandlerOption{}
92+
93+
// add interceptor if configuration is available for collector
94+
if cfg.CollectorTarget != "" {
95+
options = append(options, connect.WithInterceptors(
96+
otelconnect.NewInterceptor(otelconnect.WithTrustRemote()),
97+
))
98+
}
99+
100+
return options
101+
}
102+
84103
// buildMetricReader builds a metric reader based on provided configurations
85104
func buildMetricReader(ctx context.Context, cfg Config) (metric.Reader, error) {
86105
if cfg.MetricsExporter == "" {

core/pkg/telemetry/builder_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,33 @@ func TestBuildSpanProcessor(t *testing.T) {
107107
}
108108
}
109109

110+
func TestBuildConnectOptions(t *testing.T) {
111+
tests := []struct {
112+
name string
113+
cfg Config
114+
optionCount int
115+
}{
116+
{
117+
name: "No options for empty/default configurations",
118+
cfg: Config{},
119+
optionCount: 0,
120+
},
121+
{
122+
name: "Connect option is set when telemetry target is set",
123+
cfg: Config{
124+
CollectorTarget: "localhost:8080",
125+
},
126+
optionCount: 1,
127+
},
128+
}
129+
130+
for _, test := range tests {
131+
options := BuildConnectOptions(test.cfg)
132+
133+
require.Len(t, options, test.optionCount, "option count mismatch for test %s", test.name)
134+
}
135+
}
136+
110137
func TestBuildResourceFor(t *testing.T) {
111138
svc := "testSvc"
112139
svcVersion := "0.0.1"

flagd-proxy/go.mod

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@ require (
1515
buf.build/gen/go/open-feature/flagd/bufbuild/connect-go v1.5.2-20230222100723-491ee098dd92.1 // indirect
1616
buf.build/gen/go/open-feature/flagd/grpc/go v1.3.0-20230317150644-afd1cc2ef580.1 // indirect
1717
buf.build/gen/go/open-feature/flagd/protocolbuffers/go v1.29.1-20230317150644-afd1cc2ef580.1 // indirect
18+
github.com/Masterminds/goutils v1.1.1 // indirect
19+
github.com/Masterminds/semver v1.5.0 // indirect
1820
github.com/beorn7/perks v1.0.1 // indirect
19-
github.com/bufbuild/connect-go v1.5.2 // indirect
21+
github.com/bufbuild/connect-go v1.7.0 // indirect
2022
github.com/cenkalti/backoff/v4 v4.2.0 // indirect
2123
github.com/cespare/xxhash/v2 v2.2.0 // indirect
2224
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be // indirect
@@ -30,6 +32,7 @@ require (
3032
github.com/go-openapi/jsonpointer v0.19.6 // indirect
3133
github.com/go-openapi/jsonreference v0.20.2 // indirect
3234
github.com/go-openapi/swag v0.22.3 // indirect
35+
github.com/go-task/slim-sprig v2.20.0+incompatible // indirect
3336
github.com/gogo/protobuf v1.3.2 // indirect
3437
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
3538
github.com/golang/protobuf v1.5.3 // indirect
@@ -39,6 +42,7 @@ require (
3942
github.com/google/uuid v1.3.0 // indirect
4043
github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3 // indirect
4144
github.com/hashicorp/hcl v1.0.0 // indirect
45+
github.com/huandu/xstrings v1.4.0 // indirect
4246
github.com/imdario/mergo v0.3.13 // indirect
4347
github.com/inconshreveable/mousetrap v1.1.0 // indirect
4448
github.com/josharian/intern v1.0.0 // indirect
@@ -54,17 +58,18 @@ require (
5458
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
5559
github.com/modern-go/reflect2 v1.0.2 // indirect
5660
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
57-
github.com/open-feature/open-feature-operator v0.2.32 // indirect
61+
github.com/open-feature/open-feature-operator v0.2.34 // indirect
5862
github.com/open-feature/schemas v0.2.8 // indirect
5963
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
6064
github.com/pkg/errors v0.9.1 // indirect
61-
github.com/prometheus/client_golang v1.14.0 // indirect
65+
github.com/prometheus/client_golang v1.15.0 // indirect
6266
github.com/prometheus/client_model v0.3.0 // indirect
63-
github.com/prometheus/common v0.40.0 // indirect
67+
github.com/prometheus/common v0.42.0 // indirect
6468
github.com/prometheus/procfs v0.9.0 // indirect
6569
github.com/robfig/cron v1.2.0 // indirect
66-
github.com/rs/cors v1.8.3 // indirect
67-
github.com/rs/xid v1.4.0 // indirect
70+
github.com/rogpeppe/go-internal v1.9.0 // indirect
71+
github.com/rs/cors v1.9.0 // indirect
72+
github.com/rs/xid v1.5.0 // indirect
6873
github.com/spf13/afero v1.9.3 // indirect
6974
github.com/spf13/cast v1.5.0 // indirect
7075
github.com/spf13/jwalterweatherman v1.1.0 // indirect
@@ -87,16 +92,16 @@ require (
8792
go.opentelemetry.io/otel/trace v1.14.0 // indirect
8893
go.opentelemetry.io/proto/otlp v0.19.0 // indirect
8994
go.uber.org/atomic v1.10.0 // indirect
90-
go.uber.org/goleak v1.2.1 // indirect
9195
go.uber.org/multierr v1.9.0 // indirect
92-
golang.org/x/crypto v0.7.0 // indirect
93-
golang.org/x/net v0.8.0 // indirect
96+
golang.org/x/crypto v0.8.0 // indirect
97+
golang.org/x/net v0.9.0 // indirect
9498
golang.org/x/oauth2 v0.5.0 // indirect
9599
golang.org/x/sync v0.1.0 // indirect
96100
golang.org/x/sys v0.7.0 // indirect
97101
golang.org/x/term v0.7.0 // indirect
98102
golang.org/x/text v0.9.0 // indirect
99103
golang.org/x/time v0.3.0 // indirect
104+
golang.org/x/tools v0.7.0 // indirect
100105
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
101106
google.golang.org/appengine v1.6.7 // indirect
102107
google.golang.org/genproto v0.0.0-20230221151758-ace64dc21148 // indirect

0 commit comments

Comments
 (0)