From 6ef6ee2383297bdbd4a0ad86a9417d3464d7c888 Mon Sep 17 00:00:00 2001 From: Tyler Yahn Date: Thu, 6 Feb 2025 13:08:26 -0800 Subject: [PATCH] Replace use of github.com/hashicorp/go-version Replace with github.com/Masterminds/semver/v3 Resolve #1753 --- go.mod | 2 +- go.sum | 4 +- internal/pkg/inject/consts.go | 8 +- internal/pkg/inject/consts_test.go | 8 +- .../otel/traceglobal/probe.go | 35 +++---- .../google.golang.org/grpc/client/probe.go | 6 +- .../google.golang.org/grpc/server/probe.go | 67 ++++++-------- .../bpf/net/http/server/probe.go | 40 ++++---- .../pkg/instrumentation/manager_load_test.go | 4 +- internal/pkg/instrumentation/manager_test.go | 13 ++- .../pkg/instrumentation/probe/constraint.go | 6 +- internal/pkg/instrumentation/probe/probe.go | 6 +- .../instrumentation/testutils/testutils.go | 8 +- internal/pkg/instrumentation/utils/ebpf.go | 12 +-- .../pkg/instrumentation/utils/kernel_linux.go | 23 ++--- .../utils/kernel_linux_test.go | 16 ++-- .../pkg/instrumentation/utils/kernel_other.go | 8 +- internal/pkg/process/analyze.go | 16 ++-- internal/pkg/process/ptrace_linux.go | 14 +-- internal/pkg/structfield/json.go | 10 +- internal/pkg/structfield/structfield.go | 92 ++++++------------- internal/pkg/structfield/structfield_test.go | 42 ++++----- internal/test/e2e/autosdk/go.mod | 2 +- internal/test/e2e/autosdk/go.sum | 4 +- internal/tools/go.mod | 4 +- internal/tools/inspect/app.go | 4 +- internal/tools/inspect/builder.go | 10 +- internal/tools/inspect/cache.go | 4 +- .../tools/inspect/cmd/offsetgen/versions.go | 24 ++--- internal/tools/inspect/inspector.go | 6 +- internal/tools/inspect/manifest.go | 6 +- 31 files changed, 231 insertions(+), 273 deletions(-) diff --git a/go.mod b/go.mod index 1066e1e6c..464257359 100644 --- a/go.mod +++ b/go.mod @@ -18,9 +18,9 @@ retract ( ) require ( + github.com/Masterminds/semver/v3 v3.3.1 github.com/cilium/ebpf v0.17.2 github.com/go-logr/stdr v1.2.2 - github.com/hashicorp/go-version v1.7.0 github.com/pkg/errors v0.9.1 github.com/stretchr/testify v1.10.0 github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2 diff --git a/go.sum b/go.sum index 766dad1a6..bf563b572 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4= +github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= @@ -27,8 +29,6 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.0 h1:VD1gqscl4nYs1YxVuSdemTrSgTKrwOWDK0FVFMqm+Cg= github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.0/go.mod h1:4EgsQoS4TOhJizV+JTFg40qx1Ofh3XmXEQNBpgvNT40= -github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= -github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/jsimonetti/rtnetlink/v2 v2.0.1 h1:xda7qaHDSVOsADNouv7ukSuicKZO7GgVUCXxpaIEIlM= diff --git a/internal/pkg/inject/consts.go b/internal/pkg/inject/consts.go index b1471f6c0..f744e7283 100644 --- a/internal/pkg/inject/consts.go +++ b/internal/pkg/inject/consts.go @@ -10,8 +10,8 @@ import ( "errors" "fmt" + "github.com/Masterminds/semver/v3" "github.com/cilium/ebpf" - "github.com/hashicorp/go-version" "go.opentelemetry.io/auto/internal/pkg/process" "go.opentelemetry.io/auto/internal/pkg/structfield" @@ -139,7 +139,7 @@ func WithKeyValue(key string, value interface{}) Option { // // If the offset value is not known, an error is returned when the returned // Option is used. -func WithOffset(key string, id structfield.ID, ver *version.Version) Option { +func WithOffset(key string, id structfield.ID, ver *semver.Version) Option { if ver == nil { return errOpt{ err: fmt.Errorf("missing version: %s", id), @@ -187,10 +187,10 @@ func FindOffset(id structfield.ID, td *process.TargetDetails) (structfield.Offse return structfield.OffsetKey{Offset: uint64(v), Valid: true}, err // nolint: gosec // Bounded. } -func GetOffset(id structfield.ID, ver *version.Version) (structfield.OffsetKey, bool) { +func GetOffset(id structfield.ID, ver *semver.Version) (structfield.OffsetKey, bool) { return offsets.GetOffset(id, ver) } -func GetLatestOffset(id structfield.ID) (structfield.OffsetKey, *version.Version) { +func GetLatestOffset(id structfield.ID) (structfield.OffsetKey, *semver.Version) { return offsets.GetLatestOffset(id) } diff --git a/internal/pkg/inject/consts_test.go b/internal/pkg/inject/consts_test.go index c762c41cf..5ca2404cf 100644 --- a/internal/pkg/inject/consts_test.go +++ b/internal/pkg/inject/consts_test.go @@ -6,7 +6,7 @@ package inject import ( "testing" - "github.com/hashicorp/go-version" + "github.com/Masterminds/semver/v3" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -54,10 +54,8 @@ func TestWithAllocationDetails(t *testing.T) { } func TestWithOffset(t *testing.T) { - v10, err := version.NewVersion("1.0") - require.NoError(t, err) - v18, err := version.NewVersion("1.8") - require.NoError(t, err) + v10 := semver.New(1, 0, 0, "", "") + v18 := semver.New(1, 8, 0, "", "") const off uint64 = 1 id := structfield.NewID("std", "net/http", "Request", "Method") diff --git a/internal/pkg/instrumentation/bpf/go.opentelemetry.io/otel/traceglobal/probe.go b/internal/pkg/instrumentation/bpf/go.opentelemetry.io/otel/traceglobal/probe.go index 4d69cfffc..a8ce1aa4b 100644 --- a/internal/pkg/instrumentation/bpf/go.opentelemetry.io/otel/traceglobal/probe.go +++ b/internal/pkg/instrumentation/bpf/go.opentelemetry.io/otel/traceglobal/probe.go @@ -19,8 +19,8 @@ import ( "go.opentelemetry.io/auto/internal/pkg/process" "go.opentelemetry.io/auto/internal/pkg/structfield" + "github.com/Masterminds/semver/v3" "github.com/cilium/ebpf/perf" - "github.com/hashicorp/go-version" "golang.org/x/sys/unix" "go.opentelemetry.io/otel/attribute" @@ -42,26 +42,27 @@ const ( minGoMaps = "1.24.0" ) +func must(c *semver.Constraints, err error) *semver.Constraints { + if err != nil { + panic(err) + } + return c +} + var ( otelWithAutoSDK = probe.PackageConstrainst{ - Package: "go.opentelemetry.io/otel", - Constraints: version.MustConstraints( - version.NewConstraint(">= " + minAutoSDK), - ), + Package: "go.opentelemetry.io/otel", + Constraints: must(semver.NewConstraint(">= " + minAutoSDK)), FailureMode: probe.FailureModeIgnore, } otelWithoutAutoSDK = probe.PackageConstrainst{ - Package: "go.opentelemetry.io/otel", - Constraints: version.MustConstraints( - version.NewConstraint("< " + minAutoSDK), - ), + Package: "go.opentelemetry.io/otel", + Constraints: must(semver.NewConstraint("< " + minAutoSDK)), FailureMode: probe.FailureModeIgnore, } goWithoutSwissMaps = probe.PackageConstrainst{ - Package: "std", - Constraints: version.MustConstraints( - version.NewConstraint("< " + minGoMaps), - ), + Package: "std", + Constraints: must(semver.NewConstraint("< " + minGoMaps)), // Warn in logs that this is not supported. FailureMode: probe.FailureModeWarn, } @@ -251,7 +252,7 @@ type tracerIDContainsSchemaURL struct{} // Prior to v1.28 the tracer key did not contain schemaURL. However, in that version a // change was made to include it. // https://github.com/open-telemetry/opentelemetry-go/pull/5426/files -var schemaAddedToTracerKeyVer = version.Must(version.NewVersion("1.28.0")) +var schemaAddedToTracerKeyVer = semver.New(1, 28, 0, "", "") func (c tracerIDContainsSchemaURL) InjectOption(td *process.TargetDetails) (inject.Option, error) { ver, ok := td.Modules["go.opentelemetry.io/otel"] @@ -259,12 +260,12 @@ func (c tracerIDContainsSchemaURL) InjectOption(td *process.TargetDetails) (inje return nil, fmt.Errorf("unknown module version: %s", pkg) } - return inject.WithKeyValue("tracer_id_contains_schemaURL", ver.GreaterThanOrEqual(schemaAddedToTracerKeyVer)), nil + return inject.WithKeyValue("tracer_id_contains_schemaURL", ver.GreaterThanEqual(schemaAddedToTracerKeyVer)), nil } // In v1.32.0 the tracer key was updated to include the scope attributes. // https://github.com/open-telemetry/opentelemetry-go/pull/5924/files -var scopeAttributesAddedToTracerKeyVer = version.Must(version.NewVersion("1.32.0")) +var scopeAttributesAddedToTracerKeyVer = semver.New(1, 32, 0, "", "") // tracerIDContainsScopeAttributes is a Probe Const defining whether the tracer key contains scope attributes. type tracerIDContainsScopeAttributes struct{} @@ -275,7 +276,7 @@ func (c tracerIDContainsScopeAttributes) InjectOption(td *process.TargetDetails) return nil, fmt.Errorf("unknown module version: %s", pkg) } - return inject.WithKeyValue("tracer_id_contains_scope_attributes", ver.GreaterThanOrEqual(scopeAttributesAddedToTracerKeyVer)), nil + return inject.WithKeyValue("tracer_id_contains_scope_attributes", ver.GreaterThanEqual(scopeAttributesAddedToTracerKeyVer)), nil } type attributeKeyVal struct { diff --git a/internal/pkg/instrumentation/bpf/google.golang.org/grpc/client/probe.go b/internal/pkg/instrumentation/bpf/google.golang.org/grpc/client/probe.go index 54f311a00..8e4702e26 100644 --- a/internal/pkg/instrumentation/bpf/google.golang.org/grpc/client/probe.go +++ b/internal/pkg/instrumentation/bpf/google.golang.org/grpc/client/probe.go @@ -10,8 +10,8 @@ import ( "net" "strconv" + "github.com/Masterminds/semver/v3" "github.com/cilium/ebpf" - "github.com/hashicorp/go-version" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/otel/attribute" @@ -36,7 +36,7 @@ const ( var ( writeStatus = false - writeStatusMinVersion = version.Must(version.NewVersion("1.40.0")) + writeStatusMinVersion = semver.New(1, 40, 0, "", "") ) type writeStatusConst struct{} @@ -46,7 +46,7 @@ func (w writeStatusConst) InjectOption(td *process.TargetDetails) (inject.Option if !ok { return nil, fmt.Errorf("unknown module version: %s", pkg) } - if ver.GreaterThanOrEqual(writeStatusMinVersion) { + if ver.GreaterThanEqual(writeStatusMinVersion) { writeStatus = true } return inject.WithKeyValue("write_status_supported", writeStatus), nil diff --git a/internal/pkg/instrumentation/bpf/google.golang.org/grpc/server/probe.go b/internal/pkg/instrumentation/bpf/google.golang.org/grpc/server/probe.go index 4a095b48b..594eaf0ab 100644 --- a/internal/pkg/instrumentation/bpf/google.golang.org/grpc/server/probe.go +++ b/internal/pkg/instrumentation/bpf/google.golang.org/grpc/server/probe.go @@ -8,7 +8,7 @@ import ( "log/slog" "net" - "github.com/hashicorp/go-version" + "github.com/Masterminds/semver/v3" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/otel/attribute" @@ -27,23 +27,17 @@ import ( //go:generate go run github.com/cilium/ebpf/cmd/bpf2go -target amd64,arm64 bpf ./bpf/probe.bpf.c -const ( - // pkg is the package being instrumented. - pkg = "google.golang.org/grpc" - - // writeStatusMin is the minimum version of grpc that supports status - // parsing. - writeStatusMin = "1.40.0" - - // serverStream is the version the both the writeStatus and handleStream - // methods changed to accept a *transport.ServerStream instead of a - // *transport.Stream. - serverStream = "1.69.0" -) +// pkg is the package being instrumented. +const pkg = "google.golang.org/grpc" var ( - writeStatusMinVersion = version.Must(version.NewVersion(writeStatusMin)) - serverStreamVersion = version.Must(version.NewVersion(serverStream)) + // writeStatusMinVersion is the minimum version of grpc that supports + // status parsing. + writeStatusMinVersion = semver.New(1, 40, 0, "", "") + // serverStreamVersion is the version the both the writeStatus and + // handleStream methods changed to accept a *transport.ServerStream instead + // of a *transport.Stream. + serverStreamVersion = semver.New(1, 69, 0, "", "") ) // New returns a new [probe.Probe]. @@ -133,10 +127,8 @@ func New(logger *slog.Logger, ver string) probe.Probe { ReturnProbe: "uprobe_server_handleStream_Returns", PackageConstrainsts: []probe.PackageConstrainst{ { - Package: "google.golang.org/grpc", - Constraints: version.MustConstraints( - version.NewConstraint("< " + serverStream), - ), + Package: "google.golang.org/grpc", + Constraints: must(semver.NewConstraint("< " + serverStreamVersion.String())), FailureMode: probe.FailureModeIgnore, }, }, @@ -147,10 +139,8 @@ func New(logger *slog.Logger, ver string) probe.Probe { ReturnProbe: "uprobe_server_handleStream2_Returns", PackageConstrainsts: []probe.PackageConstrainst{ { - Package: "google.golang.org/grpc", - Constraints: version.MustConstraints( - version.NewConstraint(">= " + serverStream), - ), + Package: "google.golang.org/grpc", + Constraints: must(semver.NewConstraint(">= " + serverStreamVersion.String())), FailureMode: probe.FailureModeIgnore, }, }, @@ -165,11 +155,9 @@ func New(logger *slog.Logger, ver string) probe.Probe { PackageConstrainsts: []probe.PackageConstrainst{ { Package: "google.golang.org/grpc", - Constraints: version.MustConstraints( - version.NewConstraint( - fmt.Sprintf("> %s, < %s", writeStatusMin, serverStream), - ), - ), + Constraints: must(semver.NewConstraint( + fmt.Sprintf("> %s, < %s", writeStatusMinVersion, serverStreamVersion), + )), FailureMode: probe.FailureModeIgnore, }, }, @@ -179,10 +167,8 @@ func New(logger *slog.Logger, ver string) probe.Probe { EntryProbe: "uprobe_http2Server_WriteStatus2", PackageConstrainsts: []probe.PackageConstrainst{ { - Package: "google.golang.org/grpc", - Constraints: version.MustConstraints( - version.NewConstraint(">= " + serverStream), - ), + Package: "google.golang.org/grpc", + Constraints: must(semver.NewConstraint(">= " + serverStreamVersion.String())), FailureMode: probe.FailureModeIgnore, }, }, @@ -196,6 +182,13 @@ func New(logger *slog.Logger, ver string) probe.Probe { } } +func must(c *semver.Constraints, err error) *semver.Constraints { + if err != nil { + panic(err) + } + return c +} + // framePosConst is a Probe Const defining the position of the // http.MetaHeadersFrame parameter of the http2Server.operateHeaders method. type framePosConst struct{} @@ -204,7 +197,7 @@ type framePosConst struct{} // context was added as the first parameter. The frame became the second // parameter: // https://github.com/grpc/grpc-go/pull/6716/files#diff-4058722211b8d52e2d5b0c0b7542059ed447a04017b69520d767e94a9493409eR334 -var paramChangeVer = version.Must(version.NewVersion("1.60.0")) +var paramChangeVer = semver.New(1, 60, 0, "", "") func (c framePosConst) InjectOption(td *process.TargetDetails) (inject.Option, error) { ver, ok := td.Modules[pkg] @@ -212,13 +205,13 @@ func (c framePosConst) InjectOption(td *process.TargetDetails) (inject.Option, e return nil, fmt.Errorf("unknown module version: %s", pkg) } - return inject.WithKeyValue("is_new_frame_pos", ver.GreaterThanOrEqual(paramChangeVer)), nil + return inject.WithKeyValue("is_new_frame_pos", ver.GreaterThanEqual(paramChangeVer)), nil } type serverAddrConst struct{} var ( - serverAddrMinVersion = version.Must(version.NewVersion("1.60.0")) + serverAddrMinVersion = semver.New(1, 60, 0, "", "") serverAddr = false ) @@ -227,7 +220,7 @@ func (w serverAddrConst) InjectOption(td *process.TargetDetails) (inject.Option, if !ok { return nil, fmt.Errorf("unknown module version: %s", pkg) } - if ver.GreaterThanOrEqual(serverAddrMinVersion) { + if ver.GreaterThanEqual(serverAddrMinVersion) { serverAddr = true } return inject.WithKeyValue("server_addr_supported", serverAddr), nil diff --git a/internal/pkg/instrumentation/bpf/net/http/server/probe.go b/internal/pkg/instrumentation/bpf/net/http/server/probe.go index 6b7231d85..7cc531c70 100644 --- a/internal/pkg/instrumentation/bpf/net/http/server/probe.go +++ b/internal/pkg/instrumentation/bpf/net/http/server/probe.go @@ -7,7 +7,7 @@ import ( "log/slog" "strings" - "github.com/hashicorp/go-version" + "github.com/Masterminds/semver/v3" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/otel/attribute" @@ -26,20 +26,25 @@ import ( //go:generate go run github.com/cilium/ebpf/cmd/bpf2go -target amd64,arm64 bpf ./bpf/probe.bpf.c -const ( - // pkg is the package being instrumented. - pkg = "net/http" - minGoSwissMaps = "1.24.0" -) +// pkg is the package being instrumented. +const pkg = "net/http" -var goWithSwissMaps = probe.PackageConstrainst{ - Package: "std", - Constraints: version.MustConstraints( - version.NewConstraint(">= " + minGoSwissMaps), - ), - // Don't warn, we have a backup path. - FailureMode: probe.FailureModeIgnore, -} +var ( + minGoSwissMapsVersion = semver.New(1, 24, 0, "", "") + + goWithSwissMaps = probe.PackageConstrainst{ + Package: "std", + Constraints: func() *semver.Constraints { + c, err := semver.NewConstraint(">= " + minGoSwissMapsVersion.String()) + if err != nil { + panic(err) + } + return c + }(), + // Don't warn, we have a backup path. + FailureMode: probe.FailureModeIgnore, + } +) // New returns a new [probe.Probe]. func New(logger *slog.Logger, version string) probe.Probe { @@ -140,20 +145,19 @@ func New(logger *slog.Logger, version string) probe.Probe { type patternPathSupportedConst struct{} var ( - patternPathMinVersion = version.Must(version.NewVersion("1.22.0")) + patternPathMinVersion = semver.New(1, 22, 0, "", "") isPatternPathSupported = false ) func (c patternPathSupportedConst) InjectOption(td *process.TargetDetails) (inject.Option, error) { - isPatternPathSupported = td.GoVersion.GreaterThanOrEqual(patternPathMinVersion) + isPatternPathSupported = td.GoVersion.GreaterThanEqual(patternPathMinVersion) return inject.WithKeyValue("pattern_path_supported", isPatternPathSupported), nil } type swissMapsUsedConst struct{} func (c swissMapsUsedConst) InjectOption(td *process.TargetDetails) (inject.Option, error) { - minGoSwissMapsVersion := version.Must(version.NewVersion(minGoSwissMaps)) - isUsingGoSwissMaps := td.GoVersion.GreaterThanOrEqual(minGoSwissMapsVersion) + isUsingGoSwissMaps := td.GoVersion.GreaterThanEqual(minGoSwissMapsVersion) return inject.WithKeyValue("swiss_maps_used", isUsingGoSwissMaps), nil } diff --git a/internal/pkg/instrumentation/manager_load_test.go b/internal/pkg/instrumentation/manager_load_test.go index 764f9e8b6..22e6008c0 100644 --- a/internal/pkg/instrumentation/manager_load_test.go +++ b/internal/pkg/instrumentation/manager_load_test.go @@ -9,7 +9,7 @@ import ( "log/slog" "testing" - "github.com/hashicorp/go-version" + "github.com/Masterminds/semver/v3" "github.com/stretchr/testify/assert" "go.opentelemetry.io/auto/internal/pkg/inject" "go.opentelemetry.io/auto/internal/pkg/instrumentation/testutils" @@ -27,7 +27,7 @@ func TestLoadProbes(t *testing.T) { for _, p := range probes { manifest := p.Manifest() fields := manifest.StructFields - offsets := map[string]*version.Version{} + offsets := map[string]*semver.Version{} for _, f := range fields { _, ver := inject.GetLatestOffset(f) if ver != nil { diff --git a/internal/pkg/instrumentation/manager_test.go b/internal/pkg/instrumentation/manager_test.go index 56983706e..afb4d31af 100644 --- a/internal/pkg/instrumentation/manager_test.go +++ b/internal/pkg/instrumentation/manager_test.go @@ -13,8 +13,8 @@ import ( "testing" "time" + "github.com/Masterminds/semver/v3" "github.com/cilium/ebpf/link" - "github.com/hashicorp/go-version" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -30,8 +30,7 @@ import ( ) func TestProbeFiltering(t *testing.T) { - ver, err := version.NewVersion("1.20.0") - assert.NoError(t, err) + ver := semver.New(1, 20, 0, "", "") t.Run("empty target details", func(t *testing.T) { m := fakeManager(t) @@ -40,7 +39,7 @@ func TestProbeFiltering(t *testing.T) { PID: 1, Functions: []*binary.Func{}, GoVersion: ver, - Modules: map[string]*version.Version{}, + Modules: map[string]*semver.Version{}, AllocationDetails: nil, } m.FilterUnusedProbes(&td) @@ -58,7 +57,7 @@ func TestProbeFiltering(t *testing.T) { PID: 1, Functions: httpFuncs, GoVersion: ver, - Modules: map[string]*version.Version{}, + Modules: map[string]*semver.Version{}, AllocationDetails: nil, } m.FilterUnusedProbes(&td) @@ -77,7 +76,7 @@ func TestProbeFiltering(t *testing.T) { PID: 1, Functions: httpFuncs, GoVersion: ver, - Modules: map[string]*version.Version{}, + Modules: map[string]*semver.Version{}, AllocationDetails: nil, } m.FilterUnusedProbes(&td) @@ -97,7 +96,7 @@ func TestProbeFiltering(t *testing.T) { PID: 1, Functions: httpFuncs, GoVersion: ver, - Modules: map[string]*version.Version{}, + Modules: map[string]*semver.Version{}, AllocationDetails: nil, } m.FilterUnusedProbes(&td) diff --git a/internal/pkg/instrumentation/probe/constraint.go b/internal/pkg/instrumentation/probe/constraint.go index 103ae9ce1..09480555b 100644 --- a/internal/pkg/instrumentation/probe/constraint.go +++ b/internal/pkg/instrumentation/probe/constraint.go @@ -3,7 +3,9 @@ package probe -import "github.com/hashicorp/go-version" +import ( + "github.com/Masterminds/semver/v3" +) // FailureMode defines the behavior that is performed when a failure occurs. type FailureMode int @@ -26,7 +28,7 @@ type PackageConstrainst struct { // Constraints is the version constraint that is evaluated. If the // constraint is not satisfied, the FailureMode defines the behavior of how // the failure is handled. - Constraints version.Constraints + Constraints *semver.Constraints // FailureMode defines the behavior that is performed when the Constraint // is not satisfied. FailureMode FailureMode diff --git a/internal/pkg/instrumentation/probe/probe.go b/internal/pkg/instrumentation/probe/probe.go index 0b514ed38..0b647d77c 100644 --- a/internal/pkg/instrumentation/probe/probe.go +++ b/internal/pkg/instrumentation/probe/probe.go @@ -14,10 +14,10 @@ import ( "os" "sync/atomic" + "github.com/Masterminds/semver/v3" "github.com/cilium/ebpf" "github.com/cilium/ebpf/link" "github.com/cilium/ebpf/perf" - "github.com/hashicorp/go-version" "go.opentelemetry.io/collector/pdata/ptrace" @@ -519,7 +519,7 @@ func (c StructFieldConst) InjectOption(td *process.TargetDetails) (inject.Option // injected if the module version is greater than or equal to the MinVersion. type StructFieldConstMinVersion struct { StructField StructFieldConst - MinVersion *version.Version + MinVersion *semver.Version } // InjectOption returns the appropriately configured [inject.WithOffset] if the @@ -534,7 +534,7 @@ func (c StructFieldConstMinVersion) InjectOption(td *process.TargetDetails) (inj return nil, fmt.Errorf("unknown module version: %s", sf.ID.ModPath) } - if !ver.GreaterThanOrEqual(c.MinVersion) { + if !ver.GreaterThanEqual(c.MinVersion) { return nil, nil } diff --git a/internal/pkg/instrumentation/testutils/testutils.go b/internal/pkg/instrumentation/testutils/testutils.go index af24e6ad5..c64c26d8c 100644 --- a/internal/pkg/instrumentation/testutils/testutils.go +++ b/internal/pkg/instrumentation/testutils/testutils.go @@ -7,9 +7,9 @@ import ( "errors" "testing" + "github.com/Masterminds/semver/v3" "github.com/cilium/ebpf" "github.com/cilium/ebpf/rlimit" - "github.com/hashicorp/go-version" "github.com/stretchr/testify/assert" "go.opentelemetry.io/auto/internal/pkg/instrumentation/bpffs" @@ -17,14 +17,14 @@ import ( "go.opentelemetry.io/auto/internal/pkg/process" ) -var testGoVersion = version.Must(version.NewVersion("1.22.1")) +var testGoVersion = semver.New(1, 22, 1, "", "") type TestProbe interface { Spec() (*ebpf.CollectionSpec, error) InjectConsts(td *process.TargetDetails, spec *ebpf.CollectionSpec) error } -func ProbesLoad(t *testing.T, p TestProbe, libs map[string]*version.Version) { +func ProbesLoad(t *testing.T, p TestProbe, libs map[string]*semver.Version) { err := rlimit.RemoveMemlock() if !assert.NoError(t, err) { return @@ -36,7 +36,7 @@ func ProbesLoad(t *testing.T, p TestProbe, libs map[string]*version.Version) { StartAddr: 140434497441792, EndAddr: 140434497507328, }, - Modules: map[string]*version.Version{ + Modules: map[string]*semver.Version{ "std": testGoVersion, }, GoVersion: testGoVersion, diff --git a/internal/pkg/instrumentation/utils/ebpf.go b/internal/pkg/instrumentation/utils/ebpf.go index b74f62bef..0bb90ad6b 100644 --- a/internal/pkg/instrumentation/utils/ebpf.go +++ b/internal/pkg/instrumentation/utils/ebpf.go @@ -9,8 +9,8 @@ import ( "os" "strconv" + "github.com/Masterminds/semver/v3" "github.com/cilium/ebpf" - "github.com/hashicorp/go-version" ) const ( @@ -53,16 +53,12 @@ func ShouldShowVerifierLogs() bool { // Does kernel version check and /sys/kernel/security/lockdown inspection to determine if it's // safe to use bpf_probe_write_user. func SupportsContextPropagation() bool { - ver, err := GetLinuxKernelVersion() - if err != nil { + ver := GetLinuxKernelVersion() + if ver == nil { return false } - noLockKernel, err := version.NewVersion("5.14") - if err != nil { - fmt.Printf("Error creating version 5.14 - %v\n", err) - } - + noLockKernel := semver.New(5, 14, 0, "", "") if ver.LessThan(noLockKernel) { return true } diff --git a/internal/pkg/instrumentation/utils/kernel_linux.go b/internal/pkg/instrumentation/utils/kernel_linux.go index 831962bb5..f7e908f69 100644 --- a/internal/pkg/instrumentation/utils/kernel_linux.go +++ b/internal/pkg/instrumentation/utils/kernel_linux.go @@ -9,32 +9,35 @@ import ( "fmt" "os" "runtime" - "strconv" "strings" "syscall" "time" "golang.org/x/sys/unix" - "github.com/hashicorp/go-version" + "github.com/Masterminds/semver/v3" ) var unameFn = syscall.Uname -// parse logic adapted from https://github.com/golang/go/blob/go1.21.3/src/internal/syscall/unix/kernel_version_linux.go -func GetLinuxKernelVersion() (*version.Version, error) { +// GetLinuxKernelVersion returns the current version of the Linux kernel. If +// unable to determine the function, nil is returned. +// +// Adapted from https://github.com/golang/go/blob/go1.21.3/src/internal/syscall/unix/kernel_version_linux.go +func GetLinuxKernelVersion() *semver.Version { var uname syscall.Utsname if err := unameFn(&uname); err != nil { - return nil, err + return nil } var ( - values [2]int - value, vi int + values [2]uint64 + value uint64 + vi int ) for _, c := range uname.Release { if '0' <= c && c <= '9' { - value = (value * 10) + int(c-'0') + value = (value * 10) + uint64(c-'0') // nolint:gosec // c >= '0' } else { // Note that we're assuming N.N.N here. // If we see anything else, we are likely to mis-parse it. @@ -46,9 +49,7 @@ func GetLinuxKernelVersion() (*version.Version, error) { value = 0 } } - ver := fmt.Sprintf("%s.%s", strconv.Itoa(values[0]), strconv.Itoa(values[1])) - - return version.NewVersion(ver) + return semver.New(values[0], values[1], 0, "", "") } // KernelLockdown is the lockdown state of the Linux kernel. diff --git a/internal/pkg/instrumentation/utils/kernel_linux_test.go b/internal/pkg/instrumentation/utils/kernel_linux_test.go index c89125de9..a56bb174d 100644 --- a/internal/pkg/instrumentation/utils/kernel_linux_test.go +++ b/internal/pkg/instrumentation/utils/kernel_linux_test.go @@ -9,28 +9,29 @@ import ( "syscall" "testing" - "github.com/hashicorp/go-version" + "github.com/Masterminds/semver/v3" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestGetLinuxKernelVersion(t *testing.T) { tests := map[string]struct { unameFn func(buf *syscall.Utsname) error - want *version.Version + want *semver.Version }{ "ubuntu-23.10": { unameFn: func(buf *syscall.Utsname) error { buf.Release = [65]int8{54, 46, 53, 46, 48, 45, 57, 45, 103, 101, 110, 101, 114, 105, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} return nil }, - want: version.Must(version.NewVersion("6.5")), + want: semver.New(6, 5, 0, "", ""), }, "debian-12": { unameFn: func(buf *syscall.Utsname) error { buf.Release = [65]int8{54, 46, 49, 46, 48, 45, 49, 50, 45, 99, 108, 111, 117, 100, 45, 97, 109, 100, 54, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} return nil }, - want: version.Must(version.NewVersion("6.1")), + want: semver.New(6, 1, 0, "", ""), }, } for name, tt := range tests { @@ -41,11 +42,8 @@ func TestGetLinuxKernelVersion(t *testing.T) { t.Cleanup(func() { unameFn = oldUnameFn }) - got, err := GetLinuxKernelVersion() - if err != nil { - t.Errorf("GetLinuxKernelVersion() error = %v", err) - return - } + got := GetLinuxKernelVersion() + require.NotNil(t, got) assert.Equal(t, tt.want, got) }) diff --git a/internal/pkg/instrumentation/utils/kernel_other.go b/internal/pkg/instrumentation/utils/kernel_other.go index f9da90dcb..7daa7a0cb 100644 --- a/internal/pkg/instrumentation/utils/kernel_other.go +++ b/internal/pkg/instrumentation/utils/kernel_other.go @@ -5,13 +5,13 @@ package utils -import "github.com/hashicorp/go-version" +import ( + "github.com/Masterminds/semver/v3" +) // Stubs for non-linux systems -func GetLinuxKernelVersion() (*version.Version, error) { - return &version.Version{}, nil -} +func GetLinuxKernelVersion() *semver.Version { return nil } type KernelLockdown uint8 diff --git a/internal/pkg/process/analyze.go b/internal/pkg/process/analyze.go index ad6781fc1..866e16039 100644 --- a/internal/pkg/process/analyze.go +++ b/internal/pkg/process/analyze.go @@ -11,7 +11,7 @@ import ( "os" "strings" - "github.com/hashicorp/go-version" + "github.com/Masterminds/semver/v3" "go.opentelemetry.io/auto/internal/pkg/process/binary" ) @@ -20,15 +20,15 @@ import ( type TargetDetails struct { PID int Functions []*binary.Func - GoVersion *version.Version - Modules map[string]*version.Version + GoVersion *semver.Version + Modules map[string]*semver.Version AllocationDetails *AllocationDetails } // IsRegistersABI returns if t is supported. func (t *TargetDetails) IsRegistersABI() bool { - regAbiMinVersion, _ := version.NewVersion("1.17") - return t.GoVersion.GreaterThanOrEqual(regAbiMinVersion) + regAbiMinVersion := semver.New(1, 17, 0, "", "") + return t.GoVersion.GreaterThanEqual(regAbiMinVersion) } // GetFunctionOffset returns the offset for of the function with name. @@ -75,14 +75,14 @@ func (a *Analyzer) Analyze(pid int, relevantFuncs map[string]interface{}) (*Targ return nil, err } - goVersion, err := version.NewVersion(a.BuildInfo.GoVersion) + goVersion, err := semver.NewVersion(a.BuildInfo.GoVersion) if err != nil { return nil, err } result.GoVersion = goVersion - result.Modules = make(map[string]*version.Version, len(a.BuildInfo.Deps)+1) + result.Modules = make(map[string]*semver.Version, len(a.BuildInfo.Deps)+1) for _, dep := range a.BuildInfo.Deps { - depVersion, err := version.NewVersion(dep.Version) + depVersion, err := semver.NewVersion(dep.Version) if err != nil { a.logger.Error("parsing dependency version", "error", err, "dependency", dep) continue diff --git a/internal/pkg/process/ptrace_linux.go b/internal/pkg/process/ptrace_linux.go index d1300afe7..535067a49 100644 --- a/internal/pkg/process/ptrace_linux.go +++ b/internal/pkg/process/ptrace_linux.go @@ -13,7 +13,7 @@ import ( "golang.org/x/sys/unix" - "github.com/hashicorp/go-version" + "github.com/Masterminds/semver/v3" "github.com/pkg/errors" "go.opentelemetry.io/auto/internal/pkg/instrumentation/utils" @@ -228,18 +228,18 @@ func (p *tracedProgram) Mmap(length uint64, fd uint64) (uint64, error) { // Madvise runs madvise syscall. func (p *tracedProgram) Madvise(addr uint64, length uint64) error { advice := uint64(syscall.MADV_WILLNEED) - ver, err := utils.GetLinuxKernelVersion() - if err != nil { - return errors.WithStack(err) + ver := utils.GetLinuxKernelVersion() + if ver == nil { + return errors.WithStack(errors.New("unknown Linux version")) } - minVersion := version.Must(version.NewVersion("5.14")) + minVersion := semver.New(5, 14, 0, "", "") p.logger.Debug("Detected linux kernel version", "version", ver) - if ver.GreaterThanOrEqual(minVersion) { + if ver.GreaterThanEqual(minVersion) { advice = syscall.MADV_WILLNEED | MadvisePopulateRead | MadvisePopulateWrite } - _, err = p.Syscall(syscall.SYS_MADVISE, addr, length, advice, 0, 0, 0) + _, err := p.Syscall(syscall.SYS_MADVISE, addr, length, advice, 0, 0, 0) return err } diff --git a/internal/pkg/structfield/json.go b/internal/pkg/structfield/json.go index 0ea669193..509612765 100644 --- a/internal/pkg/structfield/json.go +++ b/internal/pkg/structfield/json.go @@ -3,11 +3,13 @@ package structfield -import "github.com/hashicorp/go-version" +import ( + "github.com/Masterminds/semver/v3" +) type jsonOffset struct { - Offset *uint64 `json:"offset"` - Versions []*version.Version `json:"versions"` + Offset *uint64 `json:"offset"` + Versions []*semver.Version `json:"versions"` } type jsonField struct { @@ -31,7 +33,7 @@ func (jf *jsonField) addOffsets(off *Offsets) { jOff.Offset = &offTmp.Offset } - jOff.Versions = mergeSorted(jOff.Versions, vers, func(a, b *version.Version) int { + jOff.Versions = mergeSorted(jOff.Versions, vers, func(a, b *semver.Version) int { return a.Compare(b) }) } diff --git a/internal/pkg/structfield/structfield.go b/internal/pkg/structfield/structfield.go index 30a4fb1bf..0ec68efc2 100644 --- a/internal/pkg/structfield/structfield.go +++ b/internal/pkg/structfield/structfield.go @@ -11,7 +11,7 @@ import ( "strings" "sync" - "github.com/hashicorp/go-version" + "github.com/Masterminds/semver/v3" ) // Index holds all struct field offsets. @@ -42,7 +42,7 @@ func (i *Index) get(id ID) (*Offsets, bool) { // GetOffset returns the offset value and true for the version ver of id // contained in the Index i. It will return zero and false for any id not // contained in i. -func (i *Index) GetOffset(id ID, ver *version.Version) (OffsetKey, bool) { +func (i *Index) GetOffset(id ID, ver *semver.Version) (OffsetKey, bool) { i.dataMu.RLock() defer i.dataMu.RUnlock() @@ -51,7 +51,7 @@ func (i *Index) GetOffset(id ID, ver *version.Version) (OffsetKey, bool) { // GetLatestOffset returns the latest known offset value and version for id // contained in the Index i. -func (i *Index) GetLatestOffset(id ID) (OffsetKey, *version.Version) { +func (i *Index) GetLatestOffset(id ID) (OffsetKey, *semver.Version) { i.dataMu.RLock() defer i.dataMu.RUnlock() @@ -60,10 +60,10 @@ func (i *Index) GetLatestOffset(id ID) (OffsetKey, *version.Version) { return OffsetKey{}, nil } off, ver := offs.getLatest() - return off, ver.ToVersion() + return off, ver } -func (i *Index) getOffset(id ID, ver *version.Version) (OffsetKey, bool) { +func (i *Index) getOffset(id ID, ver *semver.Version) (OffsetKey, bool) { offs, ok := i.get(id) if !ok { return OffsetKey{}, false @@ -91,14 +91,14 @@ func (i *Index) put(id ID, offsets *Offsets) { // // This will update any existing offsets stored for id with offset. If ver // already exists within those offsets it will overwrite that value. -func (i *Index) PutOffset(id ID, ver *version.Version, offset uint64, valid bool) { +func (i *Index) PutOffset(id ID, ver *semver.Version, offset uint64, valid bool) { i.dataMu.Lock() defer i.dataMu.Unlock() i.putOffset(id, ver, offset, valid) } -func (i *Index) putOffset(id ID, ver *version.Version, offset uint64, valid bool) { +func (i *Index) putOffset(id ID, ver *semver.Version, offset uint64, valid bool) { off, ok := i.get(id) if !ok { off = NewOffsets() @@ -234,7 +234,7 @@ type Offsets struct { mu sync.RWMutex // values is a map between version and offset value. - values map[verKey]offsetVersion + values map[semver.Version]offsetVersion // uo is the single offset in the values map. // If there is only one offset, this will be that offset and valid will be true. @@ -249,18 +249,18 @@ type uniqueOffset struct { // NewOffsets returns a new empty *Offsets. func NewOffsets() *Offsets { - return &Offsets{values: make(map[verKey]offsetVersion)} + return &Offsets{values: make(map[semver.Version]offsetVersion)} } // Get returns the offset in bytes and true if known. Otherwise, 0 and false // are returned. -func (o *Offsets) Get(ver *version.Version) (OffsetKey, bool) { - if o == nil { +func (o *Offsets) Get(ver *semver.Version) (OffsetKey, bool) { + if o == nil || ver == nil { return OffsetKey{}, false } o.mu.RLock() - v, ok := o.values[newVerKey(ver)] + v, ok := o.values[*ver] o.mu.RUnlock() if strings.HasPrefix(ver.String(), "0.0.0") && !ok && o.uo.valid { @@ -274,15 +274,15 @@ func (o *Offsets) Get(ver *version.Version) (OffsetKey, bool) { } // getLatest returns the latest known offset value and version. -func (o *Offsets) getLatest() (OffsetKey, verKey) { +func (o *Offsets) getLatest() (OffsetKey, *semver.Version) { o.mu.RLock() defer o.mu.RUnlock() - latestVersion := verKey{} + var latestVersion *semver.Version val := OffsetKey{} - for verKey, ov := range o.values { - if verKey.GreaterThan(latestVersion) && ov.offset.Valid { - latestVersion = verKey + for ver, ov := range o.values { + if latestVersion == nil || ver.GreaterThan(latestVersion) && ov.offset.Valid { + latestVersion = &ver val = ov.offset } } @@ -292,58 +292,40 @@ func (o *Offsets) getLatest() (OffsetKey, verKey) { // Put sets the offset value for ver. If an offset for ver is already known // (i.e. ver.Equal(other) == true), this will overwrite that value. -func (o *Offsets) Put(ver *version.Version, offset OffsetKey) { +func (o *Offsets) Put(ver *semver.Version, offset OffsetKey) { + if ver == nil { + return + } + ov := offsetVersion{offset: offset, version: ver} o.mu.Lock() defer o.mu.Unlock() if o.values == nil { - o.values = map[verKey]offsetVersion{newVerKey(ver): ov} + o.values = map[semver.Version]offsetVersion{*ver: ov} o.uo.valid = ov.offset.Valid o.uo.value = ov.offset.Offset return } - o.values[newVerKey(ver)] = ov + o.values[*ver] = ov if o.uo.valid && o.uo.value != ov.offset.Offset { o.uo.valid = false } } -func (v verKey) GreaterThan(other verKey) bool { - if v.major != other.major { - return v.major > other.major - } - if v.minor != other.minor { - return v.minor > other.minor - } - if v.patch != other.patch { - return v.patch > other.patch - } - return false -} - -func (v verKey) ToVersion() *version.Version { - vs := fmt.Sprintf("%d.%d.%d", v.major, v.minor, v.patch) - if v.prerelease != "" { - vs += "-" + v.prerelease - } - ver, _ := version.NewVersion(vs) - return ver -} - -func (o *Offsets) index() map[OffsetKey][]*version.Version { +func (o *Offsets) index() map[OffsetKey][]*semver.Version { o.mu.RLock() defer o.mu.RUnlock() - out := make(map[OffsetKey][]*version.Version) + out := make(map[OffsetKey][]*semver.Version) for _, ov := range o.values { vers, ok := out[ov.offset] if ok { i := sort.Search(len(vers), func(i int) bool { - return vers[i].GreaterThanOrEqual(ov.version) + return vers[i].GreaterThanEqual(ov.version) }) vers = append(vers, nil) copy(vers[i+1:], vers[i:]) @@ -356,12 +338,6 @@ func (o *Offsets) index() map[OffsetKey][]*version.Version { return out } -type verKey struct { - major, minor, patch uint64 - prerelease string - metadata string -} - // OffsetKey is the offset of a specific struct field in a specific version. // If Valid is false, the offset is not known for the struct field at the // specified version. @@ -370,19 +346,7 @@ type OffsetKey struct { Valid bool } -func newVerKey(v *version.Version) verKey { - var segs [3]int - copy(segs[:], v.Segments()) - return verKey{ - major: uint64(max(segs[0], 0)), // nolint: gosec // Bounded. - minor: uint64(max(segs[1], 0)), // nolint: gosec // Bounded. - patch: uint64(max(segs[2], 0)), // nolint: gosec // Bounded. - prerelease: v.Prerelease(), - metadata: v.Metadata(), - } -} - type offsetVersion struct { offset OffsetKey - version *version.Version + version *semver.Version } diff --git a/internal/pkg/structfield/structfield_test.go b/internal/pkg/structfield/structfield_test.go index 4b36e78b0..c25eeb2a7 100644 --- a/internal/pkg/structfield/structfield_test.go +++ b/internal/pkg/structfield/structfield_test.go @@ -10,17 +10,17 @@ import ( "strings" "testing" - "github.com/hashicorp/go-version" + "github.com/Masterminds/semver/v3" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) var ( - v110 = version.Must(version.NewVersion("1.1.0")) - v12 = version.Must(version.NewVersion("1.2")) - v120 = version.Must(version.NewVersion("1.2.0")) - v121 = version.Must(version.NewVersion("1.2.1")) - v130 = version.Must(version.NewVersion("1.3.0")) + v110 = semver.New(1, 1, 0, "", "") + v12 = semver.New(1, 2, 0, "", "") + v120 = semver.New(1, 2, 0, "", "") + v121 = semver.New(1, 2, 1, "", "") + v130 = semver.New(1, 3, 0, "", "") ) func TestOffsets(t *testing.T) { @@ -54,7 +54,7 @@ func TestOffsets(t *testing.T) { assert.Equal(t, OffsetKey{Offset: 2, Valid: true}, off, "invalid value for 1.2.1") off, ver := o.getLatest() - assert.Equal(t, v121, ver.ToVersion(), "invalid version for latest") + assert.Equal(t, v121, ver, "invalid version for latest") assert.Equal(t, OffsetKey{Offset: 2, Valid: true}, off, "invalid value for latest") o.Put(v120, OffsetKey{Offset: 1, Valid: true}) @@ -71,32 +71,32 @@ func TestOffsets(t *testing.T) { var index = &Index{ data: map[ID]*Offsets{ NewID("std", "net/http", "Request", "Method"): { - values: map[verKey]offsetVersion{ - newVerKey(v120): {offset: OffsetKey{Offset: 1, Valid: true}, version: v120}, - newVerKey(v121): {offset: OffsetKey{Offset: 1, Valid: true}, version: v121}, - newVerKey(v130): {offset: OffsetKey{Offset: 1, Valid: true}, version: v130}, + values: map[semver.Version]offsetVersion{ + *v120: {offset: OffsetKey{Offset: 1, Valid: true}, version: v120}, + *v121: {offset: OffsetKey{Offset: 1, Valid: true}, version: v121}, + *v130: {offset: OffsetKey{Offset: 1, Valid: true}, version: v130}, }, uo: uniqueOffset{value: 1, valid: true}, }, NewID("std", "net/http", "Request", "URL"): { - values: map[verKey]offsetVersion{ - newVerKey(v110): {offset: OffsetKey{Offset: 0, Valid: false}, version: v110}, - newVerKey(v120): {offset: OffsetKey{Offset: 0, Valid: true}, version: v120}, - newVerKey(v121): {offset: OffsetKey{Offset: 1, Valid: true}, version: v121}, - newVerKey(v130): {offset: OffsetKey{Offset: 2, Valid: true}, version: v130}, + values: map[semver.Version]offsetVersion{ + *v110: {offset: OffsetKey{Offset: 0, Valid: false}, version: v110}, + *v120: {offset: OffsetKey{Offset: 0, Valid: true}, version: v120}, + *v121: {offset: OffsetKey{Offset: 1, Valid: true}, version: v121}, + *v130: {offset: OffsetKey{Offset: 2, Valid: true}, version: v130}, }, uo: uniqueOffset{value: 0, valid: false}, }, NewID("std", "net/http", "Response", "Status"): { - values: map[verKey]offsetVersion{ - newVerKey(v110): {offset: OffsetKey{Offset: 0, Valid: false}, version: v110}, - newVerKey(v120): {offset: OffsetKey{Offset: 0, Valid: true}, version: v120}, + values: map[semver.Version]offsetVersion{ + *v110: {offset: OffsetKey{Offset: 0, Valid: false}, version: v110}, + *v120: {offset: OffsetKey{Offset: 0, Valid: true}, version: v120}, }, uo: uniqueOffset{value: 0, valid: false}, }, NewID("google.golang.org/grpc", "google.golang.org/grpc", "ClientConn", "target"): { - values: map[verKey]offsetVersion{ - newVerKey(v120): {offset: OffsetKey{Offset: 0, Valid: true}, version: v120}, + values: map[semver.Version]offsetVersion{ + *v120: {offset: OffsetKey{Offset: 0, Valid: true}, version: v120}, }, uo: uniqueOffset{value: 0, valid: true}, }, diff --git a/internal/test/e2e/autosdk/go.mod b/internal/test/e2e/autosdk/go.mod index 5f2812d22..86dd0c0d1 100644 --- a/internal/test/e2e/autosdk/go.mod +++ b/internal/test/e2e/autosdk/go.mod @@ -5,7 +5,7 @@ go 1.22.0 require ( go.opentelemetry.io/auto/sdk v1.1.0 go.opentelemetry.io/otel v1.34.0 - go.opentelemetry.io/otel/trace v1.34.0 + go.opentelemetry.io/otel/trace v1.34.1-0.20250205150531-85fab8be9320 ) replace go.opentelemetry.io/auto/sdk => ../../../../sdk/ diff --git a/internal/test/e2e/autosdk/go.sum b/internal/test/e2e/autosdk/go.sum index 4086277df..ed3f13432 100644 --- a/internal/test/e2e/autosdk/go.sum +++ b/internal/test/e2e/autosdk/go.sum @@ -8,7 +8,7 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY= go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI= -go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k= -go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE= +go.opentelemetry.io/otel/trace v1.34.1-0.20250205150531-85fab8be9320 h1:/NNzCi4XoacM5MYMY/vAUFyX6O4m7KDtzrJHorTGBck= +go.opentelemetry.io/otel/trace v1.34.1-0.20250205150531-85fab8be9320/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/tools/go.mod b/internal/tools/go.mod index b8812af57..c63842668 100644 --- a/internal/tools/go.mod +++ b/internal/tools/go.mod @@ -3,10 +3,10 @@ module go.opentelemetry.io/auto/internal/tools go 1.22.9 require ( + github.com/Masterminds/semver/v3 v3.3.1 github.com/docker/docker v27.5.1+incompatible github.com/golangci/golangci-lint v1.63.4 github.com/google/go-licenses/v2 v2.0.0-alpha.1 - github.com/hashicorp/go-version v1.7.0 go.opentelemetry.io/auto v0.20.0 go.opentelemetry.io/build-tools/dbotconf v0.18.0 go.opentelemetry.io/build-tools/multimod v0.18.0 @@ -26,7 +26,6 @@ require ( github.com/Crocmagnon/fatcontext v0.6.0 // indirect github.com/Djarvur/go-err113 v0.1.0 // indirect github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0 // indirect - github.com/Masterminds/semver/v3 v3.3.1 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/OpenPeeDeeP/depguard/v2 v2.2.0 // indirect github.com/ProtonMail/go-crypto v1.1.5 // indirect @@ -105,6 +104,7 @@ require ( github.com/gostaticanalysis/forcetypeassert v0.1.0 // indirect github.com/gostaticanalysis/nilerr v0.1.1 // indirect github.com/hashicorp/go-immutable-radix/v2 v2.1.0 // indirect + github.com/hashicorp/go-version v1.7.0 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/hexops/gotextdiff v1.0.3 // indirect diff --git a/internal/tools/inspect/app.go b/internal/tools/inspect/app.go index 92c0a772d..3f273cf7a 100644 --- a/internal/tools/inspect/app.go +++ b/internal/tools/inspect/app.go @@ -11,7 +11,7 @@ import ( "log/slog" "os" - "github.com/hashicorp/go-version" + "github.com/Masterminds/semver/v3" "go.opentelemetry.io/auto/internal/pkg/process" "go.opentelemetry.io/auto/internal/pkg/structfield" @@ -21,7 +21,7 @@ import ( type app struct { Renderer Renderer Builder *builder - AppVer *version.Version + AppVer *semver.Version Fields []structfield.ID log *slog.Logger diff --git a/internal/tools/inspect/builder.go b/internal/tools/inspect/builder.go index 2fdab16ab..b545b1c9a 100644 --- a/internal/tools/inspect/builder.go +++ b/internal/tools/inspect/builder.go @@ -14,6 +14,7 @@ import ( "os" "path/filepath" + "github.com/Masterminds/semver/v3" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/image" @@ -21,18 +22,17 @@ import ( "github.com/docker/docker/api/types/registry" "github.com/docker/docker/client" "github.com/docker/docker/pkg/stdcopy" - "github.com/hashicorp/go-version" ) // minCompatVer is the min "go mod" version that includes the "compat" option. -var minCompatVer = version.Must(version.NewVersion("1.17.0")) +var minCompatVer = semver.New(1, 17, 0, "", "") // builder builds a Go application into a binary using Docker. type builder struct { log *slog.Logger cli *client.Client - goVer *version.Version + goVer *semver.Version GoImage string } @@ -42,7 +42,7 @@ type builder struct { // // If goVer is nil, the latest version of the Go docker container will be used // to build applications. -func newBuilder(l *slog.Logger, cli *client.Client, goVer *version.Version) *builder { +func newBuilder(l *slog.Logger, cli *client.Client, goVer *semver.Version) *builder { img := "golang:latest" if goVer != nil { // Use goVer.String here so 1.12 means 1.12.0. If Original is used, it @@ -59,7 +59,7 @@ func newBuilder(l *slog.Logger, cli *client.Client, goVer *version.Version) *bui } // Build builds the appV version of a Go application located in dir. -func (b *builder) Build(ctx context.Context, dir string, appV *version.Version, modName string) (string, error) { +func (b *builder) Build(ctx context.Context, dir string, appV *semver.Version, modName string) (string, error) { b.log.Debug("building application...", "version", appV, "dir", dir, "image", b.GoImage) app := "app" + appV.Original() diff --git a/internal/tools/inspect/cache.go b/internal/tools/inspect/cache.go index 5a91b279e..8a1b9d08d 100644 --- a/internal/tools/inspect/cache.go +++ b/internal/tools/inspect/cache.go @@ -8,7 +8,7 @@ import ( "log/slog" "os" - "github.com/hashicorp/go-version" + "github.com/Masterminds/semver/v3" "go.opentelemetry.io/auto/internal/pkg/structfield" ) @@ -42,7 +42,7 @@ func newCache(l *slog.Logger) *Cache { // GetOffset returns the cached offset key and true for the id at the specified // version is found in the cache. If the cache does not contain a valid offset for the provided // values, 0 and false are returned. -func (c *Cache) GetOffset(ver *version.Version, id structfield.ID) (structfield.OffsetKey, bool) { +func (c *Cache) GetOffset(ver *semver.Version, id structfield.ID) (structfield.OffsetKey, bool) { if c.data == nil { return structfield.OffsetKey{}, false } diff --git a/internal/tools/inspect/cmd/offsetgen/versions.go b/internal/tools/inspect/cmd/offsetgen/versions.go index ca7cd9541..bea6a4b5e 100644 --- a/internal/tools/inspect/cmd/offsetgen/versions.go +++ b/internal/tools/inspect/cmd/offsetgen/versions.go @@ -12,7 +12,7 @@ import ( "sort" "strings" - "github.com/hashicorp/go-version" + "github.com/Masterminds/semver/v3" ) const jsonURL = "https://go.dev/dl/?mode=json&include=all" @@ -24,7 +24,7 @@ type goListResponse struct { // PkgVersions returns all locally known version of module with // moduleName. -func PkgVersions(name string) ([]*version.Version, error) { +func PkgVersions(name string) ([]*semver.Version, error) { command := "go list -m -json -versions " + name cmd := exec.Command("bash", "-c", command) @@ -40,9 +40,9 @@ func PkgVersions(name string) ([]*version.Version, error) { return nil, err } - out := make([]*version.Version, len(resp.Versions)) + out := make([]*semver.Version, len(resp.Versions)) for i, v := range resp.Versions { - conv, err := version.NewVersion(v) + conv, err := semver.NewVersion(v) if err != nil { return nil, err } @@ -58,7 +58,7 @@ type goDevResponse struct { // GoVersions returns all known GoVersions versions from the GoVersions package mirror at // https://go.dev/dl/. -func GoVersions(constraints ...string) ([]*version.Version, error) { +func GoVersions(constraints ...string) ([]*semver.Version, error) { res, err := http.Get(jsonURL) if err != nil { return nil, err @@ -76,11 +76,11 @@ func GoVersions(constraints ...string) ([]*version.Version, error) { return nil, err } - var versions []*version.Version + var versions []*semver.Version for _, v := range resp { if v.Stable { stripepdV := strings.ReplaceAll(v.Version, "go", "") - v, err := version.NewVersion(stripepdV) + v, err := semver.NewVersion(stripepdV) if err != nil { return nil, err } @@ -95,17 +95,17 @@ func GoVersions(constraints ...string) ([]*version.Version, error) { return constrained, err } -func constrain(vers []*version.Version, constrains []string) ([]*version.Version, error) { - var cnsts []version.Constraints +func constrain(vers []*semver.Version, constrains []string) ([]*semver.Version, error) { + var cnsts []*semver.Constraints for _, c := range constrains { - parsed, err := version.NewConstraint(c) + parsed, err := semver.NewConstraint(c) if err != nil { return nil, err } cnsts = append(cnsts, parsed) } - valid := func(v *version.Version) bool { + valid := func(v *semver.Version) bool { for _, c := range cnsts { if !c.Check(v) { return false @@ -114,7 +114,7 @@ func constrain(vers []*version.Version, constrains []string) ([]*version.Version return true } - var fltr []*version.Version + var fltr []*semver.Version for _, ver := range vers { if valid(ver) { fltr = append(fltr, ver) diff --git a/internal/tools/inspect/inspector.go b/internal/tools/inspect/inspector.go index a712120f3..c6417fa07 100644 --- a/internal/tools/inspect/inspector.go +++ b/internal/tools/inspect/inspector.go @@ -8,8 +8,8 @@ import ( "errors" "log/slog" + "github.com/Masterminds/semver/v3" "github.com/docker/docker/client" - "github.com/hashicorp/go-version" "golang.org/x/sync/errgroup" "go.opentelemetry.io/auto/internal/pkg/structfield" @@ -120,7 +120,7 @@ func (i *Inspector) AddManifest(manifest Manifest) error { type job struct { Renderer Renderer Builder *builder - AppVer *version.Version + AppVer *semver.Version Fields []structfield.ID } @@ -181,7 +181,7 @@ func (i *Inspector) Do(ctx context.Context) (*structfield.Index, error) { type result struct { StructField structfield.ID - Version *version.Version + Version *semver.Version Offset uint64 // Valid is true if the offset is valid for the struct field at the specified version. Valid bool diff --git a/internal/tools/inspect/manifest.go b/internal/tools/inspect/manifest.go index 2b81d7706..0d58ca1fe 100644 --- a/internal/tools/inspect/manifest.go +++ b/internal/tools/inspect/manifest.go @@ -6,7 +6,7 @@ package inspect import ( "errors" - "github.com/hashicorp/go-version" + "github.com/Masterminds/semver/v3" "go.opentelemetry.io/auto/internal/pkg/structfield" ) @@ -38,9 +38,9 @@ type Application struct { // // If this is nil, the GoVerions will also be used as the application // versions that are passed to the template. - Versions []*version.Version + Versions []*semver.Version // GoVerions are the versions of Go to build the application with. // // If this is nil, the latest version of Go will be used. - GoVerions []*version.Version + GoVerions []*semver.Version }