Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(attributes) bump semconv to 1.26.0 #6172

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
### Changed

- The function signature of `NewLogProcessor` in `go.opentelemetry.io/contrib/processors/minsev` has changed to accept the added `Severitier` interface instead of a `log.Severity`. (#6116)
- Upgrade the `go.opentelemetry.io/otel/semconv/v1.17.0` dependency to `go.opentelemetry.io/otel/semconv/v1.26.0` in `go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo`. (#6172)
- Rename attributes `db.operation` to `db.operation.name`, `db.name` to `db.namespace`, `net.peer.port` to `network.peer.port`, `net.transport` to `network.transport` and `db.statement` to `db.query.text` in `go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo`. (#6172)
- `NewSDK` in `go.opentelemetry.io/contrib/config` now returns a no-op SDK if `disabled` is set to `true`. (#6185)

### Fixed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,23 @@
// This package is compatible with v0.2.0 of
// go.mongodb.org/mongo-driver/mongo.
//
// `NewMonitor` will return an event.CommandMonitor which is used to trace
// NewMonitor will return an event.CommandMonitor which is used to trace
// requests.
//
// This code was originally based on the following:
// - https://github.com/DataDog/dd-trace-go/tree/02f0449efa3cb382d499fadc873957385dcb2192/contrib/go.mongodb.org/mongo-driver/mongo
// - https://github.com/DataDog/dd-trace-go/tree/v1.23.3/ddtrace/ext
// - https://github.com/DataDog/dd-trace-go/tree/02f0449efa3cb382d499fadc873957385dcb2192/contrib/go.mongodb.org/mongo-driver/mongo
// - https://github.com/DataDog/dd-trace-go/tree/v1.23.3/ddtrace/ext
//
// The "OTEL_SEMCONV_STABILITY_OPT_IN" environment variable can be used to opt
// into semconv/v1.26.0:
// - "mongo/v1.26.0": emit v1.26.0 semantic conventions
// - "mongo/v1.17.0": emit v1.17.0 (default) semantic conventions
// - "mongo/dup": emit the stable version (v1.17.0) and all other supported semantic conventions
//
// "mongo/dup" takes precedence over "mongo/v*". By default, otelmongo only emits v1.17.0.
//
// For example, the following will use v1.26.0 for otelmongo and duplicate
// attributes (old + new) for otelhttp:
//
// export OTEL_SEMCONV_STABILITY_OPT_IN="mongo/v1.26.0,http/dup"
package otelmongo // import "go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo"
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,20 @@ module go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/m
go 1.22

require (
github.com/stretchr/testify v1.9.0
go.mongodb.org/mongo-driver v1.17.1
go.opentelemetry.io/otel v1.30.0
go.opentelemetry.io/otel/trace v1.30.0
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/klauspost/compress v1.17.10 // indirect
github.com/montanaflynn/stats v0.7.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.1.2 // indirect
github.com/xdg-go/stringprep v1.0.4 // indirect
Expand All @@ -22,4 +25,5 @@ require (
golang.org/x/crypto v0.27.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/text v0.18.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
Original file line number Diff line number Diff line change
Expand Up @@ -63,5 +63,7 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ package otelmongo // import "go.opentelemetry.io/contrib/instrumentation/go.mong
import (
"context"
"fmt"
"net"
"os"
"strconv"
"strings"
"sync"

"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
semconv "go.opentelemetry.io/otel/semconv/v1.17.0"
semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
"go.opentelemetry.io/otel/trace"

"go.mongodb.org/mongo-driver/bson"
Expand All @@ -26,30 +28,34 @@ type spanKey struct {

type monitor struct {
sync.Mutex
spans map[spanKey]trace.Span
cfg config
spans map[spanKey]trace.Span
cfg config
semconvRegistry *semconvRegistry
}

func (m *monitor) Started(ctx context.Context, evt *event.CommandStartedEvent) {
var spanName string

hostname, port := peerInfo(evt)

attrs := []attribute.KeyValue{
semconv.DBSystemMongoDB,
semconv.DBOperation(evt.CommandName),
semconv.DBName(evt.DatabaseName),
semconv.NetPeerName(hostname),
semconv.NetPeerPort(port),
semconv.NetTransportTCP,
}
attrs := []attribute.KeyValue{semconv.DBSystemMongoDB}

attrs = appendOpNameAttrs(attrs, m.semconvRegistry, evt.CommandName)
attrs = appendDBNamespace(attrs, m.semconvRegistry, evt.DatabaseName)
attrs = appendNetworkPort(attrs, m.semconvRegistry, port)
attrs = appendNetworkHost(attrs, m.semconvRegistry, hostname)
attrs = appendNetworkAddress(attrs, m.semconvRegistry, net.JoinHostPort(hostname, strconv.Itoa(port)))
attrs = appendNetworkTransport(attrs, m.semconvRegistry)

if !m.cfg.CommandAttributeDisabled {
attrs = append(attrs, semconv.DBStatement(sanitizeCommand(evt.Command)))
attrs = appendDBStatement(attrs, m.semconvRegistry, sanitizeCommand(evt.Command))
}

var spanName string
if collection, err := extractCollection(evt); err == nil && collection != "" {
spanName = collection + "."
attrs = append(attrs, semconv.DBMongoDBCollection(collection))

attrs = appendCollection(attrs, m.semconvRegistry, collection)
}

spanName += evt.CommandName
opts := []trace.SpanStartOption{
trace.WithSpanKind(trace.SpanKindClient),
Expand Down Expand Up @@ -125,8 +131,9 @@ func extractCollection(evt *event.CommandStartedEvent) (string, error) {
func NewMonitor(opts ...Option) *event.CommandMonitor {
cfg := newConfig(opts...)
m := &monitor{
spans: make(map[spanKey]trace.Span),
cfg: cfg,
spans: make(map[spanKey]trace.Span),
cfg: cfg,
semconvRegistry: newSemconvRegistry(strings.Split(os.Getenv(semconvOptIn), ",")...),
}
return &event.CommandMonitor{
Started: m.Started,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package otelmongo // import "go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo"

import (
"go.opentelemetry.io/otel/attribute"

semconv1170 "go.opentelemetry.io/otel/semconv/v1.17.0"
semconv1260 "go.opentelemetry.io/otel/semconv/v1.26.0"
)

const (
// "OTEL_SEMCONV_STABILITY_OPT_IN" can be used to opt into semconv/v1.26.0. See
// doc.go for more information.
semconvOptIn = "OTEL_SEMCONV_STABILITY_OPT_IN"
semconvOptIn1260 = "mongo/v1.26.0"
semconvOptIn1170 = "mongo/v1.17.0"
semconvOptInDup = "mongo/dup" // v1.17.0 and all other supported semconv
)

type semconvRegistry struct {
versions []string
dup bool

opName map[string]func(string) attribute.KeyValue
dbNamespace map[string]func(string) attribute.KeyValue
dbStatement map[string]func(string) attribute.KeyValue
networkPort map[string]func(int) attribute.KeyValue
networkHost map[string]func(string) attribute.KeyValue
networkAddress map[string]func(string) attribute.KeyValue
networkTransport map[string]func(string) attribute.KeyValue
collection map[string]func(string) attribute.KeyValue
}

func newSemconvRegistry(versions ...string) *semconvRegistry {
reg := &semconvRegistry{
opName: make(map[string]func(string) attribute.KeyValue),
dbNamespace: make(map[string]func(string) attribute.KeyValue),
dbStatement: make(map[string]func(string) attribute.KeyValue),
networkPort: make(map[string]func(int) attribute.KeyValue),
networkHost: make(map[string]func(string) attribute.KeyValue),
networkAddress: make(map[string]func(string) attribute.KeyValue),
networkTransport: make(map[string]func(string) attribute.KeyValue),
collection: make(map[string]func(string) attribute.KeyValue),
}

// Don't include unknown versions
for _, version := range versions {
if version == semconvOptInDup {
reg.dup = true
}

if version == semconvOptIn1170 || version == semconvOptIn1260 {
reg.versions = append(reg.versions, version)
}
}

// If we didn't pick up any versions and we are not duplicating, then use
// the default v1.17.0.
if len(reg.versions) == 0 && !reg.dup {
reg.versions = append(reg.versions, semconvOptIn1170)
}

// v1.17.0
reg.opName[semconvOptIn1170] = semconv1170.DBOperation
reg.dbNamespace[semconvOptIn1170] = semconv1170.DBName
reg.dbStatement[semconvOptIn1170] = semconv1170.DBStatement
reg.networkPort[semconvOptIn1170] = semconv1170.NetPeerPort
reg.networkHost[semconvOptIn1170] = semconv1170.NetPeerName
reg.collection[semconvOptIn1170] = semconv1170.DBMongoDBCollection
reg.networkTransport[semconvOptIn1170] = func(string) attribute.KeyValue { return semconv1170.NetTransportTCP }

// v1.26.0
reg.opName[semconvOptIn1260] = semconv1260.DBOperationName
reg.dbNamespace[semconvOptIn1260] = semconv1260.DBNamespace
reg.dbStatement[semconvOptIn1260] = semconv1260.DBQueryText
reg.networkPort[semconvOptIn1260] = semconv1260.NetworkPeerPort
reg.networkAddress[semconvOptIn1260] = semconv1260.NetworkPeerAddress
reg.collection[semconvOptIn1260] = semconv1260.DBCollectionName
reg.networkTransport[semconvOptIn1260] = func(string) attribute.KeyValue { return semconv1260.NetworkTransportTCP }

return reg
}

func appendAttrs[T string | int](
attrs []attribute.KeyValue,
reg *semconvRegistry,
semconvMap map[string]func(T) attribute.KeyValue,
val T,
) []attribute.KeyValue {
if reg.dup {
for _, fn := range semconvMap {
attrs = append(attrs, fn(val))
}

return attrs
}

for _, version := range reg.versions {
fn, ok := semconvMap[version]
if ok {
attrs = append(attrs, fn(val))
}
}

return attrs
}

func appendOpNameAttrs(attrs []attribute.KeyValue, reg *semconvRegistry, op string) []attribute.KeyValue {
return appendAttrs(attrs, reg, reg.opName, op)
}

func appendDBNamespace(attrs []attribute.KeyValue, reg *semconvRegistry, ns string) []attribute.KeyValue {
return appendAttrs(attrs, reg, reg.dbNamespace, ns)
}

func appendDBStatement(attrs []attribute.KeyValue, reg *semconvRegistry, stmt string) []attribute.KeyValue {
return appendAttrs(attrs, reg, reg.dbStatement, stmt)
}

func appendNetworkPort(attrs []attribute.KeyValue, reg *semconvRegistry, p int) []attribute.KeyValue {
return appendAttrs(attrs, reg, reg.networkPort, p)
}

func appendNetworkHost(attrs []attribute.KeyValue, reg *semconvRegistry, h string) []attribute.KeyValue {
return appendAttrs(attrs, reg, reg.networkHost, h)
}

func appendNetworkAddress(attrs []attribute.KeyValue, reg *semconvRegistry, addr string) []attribute.KeyValue {
return appendAttrs(attrs, reg, reg.networkAddress, addr)
}

func appendNetworkTransport(attrs []attribute.KeyValue, reg *semconvRegistry) []attribute.KeyValue {
return appendAttrs(attrs, reg, reg.networkTransport, "")
}

func appendCollection(attrs []attribute.KeyValue, reg *semconvRegistry, coll string) []attribute.KeyValue {
return appendAttrs(attrs, reg, reg.collection, coll)
}
Loading
Loading