Skip to content

Commit

Permalink
implement skip paths for the exposed endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
dhontecillas committed Jan 13, 2024
1 parent dd1287d commit 2f3fb7b
Show file tree
Hide file tree
Showing 9 changed files with 79 additions and 64 deletions.
8 changes: 4 additions & 4 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ type Config struct {
Layers *LayersOpts `json:"layers"`
Exporters map[string]Exporter `json:"exporters"`
Instance *Instance `json:"instance"`
SkipPaths []string `json:"skip_paths"`
Extra map[string]interface{} `json:"extra"`
}

Expand Down Expand Up @@ -47,10 +48,9 @@ type LayersOpts struct {
// We can select if we want to disable the metrics,
// the traces, and / or the trace propagation.
type RouterOpts struct {
DisableMetrics bool `json:"disable_metrics"`
DisableTraces bool `json:"disable_traces"`
DisablePropagation bool `json:"disable_propagation"`
SkipPaths []string `json:"skip_paths"`
DisableMetrics bool `json:"disable_metrics"`
DisableTraces bool `json:"disable_traces"`
DisablePropagation bool `json:"disable_propagation"`
}

// PipeOpts has the options for the KrakenD pipe stage
Expand Down
14 changes: 14 additions & 0 deletions config/lura.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ func FromLura(srvCfg config.ServiceConfig) (*Config, error) {
return nil, err
}

// TODO: we might want to move these defaults to the config.go
// file, as is not specific to reading the config from the Lura
// config.
if cfg.Layers == nil {
cfg.Layers = &LayersOpts{}
}
Expand Down Expand Up @@ -76,6 +79,17 @@ func FromLura(srvCfg config.ServiceConfig) (*Config, error) {
}
}

if len(cfg.SkipPaths) == 0 {
// if there are no defined skip paths, we use the default ones:
// to avoid using defaultSkipPaths, provide a list with an empty string
cfg.SkipPaths = []string{
"/healthz",
"/_ah/health",
"/__debug",
"/__echo",
}
}

if cfg.ServiceName == "" {
if srvCfg.Name != "" {
cfg.ServiceName = srvCfg.Name
Expand Down
6 changes: 3 additions & 3 deletions example/make_requests.sh
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
#!/bin/bash

# for i in {1..10}
for i in {1..2}
for i in {1..1}
do
# curl localhost:54444/fake/fsf
# curl localhost:54444/combination/2
curl localhost:54444/fake/fsf
curl localhost:54444/combination/2
curl localhost:54444/combination/1
done

Expand Down
11 changes: 7 additions & 4 deletions example/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,20 +91,23 @@ func main() {

bf := func(backendConfig *config.Backend) proxy.Proxy {
reqExec := lura.HTTPRequestExecutorFromConfig(client.NewHTTPClient,
backendConfig, obsConfig.Layers.Backend)
backendConfig, obsConfig.Layers.Backend, obsConfig.SkipPaths)
return proxy.NewHTTPProxyWithHTTPExecutor(backendConfig, reqExec, backendConfig.Decoder)
}
bf = lura.BackendFactory(bf, state.GlobalState, obsConfig.Layers.Backend, obsConfig.SkipPaths)

defaultPF := proxy.NewDefaultFactory(lura.BackendFactory(bf, state.GlobalState, obsConfig.Layers.Backend), logger)
pf := lura.ProxyFactory(defaultPF, state.GlobalState, obsConfig.Layers.Pipe)
defaultPF := proxy.NewDefaultFactory(bf, logger)
pf := lura.ProxyFactory(defaultPF, state.GlobalState, obsConfig.Layers.Pipe, obsConfig.SkipPaths)

handlerF := otelgin.New(krakendgin.EndpointHandler, state.GlobalState,
obsConfig.Layers.Router, obsConfig.SkipPaths)
// setup the krakend router
routerFactory := krakendgin.NewFactory(krakendgin.Config{
Engine: gin.Default(),
ProxyFactory: pf,
Middlewares: []gin.HandlerFunc{},
Logger: logger,
HandlerFactory: otelgin.New(krakendgin.EndpointHandler, state.GlobalState, obsConfig.Layers.Router),
HandlerFactory: handlerF,
RunServer: server.RunServer,
})

Expand Down
22 changes: 9 additions & 13 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@ go 1.20

require (
github.com/gin-gonic/gin v1.9.1
github.com/luraproject/lura/v2 v2.4.0
github.com/luraproject/lura/v2 v2.4.3-0.20240111145738-b6784e5701d8
github.com/prometheus/client_golang v1.17.0
go.opentelemetry.io/otel v1.21.0
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.21.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0
go.opentelemetry.io/otel/exporters/prometheus v0.44.0
go.opentelemetry.io/otel/metric v1.21.0
go.opentelemetry.io/otel/sdk v1.21.0
go.opentelemetry.io/otel/sdk/metric v1.21.0
go.opentelemetry.io/otel/trace v1.21.0
google.golang.org/grpc v1.59.0
)

require (
Expand All @@ -31,36 +34,29 @@ require (
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/krakendio/flatmap v1.1.1 // indirect
github.com/leodido/go-urn v1.2.4 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
github.com/prometheus/client_golang v1.17.0 // indirect
github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.44.0 // indirect
github.com/prometheus/procfs v0.11.1 // indirect
github.com/rogpeppe/go-internal v1.10.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.11 // indirect
github.com/valyala/fastrand v1.1.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0 // indirect
go.opentelemetry.io/otel/exporters/prometheus v0.44.0 // indirect
go.opentelemetry.io/otel/sdk v1.21.0 // indirect
go.opentelemetry.io/proto/otlp v1.0.0 // indirect
golang.org/x/arch v0.3.0 // indirect
golang.org/x/crypto v0.14.0 // indirect
golang.org/x/crypto v0.17.0 // indirect
golang.org/x/net v0.17.0 // indirect
golang.org/x/sys v0.15.0 // indirect
golang.org/x/text v0.13.0 // indirect
golang.org/x/text v0.14.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect
google.golang.org/grpc v1.59.0 // indirect
google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
11 changes: 10 additions & 1 deletion lura/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,17 @@ var defaultOpts = otelconfig.BackendOpts{
// HTTPRequestExecutorFromConfig creates an HTTPRequestExecutor to be used
// for the backend requests.
func HTTPRequestExecutorFromConfig(clientFactory transport.HTTPClientFactory,
cfg *config.Backend, opts *otelconfig.BackendOpts,
cfg *config.Backend, opts *otelconfig.BackendOpts, skipPaths []string,
) transport.HTTPRequestExecutor {

for _, sp := range skipPaths {
if cfg.ParentEndpoint == sp {
// TODO: check if there might be some othe executor that is
// not the default one ?
return transport.DefaultHTTPRequestExecutor(clientFactory)
}
}

if !opts.Enabled() {
// no configuration for the backend, then .. no metrics nor tracing:
return transport.DefaultHTTPRequestExecutor(clientFactory)
Expand Down
20 changes: 17 additions & 3 deletions lura/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,9 @@ func Middleware(name string, stage string, gsf state.GetterFn, metricsEnabled bo

// ProxyFactory returns a pipe stage factory that wraps the provided proxy factory with the
// instrumentation [Middleware] based on the configuration options.
func ProxyFactory(pf proxy.Factory, gsfn state.GetterFn, opts *kotelconfig.PipeOpts) proxy.FactoryFunc {
func ProxyFactory(pf proxy.Factory, gsfn state.GetterFn, opts *kotelconfig.PipeOpts,
skipPaths []string) proxy.FactoryFunc {

if opts == nil {
return pf.New
}
Expand All @@ -141,8 +143,13 @@ func ProxyFactory(pf proxy.Factory, gsfn state.GetterFn, opts *kotelconfig.PipeO
if err != nil {
return next, err
}
for _, sp := range skipPaths {
if cfg.Endpoint == sp {
return next, nil
}
}

// TODO: check the followint warning:
// TODO: check the following warning:
// WARNING: this changes how it was working before:
// in original opencensus, we prefixed the endpoint with a `pipe` prefix
// return Middleware("pipe-" + cfg.Endpoint)(next), nil
Expand All @@ -153,7 +160,9 @@ func ProxyFactory(pf proxy.Factory, gsfn state.GetterFn, opts *kotelconfig.PipeO

// BackendFactory returns a backend factory that wraps the provided backend factory with the
// instrumentation [Middleware] based on the configuration options.
func BackendFactory(bf proxy.BackendFactory, gsfn state.GetterFn, opts *kotelconfig.BackendOpts) proxy.BackendFactory {
func BackendFactory(bf proxy.BackendFactory, gsfn state.GetterFn, opts *kotelconfig.BackendOpts,
skipPaths []string) proxy.BackendFactory {

if opts == nil || (opts.Metrics.DisableStage && opts.Traces.DisableStage) {
return bf
}
Expand All @@ -162,6 +171,11 @@ func BackendFactory(bf proxy.BackendFactory, gsfn state.GetterFn, opts *kotelcon

return func(cfg *config.Backend) proxy.Proxy {
next := bf(cfg)
for _, sp := range skipPaths {
if cfg.ParentEndpoint == sp {
return next
}
}
urlPattern := kotelconfig.NormalizeURLPattern(cfg.URLPattern)
return Middleware(urlPattern, "backend", gsfn, metricsEnabled, tracesEnabled)(next)
}
Expand Down
49 changes: 15 additions & 34 deletions router/gin/endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,57 +17,38 @@ import (
"github.com/krakend/krakend-otel/state"
)

var defaultSkipPaths = []string{
"/healthz",
"/_ah/health",
"/__debug",
"/__echo",
}

// defaultRouterOpts return the default options when no options
// are provided
func defaultRouterOpts() *kconfig.RouterOpts {
return &kconfig.RouterOpts{
DisableMetrics: false,
DisableTraces: false,
DisablePropagation: false,
}
}

// New wraps a handler factory adding some simple instrumentation to the generated handlers
func New(hf krakendgin.HandlerFactory, gsfn state.GetterFn, opts *kconfig.RouterOpts) krakendgin.HandlerFactory {
if opts == nil {
opts = defaultRouterOpts()
}
func New(hf krakendgin.HandlerFactory, gsfn state.GetterFn,
opts *kconfig.RouterOpts, skipPaths []string) krakendgin.HandlerFactory {

if gsfn == nil {
gsfn = state.GlobalState
}
return func(cfg *config.EndpointConfig, p proxy.Proxy) gin.HandlerFunc {
return HandlerFunc(cfg, opts, gsfn, hf(cfg, p))
return HandlerFunc(cfg, opts, gsfn, skipPaths, hf(cfg, p))
}
}

// HandlerFunc creates and instrumented gin.Handler wrapper with traces and / or metrics enabled
// according to the [config.RouterOpts].
func HandlerFunc(cfg *config.EndpointConfig, opts *kconfig.RouterOpts, gsfn state.GetterFn, next gin.HandlerFunc) gin.HandlerFunc {
s := gsfn()
func HandlerFunc(cfg *config.EndpointConfig, opts *kconfig.RouterOpts, gsfn state.GetterFn,
skipPaths []string, next gin.HandlerFunc) gin.HandlerFunc {

if opts == nil || (opts.DisableMetrics && opts.DisableTraces) {
if opts != nil && opts.DisablePropagation {
// skip paths will not try to read the propagation header, because nothing
// in the downstream pipeline will be instruemented. The header can be passed
// using the regular `headers` feature.
for _, sp := range skipPaths {
if cfg.Endpoint == sp {
return next
}
return PropagationMiddleware(next, s.Propagator())
}

if len(opts.SkipPaths) == 0 {
// if there are no defined skip paths, we use the default ones:
// to avoid using defaultSkipPaths, provide a list with an empty string
opts.SkipPaths = defaultSkipPaths
}
for _, sp := range opts.SkipPaths {
if cfg.Endpoint == sp {
s := gsfn()
if opts == nil || (opts.DisableMetrics && opts.DisableTraces) {
if opts != nil && opts.DisablePropagation {
return next
}
return PropagationMiddleware(next, s.Propagator())
}

// TODO: check that the endpoint path parameters are all standarized;
Expand Down
2 changes: 0 additions & 2 deletions router/gin/propagation.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package gin

import (
"fmt"

"github.com/gin-gonic/gin"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/trace"
Expand Down

0 comments on commit 2f3fb7b

Please sign in to comment.