diff --git a/.github/actions/cache-golangci-lint/action.yml b/.github/actions/cache-golangci-lint/action.yml index 072e526a..d50c022b 100644 --- a/.github/actions/cache-golangci-lint/action.yml +++ b/.github/actions/cache-golangci-lint/action.yml @@ -10,4 +10,4 @@ runs: path: ~/.cache/golangci-lint key: golangci-lint-${{ runner.os }}-${{ hashFiles('**/go.mod') }} restore-keys: | - golangci-lint-${{ runner.os }}-- + golangci-lint-${{ runner.os }}- diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c3df1a66..999db877 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -36,6 +36,9 @@ jobs: - name: Run tidy run: make tidy && git diff --exit-code + - name: Run generate + run: make generate && git diff --exit-code + - name: Run lint run: make lint diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 18aea6f6..be3bfae6 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -1,3 +1,4 @@ +# yaml-language-server: $schema=https://goreleaser.com/static/schema.json version: 2 project_name: keel @@ -9,11 +10,14 @@ builds: - skip: true archives: - - format: tar.gz + - formats: [ tar.gz ] format_overrides: - goos: windows - format: zip + formats: [ zip ] files: [ LICENSE, README.md ] +checksum: + name_template: checksums.txt + changelog: use: github-native diff --git a/README.md b/README.md index 7ee7243c..53afac82 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ -[](https://godoc.org/github.com/foomo/keel) +[](https://github.com/foomo/keel/actions/workflows/github-code-scanning/codeql) [](https://app.codecov.io/gh/foomo/keel) +[](https://godoc.org/github.com/foomo/keel) [](https://github.com/foomo/keel)
diff --git a/closer.go b/closer.go
index 99d48883..9a59cc1d 100644
--- a/closer.go
+++ b/closer.go
@@ -2,10 +2,10 @@ package keel
import (
"context"
- "fmt"
"github.com/foomo/keel/interfaces"
"github.com/foomo/keel/log"
+ keelsemconv "github.com/foomo/keel/semconv"
"go.uber.org/zap"
)
@@ -21,7 +21,7 @@ func closeAll(ctx context.Context, l *zap.Logger, closers []any) {
var err error
- cl := l.With(log.FName(fmt.Sprintf("%T", closer)))
+ cl := log.WithAttributes(l, keelsemconv.KeelCloserType(closer))
switch c := closer.(type) {
case interfaces.Closer:
c.Close()
@@ -58,7 +58,7 @@ func closeAll(ctx context.Context, l *zap.Logger, closers []any) {
}
if err != nil {
- cl.Warn("keel closer failed", zap.Error(err))
+ log.WithError(cl, err).Warn("keel closer failed")
} else {
cl.Debug("keel closer closed")
}
diff --git a/examples/go.mod b/examples/go.mod
index d562f72d..58ff6d6d 100644
--- a/examples/go.mod
+++ b/examples/go.mod
@@ -21,9 +21,9 @@ require (
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.24.1
go.mongodb.org/mongo-driver/v2 v2.9.1
- go.opentelemetry.io/otel v1.46.0
- go.opentelemetry.io/otel/metric v1.46.0
- go.opentelemetry.io/otel/trace v1.46.0
+ go.opentelemetry.io/otel v1.47.0
+ go.opentelemetry.io/otel/metric v1.47.0
+ go.opentelemetry.io/otel/trace v1.47.0
go.uber.org/zap v1.28.0
)
@@ -50,7 +50,7 @@ require (
github.com/foomo/gofuncy v0.4.0 // indirect
github.com/foomo/gostandards v0.3.0 // indirect
github.com/foomo/mongo-lock v0.2.0 // indirect
- github.com/foomo/opentelemetry-go v0.4.0 // indirect
+ github.com/foomo/opentelemetry-go v0.5.0 // indirect
github.com/fsnotify/fsnotify v1.10.1 // indirect
github.com/go-logr/logr v1.4.4 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
@@ -136,10 +136,10 @@ require (
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.22.0 // indirect
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.46.0 // indirect
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.46.0 // indirect
- go.opentelemetry.io/otel/log v0.22.0 // indirect
- go.opentelemetry.io/otel/sdk v1.46.0 // indirect
+ go.opentelemetry.io/otel/log v1.47.0 // indirect
+ go.opentelemetry.io/otel/sdk v1.47.0 // indirect
go.opentelemetry.io/otel/sdk/log v0.22.0 // indirect
- go.opentelemetry.io/otel/sdk/metric v1.46.0 // indirect
+ go.opentelemetry.io/otel/sdk/metric v1.47.0 // indirect
go.opentelemetry.io/proto/otlp v1.11.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.yaml.in/yaml/v3 v3.0.5 // indirect
diff --git a/examples/go.sum b/examples/go.sum
index 5a67c04c..c688db7f 100644
--- a/examples/go.sum
+++ b/examples/go.sum
@@ -112,8 +112,8 @@ github.com/foomo/gostandards v0.3.0 h1:Ev88Tdu0+52UH/d0l2KcAWx542A13o42d++LSTG0D
github.com/foomo/gostandards v0.3.0/go.mod h1:8hJ56tpyFAVwavs5FuUF3po7Bq7hOTkQ1+DzFi4GCWg=
github.com/foomo/mongo-lock v0.2.0 h1:xURP2FijZ/feACB5YL1UKUXk23M+x5L+yltEK+sJm0g=
github.com/foomo/mongo-lock v0.2.0/go.mod h1:5LMCz8IeaTMCWcgh+aPoDeIjY1qpu8MXbx+FNrGAUFA=
-github.com/foomo/opentelemetry-go v0.4.0 h1:UQneCUSokIYJXzFUKQSI8rlelbUuf6atgSZMhvD+Nzo=
-github.com/foomo/opentelemetry-go v0.4.0/go.mod h1:R3Se/rc5FRAs4ThE6JQ9Oq3cOLo2MOsUzZLJxZquwxA=
+github.com/foomo/opentelemetry-go v0.5.0 h1:4MHCj7cRB+Jr8AZsrhQ+J3M/4Gka/mXG0Xv+uv6RNDI=
+github.com/foomo/opentelemetry-go v0.5.0/go.mod h1:3jSEAGFXOJMtFLiLXepEQcr9Fkz1g/JqoWqlcihW/pk=
github.com/foomo/opentelemetry-go/exporters/glossy/glossymetric v0.4.0 h1:o2EScdH3ZgIU2sTHbOnCRXsMr6wTHjAYx63rriQRmtU=
github.com/foomo/opentelemetry-go/exporters/glossy/glossymetric v0.4.0/go.mod h1:RIWQzc+4Y8ur6bs3v9eWduKTPTUSu1WZjcgi8oRwGjs=
github.com/foomo/opentelemetry-go/exporters/glossy/glossytrace v0.4.0 h1:ZbA7PgNO0st/KOAwiJCb7qG5hzIFlSMd6WpozsX28hs=
@@ -457,8 +457,8 @@ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.71.0 h1:3g7B90U
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.71.0/go.mod h1:Ef8SuTh59BT7+ofpDxN9z+yOlc4t2GjLmKDgYNJL/NU=
go.opentelemetry.io/contrib/instrumentation/runtime v0.71.0 h1:v4KkRLVvE1cWqTJDfZZkTCG+Z4aolsa6RVos0FX7vqE=
go.opentelemetry.io/contrib/instrumentation/runtime v0.71.0/go.mod h1:g/xbuPC0XbgwMdKuyF5sKOUUEsorSkN6APydyFP/H9E=
-go.opentelemetry.io/otel v1.46.0 h1:FHt5/CDyVxi/8IM1CH7VE/rRgq3kLHa2mSTVMO8AWyc=
-go.opentelemetry.io/otel v1.46.0/go.mod h1:Gj3SEScelsNC45tp4nSxRYlS+f5iez7W8XPMCt905kE=
+go.opentelemetry.io/otel v1.47.0 h1:j7ALJ/zgkS7Z6aeJW09p8VC9804bC+PpeTfCD4XPnOM=
+go.opentelemetry.io/otel v1.47.0/go.mod h1:8wS9O2qfXrYrzp6hIF/HOYJJf/wIhFPhR2xLuP+iXQU=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.22.0 h1:Bu39F5tzJct+f2IZbB8989fwyTps3c8e7EsUQsz+vs8=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.22.0/go.mod h1:dJUwod88EsFgYCqrDHaSPzhiY9pBUpt0d85/qSfua7k=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.22.0 h1:lYk7RmxdLK865qLwibroNGldHa1U7SWKYYvNjlK7PIo=
@@ -481,24 +481,24 @@ go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.46.0 h1:PR9eAf7o0dQs3h
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.46.0/go.mod h1:2Z4KyNdH1uuzivdinyfGsxzNNT/Rl45pwtVwfYVI0xk=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.46.0 h1:KdRxPiAoMptR3vfWzvjjvutTsSiwbC2uG0496rzZNfo=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.46.0/go.mod h1:K/qSA+3G7Eovxi4K09wzrAgkWRnosS0DAOZeEpve7sM=
-go.opentelemetry.io/otel/log v0.22.0 h1:5DBNnfvaJ6CVdkJ+Jle8Tzs50aSSv49TXGj9XRsEYw0=
-go.opentelemetry.io/otel/log v0.22.0/go.mod h1:gzOt/R67vF2GniAqWu8Qv0SXy89f71muHcrkz76PCdc=
+go.opentelemetry.io/otel/log v1.47.0 h1:cOTS1CcLbSQeZKanGJ+0JpF/+t4PELi3O3bbl2lqCcI=
+go.opentelemetry.io/otel/log v1.47.0/go.mod h1:9byitSQ5pLC6PpqwGXjqdMKya6ZTswHRZh2vvXT33nw=
go.opentelemetry.io/otel/log/logtest v0.22.0 h1:0pvI8BwoRN7c0KVXqzSdZQgkFdsNBL/aokbSp3boQec=
go.opentelemetry.io/otel/log/logtest v0.22.0/go.mod h1:9+PjkCcSiKB2CEn3LYZ6Y3c37KJs7fziPXNiuyQGmRQ=
-go.opentelemetry.io/otel/metric v1.46.0 h1:yBnkXvgV7AXFILZc5K6IZe/CBFF3OS7BJ8ov6/lj0K8=
-go.opentelemetry.io/otel/metric v1.46.0/go.mod h1:iPmdWqifKUdzziPkvvzIJXITl56fQx2mGM/DHLB3/2o=
-go.opentelemetry.io/otel/metric/x v0.68.0 h1:TA/cBT23D3MnxYPwHL7YFOdYGdx0A0v+s7Mzotpd1dU=
-go.opentelemetry.io/otel/metric/x v0.68.0/go.mod h1:agudOmvWhwUTjgibWDzxD2PoWYnpw5Ht5jISYOD2Hd4=
-go.opentelemetry.io/otel/sdk v1.46.0 h1:h5CNQQjEbuQXY/JfZtgt3i7HVFV3aHPO2OAwO2eTYPI=
-go.opentelemetry.io/otel/sdk v1.46.0/go.mod h1:GAERFXFt5SYCEB+YiKUbMBeza6UaDH7GmGOZEfh2gSM=
+go.opentelemetry.io/otel/metric v1.47.0 h1:4PptaldXx3Eat1XjMZ68pPJEs5wrhlemctZE9a3UdWY=
+go.opentelemetry.io/otel/metric v1.47.0/go.mod h1:ADGSXxRrXM6bjbvLo535EstVFlPpPYZm4LBKixjDHwU=
+go.opentelemetry.io/otel/metric/x v0.69.0 h1:DjRLr15H83v+hCW7JA9NoJvOkYTtmq5YoDRbe9deYpM=
+go.opentelemetry.io/otel/metric/x v0.69.0/go.mod h1:uVvsMPMFFyj/HUQfrUnH3JjnOQ1dwFDorgFLRBasM0k=
+go.opentelemetry.io/otel/sdk v1.47.0 h1:zWXEr4j2lFefG87TU6Yg8a7ngfohIKFZHKp0Hf5hC6I=
+go.opentelemetry.io/otel/sdk v1.47.0/go.mod h1:VUc24kiOeoGsxG8G9ULx3fWKvB7jMhnGE8Oi607lgR0=
go.opentelemetry.io/otel/sdk/log v0.22.0 h1:PRL+s6P63XT4E/bheEflopPUpVxuvANqZwtt89yhoGk=
go.opentelemetry.io/otel/sdk/log v0.22.0/go.mod h1:JNp0sBELrjCTcu5W3GzABVypeU6vDJjBS+X0JISuz+g=
go.opentelemetry.io/otel/sdk/log/logtest v0.22.0 h1:infPnfNrhCNgOUZRs3gWUg8vhoBUHihq02gwK05gzlg=
go.opentelemetry.io/otel/sdk/log/logtest v0.22.0/go.mod h1:gkQZA3z15Bv3KU9vigBTi8dFechSozRP7v94X4VZv+s=
-go.opentelemetry.io/otel/sdk/metric v1.46.0 h1:0piZ26EG4RBfebb2jhDH6ERCYHoVWduc3kLgPCwSnSE=
-go.opentelemetry.io/otel/sdk/metric v1.46.0/go.mod h1:I1PbKrdVc8Qu8HYVDNtqVIwLwjNrhsV/uFuxfwg8mO4=
-go.opentelemetry.io/otel/trace v1.46.0 h1:OULy7ccdJnZtJ0UDYFOIGaCmiWzJ8Vi2G/Rsu60qs1c=
-go.opentelemetry.io/otel/trace v1.46.0/go.mod h1:J7GAXweO77XSFkB/rmAqk9D6ihszhFjLU+d9WuUxDLI=
+go.opentelemetry.io/otel/sdk/metric v1.47.0 h1:lfISg2j93VT6yqdk9OfUaZmw/GfcZqCCV3jdXtsPnKw=
+go.opentelemetry.io/otel/sdk/metric v1.47.0/go.mod h1:ypLp+mW1Nt2x+Szt3b5/i1syodyts49lMOwxpDI3VGw=
+go.opentelemetry.io/otel/trace v1.47.0 h1:JOjX/Oci8K94QHddo+bbfya/Ai/nf6/dt9ZfrFNWSrM=
+go.opentelemetry.io/otel/trace v1.47.0/go.mod h1:jNaSLa2PZEYFG6fRjJABAu+bw4FS08uDmPg28lTghu0=
go.opentelemetry.io/proto/otlp v1.11.0 h1:5rrYs0Ykyj50sdU/JU0x8etU+LubXWb+gED6TbEdMIk=
go.opentelemetry.io/proto/otlp v1.11.0/go.mod h1:SmVizdCOAm3XBtG1g1NnOdhW6jtddT72hLMhv8VwA8E=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
diff --git a/examples/persistence/mongo/main.go b/examples/persistence/mongo/main.go
index 43a9d4f5..186693bd 100644
--- a/examples/persistence/mongo/main.go
+++ b/examples/persistence/mongo/main.go
@@ -77,9 +77,9 @@ func main() {
if err := repo.Insert(context.Background(), &store.Dummy{
Entity: store.NewEntity(newEntity.ID),
}); mongo.IsDuplicateKeyError(err) {
- l.Info("OK: expected error", log.FValue(err.Error()))
+ log.WithError(l, err).Info("OK: expected error")
} else if err != nil {
- l.Error("unexpected error", log.FValue(err.Error()))
+ log.WithError(l, err).Error("unexpected error")
} else {
l.Error("unexpected success")
}
@@ -90,9 +90,9 @@ func main() {
if err := repo.Upsert(context.Background(), &store.Dummy{
Entity: store.NewEntity(newEntity.ID),
}); mongo.IsDuplicateKeyError(err) {
- l.Info("OK: expected error", log.FValue(err.Error()))
+ log.WithError(l, err).Info("OK: expected error")
} else if err != nil {
- l.Error("unexpected error", log.FValue(err.Error()))
+ log.WithError(l, err).Error("unexpected error")
} else {
l.Error("unexpected success")
}
@@ -102,9 +102,9 @@ func main() {
if err := repo.UpsertMany(context.Background(), []*store.Dummy{{
Entity: store.NewEntity(newEntity.ID),
}}); mongo.IsDuplicateKeyError(err) {
- l.Info("OK: expected error", log.FValue(err.Error()))
+ log.WithError(l, err).Info("OK: expected error")
} else if err != nil {
- l.Error("unexpected error", log.FValue(err.Error()))
+ log.WithError(l, err).Error("unexpected error")
} else {
l.Error("unexpected success")
}
@@ -123,9 +123,9 @@ func main() {
// update entity B
if err := repo.Upsert(context.Background(), newEntityB); errors.Is(err, keelpersistence.ErrDirtyWrite) {
- l.Info("OK: expected error", log.FValue(err.Error()))
+ log.WithError(l, err).Info("OK: expected error")
} else if err != nil {
- l.Error("unexpected error", log.FValue(err.Error()))
+ log.WithError(l, err).Error("unexpected error")
} else {
l.Error("unexpected success")
}
@@ -144,9 +144,9 @@ func main() {
l.Info("Try to upsert many with dirty write")
if err := repo.UpsertMany(context.Background(), []*store.Dummy{newEntityB}); errors.Is(err, keelpersistence.ErrDirtyWrite) {
- l.Info("OK: expected error", log.FValue(err.Error()))
+ log.WithError(l, err).Info("OK: expected error")
} else if err != nil {
- l.Error("unexpected error", log.FValue(err.Error()))
+ log.WithError(l, err).Error("unexpected error")
} else {
l.Error("unexpected success")
}
diff --git a/examples/stream/jetstream/main.go b/examples/stream/jetstream/main.go
index 4768be63..6103d122 100644
--- a/examples/stream/jetstream/main.go
+++ b/examples/stream/jetstream/main.go
@@ -13,7 +13,9 @@ import (
"github.com/foomo/keel"
"github.com/foomo/keel/log"
"github.com/foomo/keel/net/stream/jetstream"
+ keelsemconv "github.com/foomo/keel/semconv"
httputils "github.com/foomo/keel/utils/net/http"
+ semconv "go.opentelemetry.io/otel/semconv/v1.43.0"
)
func main() {
@@ -71,7 +73,7 @@ func main() {
return
}
- l.Info("sent message", log.FValue(msg.Name))
+ l.Info("sent message", log.Attribute(keelsemconv.Value(msg.Name)))
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("OK"))
})
@@ -83,7 +85,7 @@ func main() {
return errors.Wrap(err, "failed to unmarshall message data")
}
- l.Info("received message", log.FValue(data.Name), log.FMessagingDestination(msg.Subject))
+ l.Info("received message", log.Attribute(keelsemconv.Value(data.Name)), log.Attribute(semconv.MessagingDestinationName(msg.Subject)))
return nil
})
diff --git a/examples/stream/jetstreamraw/main.go b/examples/stream/jetstreamraw/main.go
index 939f6a85..a493db0c 100644
--- a/examples/stream/jetstreamraw/main.go
+++ b/examples/stream/jetstreamraw/main.go
@@ -10,7 +10,9 @@ import (
"github.com/foomo/keel"
"github.com/foomo/keel/log"
"github.com/foomo/keel/net/stream/jetstream"
+ keelsemconv "github.com/foomo/keel/semconv"
httputils "github.com/foomo/keel/utils/net/http"
+ semconv "go.opentelemetry.io/otel/semconv/v1.43.0"
)
func main() {
@@ -67,7 +69,7 @@ func main() {
// subscribe to the subject
subscription, err := sub.JS().Subscribe(sub.Subject(), func(msg *nats.Msg) {
- l.Info("received message", log.FValue(string(msg.Data)), log.FMessagingDestination(msg.Subject))
+ l.Info("received message", log.Attribute(keelsemconv.Value(string(msg.Data))), log.Attribute(semconv.MessagingDestinationName(msg.Subject)))
}, sub.SubOpts()...)
log.Must(l, err, "failed to subscribe to subject")
diff --git a/examples/telemetry/main.go b/examples/telemetry/main.go
index 7ad7541c..868ca8b9 100644
--- a/examples/telemetry/main.go
+++ b/examples/telemetry/main.go
@@ -61,8 +61,9 @@ func main() {
{ // counter
counter, err := meter.Int64Counter(
- "a.counter",
- metric.WithDescription("Count things"),
+ "demo.count",
+ metric.WithDescription("Number of calls to the count endpoint."),
+ metric.WithUnit("{call}"),
)
log.Must(l, err, "failed to create counter meter")
@@ -83,8 +84,9 @@ func main() {
{ // up down
upDown, err := meter.Int64UpDownCounter(
- "a.updown",
- metric.WithDescription("Up down values"),
+ "demo.level",
+ metric.WithDescription("Current level raised by the up and lowered by the down endpoint."),
+ metric.WithUnit("{level}"),
)
log.Must(l, err, "failed to create up down meter")
@@ -101,26 +103,24 @@ func main() {
}
{ // histogram
- histogram, err := meter.Int64Histogram(
- "a.histogram",
- metric.WithDescription("Up down values"),
- metric.WithUnit("ms"),
+ histogram, err := meter.Float64Histogram(
+ "demo.request.duration",
+ metric.WithDescription("Duration of histogram endpoint requests."),
+ metric.WithUnit("s"),
)
- log.Must(l, err, "failed to create up down meter")
+ log.Must(l, err, "failed to create histogram meter")
svs.HandleFunc("/histogram", func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
- time.Sleep(time.Second)
+ time.Sleep(time.Second + time.Duration(rand.Intn(100))*time.Millisecond)
- traceID := trace.SpanContextFromContext(r.Context())
- histogram.Record(r.Context(), int64(rand.Int()),
- metric.WithAttributes(
- attribute.String("key", "value"),
- attribute.String("traceID", traceID.TraceID().String()),
- ),
+ histogram.Record(r.Context(), time.Since(start).Seconds(),
+ metric.WithAttributes(attribute.String("key", "value")),
)
+ traceID := trace.SpanContextFromContext(r.Context())
+
metricRequestLatency.(prometheus.ExemplarObserver).ObserveWithExemplar(
time.Since(start).Seconds(), prometheus.Labels{"traceID": traceID.TraceID().String()},
)
diff --git a/go.mod b/go.mod
index a27186ea..221c0466 100644
--- a/go.mod
+++ b/go.mod
@@ -9,7 +9,7 @@ require (
github.com/foomo/goflux v0.10.0
github.com/foomo/gofuncy v0.4.0
github.com/foomo/gostandards v0.3.0
- github.com/foomo/opentelemetry-go v0.4.0
+ github.com/foomo/opentelemetry-go v0.5.0
github.com/go-logr/logr v1.4.4
github.com/golang-jwt/jwt/v5 v5.3.1
github.com/google/uuid v1.6.0
@@ -30,7 +30,7 @@ require (
go.opentelemetry.io/contrib/instrumentation/host v0.71.0
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.71.0
go.opentelemetry.io/contrib/instrumentation/runtime v0.71.0
- go.opentelemetry.io/otel v1.46.0
+ go.opentelemetry.io/otel v1.47.0
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.22.0
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.22.0
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.46.0
@@ -41,13 +41,13 @@ require (
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.22.0
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.46.0
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.46.0
- go.opentelemetry.io/otel/log v0.22.0
+ go.opentelemetry.io/otel/log v1.47.0
go.opentelemetry.io/otel/log/logtest v0.22.0
- go.opentelemetry.io/otel/metric v1.46.0
- go.opentelemetry.io/otel/sdk v1.46.0
+ go.opentelemetry.io/otel/metric v1.47.0
+ go.opentelemetry.io/otel/sdk v1.47.0
go.opentelemetry.io/otel/sdk/log v0.22.0
- go.opentelemetry.io/otel/sdk/metric v1.46.0
- go.opentelemetry.io/otel/trace v1.46.0
+ go.opentelemetry.io/otel/sdk/metric v1.47.0
+ go.opentelemetry.io/otel/trace v1.47.0
go.uber.org/goleak v1.3.0
go.uber.org/zap v1.28.0
golang.org/x/crypto v0.57.0
diff --git a/go.sum b/go.sum
index 854d4d3d..43397bfa 100644
--- a/go.sum
+++ b/go.sum
@@ -84,8 +84,8 @@ github.com/foomo/gofuncy v0.4.0 h1:wxfFOQSp+eZYy9YFXY7A8PPu0n51t4Xhvd6tOm0OSSs=
github.com/foomo/gofuncy v0.4.0/go.mod h1:ulEUpkz38K6trv71GM7fHjaUqa/NbWOZUE5MAbfe/Kk=
github.com/foomo/gostandards v0.3.0 h1:Ev88Tdu0+52UH/d0l2KcAWx542A13o42d++LSTG0DC4=
github.com/foomo/gostandards v0.3.0/go.mod h1:8hJ56tpyFAVwavs5FuUF3po7Bq7hOTkQ1+DzFi4GCWg=
-github.com/foomo/opentelemetry-go v0.4.0 h1:UQneCUSokIYJXzFUKQSI8rlelbUuf6atgSZMhvD+Nzo=
-github.com/foomo/opentelemetry-go v0.4.0/go.mod h1:R3Se/rc5FRAs4ThE6JQ9Oq3cOLo2MOsUzZLJxZquwxA=
+github.com/foomo/opentelemetry-go v0.5.0 h1:4MHCj7cRB+Jr8AZsrhQ+J3M/4Gka/mXG0Xv+uv6RNDI=
+github.com/foomo/opentelemetry-go v0.5.0/go.mod h1:3jSEAGFXOJMtFLiLXepEQcr9Fkz1g/JqoWqlcihW/pk=
github.com/foomo/opentelemetry-go/exporters/glossy/glossymetric v0.4.0 h1:o2EScdH3ZgIU2sTHbOnCRXsMr6wTHjAYx63rriQRmtU=
github.com/foomo/opentelemetry-go/exporters/glossy/glossymetric v0.4.0/go.mod h1:RIWQzc+4Y8ur6bs3v9eWduKTPTUSu1WZjcgi8oRwGjs=
github.com/foomo/opentelemetry-go/exporters/glossy/glossytrace v0.4.0 h1:ZbA7PgNO0st/KOAwiJCb7qG5hzIFlSMd6WpozsX28hs=
@@ -378,8 +378,8 @@ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.71.0 h1:3g7B90U
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.71.0/go.mod h1:Ef8SuTh59BT7+ofpDxN9z+yOlc4t2GjLmKDgYNJL/NU=
go.opentelemetry.io/contrib/instrumentation/runtime v0.71.0 h1:v4KkRLVvE1cWqTJDfZZkTCG+Z4aolsa6RVos0FX7vqE=
go.opentelemetry.io/contrib/instrumentation/runtime v0.71.0/go.mod h1:g/xbuPC0XbgwMdKuyF5sKOUUEsorSkN6APydyFP/H9E=
-go.opentelemetry.io/otel v1.46.0 h1:FHt5/CDyVxi/8IM1CH7VE/rRgq3kLHa2mSTVMO8AWyc=
-go.opentelemetry.io/otel v1.46.0/go.mod h1:Gj3SEScelsNC45tp4nSxRYlS+f5iez7W8XPMCt905kE=
+go.opentelemetry.io/otel v1.47.0 h1:j7ALJ/zgkS7Z6aeJW09p8VC9804bC+PpeTfCD4XPnOM=
+go.opentelemetry.io/otel v1.47.0/go.mod h1:8wS9O2qfXrYrzp6hIF/HOYJJf/wIhFPhR2xLuP+iXQU=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.22.0 h1:Bu39F5tzJct+f2IZbB8989fwyTps3c8e7EsUQsz+vs8=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.22.0/go.mod h1:dJUwod88EsFgYCqrDHaSPzhiY9pBUpt0d85/qSfua7k=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.22.0 h1:lYk7RmxdLK865qLwibroNGldHa1U7SWKYYvNjlK7PIo=
@@ -402,24 +402,24 @@ go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.46.0 h1:PR9eAf7o0dQs3h
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.46.0/go.mod h1:2Z4KyNdH1uuzivdinyfGsxzNNT/Rl45pwtVwfYVI0xk=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.46.0 h1:KdRxPiAoMptR3vfWzvjjvutTsSiwbC2uG0496rzZNfo=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.46.0/go.mod h1:K/qSA+3G7Eovxi4K09wzrAgkWRnosS0DAOZeEpve7sM=
-go.opentelemetry.io/otel/log v0.22.0 h1:5DBNnfvaJ6CVdkJ+Jle8Tzs50aSSv49TXGj9XRsEYw0=
-go.opentelemetry.io/otel/log v0.22.0/go.mod h1:gzOt/R67vF2GniAqWu8Qv0SXy89f71muHcrkz76PCdc=
+go.opentelemetry.io/otel/log v1.47.0 h1:cOTS1CcLbSQeZKanGJ+0JpF/+t4PELi3O3bbl2lqCcI=
+go.opentelemetry.io/otel/log v1.47.0/go.mod h1:9byitSQ5pLC6PpqwGXjqdMKya6ZTswHRZh2vvXT33nw=
go.opentelemetry.io/otel/log/logtest v0.22.0 h1:0pvI8BwoRN7c0KVXqzSdZQgkFdsNBL/aokbSp3boQec=
go.opentelemetry.io/otel/log/logtest v0.22.0/go.mod h1:9+PjkCcSiKB2CEn3LYZ6Y3c37KJs7fziPXNiuyQGmRQ=
-go.opentelemetry.io/otel/metric v1.46.0 h1:yBnkXvgV7AXFILZc5K6IZe/CBFF3OS7BJ8ov6/lj0K8=
-go.opentelemetry.io/otel/metric v1.46.0/go.mod h1:iPmdWqifKUdzziPkvvzIJXITl56fQx2mGM/DHLB3/2o=
-go.opentelemetry.io/otel/metric/x v0.68.0 h1:TA/cBT23D3MnxYPwHL7YFOdYGdx0A0v+s7Mzotpd1dU=
-go.opentelemetry.io/otel/metric/x v0.68.0/go.mod h1:agudOmvWhwUTjgibWDzxD2PoWYnpw5Ht5jISYOD2Hd4=
-go.opentelemetry.io/otel/sdk v1.46.0 h1:h5CNQQjEbuQXY/JfZtgt3i7HVFV3aHPO2OAwO2eTYPI=
-go.opentelemetry.io/otel/sdk v1.46.0/go.mod h1:GAERFXFt5SYCEB+YiKUbMBeza6UaDH7GmGOZEfh2gSM=
+go.opentelemetry.io/otel/metric v1.47.0 h1:4PptaldXx3Eat1XjMZ68pPJEs5wrhlemctZE9a3UdWY=
+go.opentelemetry.io/otel/metric v1.47.0/go.mod h1:ADGSXxRrXM6bjbvLo535EstVFlPpPYZm4LBKixjDHwU=
+go.opentelemetry.io/otel/metric/x v0.69.0 h1:DjRLr15H83v+hCW7JA9NoJvOkYTtmq5YoDRbe9deYpM=
+go.opentelemetry.io/otel/metric/x v0.69.0/go.mod h1:uVvsMPMFFyj/HUQfrUnH3JjnOQ1dwFDorgFLRBasM0k=
+go.opentelemetry.io/otel/sdk v1.47.0 h1:zWXEr4j2lFefG87TU6Yg8a7ngfohIKFZHKp0Hf5hC6I=
+go.opentelemetry.io/otel/sdk v1.47.0/go.mod h1:VUc24kiOeoGsxG8G9ULx3fWKvB7jMhnGE8Oi607lgR0=
go.opentelemetry.io/otel/sdk/log v0.22.0 h1:PRL+s6P63XT4E/bheEflopPUpVxuvANqZwtt89yhoGk=
go.opentelemetry.io/otel/sdk/log v0.22.0/go.mod h1:JNp0sBELrjCTcu5W3GzABVypeU6vDJjBS+X0JISuz+g=
go.opentelemetry.io/otel/sdk/log/logtest v0.22.0 h1:infPnfNrhCNgOUZRs3gWUg8vhoBUHihq02gwK05gzlg=
go.opentelemetry.io/otel/sdk/log/logtest v0.22.0/go.mod h1:gkQZA3z15Bv3KU9vigBTi8dFechSozRP7v94X4VZv+s=
-go.opentelemetry.io/otel/sdk/metric v1.46.0 h1:0piZ26EG4RBfebb2jhDH6ERCYHoVWduc3kLgPCwSnSE=
-go.opentelemetry.io/otel/sdk/metric v1.46.0/go.mod h1:I1PbKrdVc8Qu8HYVDNtqVIwLwjNrhsV/uFuxfwg8mO4=
-go.opentelemetry.io/otel/trace v1.46.0 h1:OULy7ccdJnZtJ0UDYFOIGaCmiWzJ8Vi2G/Rsu60qs1c=
-go.opentelemetry.io/otel/trace v1.46.0/go.mod h1:J7GAXweO77XSFkB/rmAqk9D6ihszhFjLU+d9WuUxDLI=
+go.opentelemetry.io/otel/sdk/metric v1.47.0 h1:lfISg2j93VT6yqdk9OfUaZmw/GfcZqCCV3jdXtsPnKw=
+go.opentelemetry.io/otel/sdk/metric v1.47.0/go.mod h1:ypLp+mW1Nt2x+Szt3b5/i1syodyts49lMOwxpDI3VGw=
+go.opentelemetry.io/otel/trace v1.47.0 h1:JOjX/Oci8K94QHddo+bbfya/Ai/nf6/dt9ZfrFNWSrM=
+go.opentelemetry.io/otel/trace v1.47.0/go.mod h1:jNaSLa2PZEYFG6fRjJABAu+bw4FS08uDmPg28lTghu0=
go.opentelemetry.io/proto/otlp v1.11.0 h1:5rrYs0Ykyj50sdU/JU0x8etU+LubXWb+gED6TbEdMIk=
go.opentelemetry.io/proto/otlp v1.11.0/go.mod h1:SmVizdCOAm3XBtG1g1NnOdhW6jtddT72hLMhv8VwA8E=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
diff --git a/integration/nats/connect.go b/integration/nats/connect.go
index 5b3dc052..2deb8074 100644
--- a/integration/nats/connect.go
+++ b/integration/nats/connect.go
@@ -5,15 +5,16 @@ import (
"errors"
"net/url"
"strconv"
+ "sync/atomic"
"time"
"github.com/foomo/keel"
"github.com/foomo/keel/log"
"github.com/foomo/opentelemetry-go/semconv/natsconv"
"github.com/nats-io/nats.go"
+ "go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
- semconv "go.opentelemetry.io/otel/semconv/v1.41.0"
- "go.uber.org/zap"
+ semconv "go.opentelemetry.io/otel/semconv/v1.43.0"
)
// Connect establishes a connection to the NATS server at rawURL with OTel
@@ -28,27 +29,44 @@ func Connect(s keel.Runtime, rawURL string, opts ...nats.Option) (*nats.Conn, er
l := s.Logger().Named("nats")
m := s.Meter()
- // Build instruments once; each returns a noop on nil meter, so errors here
- // only surface real meter-provider problems and should not block Connect.
+ // Build instruments once; each falls back to a noop on error, so errors are
+ // only reported and never block Connect.
disconnects, err := natsconv.NewClientDisconnects(m)
if err != nil {
- return nil, err
+ otel.Handle(err)
}
reconnects, err := natsconv.NewClientReconnects(m)
if err != nil {
- return nil, err
+ otel.Handle(err)
}
asyncErrors, err := natsconv.NewClientAsyncErrors(m)
if err != nil {
- return nil, err
+ otel.Handle(err)
}
// Background context for callbacks — NATS invokes these outside any request
// context, and metric recording shouldn't be cancelled by request teardown.
ctx := context.Background()
+ // ConnectedUrlRedacted is empty unless connected, so remember the last
+ // connected server for the disconnect, reconnect error and closed handlers.
+ var lastURL atomic.Pointer[string]
+
+ serverURL := func(conn *nats.Conn) string {
+ if v := conn.ConnectedUrlRedacted(); v != "" {
+ lastURL.Store(&v)
+ return v
+ }
+
+ if v := lastURL.Load(); v != nil {
+ return *v
+ }
+
+ return ""
+ }
+
opts = append(opts,
nats.MaxReconnects(-1),
nats.ReconnectWait(2*time.Second),
@@ -56,25 +74,25 @@ func Connect(s keel.Runtime, rawURL string, opts ...nats.Option) (*nats.Conn, er
nats.PingInterval(20*time.Second),
nats.ConnectHandler(func(conn *nats.Conn) {
- l.Debug("connected", log.Attributes(serverAttrs(conn)...)...)
+ l.Debug("connected", log.Attributes(serverAttrs(serverURL(conn))...)...)
}),
nats.DisconnectErrHandler(func(conn *nats.Conn, err error) {
- addr, port := serverAddrPort(conn)
+ u := serverURL(conn)
+ addr, port := serverAddrPort(u)
disconnects.Add(ctx, 1, addr, disconnects.AttrServerPort(port))
- l.Warn("disconnected", zap.Error(err),
- zap.String("addr", conn.ConnectedUrlRedacted()),
- zap.String("server_id", conn.ConnectedServerId()),
- )
+ log.WithError(l, err).Warn("disconnected", log.Attributes(serverAttrs(u)...)...)
}),
- nats.ReconnectErrHandler(func(conn *nats.Conn, err error) {
- addr, port := serverAddrPort(conn)
+ nats.ReconnectHandler(func(conn *nats.Conn) {
+ u := serverURL(conn)
+ addr, port := serverAddrPort(u)
reconnects.Add(ctx, 1, addr, reconnects.AttrServerPort(port))
- l.Info("reconnect", zap.Error(err),
- zap.String("addr", conn.ConnectedUrlRedacted()),
- zap.String("server_id", conn.ConnectedServerId()),
- )
+ l.Info("reconnected", log.Attributes(serverAttrs(u)...)...)
+ }),
+
+ nats.ReconnectErrHandler(func(conn *nats.Conn, err error) {
+ log.WithError(l, err).Warn("reconnect failed", log.Attributes(serverAttrs(serverURL(conn))...)...)
}),
nats.ErrorHandler(func(conn *nats.Conn, sub *nats.Subscription, err error) {
@@ -85,35 +103,31 @@ func Connect(s keel.Runtime, rawURL string, opts ...nats.Option) (*nats.Conn, er
extraAttrs = append(extraAttrs, asyncErrors.AttrSubject(sub.Subject))
}
- if addr, _ := serverAddrPort(conn); addr != "" {
+ u := serverURL(conn)
+ if addr, _ := serverAddrPort(u); addr != "" {
extraAttrs = append(extraAttrs, asyncErrors.AttrServerAddress(addr))
}
asyncErrors.Add(ctx, 1, kind, extraAttrs...)
- fields := []zap.Field{
- zap.Error(err),
- zap.String("kind", string(kind)),
- zap.String("addr", conn.ConnectedUrlRedacted()),
- }
+ // kind is the error.type; WithError would add the Go type name instead
+ attrs := append(serverAttrs(u),
+ semconv.ErrorTypeKey.String(string(kind)),
+ semconv.ExceptionMessage(err.Error()),
+ )
if sub != nil {
- fields = append(fields, zap.String("subject", sub.Subject))
+ attrs = append(attrs, semconv.MessagingDestinationName(sub.Subject))
}
- l.Warn("async error", fields...)
+ l.Warn("async error", log.Attributes(attrs...)...)
}),
nats.ClosedHandler(func(conn *nats.Conn) {
- l.Debug("closed",
- zap.String("addr", conn.ConnectedUrlRedacted()),
- zap.String("server_id", conn.ConnectedServerId()),
- )
+ l.Debug("closed", log.Attributes(serverAttrs(serverURL(conn))...)...)
}),
nats.LameDuckModeHandler(func(conn *nats.Conn) {
- l.Info("server lame-duck mode",
- zap.String("addr", conn.ConnectedUrlRedacted()),
- )
+ l.Info("server lame-duck mode", log.Attributes(serverAttrs(serverURL(conn))...)...)
}),
nats.NoCallbacksAfterClientClose(),
@@ -129,27 +143,25 @@ func Connect(s keel.Runtime, rawURL string, opts ...nats.Option) (*nats.Conn, er
return conn, nil
}
-// serverAttrs returns OTel semconv attributes describing the connected server.
-// Returns nil if the connected URL cannot be parsed.
-func serverAttrs(nc *nats.Conn) []attribute.KeyValue {
- u, err := url.Parse(nc.ConnectedUrlRedacted())
- if err != nil {
+// serverAttrs returns OTel semconv attributes describing the server at
+// rawURL. Returns nil if rawURL is empty or cannot be parsed.
+func serverAttrs(rawURL string) []attribute.KeyValue {
+ addr, port := serverAddrPort(rawURL)
+ if addr == "" {
return nil
}
- port, _ := strconv.Atoi(u.Port())
-
return []attribute.KeyValue{
- semconv.ServerAddress(u.Hostname()),
+ semconv.ServerAddress(addr),
semconv.ServerPort(port),
semconv.NetworkProtocolName("nats"),
}
}
-// serverAddrPort extracts just the address and port from the connected URL.
+// serverAddrPort extracts just the address and port from rawURL.
// Returns zero values if parsing fails.
-func serverAddrPort(nc *nats.Conn) (string, int) {
- u, err := url.Parse(nc.ConnectedUrlRedacted())
+func serverAddrPort(rawURL string) (string, int) {
+ u, err := url.Parse(rawURL)
if err != nil {
return "", 0
}
diff --git a/integration/nats/connect_test.go b/integration/nats/connect_test.go
new file mode 100644
index 00000000..19127069
--- /dev/null
+++ b/integration/nats/connect_test.go
@@ -0,0 +1,88 @@
+package nats_test
+
+import (
+ "context"
+ "testing"
+ "time"
+
+ testingx "github.com/foomo/go/testing"
+ keelnats "github.com/foomo/keel/integration/nats"
+ "github.com/foomo/keel/integration/nats/service"
+ "github.com/spf13/viper"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+ "go.opentelemetry.io/otel/attribute"
+ "go.opentelemetry.io/otel/metric"
+ sdkmetric "go.opentelemetry.io/otel/sdk/metric"
+ "go.opentelemetry.io/otel/sdk/metric/metricdata"
+ semconv "go.opentelemetry.io/otel/semconv/v1.43.0"
+ "go.opentelemetry.io/otel/trace"
+ "go.opentelemetry.io/otel/trace/noop"
+ "go.uber.org/zap"
+ "go.uber.org/zap/zaptest/observer"
+)
+
+type testRuntime struct {
+ ctx context.Context
+ l *zap.Logger
+ meter metric.Meter
+}
+
+func (r *testRuntime) Logger() *zap.Logger { return r.l }
+func (r *testRuntime) Config() *viper.Viper { return viper.New() }
+func (r *testRuntime) Context() context.Context { return r.ctx }
+func (r *testRuntime) Meter() metric.Meter { return r.meter }
+func (r *testRuntime) Tracer() trace.Tracer { return noop.NewTracerProvider().Tracer("") }
+func (r *testRuntime) AddCloser(any) {}
+func (r *testRuntime) AddClosers(...any) {}
+
+// TestConnect_disconnectServerAttrs asserts that the disconnect metric and log
+// carry the server address although the connection is no longer connected.
+func TestConnect_disconnectServerAttrs(t *testing.T) {
+ t.Parallel()
+
+ srv, err := service.NewEmbeddedServer(
+ service.EmbeddedServerWithPort(testingx.FreePort(t)),
+ service.EmbeddedServerWithHost("localhost"),
+ )
+ require.NoError(t, err)
+
+ go func() { _ = srv.Start(t.Context()) }()
+
+ require.Eventually(t, srv.Server().Running, time.Second, 10*time.Millisecond)
+
+ reader := sdkmetric.NewManualReader()
+ core, logs := observer.New(zap.DebugLevel)
+ rt := &testRuntime{
+ ctx: t.Context(),
+ l: zap.New(core),
+ meter: sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader)).Meter("test"),
+ }
+
+ conn, err := keelnats.Connect(rt, srv.ClientURL())
+ require.NoError(t, err)
+ t.Cleanup(conn.Close)
+
+ require.NoError(t, srv.Close(t.Context()))
+
+ require.Eventually(t, func() bool {
+ return logs.FilterMessage("disconnected").Len() > 0
+ }, 5*time.Second, 10*time.Millisecond)
+
+ assert.Equal(t, "localhost", logs.FilterMessage("disconnected").All()[0].ContextMap()["server_address"])
+
+ var rm metricdata.ResourceMetrics
+ require.NoError(t, reader.Collect(t.Context(), &rm))
+
+ var addr attribute.Value
+
+ for _, sm := range rm.ScopeMetrics {
+ for _, m := range sm.Metrics {
+ if sum, ok := m.Data.(metricdata.Sum[int64]); ok && m.Name == "nats.client.disconnects" {
+ addr, _ = sum.DataPoints[0].Attributes.Value(semconv.ServerAddressKey)
+ }
+ }
+ }
+
+ assert.Equal(t, "localhost", addr.AsString())
+}
diff --git a/integration/nats/go.mod b/integration/nats/go.mod
index 14cfdcaa..285c0f21 100644
--- a/integration/nats/go.mod
+++ b/integration/nats/go.mod
@@ -8,11 +8,15 @@ require (
github.com/foomo/go v0.17.1
github.com/foomo/gofuncy v0.4.0
github.com/foomo/keel v0.31.0
- github.com/foomo/opentelemetry-go v0.4.0
+ github.com/foomo/opentelemetry-go v0.5.0
github.com/nats-io/nats-server/v2 v2.15.0
github.com/nats-io/nats.go v1.54.0
+ github.com/spf13/viper v1.21.0
github.com/stretchr/testify v1.12.1
- go.opentelemetry.io/otel v1.46.0
+ go.opentelemetry.io/otel v1.47.0
+ go.opentelemetry.io/otel/metric v1.47.0
+ go.opentelemetry.io/otel/sdk/metric v1.47.0
+ go.opentelemetry.io/otel/trace v1.47.0
go.uber.org/zap v1.28.0
)
@@ -93,7 +97,6 @@ require (
github.com/spf13/afero v1.15.0 // indirect
github.com/spf13/cast v1.10.0 // indirect
github.com/spf13/pflag v1.0.10 // indirect
- github.com/spf13/viper v1.21.0 // indirect
github.com/spf13/viper/remote v1.21.0 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/tinylib/msgp v1.6.5 // indirect
@@ -121,12 +124,9 @@ require (
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.22.0 // indirect
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.46.0 // indirect
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.46.0 // indirect
- go.opentelemetry.io/otel/log v0.22.0 // indirect
- go.opentelemetry.io/otel/metric v1.46.0 // indirect
- go.opentelemetry.io/otel/sdk v1.46.0 // indirect
+ go.opentelemetry.io/otel/log v1.47.0 // indirect
+ go.opentelemetry.io/otel/sdk v1.47.0 // indirect
go.opentelemetry.io/otel/sdk/log v0.22.0 // indirect
- go.opentelemetry.io/otel/sdk/metric v1.46.0 // indirect
- go.opentelemetry.io/otel/trace v1.46.0 // indirect
go.opentelemetry.io/proto/otlp v1.11.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.yaml.in/yaml/v3 v3.0.5 // indirect
diff --git a/integration/nats/go.sum b/integration/nats/go.sum
index e768e3c3..2423a8d4 100644
--- a/integration/nats/go.sum
+++ b/integration/nats/go.sum
@@ -82,8 +82,8 @@ github.com/foomo/gofuncy v0.4.0 h1:wxfFOQSp+eZYy9YFXY7A8PPu0n51t4Xhvd6tOm0OSSs=
github.com/foomo/gofuncy v0.4.0/go.mod h1:ulEUpkz38K6trv71GM7fHjaUqa/NbWOZUE5MAbfe/Kk=
github.com/foomo/gostandards v0.3.0 h1:Ev88Tdu0+52UH/d0l2KcAWx542A13o42d++LSTG0DC4=
github.com/foomo/gostandards v0.3.0/go.mod h1:8hJ56tpyFAVwavs5FuUF3po7Bq7hOTkQ1+DzFi4GCWg=
-github.com/foomo/opentelemetry-go v0.4.0 h1:UQneCUSokIYJXzFUKQSI8rlelbUuf6atgSZMhvD+Nzo=
-github.com/foomo/opentelemetry-go v0.4.0/go.mod h1:R3Se/rc5FRAs4ThE6JQ9Oq3cOLo2MOsUzZLJxZquwxA=
+github.com/foomo/opentelemetry-go v0.5.0 h1:4MHCj7cRB+Jr8AZsrhQ+J3M/4Gka/mXG0Xv+uv6RNDI=
+github.com/foomo/opentelemetry-go v0.5.0/go.mod h1:3jSEAGFXOJMtFLiLXepEQcr9Fkz1g/JqoWqlcihW/pk=
github.com/foomo/opentelemetry-go/exporters/glossy/glossymetric v0.4.0 h1:o2EScdH3ZgIU2sTHbOnCRXsMr6wTHjAYx63rriQRmtU=
github.com/foomo/opentelemetry-go/exporters/glossy/glossymetric v0.4.0/go.mod h1:RIWQzc+4Y8ur6bs3v9eWduKTPTUSu1WZjcgi8oRwGjs=
github.com/foomo/opentelemetry-go/exporters/glossy/glossytrace v0.4.0 h1:ZbA7PgNO0st/KOAwiJCb7qG5hzIFlSMd6WpozsX28hs=
@@ -378,8 +378,8 @@ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.71.0 h1:3g7B90U
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.71.0/go.mod h1:Ef8SuTh59BT7+ofpDxN9z+yOlc4t2GjLmKDgYNJL/NU=
go.opentelemetry.io/contrib/instrumentation/runtime v0.71.0 h1:v4KkRLVvE1cWqTJDfZZkTCG+Z4aolsa6RVos0FX7vqE=
go.opentelemetry.io/contrib/instrumentation/runtime v0.71.0/go.mod h1:g/xbuPC0XbgwMdKuyF5sKOUUEsorSkN6APydyFP/H9E=
-go.opentelemetry.io/otel v1.46.0 h1:FHt5/CDyVxi/8IM1CH7VE/rRgq3kLHa2mSTVMO8AWyc=
-go.opentelemetry.io/otel v1.46.0/go.mod h1:Gj3SEScelsNC45tp4nSxRYlS+f5iez7W8XPMCt905kE=
+go.opentelemetry.io/otel v1.47.0 h1:j7ALJ/zgkS7Z6aeJW09p8VC9804bC+PpeTfCD4XPnOM=
+go.opentelemetry.io/otel v1.47.0/go.mod h1:8wS9O2qfXrYrzp6hIF/HOYJJf/wIhFPhR2xLuP+iXQU=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.22.0 h1:Bu39F5tzJct+f2IZbB8989fwyTps3c8e7EsUQsz+vs8=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.22.0/go.mod h1:dJUwod88EsFgYCqrDHaSPzhiY9pBUpt0d85/qSfua7k=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.22.0 h1:lYk7RmxdLK865qLwibroNGldHa1U7SWKYYvNjlK7PIo=
@@ -402,24 +402,24 @@ go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.46.0 h1:PR9eAf7o0dQs3h
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.46.0/go.mod h1:2Z4KyNdH1uuzivdinyfGsxzNNT/Rl45pwtVwfYVI0xk=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.46.0 h1:KdRxPiAoMptR3vfWzvjjvutTsSiwbC2uG0496rzZNfo=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.46.0/go.mod h1:K/qSA+3G7Eovxi4K09wzrAgkWRnosS0DAOZeEpve7sM=
-go.opentelemetry.io/otel/log v0.22.0 h1:5DBNnfvaJ6CVdkJ+Jle8Tzs50aSSv49TXGj9XRsEYw0=
-go.opentelemetry.io/otel/log v0.22.0/go.mod h1:gzOt/R67vF2GniAqWu8Qv0SXy89f71muHcrkz76PCdc=
+go.opentelemetry.io/otel/log v1.47.0 h1:cOTS1CcLbSQeZKanGJ+0JpF/+t4PELi3O3bbl2lqCcI=
+go.opentelemetry.io/otel/log v1.47.0/go.mod h1:9byitSQ5pLC6PpqwGXjqdMKya6ZTswHRZh2vvXT33nw=
go.opentelemetry.io/otel/log/logtest v0.22.0 h1:0pvI8BwoRN7c0KVXqzSdZQgkFdsNBL/aokbSp3boQec=
go.opentelemetry.io/otel/log/logtest v0.22.0/go.mod h1:9+PjkCcSiKB2CEn3LYZ6Y3c37KJs7fziPXNiuyQGmRQ=
-go.opentelemetry.io/otel/metric v1.46.0 h1:yBnkXvgV7AXFILZc5K6IZe/CBFF3OS7BJ8ov6/lj0K8=
-go.opentelemetry.io/otel/metric v1.46.0/go.mod h1:iPmdWqifKUdzziPkvvzIJXITl56fQx2mGM/DHLB3/2o=
-go.opentelemetry.io/otel/metric/x v0.68.0 h1:TA/cBT23D3MnxYPwHL7YFOdYGdx0A0v+s7Mzotpd1dU=
-go.opentelemetry.io/otel/metric/x v0.68.0/go.mod h1:agudOmvWhwUTjgibWDzxD2PoWYnpw5Ht5jISYOD2Hd4=
-go.opentelemetry.io/otel/sdk v1.46.0 h1:h5CNQQjEbuQXY/JfZtgt3i7HVFV3aHPO2OAwO2eTYPI=
-go.opentelemetry.io/otel/sdk v1.46.0/go.mod h1:GAERFXFt5SYCEB+YiKUbMBeza6UaDH7GmGOZEfh2gSM=
+go.opentelemetry.io/otel/metric v1.47.0 h1:4PptaldXx3Eat1XjMZ68pPJEs5wrhlemctZE9a3UdWY=
+go.opentelemetry.io/otel/metric v1.47.0/go.mod h1:ADGSXxRrXM6bjbvLo535EstVFlPpPYZm4LBKixjDHwU=
+go.opentelemetry.io/otel/metric/x v0.69.0 h1:DjRLr15H83v+hCW7JA9NoJvOkYTtmq5YoDRbe9deYpM=
+go.opentelemetry.io/otel/metric/x v0.69.0/go.mod h1:uVvsMPMFFyj/HUQfrUnH3JjnOQ1dwFDorgFLRBasM0k=
+go.opentelemetry.io/otel/sdk v1.47.0 h1:zWXEr4j2lFefG87TU6Yg8a7ngfohIKFZHKp0Hf5hC6I=
+go.opentelemetry.io/otel/sdk v1.47.0/go.mod h1:VUc24kiOeoGsxG8G9ULx3fWKvB7jMhnGE8Oi607lgR0=
go.opentelemetry.io/otel/sdk/log v0.22.0 h1:PRL+s6P63XT4E/bheEflopPUpVxuvANqZwtt89yhoGk=
go.opentelemetry.io/otel/sdk/log v0.22.0/go.mod h1:JNp0sBELrjCTcu5W3GzABVypeU6vDJjBS+X0JISuz+g=
go.opentelemetry.io/otel/sdk/log/logtest v0.22.0 h1:infPnfNrhCNgOUZRs3gWUg8vhoBUHihq02gwK05gzlg=
go.opentelemetry.io/otel/sdk/log/logtest v0.22.0/go.mod h1:gkQZA3z15Bv3KU9vigBTi8dFechSozRP7v94X4VZv+s=
-go.opentelemetry.io/otel/sdk/metric v1.46.0 h1:0piZ26EG4RBfebb2jhDH6ERCYHoVWduc3kLgPCwSnSE=
-go.opentelemetry.io/otel/sdk/metric v1.46.0/go.mod h1:I1PbKrdVc8Qu8HYVDNtqVIwLwjNrhsV/uFuxfwg8mO4=
-go.opentelemetry.io/otel/trace v1.46.0 h1:OULy7ccdJnZtJ0UDYFOIGaCmiWzJ8Vi2G/Rsu60qs1c=
-go.opentelemetry.io/otel/trace v1.46.0/go.mod h1:J7GAXweO77XSFkB/rmAqk9D6ihszhFjLU+d9WuUxDLI=
+go.opentelemetry.io/otel/sdk/metric v1.47.0 h1:lfISg2j93VT6yqdk9OfUaZmw/GfcZqCCV3jdXtsPnKw=
+go.opentelemetry.io/otel/sdk/metric v1.47.0/go.mod h1:ypLp+mW1Nt2x+Szt3b5/i1syodyts49lMOwxpDI3VGw=
+go.opentelemetry.io/otel/trace v1.47.0 h1:JOjX/Oci8K94QHddo+bbfya/Ai/nf6/dt9ZfrFNWSrM=
+go.opentelemetry.io/otel/trace v1.47.0/go.mod h1:jNaSLa2PZEYFG6fRjJABAu+bw4FS08uDmPg28lTghu0=
go.opentelemetry.io/proto/otlp v1.11.0 h1:5rrYs0Ykyj50sdU/JU0x8etU+LubXWb+gED6TbEdMIk=
go.opentelemetry.io/proto/otlp v1.11.0/go.mod h1:SmVizdCOAm3XBtG1g1NnOdhW6jtddT72hLMhv8VwA8E=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
diff --git a/integration/nats/jetstream.go b/integration/nats/jetstream.go
index 2e92a0c6..e737676b 100644
--- a/integration/nats/jetstream.go
+++ b/integration/nats/jetstream.go
@@ -5,10 +5,12 @@ import (
"time"
"github.com/foomo/keel"
+ "github.com/foomo/keel/log"
"github.com/foomo/opentelemetry-go/semconv/natsconv"
"github.com/nats-io/nats.go"
"github.com/nats-io/nats.go/jetstream"
- "go.uber.org/zap"
+ "go.opentelemetry.io/otel"
+ semconv "go.opentelemetry.io/otel/semconv/v1.43.0"
)
// NewJetStream creates a JetStream context on nc with production-sensible
@@ -24,7 +26,7 @@ func NewJetStream(s keel.Runtime, nc *nats.Conn, opts ...jetstream.JetStreamOpt)
asyncErrors, err := natsconv.NewClientAsyncErrors(m)
if err != nil {
- return nil, err
+ otel.Handle(err)
}
ctx := context.Background()
@@ -35,12 +37,9 @@ func NewJetStream(s keel.Runtime, nc *nats.Conn, opts ...jetstream.JetStreamOpt)
jetstream.WithPublishAsyncMaxPending(256),
jetstream.WithPublishAsyncTimeout(10 * time.Second),
jetstream.WithPublishAsyncErrHandler(func(_ jetstream.JetStream, msg *nats.Msg, err error) {
- asyncErrors.Add(ctx, 1, natsconv.AsyncErrorKindOther,
- asyncErrors.AttrSubject(msg.Subject),
- )
- l.Error("publish async error",
- zap.Error(err),
- zap.String("subject", msg.Subject),
+ asyncErrors.Add(ctx, 1, natsconv.AsyncErrorKindOther)
+ log.WithError(l, err).Error("publish async error",
+ log.Attribute(semconv.MessagingDestinationName(msg.Subject)),
)
}),
}, opts...)
diff --git a/integration/temporal/client.go b/integration/temporal/client.go
index bb100a4f..df29a7c8 100644
--- a/integration/temporal/client.go
+++ b/integration/temporal/client.go
@@ -173,7 +173,10 @@ func NewClient(ctx context.Context, endpoint string, opts ...ClientOption) (clie
}
clientOpts.Interceptors = append(clientOpts.Interceptors, tracingInterceptor)
- clientOpts.MetricsHandler = NewMetricsHandler(telemetry.Meter())
+ clientOpts.MetricsHandler = opentelemetry.NewMetricsHandler(opentelemetry.MetricsHandlerOptions{
+ Meter: telemetry.Meter(),
+ OnError: otel.Handle,
+ })
}
return client.Dial(clientOpts)
diff --git a/integration/temporal/doc.go b/integration/temporal/doc.go
index c5b8aa38..4b639aa4 100644
--- a/integration/temporal/doc.go
+++ b/integration/temporal/doc.go
@@ -3,9 +3,8 @@
//
// It covers client construction with optional namespace registration and
// OpenTelemetry instrumentation ([NewClient]), a keel service wrapper for
-// Temporal workers ([NewService]), adapters bridging Temporal's logger and
-// metrics interfaces to zap and OpenTelemetry ([NewLogger],
-// [NewMetricsHandler]), activity option helpers ([WithActivityOptions]) and
+// Temporal workers ([NewService]), an adapter bridging Temporal's logger to
+// zap ([NewLogger]), activity option helpers ([WithActivityOptions]) and
// error classification helpers ([NewActivityError], [IsActivityError],
// [AsApplicationError]).
//
diff --git a/integration/temporal/go.mod b/integration/temporal/go.mod
index 7fffbbbb..da17522b 100644
--- a/integration/temporal/go.mod
+++ b/integration/temporal/go.mod
@@ -8,8 +8,8 @@ require (
github.com/foomo/go v0.17.1
github.com/foomo/keel v0.31.0
github.com/pkg/errors v0.9.1
- go.opentelemetry.io/otel v1.46.0
- go.opentelemetry.io/otel/metric v1.46.0
+ go.opentelemetry.io/otel v1.47.0
+ go.opentelemetry.io/otel/metric v1.47.0
go.temporal.io/api v1.63.6
go.temporal.io/sdk v1.49.0
go.temporal.io/sdk/contrib/opentelemetry v0.8.1
@@ -23,7 +23,7 @@ require (
github.com/ebitengine/purego v0.10.2 // indirect
github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a // indirect
github.com/fbiville/markdown-table-formatter v0.3.0 // indirect
- github.com/foomo/opentelemetry-go v0.4.0 // indirect
+ github.com/foomo/opentelemetry-go v0.5.0 // indirect
github.com/go-logr/logr v1.4.4 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
@@ -68,11 +68,11 @@ require (
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.22.0 // indirect
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.46.0 // indirect
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.46.0 // indirect
- go.opentelemetry.io/otel/log v0.22.0 // indirect
- go.opentelemetry.io/otel/sdk v1.46.0 // indirect
+ go.opentelemetry.io/otel/log v1.47.0 // indirect
+ go.opentelemetry.io/otel/sdk v1.47.0 // indirect
go.opentelemetry.io/otel/sdk/log v0.22.0 // indirect
- go.opentelemetry.io/otel/sdk/metric v1.46.0 // indirect
- go.opentelemetry.io/otel/trace v1.46.0 // indirect
+ go.opentelemetry.io/otel/sdk/metric v1.47.0 // indirect
+ go.opentelemetry.io/otel/trace v1.47.0 // indirect
go.opentelemetry.io/proto/otlp v1.11.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.yaml.in/yaml/v3 v3.0.5 // indirect
diff --git a/integration/temporal/go.sum b/integration/temporal/go.sum
index 859b481b..ee3bda61 100644
--- a/integration/temporal/go.sum
+++ b/integration/temporal/go.sum
@@ -12,8 +12,8 @@ github.com/fbiville/markdown-table-formatter v0.3.0 h1:PIm1UNgJrFs8q1htGTw+wnnNY
github.com/fbiville/markdown-table-formatter v0.3.0/go.mod h1:q89TDtSEVDdTaufgSbfHpNVdPU/bmfvqNkrC5HagmLY=
github.com/foomo/go v0.17.1 h1:tDrovWbh1dOzsBX19pII6nAPIECswhBmNSPEGBYNawY=
github.com/foomo/go v0.17.1/go.mod h1:Zz5aBFte6ayLEJ17n4L1bqYmEEja9xTeLKC0Z1wAy+0=
-github.com/foomo/opentelemetry-go v0.4.0 h1:UQneCUSokIYJXzFUKQSI8rlelbUuf6atgSZMhvD+Nzo=
-github.com/foomo/opentelemetry-go v0.4.0/go.mod h1:R3Se/rc5FRAs4ThE6JQ9Oq3cOLo2MOsUzZLJxZquwxA=
+github.com/foomo/opentelemetry-go v0.5.0 h1:4MHCj7cRB+Jr8AZsrhQ+J3M/4Gka/mXG0Xv+uv6RNDI=
+github.com/foomo/opentelemetry-go v0.5.0/go.mod h1:3jSEAGFXOJMtFLiLXepEQcr9Fkz1g/JqoWqlcihW/pk=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.4 h1:tG4xh9yMsRCAiodLVTxyrkzSZ9+o0L1Kg/+cPVcbP/8=
github.com/go-logr/logr v1.4.4/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
@@ -95,8 +95,8 @@ go.opentelemetry.io/contrib/instrumentation/host v0.71.0 h1:w4LFwIdxvbuLJFS4GgUS
go.opentelemetry.io/contrib/instrumentation/host v0.71.0/go.mod h1:3bLYpeWrDSzFnG5Hvuz7EON6f+ZbcRo/NriKeIXh72E=
go.opentelemetry.io/contrib/instrumentation/runtime v0.71.0 h1:v4KkRLVvE1cWqTJDfZZkTCG+Z4aolsa6RVos0FX7vqE=
go.opentelemetry.io/contrib/instrumentation/runtime v0.71.0/go.mod h1:g/xbuPC0XbgwMdKuyF5sKOUUEsorSkN6APydyFP/H9E=
-go.opentelemetry.io/otel v1.46.0 h1:FHt5/CDyVxi/8IM1CH7VE/rRgq3kLHa2mSTVMO8AWyc=
-go.opentelemetry.io/otel v1.46.0/go.mod h1:Gj3SEScelsNC45tp4nSxRYlS+f5iez7W8XPMCt905kE=
+go.opentelemetry.io/otel v1.47.0 h1:j7ALJ/zgkS7Z6aeJW09p8VC9804bC+PpeTfCD4XPnOM=
+go.opentelemetry.io/otel v1.47.0/go.mod h1:8wS9O2qfXrYrzp6hIF/HOYJJf/wIhFPhR2xLuP+iXQU=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.22.0 h1:Bu39F5tzJct+f2IZbB8989fwyTps3c8e7EsUQsz+vs8=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.22.0/go.mod h1:dJUwod88EsFgYCqrDHaSPzhiY9pBUpt0d85/qSfua7k=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.22.0 h1:lYk7RmxdLK865qLwibroNGldHa1U7SWKYYvNjlK7PIo=
@@ -119,24 +119,24 @@ go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.46.0 h1:PR9eAf7o0dQs3h
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.46.0/go.mod h1:2Z4KyNdH1uuzivdinyfGsxzNNT/Rl45pwtVwfYVI0xk=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.46.0 h1:KdRxPiAoMptR3vfWzvjjvutTsSiwbC2uG0496rzZNfo=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.46.0/go.mod h1:K/qSA+3G7Eovxi4K09wzrAgkWRnosS0DAOZeEpve7sM=
-go.opentelemetry.io/otel/log v0.22.0 h1:5DBNnfvaJ6CVdkJ+Jle8Tzs50aSSv49TXGj9XRsEYw0=
-go.opentelemetry.io/otel/log v0.22.0/go.mod h1:gzOt/R67vF2GniAqWu8Qv0SXy89f71muHcrkz76PCdc=
+go.opentelemetry.io/otel/log v1.47.0 h1:cOTS1CcLbSQeZKanGJ+0JpF/+t4PELi3O3bbl2lqCcI=
+go.opentelemetry.io/otel/log v1.47.0/go.mod h1:9byitSQ5pLC6PpqwGXjqdMKya6ZTswHRZh2vvXT33nw=
go.opentelemetry.io/otel/log/logtest v0.22.0 h1:0pvI8BwoRN7c0KVXqzSdZQgkFdsNBL/aokbSp3boQec=
go.opentelemetry.io/otel/log/logtest v0.22.0/go.mod h1:9+PjkCcSiKB2CEn3LYZ6Y3c37KJs7fziPXNiuyQGmRQ=
-go.opentelemetry.io/otel/metric v1.46.0 h1:yBnkXvgV7AXFILZc5K6IZe/CBFF3OS7BJ8ov6/lj0K8=
-go.opentelemetry.io/otel/metric v1.46.0/go.mod h1:iPmdWqifKUdzziPkvvzIJXITl56fQx2mGM/DHLB3/2o=
-go.opentelemetry.io/otel/metric/x v0.68.0 h1:TA/cBT23D3MnxYPwHL7YFOdYGdx0A0v+s7Mzotpd1dU=
-go.opentelemetry.io/otel/metric/x v0.68.0/go.mod h1:agudOmvWhwUTjgibWDzxD2PoWYnpw5Ht5jISYOD2Hd4=
-go.opentelemetry.io/otel/sdk v1.46.0 h1:h5CNQQjEbuQXY/JfZtgt3i7HVFV3aHPO2OAwO2eTYPI=
-go.opentelemetry.io/otel/sdk v1.46.0/go.mod h1:GAERFXFt5SYCEB+YiKUbMBeza6UaDH7GmGOZEfh2gSM=
+go.opentelemetry.io/otel/metric v1.47.0 h1:4PptaldXx3Eat1XjMZ68pPJEs5wrhlemctZE9a3UdWY=
+go.opentelemetry.io/otel/metric v1.47.0/go.mod h1:ADGSXxRrXM6bjbvLo535EstVFlPpPYZm4LBKixjDHwU=
+go.opentelemetry.io/otel/metric/x v0.69.0 h1:DjRLr15H83v+hCW7JA9NoJvOkYTtmq5YoDRbe9deYpM=
+go.opentelemetry.io/otel/metric/x v0.69.0/go.mod h1:uVvsMPMFFyj/HUQfrUnH3JjnOQ1dwFDorgFLRBasM0k=
+go.opentelemetry.io/otel/sdk v1.47.0 h1:zWXEr4j2lFefG87TU6Yg8a7ngfohIKFZHKp0Hf5hC6I=
+go.opentelemetry.io/otel/sdk v1.47.0/go.mod h1:VUc24kiOeoGsxG8G9ULx3fWKvB7jMhnGE8Oi607lgR0=
go.opentelemetry.io/otel/sdk/log v0.22.0 h1:PRL+s6P63XT4E/bheEflopPUpVxuvANqZwtt89yhoGk=
go.opentelemetry.io/otel/sdk/log v0.22.0/go.mod h1:JNp0sBELrjCTcu5W3GzABVypeU6vDJjBS+X0JISuz+g=
go.opentelemetry.io/otel/sdk/log/logtest v0.22.0 h1:infPnfNrhCNgOUZRs3gWUg8vhoBUHihq02gwK05gzlg=
go.opentelemetry.io/otel/sdk/log/logtest v0.22.0/go.mod h1:gkQZA3z15Bv3KU9vigBTi8dFechSozRP7v94X4VZv+s=
-go.opentelemetry.io/otel/sdk/metric v1.46.0 h1:0piZ26EG4RBfebb2jhDH6ERCYHoVWduc3kLgPCwSnSE=
-go.opentelemetry.io/otel/sdk/metric v1.46.0/go.mod h1:I1PbKrdVc8Qu8HYVDNtqVIwLwjNrhsV/uFuxfwg8mO4=
-go.opentelemetry.io/otel/trace v1.46.0 h1:OULy7ccdJnZtJ0UDYFOIGaCmiWzJ8Vi2G/Rsu60qs1c=
-go.opentelemetry.io/otel/trace v1.46.0/go.mod h1:J7GAXweO77XSFkB/rmAqk9D6ihszhFjLU+d9WuUxDLI=
+go.opentelemetry.io/otel/sdk/metric v1.47.0 h1:lfISg2j93VT6yqdk9OfUaZmw/GfcZqCCV3jdXtsPnKw=
+go.opentelemetry.io/otel/sdk/metric v1.47.0/go.mod h1:ypLp+mW1Nt2x+Szt3b5/i1syodyts49lMOwxpDI3VGw=
+go.opentelemetry.io/otel/trace v1.47.0 h1:JOjX/Oci8K94QHddo+bbfya/Ai/nf6/dt9ZfrFNWSrM=
+go.opentelemetry.io/otel/trace v1.47.0/go.mod h1:jNaSLa2PZEYFG6fRjJABAu+bw4FS08uDmPg28lTghu0=
go.opentelemetry.io/proto/otlp v1.11.0 h1:5rrYs0Ykyj50sdU/JU0x8etU+LubXWb+gED6TbEdMIk=
go.opentelemetry.io/proto/otlp v1.11.0/go.mod h1:SmVizdCOAm3XBtG1g1NnOdhW6jtddT72hLMhv8VwA8E=
go.temporal.io/api v1.63.6 h1:LoV2ubLM9M5uiGeBcYCSCTmHAPGQPy18dC8Vcw8TciQ=
diff --git a/integration/temporal/metrics.go b/integration/temporal/metrics.go
index 702e9dea..9391be80 100644
--- a/integration/temporal/metrics.go
+++ b/integration/temporal/metrics.go
@@ -1,119 +1,20 @@
package keeltemporal
import (
- "context"
- "time"
-
"go.opentelemetry.io/otel"
- "go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/metric"
"go.temporal.io/sdk/client"
+ "go.temporal.io/sdk/contrib/opentelemetry"
)
-// metricsHandler implements [client.MetricsHandler] on top of an
-// OpenTelemetry meter.
-type metricsHandler struct {
- meter metric.Meter
- attr []attribute.KeyValue
-}
-
// NewMetricsHandler returns a Temporal metrics handler that records counters,
-// gauges and timers with meter. Instrument creation errors are reported via
-// [otel.Handle].
+// gauges and timers (in seconds) with meter. Instrument creation errors are
+// reported via [otel.Handle].
+//
+// Deprecated: Use [opentelemetry.NewMetricsHandler] instead.
func NewMetricsHandler(meter metric.Meter) client.MetricsHandler {
- return metricsHandler{meter: meter}
-}
-
-// WithTags returns a handler whose instruments record tags as string
-// attributes. Tags replace any previously set tags.
-func (m metricsHandler) WithTags(tags map[string]string) client.MetricsHandler {
- attr := make([]attribute.KeyValue, 0, len(tags))
- for k, v := range tags {
- attr = append(attr, attribute.String(k, v))
- }
-
- return metricsHandler{meter: m.meter, attr: attr}
-}
-
-// counter adapts an Int64Counter to [client.MetricsCounter].
-type counter struct {
- inst metric.Int64Counter
- attr []attribute.KeyValue
-}
-
-// Inc adds v to the counter.
-func (c *counter) Inc(v int64) {
- c.inst.Add(context.Background(), v, metric.WithAttributes(c.attr...))
-}
-
-// Counter returns an Int64Counter instrument with the given name.
-func (m metricsHandler) Counter(name string) client.MetricsCounter {
- c, err := m.meter.Int64Counter(name)
- if err != nil {
- otel.Handle(err)
- }
-
- return &counter{
- attr: m.attr,
- inst: c,
- }
-}
-
-// gauge adapts a Float64ObservableGauge to [client.MetricsGauge]; the last
-// updated value is reported on each collection.
-type gauge struct {
- inst metric.Float64ObservableGauge
- value float64
-}
-
-// Update sets the value reported by the gauge.
-func (c *gauge) Update(v float64) {
- c.value = v
-}
-
-// Gauge returns a Float64ObservableGauge instrument with the given name.
-func (m metricsHandler) Gauge(name string) client.MetricsGauge {
- c, err := m.meter.Float64ObservableGauge(name)
- if err != nil {
- otel.Handle(err)
- }
-
- inst := &gauge{
- inst: c,
- }
-
- _, err = m.meter.RegisterCallback(func(ctx context.Context, o metric.Observer) error {
- o.ObserveFloat64(c, inst.value, metric.WithAttributes(m.attr...))
- return nil
+ return opentelemetry.NewMetricsHandler(opentelemetry.MetricsHandlerOptions{
+ Meter: meter,
+ OnError: otel.Handle,
})
- if err != nil {
- otel.Handle(err)
- }
-
- return inst
-}
-
-// timer adapts an Int64Histogram to [client.MetricsTimer].
-type timer struct {
- inst metric.Int64Histogram
- attr []attribute.KeyValue
-}
-
-// Record records v in milliseconds.
-func (c *timer) Record(v time.Duration) {
- c.inst.Record(context.TODO(), v.Milliseconds(), metric.WithAttributes(c.attr...))
-}
-
-// Timer returns an Int64Histogram instrument with the given name that records
-// durations in milliseconds.
-func (m metricsHandler) Timer(name string) client.MetricsTimer {
- c, err := m.meter.Int64Histogram(name)
- if err != nil {
- otel.Handle(err)
- }
-
- return &timer{
- inst: c,
- attr: m.attr,
- }
}
diff --git a/job.go b/job.go
index 3444f8bc..cb8deefe 100644
--- a/job.go
+++ b/job.go
@@ -2,7 +2,6 @@ package keel
import (
"context"
- "fmt"
"os"
"os/signal"
"slices"
@@ -87,7 +86,7 @@ func NewJob(opts ...JobOption) *Job {
inst.name = env.Get("OTEL_SERVICE_NAME", telemetry.DefaultServiceName)
}
- inst.l = log.WithAttributes(inst.l, keelsemconv.KeelServiceType("job"), keelsemconv.KeelServiceName(inst.name))
+ inst.l = log.WithAttributes(inst.l, keelsemconv.KeelServiceType(keelsemconv.KeelServiceTypeJob), keelsemconv.KeelServiceName(inst.name))
{ // setup telemetry
otel.SetLogger(logr.New(internalotel.NewLogger(inst.l)))
@@ -150,7 +149,7 @@ func (j *Job) AddStep(name string, fn StepFn) {
// twice is a no-op.
func (j *Job) AddCloser(closer any) {
if !IsCloser(closer) {
- j.l.Warn("unable to add closer", log.FValue(fmt.Sprintf("%T", closer)))
+ j.l.Warn("unable to add closer", log.Attribute(keelsemconv.KeelCloserType(closer)))
return
}
@@ -203,9 +202,9 @@ func (j *Job) RunE() error {
err := j.run(ctx)
if err != nil {
- log.WithError(j.l, err).Error("keel job failed", log.FDuration(time.Since(start)))
+ log.WithError(j.l, err).Error("keel job failed", log.Attribute(keelsemconv.Duration(time.Since(start))))
} else {
- j.l.Info("keel job completed", log.FDuration(time.Since(start)))
+ j.l.Info("keel job completed", log.Attribute(keelsemconv.Duration(time.Since(start))))
}
return err
@@ -265,17 +264,17 @@ func (j *Job) runSteps(ctx context.Context) error {
// execStep adapts a StepFn to gofuncy's Func, adding the per-step logger and
// completion logging. The span, panic recovery, and metrics are gofuncy's.
func (j *Job) execStep(ctx context.Context, step jobStep) error {
- l := j.l.With(zap.String("keel_job_step", step.name))
+ l := j.l.With(log.Attribute(keelsemconv.KeelJobStep(step.name)))
l.Info("starting keel job step")
start := time.Now()
if err := step.fn(ctx, l); err != nil {
- log.WithError(l, err).Error("keel job step failed", log.FDuration(time.Since(start)))
+ log.WithError(l, err).Error("keel job step failed", log.Attribute(keelsemconv.Duration(time.Since(start))))
return err
}
- l.Info("keel job step completed", log.FDuration(time.Since(start)))
+ l.Info("keel job step completed", log.Attribute(keelsemconv.Duration(time.Since(start))))
return nil
}
@@ -287,7 +286,7 @@ func (j *Job) finalize() {
ctx, cancel := context.WithTimeout(context.WithoutCancel(j.ctx), j.gracefulPeriod)
defer cancel()
- j.l.Info("keel job finalize", zap.Duration("graceful_period", j.gracefulPeriod))
+ j.l.Info("keel job finalize", log.Attribute(keelsemconv.KeelGracefulPeriod(j.gracefulPeriod)))
for _, push := range j.pushers {
if err := push(ctx); err != nil {
diff --git a/keeltest/server.go b/keeltest/server.go
index 1165dd5b..e1b42b9d 100644
--- a/keeltest/server.go
+++ b/keeltest/server.go
@@ -119,7 +119,7 @@ func (s *Server) Start() {
for _, service := range s.services {
s.serviceMap[service.Name()] = service
if err := service.Start(s.Context()); err != nil {
- s.l.Error("failed to start service", log.FError(err))
+ log.WithError(s.l, err).Error("failed to start service")
}
}
}
@@ -129,7 +129,7 @@ func (s *Server) Start() {
func (s *Server) Close() {
for _, service := range s.services {
if err := service.Close(context.WithoutCancel(s.Context())); err != nil {
- s.l.Error("failed to close service", log.FError(err))
+ log.WithError(s.l, err).Error("failed to close service")
}
}
}
diff --git a/keeltest/servicehttp.go b/keeltest/servicehttp.go
index da9b0db1..cfe94000 100644
--- a/keeltest/servicehttp.go
+++ b/keeltest/servicehttp.go
@@ -8,7 +8,7 @@ import (
"strings"
keelhttp "github.com/foomo/keel/net/http"
- semconv "go.opentelemetry.io/otel/semconv/v1.41.0"
+ semconv "go.opentelemetry.io/otel/semconv/v1.43.0"
"go.uber.org/zap"
"github.com/foomo/keel/log"
diff --git a/log/configure.go b/log/configure.go
index c76a6a25..1c49270c 100644
--- a/log/configure.go
+++ b/log/configure.go
@@ -27,9 +27,9 @@ func (c *Config) Logger() *zap.Logger {
return c.l
}
-// Error adds err using [FError].
+// Error adds err using [WithError].
func (c *Config) Error(err error) *Config {
- c.l = c.l.With(FError(err))
+ c.l = WithError(c.l, err)
return c
}
diff --git a/log/doc.go b/log/doc.go
index 93ae91e8..6890b013 100644
--- a/log/doc.go
+++ b/log/doc.go
@@ -8,13 +8,20 @@
//
// # Fields
//
-// F* functions create single [zap.Field] values with well-known keys, and
-// [Attribute] and [Attributes] convert OpenTelemetry attributes to fields.
-// With* functions return a child logger with fields added, e.g. from an
-// [net/http.Request]:
+// [Attribute] and [Attributes] convert OpenTelemetry attributes to fields, so
+// the same semconv attributes can be shared between logs, metrics and traces.
+// Use the upstream go.opentelemetry.io/otel/semconv package or
+// github.com/foomo/keel/semconv for keel specific keys. With* functions return
+// a child logger with fields added, e.g. from an [net/http.Request]:
//
// l := log.WithHTTPRequest(nil, r)
-// l.Info("handled", log.FDuration(time.Since(start)))
+// l.Info("handled", log.Attribute(keelsemconv.Duration(time.Since(start))))
+//
+// F* functions create single [zap.Field] values with legacy keys and are kept
+// for backward compatibility.
+//
+// TODO: deprecate the remaining F* functions and *Key constants in the next
+// version in favor of semconv attributes with [Attribute] and [Attributes].
//
// A [Labeler] stored in a context collects fields that are added while a
// request is processed.
diff --git a/log/fields_messaging.go b/log/fields_messaging.go
index 59049267..52963506 100644
--- a/log/fields_messaging.go
+++ b/log/fields_messaging.go
@@ -1,7 +1,7 @@
package log
import (
- semconv "go.opentelemetry.io/otel/semconv/v1.41.0"
+ semconv "go.opentelemetry.io/otel/semconv/v1.43.0"
"go.uber.org/zap"
)
diff --git a/log/fields_net.go b/log/fields_net.go
index 8651b211..e41fca88 100644
--- a/log/fields_net.go
+++ b/log/fields_net.go
@@ -1,7 +1,7 @@
package log
import (
- semconv "go.opentelemetry.io/otel/semconv/v1.41.0"
+ semconv "go.opentelemetry.io/otel/semconv/v1.43.0"
"go.uber.org/zap"
)
diff --git a/log/logger.go b/log/logger.go
index 51dc0ac1..159f7883 100644
--- a/log/logger.go
+++ b/log/logger.go
@@ -1,7 +1,7 @@
package log
import (
- semconv "go.opentelemetry.io/otel/semconv/v1.41.0"
+ semconv "go.opentelemetry.io/otel/semconv/v1.43.0"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
diff --git a/log/must.go b/log/must.go
index d0327646..09853e02 100644
--- a/log/must.go
+++ b/log/must.go
@@ -20,6 +20,6 @@ func Must(l *zap.Logger, err error, msgAndArgs ...any) {
msg, msgAndArgs = fmt.Sprintf("%v", msgAndArgs[0]), msgAndArgs[1:]
}
- l.WithOptions(zap.AddCallerSkip(1)).Fatal(fmt.Sprintf(msg, msgAndArgs...), FError(err))
+ WithError(l, err).WithOptions(zap.AddCallerSkip(1)).Fatal(fmt.Sprintf(msg, msgAndArgs...))
}
}
diff --git a/log/with.go b/log/with.go
index e4315588..0378cb88 100644
--- a/log/with.go
+++ b/log/with.go
@@ -9,11 +9,12 @@ import (
foomosemconv "github.com/foomo/opentelemetry-go/semconv"
"go.opentelemetry.io/otel/attribute"
- semconv "go.opentelemetry.io/otel/semconv/v1.41.0"
+ semconv "go.opentelemetry.io/otel/semconv/v1.43.0"
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap"
keelhttpcontext "github.com/foomo/keel/net/http/context"
+ keelsemconv "github.com/foomo/keel/semconv"
)
// With returns a child of l with fields added. A nil l selects [Logger].
@@ -40,10 +41,14 @@ func WithAttributes(l *zap.Logger, attrs ...attribute.KeyValue) *zap.Logger {
return l.With(fields...)
}
-// WithError returns a child of l with the error type and message of err.
-// It panics if err is nil.
+// WithError returns a child of l with the semconv error type and exception
+// message of err. A nil err adds nothing.
func WithError(l *zap.Logger, err error) *zap.Logger {
- return With(l, FErrorType(err), FError(err))
+ if err == nil {
+ return With(l)
+ }
+
+ return WithAttributes(l, foomosemconv.ErrorType(err), semconv.ExceptionMessage(err.Error()))
}
// WithServiceName returns a child of l with the semconv service name.
@@ -55,7 +60,10 @@ func WithServiceName(l *zap.Logger, name string) *zap.Logger {
// in ctx, or l unchanged if that span is invalid or not sampled.
func WithTraceID(l *zap.Logger, ctx context.Context) *zap.Logger {
if spanCtx := trace.SpanContextFromContext(ctx); spanCtx.IsValid() && spanCtx.IsSampled() {
- l = With(l, FTraceID(spanCtx.TraceID().String()), FSpanID(spanCtx.SpanID().String()))
+ l = WithAttributes(l,
+ keelsemconv.TraceID(spanCtx.TraceID().String()),
+ keelsemconv.SpanID(spanCtx.SpanID().String()),
+ )
}
return l
@@ -98,9 +106,9 @@ func WithHTTPSessionID(l *zap.Logger, r *http.Request) *zap.Logger {
// X-Request-ID header or the request context, or l unchanged if none is set.
func WithHTTPRequestID(l *zap.Logger, r *http.Request) *zap.Logger {
if id := r.Header.Get("X-Request-ID"); id != "" {
- return With(l, Attribute(foomosemconv.HTTPXRequestID(id)))
+ return WithAttributes(l, semconv.HTTPRequestHeader("x-request-id", id))
} else if id, ok := keelhttpcontext.GetRequestID(r.Context()); ok && id != "" {
- return With(l, Attribute(foomosemconv.HTTPXRequestID(id)))
+ return WithAttributes(l, semconv.HTTPRequestHeader("x-request-id", id))
} else {
return l
}
@@ -110,9 +118,9 @@ func WithHTTPRequestID(l *zap.Logger, r *http.Request) *zap.Logger {
// or Referer header, or l unchanged if none is set.
func WithHTTPReferer(l *zap.Logger, r *http.Request) *zap.Logger {
if value := r.Header.Get("X-Referer"); value != "" {
- return With(l, Attribute(foomosemconv.HTTPXRequestReferer(value)))
+ return WithAttributes(l, semconv.HTTPRequestHeader("referer", value))
} else if value := r.Referer(); value != "" {
- return With(l, Attribute(foomosemconv.HTTPXRequestReferer(value)))
+ return WithAttributes(l, semconv.HTTPRequestHeader("referer", value))
} else {
return l
}
diff --git a/net/http/client.go b/net/http/client.go
index f2630886..5f26cd6f 100644
--- a/net/http/client.go
+++ b/net/http/client.go
@@ -274,6 +274,10 @@ func HTTPClientWithRoundTripware(l *zap.Logger, roundTripware ...roundtripware.R
//
// If a retrying round tripper is also in play, put telemetry outermost so it
// reports one span per logical call rather than one per attempt.
+//
+// Spans are named "HTTP GET" by default. Pass [otelhttp.WithSpanNameFormatter]
+// returning "{method} {url.template}" (e.g. "GET /prices/{sku}"); never use
+// the URL path, as it makes span names unbounded.
func HTTPClientWithTelemetry(opts ...otelhttp.Option) HTTPClientOption {
return func(v *http.Client) {
v.Transport = otelhttp.NewTransport(v.Transport, opts...)
diff --git a/net/http/middleware/logger.go b/net/http/middleware/logger.go
index 67116bc6..564009be 100644
--- a/net/http/middleware/logger.go
+++ b/net/http/middleware/logger.go
@@ -6,11 +6,12 @@ import (
keelhttp "github.com/foomo/keel/net/http"
httplog "github.com/foomo/keel/net/http/log"
- semconv "go.opentelemetry.io/otel/semconv/v1.41.0"
+ semconv "go.opentelemetry.io/otel/semconv/v1.43.0"
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap"
"github.com/foomo/keel/log"
+ keelsemconv "github.com/foomo/keel/semconv"
)
type (
@@ -112,10 +113,10 @@ func LoggerWithOptions(opts LoggerOptions) keelhttp.Middleware {
next.ServeHTTP(wr, r)
- l = l.With(
- log.FDuration(time.Since(start)),
- log.Attribute(semconv.HTTPResponseStatusCode(wr.StatusCode())),
- log.Attribute(semconv.HTTPResponseSize(wr.Size())),
+ l = log.WithAttributes(l,
+ keelsemconv.Duration(time.Since(start)),
+ semconv.HTTPResponseStatusCode(wr.StatusCode()),
+ semconv.HTTPResponseSize(wr.Size()),
)
if labeler != nil {
@@ -123,7 +124,7 @@ func LoggerWithOptions(opts LoggerOptions) keelhttp.Middleware {
}
if err := r.Context().Err(); err != nil {
- l = l.With(zap.String("error_context", err.Error()))
+ l = log.WithAttributes(l, keelsemconv.ContextError(err))
}
switch {
diff --git a/net/http/middleware/rbac.go b/net/http/middleware/rbac.go
index e34f5fb5..a7d9d65f 100644
--- a/net/http/middleware/rbac.go
+++ b/net/http/middleware/rbac.go
@@ -3,8 +3,12 @@ package middleware
import (
"net/http"
+ "github.com/foomo/keel/log"
keelhttp "github.com/foomo/keel/net/http"
"github.com/foomo/keel/net/http/rbac"
+ keelsemconv "github.com/foomo/keel/semconv"
+ "go.opentelemetry.io/otel/attribute"
+ semconv "go.opentelemetry.io/otel/semconv/v1.43.0"
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap"
)
@@ -57,17 +61,17 @@ func RBAC(m *rbac.Matcher, extract rbac.RolesExtractor) keelhttp.Middleware {
}
if l != nil {
- fields := []zap.Field{
- zap.String("path", r.URL.Path),
- zap.String("outcome", string(d.Outcome)),
- zap.Bool("authenticated", d.Authed),
- zap.Strings("roles", d.Roles),
+ attrs := []attribute.KeyValue{
+ semconv.URLPath(r.URL.Path),
+ keelsemconv.KeelRBACOutcome(string(d.Outcome)),
+ keelsemconv.KeelRBACAuthenticated(d.Authed),
+ keelsemconv.KeelRBACRoles(d.Roles),
}
if d.Rule != nil {
- fields = append(fields, zap.String("rule_path", d.Rule.Raw.Path))
+ attrs = append(attrs, keelsemconv.KeelRBACRulePath(d.Rule.Raw.Path))
}
- l.Warn("rbac denied request", fields...)
+ l.Warn("rbac denied request", log.Attributes(attrs...)...)
}
status := http.StatusForbidden
diff --git a/net/http/middleware/recover.go b/net/http/middleware/recover.go
index d25d32e1..b1766f47 100644
--- a/net/http/middleware/recover.go
+++ b/net/http/middleware/recover.go
@@ -9,8 +9,11 @@ import (
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap"
+ "runtime/debug"
+
"github.com/foomo/keel/log"
httputils "github.com/foomo/keel/utils/net/http"
+ semconv "go.opentelemetry.io/otel/semconv/v1.43.0"
)
type (
@@ -74,7 +77,7 @@ func RecoverWithOptions(opts RecoverOptions) keelhttp.Middleware {
ll := log.WithError(l, err)
if !opts.DisablePrintStack {
- ll = ll.With(log.FStackSkip(3))
+ ll = ll.With(log.Attribute(semconv.ExceptionStacktrace(string(debug.Stack()))))
}
httputils.InternalServerError(ll, w, r, errors.Wrap(err, "recovering from panic"))
diff --git a/net/http/middleware/referrer.go b/net/http/middleware/referrer.go
index 5ad673f8..58539c64 100644
--- a/net/http/middleware/referrer.go
+++ b/net/http/middleware/referrer.go
@@ -6,7 +6,7 @@ import (
keelhttp "github.com/foomo/keel/net/http"
"github.com/foomo/keel/net/http/context"
- semconv "go.opentelemetry.io/otel/semconv/v1.41.0"
+ semconv "go.opentelemetry.io/otel/semconv/v1.43.0"
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap"
)
diff --git a/net/http/middleware/requestid.go b/net/http/middleware/requestid.go
index 367ffab8..94c21847 100644
--- a/net/http/middleware/requestid.go
+++ b/net/http/middleware/requestid.go
@@ -5,7 +5,7 @@ import (
"strings"
keelhttp "github.com/foomo/keel/net/http"
- semconv "go.opentelemetry.io/otel/semconv/v1.41.0"
+ semconv "go.opentelemetry.io/otel/semconv/v1.43.0"
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap"
diff --git a/net/http/middleware/responsecontroller.go b/net/http/middleware/responsecontroller.go
index 42cb58f6..3b73afb7 100644
--- a/net/http/middleware/responsecontroller.go
+++ b/net/http/middleware/responsecontroller.go
@@ -38,7 +38,7 @@ func ResponseController(h func(rc *http.ResponseController) error) keelhttp.Midd
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if h != nil {
if err := h(http.NewResponseController(w)); err != nil {
- l.Warn("failed to apply response controller", log.FError(err))
+ log.WithError(l, err).Warn("failed to apply response controller")
}
}
diff --git a/net/http/middleware/responsetime.go b/net/http/middleware/responsetime.go
index 8ac430c1..d7dc24c2 100644
--- a/net/http/middleware/responsetime.go
+++ b/net/http/middleware/responsetime.go
@@ -9,6 +9,7 @@ import (
"go.uber.org/zap"
"github.com/foomo/keel/log"
+ keelsemconv "github.com/foomo/keel/semconv"
)
type (
@@ -92,7 +93,7 @@ func ResponseTimeWithOptions(opts ResponseTimeOptions) keelhttp.Middleware {
duration := time.Since(start)
if opts.MaxDuration > 0 && duration > opts.MaxDuration {
- l.Warn(opts.MaxDurationMessage, log.FDuration(opts.MaxDuration), log.FValue(duration.Microseconds()))
+ l.Warn(opts.MaxDurationMessage, log.Attributes(keelsemconv.MaxDuration(opts.MaxDuration), keelsemconv.Duration(duration))...)
}
})
}
diff --git a/net/http/middleware/serverheader.go b/net/http/middleware/serverheader.go
index be9e49d0..16da31be 100644
--- a/net/http/middleware/serverheader.go
+++ b/net/http/middleware/serverheader.go
@@ -4,7 +4,7 @@ import (
"net/http"
"strings"
- semconv "go.opentelemetry.io/otel/semconv/v1.41.0"
+ semconv "go.opentelemetry.io/otel/semconv/v1.43.0"
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap"
diff --git a/net/http/middleware/sessionid.go b/net/http/middleware/sessionid.go
index 0529bcc6..7b81c2d7 100644
--- a/net/http/middleware/sessionid.go
+++ b/net/http/middleware/sessionid.go
@@ -6,7 +6,7 @@ import (
"github.com/google/uuid"
"github.com/pkg/errors"
- semconv "go.opentelemetry.io/otel/semconv/v1.41.0"
+ semconv "go.opentelemetry.io/otel/semconv/v1.43.0"
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap"
diff --git a/net/http/middleware/telemetry.go b/net/http/middleware/telemetry.go
index a42eb6f6..471103d8 100644
--- a/net/http/middleware/telemetry.go
+++ b/net/http/middleware/telemetry.go
@@ -6,6 +6,7 @@ import (
"github.com/foomo/keel/log"
keelhttp "github.com/foomo/keel/net/http"
httplog "github.com/foomo/keel/net/http/log"
+ keelsemconv "github.com/foomo/keel/semconv"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/propagation"
@@ -95,8 +96,8 @@ func TelemetryWithOptions(opts TelemetryOptions) keelhttp.Middleware {
if labeler, ok := httplog.LabelerFromRequest(r); ok {
if spanCtx := trace.SpanContextFromContext(r.Context()); spanCtx.IsValid() && spanCtx.IsSampled() {
- labeler.Add(log.FTraceID(spanCtx.TraceID().String()))
- labeler.Add(log.FSpanID(spanCtx.SpanID().String()))
+ labeler.Add(log.Attribute(keelsemconv.TraceID(spanCtx.TraceID().String())))
+ labeler.Add(log.Attribute(keelsemconv.SpanID(spanCtx.SpanID().String())))
}
}
diff --git a/net/http/middleware/trackingid.go b/net/http/middleware/trackingid.go
index 581b6f27..ba3287ec 100644
--- a/net/http/middleware/trackingid.go
+++ b/net/http/middleware/trackingid.go
@@ -7,7 +7,7 @@ import (
"github.com/google/uuid"
"github.com/pkg/errors"
- semconv "go.opentelemetry.io/otel/semconv/v1.41.0"
+ semconv "go.opentelemetry.io/otel/semconv/v1.43.0"
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap"
diff --git a/net/http/rbac/helper_test.go b/net/http/rbac/helper_test.go
index 077922c9..48c962c7 100644
--- a/net/http/rbac/helper_test.go
+++ b/net/http/rbac/helper_test.go
@@ -106,7 +106,7 @@ func TestRBAC_outcomes(t *testing.T) {
entry := logs.All()[0]
assert.Equal(t, "rbac denied request", entry.Message)
assert.Equal(t, zap.WarnLevel, entry.Level)
- assert.Equal(t, tc.path, entry.ContextMap()["path"])
+ assert.Equal(t, tc.path, entry.ContextMap()["url_path"])
} else {
assert.Equal(t, 0, logs.Len(), "expected no log entries")
}
@@ -204,7 +204,7 @@ func TestRBAC_pathMatching(t *testing.T) {
if tc.wantRule != "" {
require.Equal(t, 1, logs.Len(), "expected one deny log entry")
- assert.Equal(t, tc.wantRule, logs.All()[0].ContextMap()["rule_path"])
+ assert.Equal(t, tc.wantRule, logs.All()[0].ContextMap()["keel_rbac_rule_path"])
}
})
}
diff --git a/net/http/roundtripware/circuitbreaker.go b/net/http/roundtripware/circuitbreaker.go
index 2761b7fd..50cc3c2a 100644
--- a/net/http/roundtripware/circuitbreaker.go
+++ b/net/http/roundtripware/circuitbreaker.go
@@ -6,6 +6,9 @@ import (
"time"
"github.com/foomo/keel/log"
+ keelsemconv "github.com/foomo/keel/semconv"
+ foomosemconv "github.com/foomo/opentelemetry-go/semconv"
+ "github.com/foomo/opentelemetry-go/semconv/circuitbreakerconv"
"github.com/sony/gobreaker"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/metric"
@@ -159,24 +162,23 @@ func CircuitBreaker(set *CircuitBreakerSettings, opts ...CircuitBreakerOption) R
toState := circuitBreaker.State()
if fromState != toState {
l.Warn("state change occurred",
- zap.String("state_from", fromState.String()),
- zap.String("state_to", toState.String()),
+ log.Attributes(
+ keelsemconv.KeelCircuitBreakerPreviousState(string(circuitBreakerState(fromState))),
+ foomosemconv.CircuitBreakerState(string(circuitBreakerState(toState))),
+ )...,
)
}
- attributes := []attribute.KeyValue{
- attribute.String("current_state", toState.String()),
- attribute.String("previous_state", fromState.String()),
- attribute.Bool("state_change", fromState != toState),
- }
-
- if err != nil {
- if o.Counter != nil {
- attributes := append(attributes, attribute.Bool("error", true))
- o.Counter.Add(r.Context(), 1, metric.WithAttributes(attributes...))
+ if o.Counter != nil {
+ attributes := []attribute.KeyValue{
+ foomosemconv.CircuitBreakerState(string(circuitBreakerState(toState))),
+ keelsemconv.KeelCircuitBreakerPreviousState(string(circuitBreakerState(fromState))),
+ keelsemconv.KeelCircuitBreakerStateChange(fromState != toState),
}
- } else if o.Counter != nil {
- attributes := append(attributes, attribute.Bool("error", false))
+ if err != nil {
+ attributes = append(attributes, foomosemconv.ErrorType(err))
+ }
+
o.Counter.Add(r.Context(), 1, metric.WithAttributes(attributes...))
}
}()
@@ -186,7 +188,7 @@ func CircuitBreaker(set *CircuitBreakerSettings, opts ...CircuitBreakerOption) R
reqCopy, errCopy := copyRequest(r, o.CopyReqBody)
if errCopy != nil {
- l.Error("unable to copy request", log.FError(errCopy))
+ log.WithError(l, errCopy).Error("unable to copy request")
return nil, errCopy
} else if o.CopyReqBody && reqCopy.Body != nil {
// make sure the body is closed again - since it is a NopCloser it does not make a difference though
@@ -200,9 +202,8 @@ func CircuitBreaker(set *CircuitBreakerSettings, opts ...CircuitBreakerOption) R
if errors.Is(err, gobreaker.ErrTooManyRequests) || errors.Is(err, gobreaker.ErrOpenState) {
return nil, errors.Join(ErrCircuitBreaker, err)
} else if err != nil {
- l.Error("unexpected error in circuit breaker",
- log.FError(err),
- zap.String("state", fromState.String()),
+ log.WithError(l, err).Error("unexpected error in circuit breaker",
+ log.Attribute(foomosemconv.CircuitBreakerState(string(circuitBreakerState(fromState)))),
)
return nil, err
@@ -216,7 +217,7 @@ func CircuitBreaker(set *CircuitBreakerSettings, opts ...CircuitBreakerOption) R
// clone the response and the body if wanted
respCopy, errCopy = copyResponse(resp, o.CopyRespBody)
if errCopy != nil {
- l.Error("unable to copy response", log.FError(errCopy))
+ log.WithError(l, errCopy).Error("unable to copy response")
return nil, errCopy
} else if o.CopyRespBody && respCopy.Body != nil {
// make sure the body is closed again - since it is a NopCloser it does not make a difference though
@@ -225,10 +226,7 @@ func CircuitBreaker(set *CircuitBreakerSettings, opts ...CircuitBreakerOption) R
}
if errSuccess := o.IsSuccessful(err, reqCopy, respCopy); errors.Is(errSuccess, errNoBody) {
- l.Error("encountered read from not previously copied request/response body",
- zap.Bool("copy_request", o.CopyReqBody),
- zap.Bool("copy_response", o.CopyRespBody),
- )
+ l.Error("encountered read from not previously copied request/response body")
// we actually want to return an error instead of the original request and error since the user
// should be made aware that there is a misconfiguration
return nil, ErrReadFromActualBody
@@ -241,3 +239,16 @@ func CircuitBreaker(set *CircuitBreakerSettings, opts ...CircuitBreakerOption) R
}
}
}
+
+// circuitBreakerState maps a gobreaker state to the circuit_breaker.state
+// enum value.
+func circuitBreakerState(s gobreaker.State) circuitbreakerconv.StateAttr {
+ switch s {
+ case gobreaker.StateOpen:
+ return circuitbreakerconv.StateOpen
+ case gobreaker.StateHalfOpen:
+ return circuitbreakerconv.StateHalfOpen
+ default:
+ return circuitbreakerconv.StateClosed
+ }
+}
diff --git a/net/http/roundtripware/logger.go b/net/http/roundtripware/logger.go
index fc469c46..56af56e7 100644
--- a/net/http/roundtripware/logger.go
+++ b/net/http/roundtripware/logger.go
@@ -4,11 +4,12 @@ import (
"net/http"
"time"
- semconv "go.opentelemetry.io/otel/semconv/v1.41.0"
+ semconv "go.opentelemetry.io/otel/semconv/v1.43.0"
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap"
"github.com/foomo/keel/log"
+ keelsemconv "github.com/foomo/keel/semconv"
)
type (
@@ -109,7 +110,7 @@ func Logger(opts ...LoggerOption) RoundTripware {
statusCode = resp.StatusCode
}
- l = l.With(log.FDuration(time.Since(start)))
+ l = log.WithAttributes(l, keelsemconv.Duration(time.Since(start)))
switch {
case err != nil:
diff --git a/net/http/roundtripware/metric.go b/net/http/roundtripware/metric.go
index dcad4406..299687c5 100644
--- a/net/http/roundtripware/metric.go
+++ b/net/http/roundtripware/metric.go
@@ -4,8 +4,8 @@ import (
"net/http"
"time"
- "go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/metric"
+ semconv "go.opentelemetry.io/otel/semconv/v1.43.0"
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap"
)
@@ -41,10 +41,10 @@ func Metric(meter metric.Meter, name, description string) RoundTripware {
return resp, err
}
- attributes := append(labeler.Get(), attribute.String("method", r.Method))
+ attributes := append(labeler.Get(), semconv.HTTPRequestMethodKey.String(r.Method))
if resp != nil {
- attributes = append(labeler.Get(), attribute.Int("status_code", resp.StatusCode))
+ attributes = append(attributes, semconv.HTTPResponseStatusCode(resp.StatusCode))
}
histogram.Record(ctx, duration.Seconds(), metric.WithAttributes(attributes...))
diff --git a/net/http/roundtripware/recover.go b/net/http/roundtripware/recover.go
index 639925df..d9ae08ab 100644
--- a/net/http/roundtripware/recover.go
+++ b/net/http/roundtripware/recover.go
@@ -3,11 +3,13 @@ package roundtripware
import (
"fmt"
"net/http"
+ "runtime/debug"
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap"
"github.com/foomo/keel/log"
+ semconv "go.opentelemetry.io/otel/semconv/v1.43.0"
)
type (
@@ -68,7 +70,7 @@ func RecoverWithOptions(opts RecoverOptions) RoundTripware {
ll := log.WithError(l, err)
if !opts.DisablePrintStack {
- ll = ll.With(log.FStackSkip(3))
+ ll = log.WithAttributes(ll, semconv.ExceptionStacktrace(string(debug.Stack())))
}
ll.Error("recovering from panic")
diff --git a/net/http/roundtripware/referer.go b/net/http/roundtripware/referer.go
index 922d699a..68d64e59 100644
--- a/net/http/roundtripware/referer.go
+++ b/net/http/roundtripware/referer.go
@@ -4,7 +4,7 @@ import (
"net/http"
"strings"
- semconv "go.opentelemetry.io/otel/semconv/v1.41.0"
+ semconv "go.opentelemetry.io/otel/semconv/v1.43.0"
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap"
diff --git a/net/http/roundtripware/requestid.go b/net/http/roundtripware/requestid.go
index 51a7a5cf..ae1e8ab1 100644
--- a/net/http/roundtripware/requestid.go
+++ b/net/http/roundtripware/requestid.go
@@ -4,7 +4,7 @@ import (
"net/http"
"strings"
- semconv "go.opentelemetry.io/otel/semconv/v1.41.0"
+ semconv "go.opentelemetry.io/otel/semconv/v1.43.0"
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap"
diff --git a/net/http/roundtripware/retry.go b/net/http/roundtripware/retry.go
index 748ab4ef..9947f732 100644
--- a/net/http/roundtripware/retry.go
+++ b/net/http/roundtripware/retry.go
@@ -7,7 +7,7 @@ import (
"time"
"github.com/avast/retry-go/v4"
- semconv "go.opentelemetry.io/otel/semconv/v1.10.0"
+ semconv "go.opentelemetry.io/otel/semconv/v1.43.0"
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap"
)
@@ -124,8 +124,8 @@ func Retry(opts ...RetryOption) RoundTripware {
var err error
- if span.IsRecording() {
- span.SetAttributes(semconv.HTTPRetryCountKey.Int(attempt))
+ if attempt > 1 && span.IsRecording() {
+ span.SetAttributes(semconv.HTTPRequestResendCount(attempt - 1))
}
resp, err = next(req) //nolint:bodyclose
diff --git a/net/http/roundtripware/sessionid.go b/net/http/roundtripware/sessionid.go
index e52e1a48..21ab9e5f 100644
--- a/net/http/roundtripware/sessionid.go
+++ b/net/http/roundtripware/sessionid.go
@@ -3,7 +3,7 @@ package roundtripware
import (
"net/http"
- semconv "go.opentelemetry.io/otel/semconv/v1.41.0"
+ semconv "go.opentelemetry.io/otel/semconv/v1.43.0"
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap"
diff --git a/net/http/roundtripware/trackingid.go b/net/http/roundtripware/trackingid.go
index 9f053dc4..fbf68b5c 100644
--- a/net/http/roundtripware/trackingid.go
+++ b/net/http/roundtripware/trackingid.go
@@ -4,7 +4,7 @@ import (
"net/http"
"strings"
- semconv "go.opentelemetry.io/otel/semconv/v1.41.0"
+ semconv "go.opentelemetry.io/otel/semconv/v1.43.0"
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap"
diff --git a/net/stream/go.mod b/net/stream/go.mod
index 2e8286bb..1b6f93fa 100644
--- a/net/stream/go.mod
+++ b/net/stream/go.mod
@@ -7,11 +7,12 @@ replace github.com/foomo/keel => ../../
require (
github.com/foomo/go v0.17.1
github.com/foomo/keel v0.31.0
+ github.com/foomo/opentelemetry-go v0.5.0
github.com/nats-io/nats.go v1.54.0
github.com/pkg/errors v0.9.1
github.com/stretchr/testify v1.12.1
github.com/testcontainers/testcontainers-go/modules/nats v0.44.0
- go.opentelemetry.io/otel v1.46.0
+ go.opentelemetry.io/otel v1.47.0
go.uber.org/zap v1.28.0
)
@@ -32,7 +33,6 @@ require (
github.com/ebitengine/purego v0.10.2 // indirect
github.com/fbiville/markdown-table-formatter v0.3.0 // indirect
github.com/felixge/httpsnoop v1.1.0 // indirect
- github.com/foomo/opentelemetry-go v0.4.0 // indirect
github.com/go-logr/logr v1.4.4 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
@@ -62,8 +62,9 @@ require (
github.com/yusufpapurcu/wmi v1.2.4 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.71.0 // indirect
- go.opentelemetry.io/otel/metric v1.46.0 // indirect
- go.opentelemetry.io/otel/trace v1.46.0 // indirect
+ go.opentelemetry.io/otel/log v1.47.0 // indirect
+ go.opentelemetry.io/otel/metric v1.47.0 // indirect
+ go.opentelemetry.io/otel/trace v1.47.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.yaml.in/yaml/v3 v3.0.5 // indirect
golang.org/x/crypto v0.57.0 // indirect
diff --git a/net/stream/go.sum b/net/stream/go.sum
index c4000ba5..8f265d5e 100644
--- a/net/stream/go.sum
+++ b/net/stream/go.sum
@@ -36,8 +36,8 @@ github.com/felixge/httpsnoop v1.1.0 h1:3YtUj32ZZkqZtt3sZZsClsymw/QDuVfpNhoA31zeO
github.com/felixge/httpsnoop v1.1.0/go.mod h1:Zqxgdd+1Rkcz8euOqdr7lqgCRJztwr5hp9vDSi5UZCE=
github.com/foomo/go v0.17.1 h1:tDrovWbh1dOzsBX19pII6nAPIECswhBmNSPEGBYNawY=
github.com/foomo/go v0.17.1/go.mod h1:Zz5aBFte6ayLEJ17n4L1bqYmEEja9xTeLKC0Z1wAy+0=
-github.com/foomo/opentelemetry-go v0.4.0 h1:UQneCUSokIYJXzFUKQSI8rlelbUuf6atgSZMhvD+Nzo=
-github.com/foomo/opentelemetry-go v0.4.0/go.mod h1:R3Se/rc5FRAs4ThE6JQ9Oq3cOLo2MOsUzZLJxZquwxA=
+github.com/foomo/opentelemetry-go v0.5.0 h1:4MHCj7cRB+Jr8AZsrhQ+J3M/4Gka/mXG0Xv+uv6RNDI=
+github.com/foomo/opentelemetry-go v0.5.0/go.mod h1:3jSEAGFXOJMtFLiLXepEQcr9Fkz1g/JqoWqlcihW/pk=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.4 h1:tG4xh9yMsRCAiodLVTxyrkzSZ9+o0L1Kg/+cPVcbP/8=
github.com/go-logr/logr v1.4.4/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
@@ -110,16 +110,18 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.71.0 h1:3g7B90UzBltIDKq1/5mrTGxTnOFDV0ICOhLoxiZ8jlg=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.71.0/go.mod h1:Ef8SuTh59BT7+ofpDxN9z+yOlc4t2GjLmKDgYNJL/NU=
-go.opentelemetry.io/otel v1.46.0 h1:FHt5/CDyVxi/8IM1CH7VE/rRgq3kLHa2mSTVMO8AWyc=
-go.opentelemetry.io/otel v1.46.0/go.mod h1:Gj3SEScelsNC45tp4nSxRYlS+f5iez7W8XPMCt905kE=
-go.opentelemetry.io/otel/metric v1.46.0 h1:yBnkXvgV7AXFILZc5K6IZe/CBFF3OS7BJ8ov6/lj0K8=
-go.opentelemetry.io/otel/metric v1.46.0/go.mod h1:iPmdWqifKUdzziPkvvzIJXITl56fQx2mGM/DHLB3/2o=
-go.opentelemetry.io/otel/sdk v1.46.0 h1:h5CNQQjEbuQXY/JfZtgt3i7HVFV3aHPO2OAwO2eTYPI=
-go.opentelemetry.io/otel/sdk v1.46.0/go.mod h1:GAERFXFt5SYCEB+YiKUbMBeza6UaDH7GmGOZEfh2gSM=
-go.opentelemetry.io/otel/sdk/metric v1.46.0 h1:0piZ26EG4RBfebb2jhDH6ERCYHoVWduc3kLgPCwSnSE=
-go.opentelemetry.io/otel/sdk/metric v1.46.0/go.mod h1:I1PbKrdVc8Qu8HYVDNtqVIwLwjNrhsV/uFuxfwg8mO4=
-go.opentelemetry.io/otel/trace v1.46.0 h1:OULy7ccdJnZtJ0UDYFOIGaCmiWzJ8Vi2G/Rsu60qs1c=
-go.opentelemetry.io/otel/trace v1.46.0/go.mod h1:J7GAXweO77XSFkB/rmAqk9D6ihszhFjLU+d9WuUxDLI=
+go.opentelemetry.io/otel v1.47.0 h1:j7ALJ/zgkS7Z6aeJW09p8VC9804bC+PpeTfCD4XPnOM=
+go.opentelemetry.io/otel v1.47.0/go.mod h1:8wS9O2qfXrYrzp6hIF/HOYJJf/wIhFPhR2xLuP+iXQU=
+go.opentelemetry.io/otel/log v1.47.0 h1:cOTS1CcLbSQeZKanGJ+0JpF/+t4PELi3O3bbl2lqCcI=
+go.opentelemetry.io/otel/log v1.47.0/go.mod h1:9byitSQ5pLC6PpqwGXjqdMKya6ZTswHRZh2vvXT33nw=
+go.opentelemetry.io/otel/metric v1.47.0 h1:4PptaldXx3Eat1XjMZ68pPJEs5wrhlemctZE9a3UdWY=
+go.opentelemetry.io/otel/metric v1.47.0/go.mod h1:ADGSXxRrXM6bjbvLo535EstVFlPpPYZm4LBKixjDHwU=
+go.opentelemetry.io/otel/sdk v1.47.0 h1:zWXEr4j2lFefG87TU6Yg8a7ngfohIKFZHKp0Hf5hC6I=
+go.opentelemetry.io/otel/sdk v1.47.0/go.mod h1:VUc24kiOeoGsxG8G9ULx3fWKvB7jMhnGE8Oi607lgR0=
+go.opentelemetry.io/otel/sdk/metric v1.47.0 h1:lfISg2j93VT6yqdk9OfUaZmw/GfcZqCCV3jdXtsPnKw=
+go.opentelemetry.io/otel/sdk/metric v1.47.0/go.mod h1:ypLp+mW1Nt2x+Szt3b5/i1syodyts49lMOwxpDI3VGw=
+go.opentelemetry.io/otel/trace v1.47.0 h1:JOjX/Oci8K94QHddo+bbfya/Ai/nf6/dt9ZfrFNWSrM=
+go.opentelemetry.io/otel/trace v1.47.0/go.mod h1:jNaSLa2PZEYFG6fRjJABAu+bw4FS08uDmPg28lTghu0=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
diff --git a/net/stream/jetstream/stream.go b/net/stream/jetstream/stream.go
index 5510baad..af4c44c2 100644
--- a/net/stream/jetstream/stream.go
+++ b/net/stream/jetstream/stream.go
@@ -2,15 +2,19 @@ package jetstream
import (
"encoding/json"
+ "net/url"
"slices"
+ "strconv"
"time"
"github.com/nats-io/nats.go"
"github.com/pkg/errors"
- semconv "go.opentelemetry.io/otel/semconv/v1.41.0"
+ "go.opentelemetry.io/otel/attribute"
+ semconv "go.opentelemetry.io/otel/semconv/v1.43.0"
"go.uber.org/zap"
"github.com/foomo/keel/log"
+ foomosemconv "github.com/foomo/opentelemetry-go/semconv"
)
type (
@@ -147,9 +151,9 @@ func SubscriberWithUnmarshal(unmarshal UnmarshalFn) SubscriberOption {
// reconnect options. It returns an error if the initial connect fails.
func New(l *zap.Logger, name, addr string, opts ...Option) (*Stream, error) {
stream := &Stream{
- l: l.With(
- log.Attribute(semconv.MessagingSystemKey.String("jetstream")),
- log.FName(name),
+ l: log.WithAttributes(l,
+ foomosemconv.MessagingSystemNats,
+ foomosemconv.MessagingNATSStream(name),
),
name: name,
addr: addr,
@@ -274,6 +278,34 @@ func (s *Stream) Close() {
s.conn.Close()
}
+// serverAttrs returns OTel semconv attributes describing the server at
+// rawURL. Returns nil if rawURL is empty or cannot be parsed.
+func serverAttrs(rawURL string) []attribute.KeyValue {
+ addr, port := serverAddrPort(rawURL)
+ if addr == "" {
+ return nil
+ }
+
+ return []attribute.KeyValue{
+ semconv.ServerAddress(addr),
+ semconv.ServerPort(port),
+ semconv.NetworkProtocolName("jetstream"),
+ }
+}
+
+// serverAddrPort extracts just the address and port from rawURL.
+// Returns zero values if parsing fails.
+func serverAddrPort(rawURL string) (string, int) {
+ u, err := url.Parse(rawURL)
+ if err != nil {
+ return "", 0
+ }
+
+ port, _ := strconv.Atoi(u.Port())
+
+ return u.Hostname(), port
+}
+
// connect establishes the NATS connection and JetStream context and creates
// or updates the stream if a config is set.
func (s *Stream) connect() error {
@@ -283,14 +315,15 @@ func (s *Stream) connect() error {
return errors.Wrap(err, "failed to connect to nats addr "+s.addr)
}
- s.l.Info("nats connected", zap.String("addr", s.addr))
+ l := log.WithAttributes(s.l, serverAttrs(conn.ConnectedUrlRedacted())...)
+ l.Debug("jetstream connected")
// create jet stream
js, err := conn.JetStream(
append(
[]nats.JSOpt{
nats.PublishAsyncErrHandler(func(js nats.JetStream, msg *nats.Msg, err error) {
- s.l.Error("nats async publish error", log.FError(err))
+ log.WithError(l, err).Error("nats async publish error")
}),
},
s.jsOptions...,
@@ -300,7 +333,7 @@ func (s *Stream) connect() error {
return err
}
- s.l.Info("jetstream created", zap.String("namespace", s.namespace))
+ l.Debug("jetstream created")
// create / update stream if config exists
if s.config != nil {
@@ -308,8 +341,6 @@ func (s *Stream) connect() error {
if _, err = js.StreamInfo(s.Name(), s.configJSOptions...); errors.Is(err, nats.ErrStreamNotFound) {
if info, err := js.AddStream(s.config, s.configJSOptions...); err != nil {
return errors.Wrap(err, "failed to add stream")
- } else if err != nil {
- return errors.Wrap(err, "failed to retrieve stream info")
} else {
s.info = info
}
@@ -322,7 +353,7 @@ func (s *Stream) connect() error {
}
}
- s.l.Info("jetstream configured")
+ l.Info("jetstream configured")
s.js = js
s.conn = conn
@@ -335,15 +366,14 @@ func (s *Stream) connect() error {
func (s *Stream) initNatsOptions() {
natsOpts := append([]nats.Option{
nats.ErrorHandler(func(conn *nats.Conn, subscription *nats.Subscription, err error) {
- s.l.Error("nats error",
- log.FError(err),
+ log.WithError(s.l, err).Error("nats error",
log.Attribute(semconv.MessagingDestinationName(subscription.Queue)),
log.Attribute(semconv.MessagingDestinationSubscriptionName(subscription.Subject)),
)
}),
nats.ClosedHandler(func(conn *nats.Conn) {
if err := conn.LastError(); err != nil {
- s.l.Error("nats closed", log.FError(err))
+ log.WithError(s.l, err).Error("nats closed")
} else {
s.l.Info("nats closed")
}
@@ -353,13 +383,13 @@ func (s *Stream) initNatsOptions() {
}),
nats.DisconnectErrHandler(func(conn *nats.Conn, err error) {
if err != nil {
- s.l.Error("nats disconnected error", log.FError(err))
+ log.WithError(s.l, err).Error("nats disconnected error")
var errRetry error
for range s.reconnectMaxRetries {
errRetry = s.connect()
if errRetry != nil {
- s.l.Error("nats reconnect failed", log.FError(errRetry))
+ log.WithError(s.l, errRetry).Error("nats reconnect failed")
time.Sleep(s.reconnectTimeout)
} else {
break
diff --git a/net/stream/jetstream/subscriber.go b/net/stream/jetstream/subscriber.go
index 28ed550b..1a9cc8f8 100644
--- a/net/stream/jetstream/subscriber.go
+++ b/net/stream/jetstream/subscriber.go
@@ -81,5 +81,5 @@ func (s *Subscriber) Unmarshal(msg *nats.Msg, v any) error {
// errorHandler logs a handler error.
func (s *Subscriber) errorHandler(err error) {
- s.stream.l.Error("failed to handle message", log.FError(err))
+ log.WithError(s.stream.l, err).Error("failed to handle message")
}
diff --git a/persistence/mongo/go.mod b/persistence/mongo/go.mod
index 99686071..a7c62037 100644
--- a/persistence/mongo/go.mod
+++ b/persistence/mongo/go.mod
@@ -16,8 +16,9 @@ require (
require (
github.com/cespare/xxhash/v2 v2.3.0 // indirect
+ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/fbiville/markdown-table-formatter v0.3.0 // indirect
- github.com/foomo/opentelemetry-go v0.4.0 // indirect
+ github.com/foomo/opentelemetry-go v0.5.0 // indirect
github.com/go-logr/logr v1.4.4 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/klauspost/compress v1.20.1 // indirect
@@ -28,9 +29,10 @@ require (
github.com/xdg-go/stringprep v1.0.4 // indirect
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
- go.opentelemetry.io/otel v1.46.0 // indirect
- go.opentelemetry.io/otel/metric v1.46.0 // indirect
- go.opentelemetry.io/otel/trace v1.46.0 // indirect
+ go.opentelemetry.io/otel v1.47.0 // indirect
+ go.opentelemetry.io/otel/log v1.47.0 // indirect
+ go.opentelemetry.io/otel/metric v1.47.0 // indirect
+ go.opentelemetry.io/otel/trace v1.47.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.57.0 // indirect
golang.org/x/sync v0.23.0 // indirect
diff --git a/persistence/mongo/go.sum b/persistence/mongo/go.sum
index daf6ac6b..b0170420 100644
--- a/persistence/mongo/go.sum
+++ b/persistence/mongo/go.sum
@@ -34,8 +34,8 @@ github.com/felixge/httpsnoop v1.1.0 h1:3YtUj32ZZkqZtt3sZZsClsymw/QDuVfpNhoA31zeO
github.com/felixge/httpsnoop v1.1.0/go.mod h1:Zqxgdd+1Rkcz8euOqdr7lqgCRJztwr5hp9vDSi5UZCE=
github.com/foomo/mongo-lock v0.2.0 h1:xURP2FijZ/feACB5YL1UKUXk23M+x5L+yltEK+sJm0g=
github.com/foomo/mongo-lock v0.2.0/go.mod h1:5LMCz8IeaTMCWcgh+aPoDeIjY1qpu8MXbx+FNrGAUFA=
-github.com/foomo/opentelemetry-go v0.4.0 h1:UQneCUSokIYJXzFUKQSI8rlelbUuf6atgSZMhvD+Nzo=
-github.com/foomo/opentelemetry-go v0.4.0/go.mod h1:R3Se/rc5FRAs4ThE6JQ9Oq3cOLo2MOsUzZLJxZquwxA=
+github.com/foomo/opentelemetry-go v0.5.0 h1:4MHCj7cRB+Jr8AZsrhQ+J3M/4Gka/mXG0Xv+uv6RNDI=
+github.com/foomo/opentelemetry-go v0.5.0/go.mod h1:3jSEAGFXOJMtFLiLXepEQcr9Fkz1g/JqoWqlcihW/pk=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.4 h1:tG4xh9yMsRCAiodLVTxyrkzSZ9+o0L1Kg/+cPVcbP/8=
github.com/go-logr/logr v1.4.4/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
@@ -116,16 +116,18 @@ go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/v2/mongo
go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/v2/mongo/otelmongo v0.0.0-20260826095902-c4c6248ec228/go.mod h1:tfjajq3dcdhtCQCuU9YBOCckNUTOE1p1OZV5qRVLs2A=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.71.0 h1:3g7B90UzBltIDKq1/5mrTGxTnOFDV0ICOhLoxiZ8jlg=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.71.0/go.mod h1:Ef8SuTh59BT7+ofpDxN9z+yOlc4t2GjLmKDgYNJL/NU=
-go.opentelemetry.io/otel v1.46.0 h1:FHt5/CDyVxi/8IM1CH7VE/rRgq3kLHa2mSTVMO8AWyc=
-go.opentelemetry.io/otel v1.46.0/go.mod h1:Gj3SEScelsNC45tp4nSxRYlS+f5iez7W8XPMCt905kE=
-go.opentelemetry.io/otel/metric v1.46.0 h1:yBnkXvgV7AXFILZc5K6IZe/CBFF3OS7BJ8ov6/lj0K8=
-go.opentelemetry.io/otel/metric v1.46.0/go.mod h1:iPmdWqifKUdzziPkvvzIJXITl56fQx2mGM/DHLB3/2o=
-go.opentelemetry.io/otel/sdk v1.46.0 h1:h5CNQQjEbuQXY/JfZtgt3i7HVFV3aHPO2OAwO2eTYPI=
-go.opentelemetry.io/otel/sdk v1.46.0/go.mod h1:GAERFXFt5SYCEB+YiKUbMBeza6UaDH7GmGOZEfh2gSM=
-go.opentelemetry.io/otel/sdk/metric v1.46.0 h1:0piZ26EG4RBfebb2jhDH6ERCYHoVWduc3kLgPCwSnSE=
-go.opentelemetry.io/otel/sdk/metric v1.46.0/go.mod h1:I1PbKrdVc8Qu8HYVDNtqVIwLwjNrhsV/uFuxfwg8mO4=
-go.opentelemetry.io/otel/trace v1.46.0 h1:OULy7ccdJnZtJ0UDYFOIGaCmiWzJ8Vi2G/Rsu60qs1c=
-go.opentelemetry.io/otel/trace v1.46.0/go.mod h1:J7GAXweO77XSFkB/rmAqk9D6ihszhFjLU+d9WuUxDLI=
+go.opentelemetry.io/otel v1.47.0 h1:j7ALJ/zgkS7Z6aeJW09p8VC9804bC+PpeTfCD4XPnOM=
+go.opentelemetry.io/otel v1.47.0/go.mod h1:8wS9O2qfXrYrzp6hIF/HOYJJf/wIhFPhR2xLuP+iXQU=
+go.opentelemetry.io/otel/log v1.47.0 h1:cOTS1CcLbSQeZKanGJ+0JpF/+t4PELi3O3bbl2lqCcI=
+go.opentelemetry.io/otel/log v1.47.0/go.mod h1:9byitSQ5pLC6PpqwGXjqdMKya6ZTswHRZh2vvXT33nw=
+go.opentelemetry.io/otel/metric v1.47.0 h1:4PptaldXx3Eat1XjMZ68pPJEs5wrhlemctZE9a3UdWY=
+go.opentelemetry.io/otel/metric v1.47.0/go.mod h1:ADGSXxRrXM6bjbvLo535EstVFlPpPYZm4LBKixjDHwU=
+go.opentelemetry.io/otel/sdk v1.47.0 h1:zWXEr4j2lFefG87TU6Yg8a7ngfohIKFZHKp0Hf5hC6I=
+go.opentelemetry.io/otel/sdk v1.47.0/go.mod h1:VUc24kiOeoGsxG8G9ULx3fWKvB7jMhnGE8Oi607lgR0=
+go.opentelemetry.io/otel/sdk/metric v1.47.0 h1:lfISg2j93VT6yqdk9OfUaZmw/GfcZqCCV3jdXtsPnKw=
+go.opentelemetry.io/otel/sdk/metric v1.47.0/go.mod h1:ypLp+mW1Nt2x+Szt3b5/i1syodyts49lMOwxpDI3VGw=
+go.opentelemetry.io/otel/trace v1.47.0 h1:JOjX/Oci8K94QHddo+bbfya/Ai/nf6/dt9ZfrFNWSrM=
+go.opentelemetry.io/otel/trace v1.47.0/go.mod h1:jNaSLa2PZEYFG6fRjJABAu+bw4FS08uDmPg28lTghu0=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
diff --git a/persistence/postgres/go.mod b/persistence/postgres/go.mod
index 2c8264ab..6f68aeda 100644
--- a/persistence/postgres/go.mod
+++ b/persistence/postgres/go.mod
@@ -14,8 +14,8 @@ require (
require (
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/fbiville/markdown-table-formatter v0.3.0 // indirect
- github.com/foomo/opentelemetry-go v0.4.0 // indirect
- go.opentelemetry.io/otel v1.46.0 // indirect
- go.opentelemetry.io/otel/trace v1.46.0 // indirect
+ github.com/foomo/opentelemetry-go v0.5.0 // indirect
+ go.opentelemetry.io/otel v1.47.0 // indirect
+ go.opentelemetry.io/otel/trace v1.47.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
)
diff --git a/persistence/postgres/go.sum b/persistence/postgres/go.sum
index db96cddf..ca9abbed 100644
--- a/persistence/postgres/go.sum
+++ b/persistence/postgres/go.sum
@@ -2,8 +2,8 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/fbiville/markdown-table-formatter v0.3.0 h1:PIm1UNgJrFs8q1htGTw+wnnNYvwXQMMMIKNZop2SSho=
github.com/fbiville/markdown-table-formatter v0.3.0/go.mod h1:q89TDtSEVDdTaufgSbfHpNVdPU/bmfvqNkrC5HagmLY=
-github.com/foomo/opentelemetry-go v0.4.0 h1:UQneCUSokIYJXzFUKQSI8rlelbUuf6atgSZMhvD+Nzo=
-github.com/foomo/opentelemetry-go v0.4.0/go.mod h1:R3Se/rc5FRAs4ThE6JQ9Oq3cOLo2MOsUzZLJxZquwxA=
+github.com/foomo/opentelemetry-go v0.5.0 h1:4MHCj7cRB+Jr8AZsrhQ+J3M/4Gka/mXG0Xv+uv6RNDI=
+github.com/foomo/opentelemetry-go v0.5.0/go.mod h1:3jSEAGFXOJMtFLiLXepEQcr9Fkz1g/JqoWqlcihW/pk=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/lib/pq v1.12.3 h1:tTWxr2YLKwIvK90ZXEw8GP7UFHtcbTtty8zsI+YjrfQ=
@@ -12,10 +12,10 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/stretchr/testify v1.12.1 h1:EuwCh5fleGS7H32xRwO3wRGT7DxrDhLAT6FF8MpWDWE=
github.com/stretchr/testify v1.12.1/go.mod h1:MDEgiDPPsNp5cuIrHPPCyornHKgEVbtFUmoNlxoYthg=
-go.opentelemetry.io/otel v1.46.0 h1:FHt5/CDyVxi/8IM1CH7VE/rRgq3kLHa2mSTVMO8AWyc=
-go.opentelemetry.io/otel v1.46.0/go.mod h1:Gj3SEScelsNC45tp4nSxRYlS+f5iez7W8XPMCt905kE=
-go.opentelemetry.io/otel/trace v1.46.0 h1:OULy7ccdJnZtJ0UDYFOIGaCmiWzJ8Vi2G/Rsu60qs1c=
-go.opentelemetry.io/otel/trace v1.46.0/go.mod h1:J7GAXweO77XSFkB/rmAqk9D6ihszhFjLU+d9WuUxDLI=
+go.opentelemetry.io/otel v1.47.0 h1:j7ALJ/zgkS7Z6aeJW09p8VC9804bC+PpeTfCD4XPnOM=
+go.opentelemetry.io/otel v1.47.0/go.mod h1:8wS9O2qfXrYrzp6hIF/HOYJJf/wIhFPhR2xLuP+iXQU=
+go.opentelemetry.io/otel/trace v1.47.0 h1:JOjX/Oci8K94QHddo+bbfya/Ai/nf6/dt9ZfrFNWSrM=
+go.opentelemetry.io/otel/trace v1.47.0/go.mod h1:jNaSLa2PZEYFG6fRjJABAu+bw4FS08uDmPg28lTghu0=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
diff --git a/semconv/circuitbreaker.go b/semconv/circuitbreaker.go
new file mode 100644
index 00000000..e40837cf
--- /dev/null
+++ b/semconv/circuitbreaker.go
@@ -0,0 +1,22 @@
+package semconv
+
+import (
+ "go.opentelemetry.io/otel/attribute"
+)
+
+const (
+ // CircuitBreakerPreviousStateKey is the key for circuit_breaker.previous_state.
+ CircuitBreakerPreviousStateKey = attribute.Key("circuit_breaker.previous_state")
+ // CircuitBreakerStateChangeKey is the key for circuit_breaker.state_change.
+ CircuitBreakerStateChangeKey = attribute.Key("circuit_breaker.state_change")
+)
+
+// KeelCircuitBreakerPreviousState returns a new attribute.KeyValue for circuit_breaker.previous_state.
+func KeelCircuitBreakerPreviousState(v string) attribute.KeyValue {
+ return CircuitBreakerPreviousStateKey.String(v)
+}
+
+// KeelCircuitBreakerStateChange returns a new attribute.KeyValue for circuit_breaker.state_change.
+func KeelCircuitBreakerStateChange(v bool) attribute.KeyValue {
+ return CircuitBreakerStateChangeKey.Bool(v)
+}
diff --git a/semconv/debug.go b/semconv/debug.go
index 38527aa5..a44f2a6b 100644
--- a/semconv/debug.go
+++ b/semconv/debug.go
@@ -6,10 +6,14 @@ import (
const (
// DebugEnabledKey is the key for debug.enabled.
+ //
+ // Deprecated: use foomosemconv.SpanSamplingPriorityKey.
DebugEnabledKey = attribute.Key("debug.enabled")
)
// DebugEnabled returns a new attribute.KeyValue for debug.enabled.
+//
+// Deprecated: use foomosemconv.SetSpanSamplingPriority.
func DebugEnabled(v bool) attribute.KeyValue {
return DebugEnabledKey.Bool(v)
}
diff --git a/semconv/doc.go b/semconv/doc.go
index 9c5c7568..1f440e47 100644
--- a/semconv/doc.go
+++ b/semconv/doc.go
@@ -5,5 +5,10 @@
// [go.opentelemetry.io/otel/attribute.Key] constant (for example
// [KeelServiceNameKey]) and a constructor returning a
// [go.opentelemetry.io/otel/attribute.KeyValue] (for example
-// [KeelServiceName]). Attributes cover keel services and debug state.
+// [KeelServiceName]). Attributes cover keel services, jobs, closers, circuit
+// breakers, RBAC, streams, debug state and generic values (name,
+// value, duration, trace and span ids) that replace the legacy log fields.
+// Use them with log.Attribute and log.Attributes to share keys between logs,
+// metrics and traces. Prefer upstream go.opentelemetry.io/otel/semconv keys
+// where they exist.
package semconv
diff --git a/semconv/generic.go b/semconv/generic.go
new file mode 100644
index 00000000..9ebb994a
--- /dev/null
+++ b/semconv/generic.go
@@ -0,0 +1,69 @@
+package semconv
+
+import (
+ "fmt"
+ "time"
+
+ "go.opentelemetry.io/otel/attribute"
+)
+
+const (
+ // NameKey is the key for name.
+ NameKey = attribute.Key("name")
+ // ValueKey is the key for value.
+ ValueKey = attribute.Key("value")
+ // NumKey is the key for num.
+ NumKey = attribute.Key("num")
+ // DurationKey is the key for duration, in seconds.
+ DurationKey = attribute.Key("duration")
+ // MaxDurationKey is the key for max_duration, in seconds.
+ MaxDurationKey = attribute.Key("max_duration")
+ // TraceIDKey is the key for trace.id.
+ TraceIDKey = attribute.Key("trace.id")
+ // SpanIDKey is the key for span.id.
+ SpanIDKey = attribute.Key("span.id")
+ // ContextErrorKey is the key for context.error.
+ ContextErrorKey = attribute.Key("context.error")
+)
+
+// Name returns a new attribute.KeyValue for name.
+func Name(v string) attribute.KeyValue {
+ return NameKey.String(v)
+}
+
+// Value returns a new attribute.KeyValue for value with v formatted
+// by %v.
+func Value(v any) attribute.KeyValue {
+ return ValueKey.String(fmt.Sprintf("%v", v))
+}
+
+// Num returns a new attribute.KeyValue for num.
+func Num(v int) attribute.KeyValue {
+ return NumKey.Int(v)
+}
+
+// Duration returns a new attribute.KeyValue for duration in seconds.
+func Duration(v time.Duration) attribute.KeyValue {
+ return DurationKey.Float64(v.Seconds())
+}
+
+// MaxDuration returns a new attribute.KeyValue for max_duration in seconds.
+func MaxDuration(v time.Duration) attribute.KeyValue {
+ return MaxDurationKey.Float64(v.Seconds())
+}
+
+// TraceID returns a new attribute.KeyValue for trace.id.
+func TraceID(v string) attribute.KeyValue {
+ return TraceIDKey.String(v)
+}
+
+// SpanID returns a new attribute.KeyValue for span.id.
+func SpanID(v string) attribute.KeyValue {
+ return SpanIDKey.String(v)
+}
+
+// ContextError returns a new attribute.KeyValue for context.error
+// with the message of the given context error.
+func ContextError(err error) attribute.KeyValue {
+ return ContextErrorKey.String(err.Error())
+}
diff --git a/semconv/keel.go b/semconv/keel.go
index 64c4113b..f93ede63 100644
--- a/semconv/keel.go
+++ b/semconv/keel.go
@@ -1,6 +1,9 @@
package semconv
import (
+ "fmt"
+ "time"
+
"go.opentelemetry.io/otel/attribute"
)
@@ -11,11 +14,55 @@ const (
KeelServiceNameKey = attribute.Key("keel.service.name")
// KeelServiceInstKey is the key for keel.service.inst.
KeelServiceInstKey = attribute.Key("keel.service.inst")
+ // KeelGracefulPeriodKey is the key for keel.graceful_period, in seconds.
+ KeelGracefulPeriodKey = attribute.Key("keel.graceful_period")
+ // KeelJobStepKey is the key for keel.job.step.
+ KeelJobStepKey = attribute.Key("keel.job.step")
+ // KeelCloserTypeKey is the key for keel.closer.type.
+ KeelCloserTypeKey = attribute.Key("keel.closer.type")
+ // KeelHealthzProbeTypeKey is the key for keel.healthz.probe.type.
+ KeelHealthzProbeTypeKey = attribute.Key("keel.healthz.probe.type")
+)
+
+// KeelGracefulPeriod returns a new attribute.KeyValue for keel.graceful_period in seconds.
+func KeelGracefulPeriod(v time.Duration) attribute.KeyValue {
+ return KeelGracefulPeriodKey.Float64(v.Seconds())
+}
+
+// KeelJobStep returns a new attribute.KeyValue for keel.job.step.
+func KeelJobStep(v string) attribute.KeyValue {
+ return KeelJobStepKey.String(v)
+}
+
+// KeelCloserType returns a new attribute.KeyValue for keel.closer.type with
+// the Go type name of closer.
+func KeelCloserType(closer any) attribute.KeyValue {
+ return KeelCloserTypeKey.String(fmt.Sprintf("%T", closer))
+}
+
+// KeelHealthzProbeType returns a new attribute.KeyValue for
+// keel.healthz.probe.type with the Go type name of probe.
+func KeelHealthzProbeType(probe any) attribute.KeyValue {
+ return KeelHealthzProbeTypeKey.String(fmt.Sprintf("%T", probe))
+}
+
+// KeelServiceTypeAttr is an enum value of keel.service.type.
+type KeelServiceTypeAttr string
+
+const (
+ // KeelServiceTypeHTTP is the keel.service.type of an HTTP service.
+ KeelServiceTypeHTTP KeelServiceTypeAttr = "http"
+ // KeelServiceTypeGoRoutine is the keel.service.type of a goroutine service.
+ KeelServiceTypeGoRoutine KeelServiceTypeAttr = "goroutine"
+ // KeelServiceTypeSubscription is the keel.service.type of a subscription service.
+ KeelServiceTypeSubscription KeelServiceTypeAttr = "sub"
+ // KeelServiceTypeJob is the keel.service.type of a job.
+ KeelServiceTypeJob KeelServiceTypeAttr = "job"
)
// KeelServiceType returns a new attribute.KeyValue for keel.service.type.
-func KeelServiceType(v string) attribute.KeyValue {
- return KeelServiceTypeKey.String(v)
+func KeelServiceType(v KeelServiceTypeAttr) attribute.KeyValue {
+ return KeelServiceTypeKey.String(string(v))
}
// KeelServiceName returns a new attribute.KeyValue for keel.service.name.
diff --git a/semconv/rbac.go b/semconv/rbac.go
new file mode 100644
index 00000000..dcbafa95
--- /dev/null
+++ b/semconv/rbac.go
@@ -0,0 +1,36 @@
+package semconv
+
+import (
+ "go.opentelemetry.io/otel/attribute"
+)
+
+const (
+ // KeelRBACOutcomeKey is the key for keel.rbac.outcome.
+ KeelRBACOutcomeKey = attribute.Key("keel.rbac.outcome")
+ // KeelRBACAuthenticatedKey is the key for keel.rbac.authenticated.
+ KeelRBACAuthenticatedKey = attribute.Key("keel.rbac.authenticated")
+ // KeelRBACRolesKey is the key for keel.rbac.roles.
+ KeelRBACRolesKey = attribute.Key("keel.rbac.roles")
+ // KeelRBACRulePathKey is the key for keel.rbac.rule.path.
+ KeelRBACRulePathKey = attribute.Key("keel.rbac.rule.path")
+)
+
+// KeelRBACOutcome returns a new attribute.KeyValue for keel.rbac.outcome.
+func KeelRBACOutcome(v string) attribute.KeyValue {
+ return KeelRBACOutcomeKey.String(v)
+}
+
+// KeelRBACAuthenticated returns a new attribute.KeyValue for keel.rbac.authenticated.
+func KeelRBACAuthenticated(v bool) attribute.KeyValue {
+ return KeelRBACAuthenticatedKey.Bool(v)
+}
+
+// KeelRBACRoles returns a new attribute.KeyValue for keel.rbac.roles.
+func KeelRBACRoles(v []string) attribute.KeyValue {
+ return KeelRBACRolesKey.StringSlice(v)
+}
+
+// KeelRBACRulePath returns a new attribute.KeyValue for keel.rbac.rule.path.
+func KeelRBACRulePath(v string) attribute.KeyValue {
+ return KeelRBACRulePathKey.String(v)
+}
diff --git a/server.go b/server.go
index 1a54d7dc..e740f56f 100644
--- a/server.go
+++ b/server.go
@@ -3,7 +3,6 @@ package keel
import (
"context"
"errors"
- "fmt"
"net/http"
"os"
"os/signal"
@@ -22,6 +21,7 @@ import (
"github.com/foomo/keel/log"
"github.com/foomo/keel/markdown"
keelhttp "github.com/foomo/keel/net/http"
+ keelsemconv "github.com/foomo/keel/semconv"
"github.com/foomo/keel/service"
"github.com/foomo/keel/telemetry"
"github.com/go-logr/logr"
@@ -119,7 +119,7 @@ func NewServer(opts ...Option) *Server {
defer timeoutCancel()
inst.l.Info("keel closer closed",
- zap.Duration("graceful_period", inst.gracefulPeriod),
+ log.Attribute(keelsemconv.KeelGracefulPeriod(inst.gracefulPeriod)),
)
// append internal closers
@@ -257,7 +257,7 @@ func (s *Server) AddServices(services ...Service) {
// [IsCloser]; adding the same closer twice is a no-op.
func (s *Server) AddCloser(closer any) {
if !IsCloser(closer) {
- s.l.Warn("unable to add closer", log.FValue(fmt.Sprintf("%T", closer)))
+ s.l.Warn("unable to add closer", log.Attribute(keelsemconv.KeelCloserType(closer)))
}
if slices.Contains(s.closers(), closer) {
@@ -296,7 +296,7 @@ func (s *Server) AddHealthzer(typ healthz.Type, probe any) {
if IsHealthz(probe) {
s.addProbes(typ, probe)
} else {
- s.l.Debug("not a healthz probe", log.FValue(fmt.Sprintf("%T", probe)))
+ s.l.Debug("not a healthz probe", log.Attribute(keelsemconv.KeelHealthzProbeType(probe)))
}
}
diff --git a/service/goroutine.go b/service/goroutine.go
index b327acc0..1ddd03fd 100644
--- a/service/goroutine.go
+++ b/service/goroutine.go
@@ -42,7 +42,7 @@ func NewGoRoutine(l *zap.Logger, name string, handler GoRoutineFn, opts ...GoRou
}
// enrich the log
l = log.WithAttributes(l,
- keelsemconv.KeelServiceType("goroutine"),
+ keelsemconv.KeelServiceType(keelsemconv.KeelServiceTypeGoRoutine),
keelsemconv.KeelServiceName(name),
)
diff --git a/service/goroutine_test.go b/service/goroutine_test.go
index 72ef4537..f21a0b1c 100644
--- a/service/goroutine_test.go
+++ b/service/goroutine_test.go
@@ -47,14 +47,14 @@ func ExampleNewGoRoutine() {
// {"level":"info","msg":"starting keel service","keel_service_type":"goroutine","keel_service_name":"demo"}
// {"level":"info","msg":"ping","keel_service_type":"goroutine","keel_service_name":"demo","keel_service_inst":0}
// {"level":"info","msg":"ping","keel_service_type":"goroutine","keel_service_name":"demo","keel_service_inst":0}
- // {"level":"info","msg":"keel closer closed","graceful_period":"3s"}
+ // {"level":"info","msg":"keel closer closed","keel_graceful_period":3}
// {"level":"info","msg":"keel closer closed: closers"}
// {"level":"info","msg":"stopping keel service","keel_service_type":"goroutine","keel_service_name":"demo"}
// {"level":"info","msg":"context has been canceled du to graceful shutdown","keel_service_type":"goroutine","keel_service_name":"demo","keel_service_inst":0}
- // {"level":"debug","msg":"keel closer closed","name":"*service.GoRoutine"}
- // {"level":"debug","msg":"keel closer closed","name":"noop.TracerProvider"}
- // {"level":"debug","msg":"keel closer closed","name":"noop.MeterProvider"}
- // {"level":"debug","msg":"keel closer closed","name":"noop.LoggerProvider"}
+ // {"level":"debug","msg":"keel closer closed","keel_closer_type":"*service.GoRoutine"}
+ // {"level":"debug","msg":"keel closer closed","keel_closer_type":"noop.TracerProvider"}
+ // {"level":"debug","msg":"keel closer closed","keel_closer_type":"noop.MeterProvider"}
+ // {"level":"debug","msg":"keel closer closed","keel_closer_type":"noop.LoggerProvider"}
// {"level":"info","msg":"keel closer closed: complete"}
// {"level":"info","msg":"keel server stopped"}
}
diff --git a/service/http.go b/service/http.go
index 23d3e202..89c3a6f9 100644
--- a/service/http.go
+++ b/service/http.go
@@ -11,7 +11,7 @@ import (
keelhttp "github.com/foomo/keel/net/http"
keelsemconv "github.com/foomo/keel/semconv"
"github.com/pkg/errors"
- semconv "go.opentelemetry.io/otel/semconv/v1.41.0"
+ semconv "go.opentelemetry.io/otel/semconv/v1.43.0"
"go.uber.org/zap"
"github.com/foomo/keel/log"
@@ -38,7 +38,7 @@ func NewHTTP(l *zap.Logger, name, addr string, handler http.Handler, middlewares
}
// enrich the log
l = log.WithAttributes(l,
- keelsemconv.KeelServiceType("http"),
+ keelsemconv.KeelServiceType(keelsemconv.KeelServiceTypeHTTP),
keelsemconv.KeelServiceName(name),
)
diff --git a/service/http_test.go b/service/http_test.go
index 44fd37a7..7e665f85 100644
--- a/service/http_test.go
+++ b/service/http_test.go
@@ -89,13 +89,13 @@ func _ExampleNewHTTP() {
// {"level":"info","msg":"starting keel server"}
// {"level":"info","msg":"starting keel service","keel_service_type":"http","keel_service_name":"demo","net_host_ip":"localhost","net_host_port":"8080"}
// {"level":"info","msg":"OK"}
- // {"level":"info","msg":"keel closer closed","graceful_period":"10s"}
+ // {"level":"info","msg":"keel closer closed","keel_graceful_period":10}
// {"level":"info","msg":"keel closer closed: closers"}
// {"level":"info","msg":"stopping keel service","keel_service_type":"http","keel_service_name":"demo"}
- // {"level":"debug","msg":"keel closer closed","name":"*service.HTTP"}
- // {"level":"debug","msg":"keel closer closed","name":"noop.TracerProvider"}
- // {"level":"debug","msg":"keel closer closed","name":"noop.MeterProvider"}
- // {"level":"debug","msg":"keel closer closed","name":"noop.LoggerProvider"}
+ // {"level":"debug","msg":"keel closer closed","keel_closer_type":"*service.HTTP"}
+ // {"level":"debug","msg":"keel closer closed","keel_closer_type":"noop.TracerProvider"}
+ // {"level":"debug","msg":"keel closer closed","keel_closer_type":"noop.MeterProvider"}
+ // {"level":"debug","msg":"keel closer closed","keel_closer_type":"noop.LoggerProvider"}
// {"level":"info","msg":"keel closer closed: complete"}
// {"level":"info","msg":"keel server stopped"}
}
diff --git a/service/httphealthz.go b/service/httphealthz.go
index 6d5fbe2c..439215f9 100644
--- a/service/httphealthz.go
+++ b/service/httphealthz.go
@@ -8,7 +8,7 @@ import (
"github.com/foomo/keel/healthz"
"github.com/foomo/keel/interfaces"
"github.com/foomo/keel/log"
- semconv "go.opentelemetry.io/otel/semconv/v1.41.0"
+ semconv "go.opentelemetry.io/otel/semconv/v1.43.0"
"go.uber.org/zap"
)
diff --git a/service/subscription.go b/service/subscription.go
index 406b54cf..19bc9f62 100644
--- a/service/subscription.go
+++ b/service/subscription.go
@@ -9,6 +9,7 @@ import (
"github.com/foomo/goflux"
"github.com/foomo/keel/log"
keelsemconv "github.com/foomo/keel/semconv"
+ semconv "go.opentelemetry.io/otel/semconv/v1.43.0"
"go.uber.org/zap"
"golang.org/x/sync/errgroup"
)
@@ -46,7 +47,7 @@ func NewSubscription[T any](
}
l = log.WithAttributes(l,
- keelsemconv.KeelServiceType("sub"),
+ keelsemconv.KeelServiceType(keelsemconv.KeelServiceTypeSubscription),
keelsemconv.KeelServiceName(name),
)
@@ -102,7 +103,7 @@ func (s *Subscription[T]) Start(ctx context.Context) error {
l := s.l
s.wg.Go(func() error {
- l.Info("subscribing", zap.String("subject", s.subject))
+ l.Info("subscribing", log.Attribute(semconv.MessagingDestinationName(s.subject)))
return s.subscriber.Subscribe(ctx, s.subject, s.handler)
})
@@ -126,7 +127,7 @@ func (s *Subscription[T]) Close(ctx context.Context) error {
s.cancelLock.Unlock()
if err := s.subscriber.Close(); err != nil {
- s.l.Warn("subscriber close failed", zap.Error(err))
+ log.WithError(s.l, err).Warn("subscriber close failed")
}
return s.wg.Wait()
diff --git a/serviceenabler.go b/serviceenabler.go
index ff975c0d..1d89f83f 100644
--- a/serviceenabler.go
+++ b/serviceenabler.go
@@ -159,12 +159,12 @@ func (w *ServiceEnabler) watch(ctx context.Context) {
if value {
go func() {
if err := w.enable(ctx); err != nil {
- w.l.Fatal("failed to dynamically start service", log.FError(err))
+ log.WithError(w.l, err).Fatal("failed to dynamically start service")
}
}()
} else {
if err := w.disable(context.TODO()); err != nil { //nolint:contextcheck
- w.l.Fatal("failed to dynamically close service", log.FError(err))
+ log.WithError(w.l, err).Fatal("failed to dynamically close service")
}
}
}
diff --git a/telemetry/code.go b/telemetry/code.go
index 49096212..512140fe 100644
--- a/telemetry/code.go
+++ b/telemetry/code.go
@@ -3,7 +3,7 @@ package telemetry
import (
goruntime "github.com/foomo/go/runtime"
"go.opentelemetry.io/otel/attribute"
- semconv "go.opentelemetry.io/otel/semconv/v1.41.0"
+ semconv "go.opentelemetry.io/otel/semconv/v1.43.0"
)
// CodeCaller returns the code.function.name, code.file.path and
diff --git a/telemetry/context.go b/telemetry/context.go
index 611a4267..2d98a02d 100644
--- a/telemetry/context.go
+++ b/telemetry/context.go
@@ -152,7 +152,8 @@ func (c Context) DeferEndSpan(err *error, opts ...trace.SpanEndOption) {
DeferEndSpan(c.Span(), err, opts...)
}
-// SetSpanStatusOK sets the status of the current span to ok.
+// SetSpanStatusOK sets the status of the current span to ok, see
+// [SetSpanStatusOK] for when to use it.
func (c Context) SetSpanStatusOK() {
c.Span().SetStatus(codes.Ok, "")
}
@@ -160,7 +161,6 @@ func (c Context) SetSpanStatusOK() {
// SetSpanStatusError sets the status of the current span to error with the
// given description.
func (c Context) SetSpanStatusError(description string) {
- c.Span().SetStatus(codes.Error, description)
SetSpanStatusError(c.Span(), description)
}
@@ -176,7 +176,7 @@ func (c Context) SetSpanAttributes(kv ...attribute.KeyValue) {
// RecordError records a non-nil err with kv and a stack trace on the
// current span and sets the span status to error with the root cause
-// message. It does not log the error.
+// message and error.type. It does not log the error.
func (c Context) RecordError(err error, kv ...attribute.KeyValue) {
if err != nil {
sp := c.Span()
@@ -185,6 +185,7 @@ func (c Context) RecordError(err error, kv ...attribute.KeyValue) {
trace.WithAttributes(CodeStacktrace(5, 1)),
)
sp.SetStatus(codes.Error, goerrors.Cause(err).Error())
+ sp.SetAttributes(foomosemconv.ErrorType(err))
}
}
diff --git a/telemetry/logger.go b/telemetry/logger.go
index 4a8a1a70..fb47426c 100644
--- a/telemetry/logger.go
+++ b/telemetry/logger.go
@@ -8,7 +8,7 @@ import (
"github.com/foomo/keel/log"
foomosemconv "github.com/foomo/opentelemetry-go/semconv"
"go.opentelemetry.io/otel/attribute"
- semconv "go.opentelemetry.io/otel/semconv/v1.41.0"
+ semconv "go.opentelemetry.io/otel/semconv/v1.43.0"
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
diff --git a/telemetry/loggerprovider.go b/telemetry/loggerprovider.go
index a73356b1..b5805caf 100644
--- a/telemetry/loggerprovider.go
+++ b/telemetry/loggerprovider.go
@@ -6,11 +6,11 @@ import (
"github.com/foomo/keel/env"
otelzap "github.com/foomo/keel/internal/otel/exporters/zap"
otelzapbridge "go.opentelemetry.io/contrib/bridges/otelzap"
+ "go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc"
"go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp"
"go.opentelemetry.io/otel/exporters/stdout/stdoutlog"
"go.opentelemetry.io/otel/log"
- "go.opentelemetry.io/otel/log/global"
"go.opentelemetry.io/otel/log/noop"
sdklog "go.opentelemetry.io/otel/sdk/log"
"go.uber.org/zap"
@@ -22,7 +22,7 @@ const instrumentationName = "github.com/foomo/keel"
// LoggerProvider returns the global logger provider instance used throughout the application.
func LoggerProvider() log.LoggerProvider {
- return global.GetLoggerProvider()
+ return otel.GetLoggerProvider()
}
// NewNoopLoggerProvider returns a no-op [log.LoggerProvider].
@@ -113,7 +113,7 @@ func newLoggerProvider(ctx context.Context, p sdklog.Processor) (log.LoggerProvi
sdklog.WithResource(resource),
sdklog.WithProcessor(p),
)
- global.SetLoggerProvider(provider)
+ otel.SetLoggerProvider(provider)
return provider, nil
}
diff --git a/telemetry/meter.go b/telemetry/meter.go
index 5066f48b..a78dbb6d 100644
--- a/telemetry/meter.go
+++ b/telemetry/meter.go
@@ -2,11 +2,13 @@ package telemetry
import (
"go.opentelemetry.io/otel/metric"
+ semconv "go.opentelemetry.io/otel/semconv/v1.43.0"
)
// Meter returns a [metric.Meter] named [Name] from the global
// [MeterProvider]. The instrumentation scope version defaults to [Version];
-// pass [metric.WithInstrumentationVersion] to override it.
+// pass [metric.WithInstrumentationVersion] to override it. The schema URL
+// defaults to the semconv version used by keel.
func Meter(opts ...metric.MeterOption) metric.Meter {
- return MeterProvider().Meter(Name, append([]metric.MeterOption{metric.WithInstrumentationVersion(Version())}, opts...)...)
+ return MeterProvider().Meter(Name, append([]metric.MeterOption{metric.WithInstrumentationVersion(Version()), metric.WithSchemaURL(semconv.SchemaURL)}, opts...)...)
}
diff --git a/telemetry/profiler.go b/telemetry/profiler.go
index a1258de4..b2bf4369 100644
--- a/telemetry/profiler.go
+++ b/telemetry/profiler.go
@@ -10,7 +10,7 @@ import (
otelpyroscope "github.com/grafana/otel-profiling-go"
"github.com/grafana/pyroscope-go"
"go.opentelemetry.io/otel"
- semconv "go.opentelemetry.io/otel/semconv/v1.41.0"
+ semconv "go.opentelemetry.io/otel/semconv/v1.43.0"
)
// NewProfiler starts a pyroscope profiler named after the service and tagged
diff --git a/telemetry/resource.go b/telemetry/resource.go
index 2a6273da..80ac5f35 100644
--- a/telemetry/resource.go
+++ b/telemetry/resource.go
@@ -6,7 +6,7 @@ import (
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/sdk/resource"
- semconv "go.opentelemetry.io/otel/semconv/v1.41.0"
+ semconv "go.opentelemetry.io/otel/semconv/v1.43.0"
)
// envAttributes maps environment variables to semantic attributes.
diff --git a/telemetry/span.go b/telemetry/span.go
index 62501e83..2b6ab163 100644
--- a/telemetry/span.go
+++ b/telemetry/span.go
@@ -7,9 +7,10 @@ import (
goerrors "github.com/foomo/go/errors"
goruntime "github.com/foomo/go/runtime"
keelsemconv "github.com/foomo/keel/semconv"
+ foomosemconv "github.com/foomo/opentelemetry-go/semconv"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
- semconv "go.opentelemetry.io/otel/semconv/v1.41.0"
+ semconv "go.opentelemetry.io/otel/semconv/v1.43.0"
"go.opentelemetry.io/otel/trace"
)
@@ -20,15 +21,21 @@ func Start(ctx context.Context, spanName string, opts ...trace.SpanStartOption)
return StartSpanWithSkip(ctx, 1, opts...)
}
-// StartSpan starts a span named after the calling package, annotated with
-// the caller's function, file and line, from the global [Tracer].
+// StartSpan starts a span named