Skip to content

Commit 652e8c9

Browse files
committed
normalize attributes in different spans and update todos
1 parent c98bf2c commit 652e8c9

File tree

12 files changed

+107
-51
lines changed

12 files changed

+107
-51
lines changed

doc/TODO.md

+29
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,44 @@
11
# TODO
22

3+
- **we are reporting the size and time in `io.instruments.go` as both a counter and a histogram**
4+
(count can be extracted from histogram in all "backends": prometheus, datadog, new relic, etc..?)
5+
36
- allow different formats for the propagation of the trace (the `TextMapPropagator`)
47
in [endpoint.go](../router/gin/endpoint.go).
8+
59
- review how we pass the state.
610

711
- we cannot use `skipPaths` with the same value that we have to define the endpoints
812
at the global layer, because we cannot know the matched pattern
913

1014
- clean shutdown
1115

16+
- add configuration options to allow to use grpc credentials
17+
18+
- allow to tweak the `bucket` limits for different histograms (like
19+
latency and size)
20+
- `http/client/transport_metrics.go`: `timeBucketsOpt`, `sizeBucketsOpt`
21+
- `http/server/metrics.go`: `timeBucketsOpt`, `sizeBucketsOpt`
22+
- `io/instrumens.go`: `timeBucketsOpt`, `sizeBucketsOpt`
23+
1224
# TO DECIDE
1325

1426
- do we want to have the `service_name` to override the global ServiceConfig name for
1527
the KrakenD gateway ?
28+
29+
- in `exporter/prometheus/prometheus.go` we could add a config option that will
30+
add a prefix to all reported metrics (using the `WithNamespace` option).
31+
32+
- in `lura/backend.go` and `lura/proxy.go` we are setting the static attrs,
33+
and using `semconv.ServerAddress`, to set the concatenated list of hosts.
34+
Is that something that we want ?
35+
36+
# TO CHECK
37+
38+
- in `exporter/otelcollector/otelcollector.go`, the `WithEndpoint` states that
39+
**no http** schema should be in cluded (nor path). To use `http` reporting methods,
40+
the `WithInsecure` option should be used (and to user a path `WithURLPath`).
41+
Check that current implementation works as expected, or fix it.
42+
43+
- in `http/client/transport.go` we have commented out the `StartOptions` for
44+
trace: review if would be useful to expose that in the config.

exporter/otelcollector/otelcollector.go

-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ func Exporter(ctx context.Context, cfg config.OTLPExporter) (*OtelCollector, err
6161
// WARN: we do not clean up / canonicalize the header name
6262
headers[kvh.Key] = kvh.Value
6363
}
64-
// TODO: allow to use http in config
6564
exporter, err = otlptracehttp.New(ctx,
6665
otlptracehttp.WithHeaders(headers),
6766
otlptracehttp.WithEndpoint(fmt.Sprintf("%s:%d", cfg.Host, cfg.Port)),

exporter/prometheus/prometheus.go

-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ func Exporter(ctx context.Context, cfg config.PrometheusExporter) (*PrometheusCo
5353
}
5454
}
5555

56-
// TODO: should we put a WithNamespace option here ?
5756
exporter, err := prometheus.New(prometheus.WithRegisterer(prometheusRegistry))
5857
if err != nil {
5958
return nil, err

http/client/client.go

+2-4
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,10 @@ import (
4040
)
4141

4242
// InstrumentedHTTPClient creates a new instrumented http client with the options provided.
43-
// If the provided options are nil, the default options (with everything enabled) will be used.
43+
// If the provided options are nil, the default options (with everything enabled, except
44+
// the detailed connection data: DNS, TLS, time to get a connection...) will be used.
4445
// Check the [TransportOptions] struct for details..
4546
func InstrumentedHTTPClient(c *http.Client, t *TransportOptions, clientName string) *http.Client {
46-
// the default options is to have everything activated
47-
// TODO: we might want to return the provided client if no transport options are provided ?
48-
// TODO: we might want to return an error if no transport options are provided ?
4947
opts := TransportOptions{
5048
MetricsOpts: TransportMetricsOptions{
5149
RoundTrip: true,

http/client/transport.go

-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ type Transport struct {
5656
//
5757
// StartOptions.SpanKind will always be set to trace.SpanKindClient
5858
// for spans started by this transport.
59-
// TODO:
6059
// StartOptions trace.StartOptions
6160

6261
tracesOpts TransportTracesOptions

http/client/transport_metrics.go

-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import (
1010
)
1111

1212
var (
13-
// TODO: we can tweak the level of detail for the time buckets:
1413
// this will generate 20 time series for the metric
1514
timeBucketsOpt = metric.WithExplicitBucketBoundaries(
1615
0.010, 0.020, 0.030, 0.040,

http/server/metrics.go

-6
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,7 @@ import (
66
"go.opentelemetry.io/otel/semconv/v1.21.0"
77
)
88

9-
// TODO: we must decide if we want a single shared configuration of the
10-
// time buckets, and the size buckets, or if we want to be able to tweak
11-
// the buckets for each layer (or give some options, like low / medium / high
12-
// detail that would add more or less buckets).
139
var (
14-
// TODO: we can tweak the level of detail for the time buckets:
15-
// this will generate 20 time series for the metric
1610
timeBucketsOpt = metric.WithExplicitBucketBoundaries(
1711
0.010, 0.020, 0.030, 0.040,
1812
0.050, 0.065, 0.080, 0.100,

http/server/server.go

-2
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,6 @@ func NewTrackingHandler(next http.Handler, obsCfg *kotelconfig.Config, stateFn s
6464

6565
var m *metricsHTTP
6666
if !gCfg.DisableMetrics {
67-
// TODO: we might want to create a single "meter" in the state instead of using
68-
// meter provider
6967
meter := s.Meter()
7068
staticAttrs := []attribute.KeyValue{
7169
attribute.String("krakend.stage", "global"),

io/instruments.go

-3
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,6 @@ type instruments struct {
4141
metricFixedAttrs []attribute.KeyValue
4242
traceFixedAttrs []attribute.KeyValue
4343

44-
// Metrics:
45-
// the count of number of bytes sent (TODO: we might remove
46-
// this, because that count can be extracted from the histogram)
4744
sizeCount metric.Int64Counter
4845
sizeHistogram metric.Int64Histogram
4946
timeCount metric.Float64Counter

lura/attributes.go

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package lura
2+
3+
import (
4+
"sort"
5+
"strings"
6+
7+
"go.opentelemetry.io/otel/attribute"
8+
"go.opentelemetry.io/otel/semconv/v1.21.0"
9+
10+
"github.com/luraproject/lura/v2/config"
11+
12+
kotelconfig "github.com/krakend/krakend-otel/config"
13+
)
14+
15+
// backendConfigAttributes returnsa list of attributes
16+
// that will be set for both traces and
17+
// metrics, as those are expected to have low cardinality
18+
// - the method: one of the `GET`, `POST`, `PUT` .. etc
19+
// - the "path" , that is actually the path "template" to not have different values
20+
// for different params but the same endpoint.
21+
// - the krakend stage, that can be one of
22+
// - router: includes from the very point of receiving a request until
23+
// a response is returned to the client.
24+
// - pipe: includes all the processing that is performed
25+
// for the endpoint part of a request (like merging and grouping
26+
// responses from different backends).
27+
// - backend: includes all middlewares and processing that is done for
28+
// a given backend.
29+
// - backend-request: when reporting the request to the backends
30+
// - server address: the host for the request
31+
func backendConfigAttributes(cfg *config.Backend, stage string) []attribute.KeyValue {
32+
33+
urlPattern := kotelconfig.NormalizeURLPattern(cfg.URLPattern)
34+
parentEndpoint := kotelconfig.NormalizeURLPattern(cfg.ParentEndpoint)
35+
36+
attrs := []attribute.KeyValue{
37+
semconv.HTTPRequestMethodOriginal(cfg.Method),
38+
semconv.URLPath(urlPattern), // <- for traces we can use URLFull to not have the matched path
39+
attribute.String("krakend.stage", stage),
40+
attribute.String("krakend.endpoint", parentEndpoint),
41+
}
42+
numHosts := len(cfg.Host)
43+
if numHosts > 0 {
44+
if numHosts == 1 {
45+
attrs = append(attrs, semconv.ServerAddress(cfg.Host[0]))
46+
} else {
47+
hosts := make([]string, 0, numHosts)
48+
copy(hosts, cfg.Host)
49+
sort.StringSlice(hosts).Sort()
50+
strHosts := strings.Join(hosts, "_")
51+
attrs = append(attrs, semconv.ServerAddress(strHosts))
52+
}
53+
}
54+
55+
return attrs
56+
}

lura/backend.go

+17-19
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"net/http"
66

77
"go.opentelemetry.io/otel/attribute"
8-
"go.opentelemetry.io/otel/semconv/v1.21.0"
98

109
"github.com/luraproject/lura/v2/config"
1110
transport "github.com/luraproject/lura/v2/transport/http/client"
@@ -21,16 +20,14 @@ var defaultOpts = otelconfig.BackendOpts{
2120
RoundTrip: true,
2221
ReadPayload: true,
2322
DetailedConnection: true,
24-
// TODO: THIS IS NOT BEING USED !!
25-
StaticAttributes: make(otelconfig.Attributes, 0),
23+
StaticAttributes: make(otelconfig.Attributes, 0),
2624
},
2725
Traces: &otelconfig.BackendTraceOpts{
2826
DisableStage: false,
2927
RoundTrip: true,
3028
ReadPayload: true,
3129
DetailedConnection: true,
32-
// TODO: THIS IS NOT BEING USED !!
33-
StaticAttributes: make(otelconfig.Attributes, 0),
30+
StaticAttributes: make(otelconfig.Attributes, 0),
3431
},
3532
}
3633

@@ -86,38 +83,39 @@ func InstrumentedHTTPClientFactory(clientFactory transport.HTTPClientFactory,
8683
// - backend: includes all middlewares and processing that is done for
8784
// a given backend.
8885
// - backend-request: when reporting the request to the backends
89-
attrs := []attribute.KeyValue{
90-
semconv.HTTPRequestMethodOriginal(cfg.Method),
91-
semconv.URLPath(urlPattern), // <- for traces we can use URLFull to not have the matched path
92-
attribute.String("krakend.stage", "backend-request"),
93-
}
86+
attrs := backendConfigAttributes(cfg, "backend-request")
9487

95-
if len(cfg.Host) > 0 {
96-
attrs = append(attrs, semconv.ServerAddress(cfg.Host[0]))
88+
metricAttrs := attrs
89+
if len(opts.Metrics.StaticAttributes) > 0 {
90+
for _, kv := range opts.Metrics.StaticAttributes {
91+
metricAttrs = append(metricAttrs, attribute.String(kv.Key, kv.Value))
92+
}
93+
}
94+
traceAttrs := attrs
95+
if len(opts.Traces.StaticAttributes) > 0 {
96+
for _, kv := range opts.Metrics.StaticAttributes {
97+
traceAttrs = append(traceAttrs, attribute.String(kv.Key, kv.Value))
98+
}
9799
}
98-
99-
// TODO: check how we want to deal with this "clientName"
100-
clientName := cfg.ParentEndpoint + "." + urlPattern
101-
102100
t := clienthttp.TransportOptions{
103101
MetricsOpts: clienthttp.TransportMetricsOptions{
104102
RoundTrip: opts.Metrics.RoundTrip,
105103
ReadPayload: opts.Metrics.ReadPayload,
106104
DetailedConnection: opts.Metrics.DetailedConnection,
107-
FixedAttributes: attrs,
105+
FixedAttributes: metricAttrs,
108106
},
109107
TracesOpts: clienthttp.TransportTracesOptions{
110108
RoundTrip: opts.Traces.RoundTrip,
111109
ReadPayload: opts.Traces.ReadPayload,
112110
DetailedConnection: opts.Traces.DetailedConnection,
113-
FixedAttributes: attrs,
111+
FixedAttributes: traceAttrs,
114112
},
115113
OTELInstance: getState,
116114
}
117115

118116
return func(ctx context.Context) *http.Client {
119117
// TODO: this can be optimized, because inside InstrumentedHTTPClient we
120118
// are creating a RoundTripper that could be "prebuilt" and reused
121-
return clienthttp.InstrumentedHTTPClient(clientFactory(ctx), &t, clientName)
119+
return clienthttp.InstrumentedHTTPClient(clientFactory(ctx), &t, urlPattern)
122120
}
123121
}

lura/proxy.go

+3-13
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package lura
33
import (
44
"context"
55
"errors"
6-
"strings"
76
"time"
87

98
"go.opentelemetry.io/otel/attribute"
@@ -187,18 +186,9 @@ func OTELBackendFactory(bf proxy.BackendFactory, gsfn state.GetterFn, metricsEna
187186
return next
188187
}
189188
}
189+
staticAttrs := backendConfigAttributes(cfg, "backend")
190+
190191
urlPattern := kotelconfig.NormalizeURLPattern(cfg.URLPattern)
191-
parentEndpoint := kotelconfig.NormalizeURLPattern(cfg.ParentEndpoint)
192-
hosts := strings.Join(cfg.Host, "_")
193-
// TODO: check if we want to have the hosts as static attribute
194-
staticAttrs := []attribute.KeyValue{
195-
semconv.URLPath(urlPattern),
196-
attribute.String("krakend.stage", "backend"),
197-
attribute.String("krakend.endpoint", parentEndpoint),
198-
semconv.ServerAddress(hosts),
199-
}
200-
// TODO: check if we want to have the hosts, to paths that are the same, but for different hosts
201-
spanName := strings.Join(cfg.Host, "_") + urlPattern
202-
return Middleware(staticAttrs, gsfn, metricsEnabled, tracesEnabled, spanName)(next)
192+
return Middleware(staticAttrs, gsfn, metricsEnabled, tracesEnabled, urlPattern)(next)
203193
}
204194
}

0 commit comments

Comments
 (0)