Skip to content

Commit 3968ad0

Browse files
authored
tracing: make otel dependency optional for rego+topdown (#4127)
This follows the same approach as the wasm feature: by default, importers of github.com/open-policy-agent/opa/rego github.com/open-policy-agent/opa/topdown will not get a transitive dependency on the otel libraries. In terms of functionality, nothing changes for the server and runtime. Signed-off-by: Stephan Renatus <[email protected]>
1 parent 883dc88 commit 3968ad0

File tree

17 files changed

+252
-104
lines changed

17 files changed

+252
-104
lines changed

cmd/features.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Use of this source code is governed by an Apache2
33
// license that can be found in the LICENSE file.
44

5+
//go:build opa_wasm
56
// +build opa_wasm
67

78
package cmd

cmd/run.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ func initRuntime(ctx context.Context, params runCmdParams, args []string) (*runt
282282
return nil, err
283283
}
284284

285-
rt.SetDistributedTracingErrorHandler()
285+
rt.SetDistributedTracingLogging()
286286

287287
return rt, nil
288288
}

features/tracing/tracing.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright 2021 The OPA Authors. All rights reserved.
2+
// Use of this source code is governed by an Apache2
3+
// license that can be found in the LICENSE file.
4+
5+
package tracing
6+
7+
import (
8+
"net/http"
9+
10+
pkg_tracing "github.com/open-policy-agent/opa/tracing"
11+
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
12+
)
13+
14+
func init() {
15+
pkg_tracing.RegisterHTTPTracing(&factory{})
16+
}
17+
18+
type factory struct{}
19+
20+
func (*factory) NewTransport(tr http.RoundTripper, opts pkg_tracing.Options) http.RoundTripper {
21+
return otelhttp.NewTransport(tr, convertOpts(opts)...)
22+
}
23+
24+
func (*factory) NewHandler(f http.Handler, label string, opts pkg_tracing.Options) http.Handler {
25+
return otelhttp.NewHandler(f, label, convertOpts(opts)...)
26+
}
27+
28+
func convertOpts(opts pkg_tracing.Options) []otelhttp.Option {
29+
otelOpts := make([]otelhttp.Option, 0, len(opts))
30+
for _, opt := range opts {
31+
otelOpts = append(otelOpts, opt.(otelhttp.Option))
32+
}
33+
return otelOpts
34+
}

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ require (
1313
github.com/fsnotify/fsnotify v1.5.1
1414
github.com/ghodss/yaml v1.0.0
1515
github.com/go-ini/ini v1.66.2
16+
github.com/go-logr/logr v1.2.1
1617
github.com/gobwas/glob v0.2.3
1718
github.com/golang/glog v1.0.0 // indirect
1819
github.com/golang/snappy v0.0.4 // indirect

internal/distributedtracing/distributedtracing.go

Lines changed: 58 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
// Copyright 2021 The OPA Authors. All rights reserved.
2+
// Use of this source code is governed by an Apache2
3+
// license that can be found in the LICENSE file.
4+
15
package distributedtracing
26

37
import (
@@ -7,9 +11,7 @@ import (
711
"fmt"
812
"io/ioutil"
913

10-
"github.com/open-policy-agent/opa/config"
11-
"github.com/open-policy-agent/opa/logging"
12-
"github.com/open-policy-agent/opa/util"
14+
"github.com/go-logr/logr"
1315
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
1416
"go.opentelemetry.io/otel"
1517
"go.opentelemetry.io/otel/exporters/otlp/otlptrace"
@@ -19,6 +21,16 @@ import (
1921
"go.opentelemetry.io/otel/sdk/trace"
2022
semconv "go.opentelemetry.io/otel/semconv/v1.7.0"
2123
"google.golang.org/grpc/credentials"
24+
25+
"github.com/open-policy-agent/opa/config"
26+
"github.com/open-policy-agent/opa/logging"
27+
"github.com/open-policy-agent/opa/tracing"
28+
"github.com/open-policy-agent/opa/util"
29+
30+
// The import registers opentelemetry with the top-level `tracing` package,
31+
// so the latter can be used from rego/topdown without an explicit build-time
32+
// dependency.
33+
_ "github.com/open-policy-agent/opa/features/tracing"
2234
)
2335

2436
const (
@@ -55,9 +67,7 @@ type distributedTracingConfig struct {
5567
TLSCACertFile string `json:"tls_ca_cert_file,omitempty"`
5668
}
5769

58-
type Options []otelhttp.Option
59-
60-
func Init(ctx context.Context, raw []byte, id string) (traceExporter *otlptrace.Exporter, options Options, err error) {
70+
func Init(ctx context.Context, raw []byte, id string) (*otlptrace.Exporter, tracing.Options, error) {
6171
parsedConfig, err := config.ParseConfig(raw, id)
6272
if err != nil {
6373
return nil, nil, err
@@ -87,8 +97,10 @@ func Init(ctx context.Context, raw []byte, id string) (traceExporter *otlptrace.
8797
return nil, nil, err
8898
}
8999

90-
traceExporter = otlptracegrpc.NewUnstarted(otlptracegrpc.WithEndpoint(distributedTracingConfig.Address),
91-
tlsOption)
100+
traceExporter := otlptracegrpc.NewUnstarted(
101+
otlptracegrpc.WithEndpoint(distributedTracingConfig.Address),
102+
tlsOption,
103+
)
92104

93105
res, err := resource.New(ctx,
94106
resource.WithAttributes(
@@ -105,18 +117,17 @@ func Init(ctx context.Context, raw []byte, id string) (traceExporter *otlptrace.
105117
trace.WithSpanProcessor(trace.NewBatchSpanProcessor(traceExporter)),
106118
)
107119

108-
options = append(options,
120+
options := tracing.NewOptions(
109121
otelhttp.WithTracerProvider(traceProvider),
110122
otelhttp.WithPropagators(propagation.TraceContext{}),
111123
)
112124

113125
return traceExporter, options, nil
114126
}
115127

116-
func SetErrorHandler(logger logging.Logger) {
117-
otel.SetErrorHandler(&errorHandler{
118-
logger: logger,
119-
})
128+
func SetupLogging(logger logging.Logger) {
129+
otel.SetErrorHandler(&errorHandler{logger: logger})
130+
otel.SetLogger(logr.New(&sink{logger: logger}))
120131
}
121132

122133
func parseDistributedTracingConfig(raw []byte) (*distributedTracingConfig, error) {
@@ -241,3 +252,37 @@ type errorHandler struct {
241252
func (e *errorHandler) Handle(err error) {
242253
e.logger.Warn("Distributed tracing: " + err.Error())
243254
}
255+
256+
// NOTE(sr): This adapter code is used to ensure that whatever otel logs, now or
257+
// in the future, will end up in "our" logs, and not go through whatever defaults
258+
// it has set up with its global logger. As such, it's to a full-featured
259+
// implementation fo the logr.LogSink interface, but a rather minimal one. Notably,
260+
// fields are no supported, the initial runtime time info is ignored, and there is
261+
// no support for different verbosity level is "info" logs: they're all printed
262+
// as-is.
263+
264+
type sink struct {
265+
logger logging.Logger
266+
}
267+
268+
func (s *sink) Enabled(level int) bool {
269+
return int(s.logger.GetLevel()) >= level
270+
}
271+
272+
func (*sink) Init(logr.RuntimeInfo) {} // ignored
273+
274+
func (s *sink) Info(_ int, msg string, _ ...interface{}) {
275+
s.logger.Info(msg)
276+
}
277+
278+
func (s *sink) Error(err error, msg string, _ ...interface{}) {
279+
s.logger.WithFields(map[string]interface{}{"err": err}).Error(msg)
280+
}
281+
282+
func (s *sink) WithName(name string) logr.LogSink {
283+
return &sink{s.logger.WithFields(map[string]interface{}{"name": name})}
284+
}
285+
286+
func (s *sink) WithValues(...interface{}) logr.LogSink { // ignored
287+
return s
288+
}

rego/rego.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import (
1818
"github.com/open-policy-agent/opa/bundle"
1919
bundleUtils "github.com/open-policy-agent/opa/internal/bundle"
2020
"github.com/open-policy-agent/opa/internal/compiler/wasm"
21-
"github.com/open-policy-agent/opa/internal/distributedtracing"
2221
"github.com/open-policy-agent/opa/internal/future"
2322
"github.com/open-policy-agent/opa/internal/ir"
2423
"github.com/open-policy-agent/opa/internal/planner"
@@ -32,6 +31,7 @@ import (
3231
"github.com/open-policy-agent/opa/topdown"
3332
"github.com/open-policy-agent/opa/topdown/cache"
3433
"github.com/open-policy-agent/opa/topdown/print"
34+
"github.com/open-policy-agent/opa/tracing"
3535
"github.com/open-policy-agent/opa/types"
3636
"github.com/open-policy-agent/opa/util"
3737
)
@@ -514,7 +514,7 @@ type Rego struct {
514514
generateJSON func(*ast.Term, *EvalContext) (interface{}, error)
515515
printHook print.Hook
516516
enablePrintStatements bool
517-
distributedTacingOpts distributedtracing.Options
517+
distributedTacingOpts tracing.Options
518518
}
519519

520520
// Function represents a built-in function that is callable in Rego.
@@ -1065,7 +1065,7 @@ func PrintHook(h print.Hook) func(r *Rego) {
10651065
}
10661066

10671067
// DistributedTracingOpts sets the options to be used by distributed tracing.
1068-
func DistributedTracingOpts(tr distributedtracing.Options) func(r *Rego) {
1068+
func DistributedTracingOpts(tr tracing.Options) func(r *Rego) {
10691069
return func(r *Rego) {
10701070
r.distributedTacingOpts = tr
10711071
}

runtime/runtime.go

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,13 @@ import (
2222

2323
"github.com/fsnotify/fsnotify"
2424
"github.com/gorilla/mux"
25-
"github.com/pkg/errors"
2625
"go.opentelemetry.io/otel/exporters/otlp/otlptrace"
2726
"go.uber.org/automaxprocs/maxprocs"
2827

2928
"github.com/open-policy-agent/opa/ast"
3029
"github.com/open-policy-agent/opa/bundle"
3130
"github.com/open-policy-agent/opa/internal/config"
32-
"github.com/open-policy-agent/opa/internal/distributedtracing"
31+
internal_tracing "github.com/open-policy-agent/opa/internal/distributedtracing"
3332
internal_logging "github.com/open-policy-agent/opa/internal/logging"
3433
"github.com/open-policy-agent/opa/internal/prometheus"
3534
"github.com/open-policy-agent/opa/internal/report"
@@ -46,6 +45,7 @@ import (
4645
"github.com/open-policy-agent/opa/server"
4746
"github.com/open-policy-agent/opa/storage"
4847
"github.com/open-policy-agent/opa/storage/inmem"
48+
"github.com/open-policy-agent/opa/tracing"
4949
"github.com/open-policy-agent/opa/util"
5050
"github.com/open-policy-agent/opa/version"
5151
)
@@ -202,7 +202,7 @@ type Params struct {
202202
// If it is nil, a new mux.Router will be created
203203
Router *mux.Router
204204

205-
DistrbutedTracingOpts distributedtracing.Options
205+
DistributedTracingOpts tracing.Options
206206
}
207207

208208
// LoggingConfig stores the configuration for OPA's logging behaviour.
@@ -277,21 +277,21 @@ func NewRuntime(ctx context.Context, params Params) (*Runtime, error) {
277277

278278
config, err := config.Load(params.ConfigFile, params.ConfigOverrides, params.ConfigOverrideFiles)
279279
if err != nil {
280-
return nil, errors.Wrap(err, "config error")
280+
return nil, fmt.Errorf("config error: %w", err)
281281
}
282282

283283
var reporter *report.Reporter
284284
if params.EnableVersionCheck {
285285
var err error
286286
reporter, err = report.New(params.ID, report.Options{Logger: logger})
287287
if err != nil {
288-
return nil, errors.Wrap(err, "config error")
288+
return nil, fmt.Errorf("config error: %w", err)
289289
}
290290
}
291291

292292
loaded, err := initload.LoadPaths(params.Paths, params.Filter, params.BundleMode, params.BundleVerificationConfig, params.SkipBundleVerification)
293293
if err != nil {
294-
return nil, errors.Wrap(err, "load error")
294+
return nil, fmt.Errorf("load error: %w", err)
295295
}
296296

297297
info, err := runtime.Term(runtime.Params{Config: config})
@@ -327,26 +327,26 @@ func NewRuntime(ctx context.Context, params Params) (*Runtime, error) {
327327
plugins.PrintHook(loggingPrintHook{logger: logger}),
328328
plugins.WithRouter(params.Router))
329329
if err != nil {
330-
return nil, errors.Wrap(err, "config error")
330+
return nil, fmt.Errorf("config error: %w", err)
331331
}
332332

333333
if err := manager.Init(ctx); err != nil {
334-
return nil, errors.Wrap(err, "initialization error")
334+
return nil, fmt.Errorf("initialization error: %w", err)
335335
}
336336

337337
metrics := prometheus.New(metrics.New(), errorLogger(logger))
338338

339-
traceExporter, distrbutedTracingOpts, err := distributedtracing.Init(ctx, config, params.ID)
339+
traceExporter, distributedTracingOpts, err := internal_tracing.Init(ctx, config, params.ID)
340340
if err != nil {
341341
return nil, fmt.Errorf("config error: %w", err)
342342
}
343-
if distrbutedTracingOpts != nil {
344-
params.DistrbutedTracingOpts = distrbutedTracingOpts
343+
if distributedTracingOpts != nil {
344+
params.DistributedTracingOpts = distributedTracingOpts
345345
}
346346

347347
disco, err := discovery.New(manager, discovery.Factories(registeredPlugins), discovery.Metrics(metrics))
348348
if err != nil {
349-
return nil, errors.Wrap(err, "config error")
349+
return nil, fmt.Errorf("config error: %w", err)
350350
}
351351

352352
manager.Register("discovery", disco)
@@ -418,14 +418,14 @@ func (rt *Runtime) Serve(ctx context.Context) error {
418418

419419
if rt.traceExporter != nil {
420420
if err := rt.traceExporter.Start(ctx); err != nil {
421-
rt.logger.WithFields(map[string]interface{}{"err": err}).Error("Failed to start trace exporter.")
421+
rt.logger.WithFields(map[string]interface{}{"err": err}).Error("Failed to start OpenTelemetry trace exporter.")
422422
return err
423423
}
424424

425425
defer func() {
426426
err := rt.traceExporter.Shutdown(ctx)
427427
if err != nil {
428-
rt.logger.Error("Failed to shutdown OpenTelemetry trace exporter gracefully.")
428+
rt.logger.WithFields(map[string]interface{}{"err": err}).Error("Failed to shutdown OpenTelemetry trace exporter gracefully.")
429429
}
430430
}()
431431
}
@@ -448,7 +448,7 @@ func (rt *Runtime) Serve(ctx context.Context) error {
448448
WithRuntime(rt.Manager.Info).
449449
WithMetrics(rt.metrics).
450450
WithMinTLSVersion(rt.Params.MinTLSVersion).
451-
WithDistributedTracingOpts(rt.Params.DistrbutedTracingOpts)
451+
WithDistributedTracingOpts(rt.Params.DistributedTracingOpts)
452452

453453
if rt.Params.DiagnosticAddrs != nil {
454454
rt.server = rt.server.WithDiagnosticAddresses(*rt.Params.DiagnosticAddrs)
@@ -586,9 +586,10 @@ func (rt *Runtime) StartREPL(ctx context.Context) {
586586
repl.Loop(ctx)
587587
}
588588

589-
// SetDistributedTracingErrorHandler configures the distributed tracing's ErrorHandler.
590-
func (rt *Runtime) SetDistributedTracingErrorHandler() {
591-
distributedtracing.SetErrorHandler(rt.logger)
589+
// SetDistributedTracingLogging configures the distributed tracing's ErrorHandler,
590+
// and logger instances.
591+
func (rt *Runtime) SetDistributedTracingLogging() {
592+
internal_tracing.SetupLogging(rt.logger)
592593
}
593594

594595
func (rt *Runtime) checkOPAUpdate(ctx context.Context) *report.DataResponse {

server/features.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Use of this source code is governed by an Apache2
33
// license that can be found in the LICENSE file.
44

5+
//go:build opa_wasm
56
// +build opa_wasm
67

78
package server

0 commit comments

Comments
 (0)