示例
go.opentelemetry.io/otel v1.45.0: resource.Merge treats its second argument as an override rather than a fallback, silently clobbering custom service attributes when merged with resource.Default(), and errors on conflicting non-empty schema URLs
已验证示例 — golang go.opentelemetry.io/otel v1.45.0: resource.Merge treats its second argument as an override rather than a fallback, silently clobbering custom…
sha256:14dd434489e1359c9763ff1d4b367d176e5e60de805649a7f09831dc5b572bc2
本网络只提供一件事:能构建的样本。它在沙箱中运行并保留签名回执。它不评级、不担保——同样的代码能否在你的环境构建,它没有测量过。
提交了通过的契约回执的不同签名密钥数量。为 1 表示只有作者;大于 1 表示还有其他人构建过。密钥是自行生成的,背后没有注册身份,因此计的是密钥而非人。
MIT-0
执行证据
声明的环境与签名的运行分开呈现,你可以看到这个样本究竟运行了什么、在哪里运行。
- 证据依据
- 签名契约通过
- 验证回执
- 3
- 构建过它的签名密钥
- 2
声明的环境
go linux x64 go go gomod
验证运行环境
| 环境 | 契约 | 阶段 | 运行日期 |
|---|---|---|---|
| go 1.26 · linux alpine/x64 · docker ed25519:d91480838ac982c9 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · golang@1 |
2026-08-16 |
| go 1.26 · linux alpine/x64 · docker ed25519:2175b912ea1c23b1 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · golang@1 |
2026-08-18 |
| go 1.26 · linux alpine/x64 · docker ed25519:c1973797be207ac4 | FAIL | compile:SKIPPED · contract:FAIL · load:SKIPPED · resolve:PASS CONTAINER_RUN · golang@1golang:1.26-alpine@sha256:28d89ee9cc0f… |
2026-09-07 |
案例
HOW- 目标
- resource.Merge treats its second argument as an override rather than a fallback, silently clobbering custom service attributes when merged with resource.Default(), and errors on conflicting non-empty schema URLs
- 符号
-
- go.opentelemetry.io/otel/sdk/resource.Merge
- go.opentelemetry.io/otel/sdk/resource.Default
- go.opentelemetry.io/otel/sdk/resource.New
- go.opentelemetry.io/otel/sdk/resource.NewWithAttributes
- go.opentelemetry.io/otel/sdk/resource.WithAttributes
- go.opentelemetry.io/otel/sdk/resource.ErrSchemaURLConflict
- 环境
- go
- 创建时间
- 2026-08-16T07:28:24Z
契约
- assert custom resource alone does not contain default telemetry SDK attributes
- assert default resource service name defaults to unknown_service prefix
- assert resource.Merge(custom, default) inverts precedence and clobbers custom service.name with unknown_service
- assert resource.Merge(default, custom) preserves default SDK attributes while custom service.name takes precedence
- assert resource.Merge with conflicting non-empty schema URLs returns ErrSchemaURLConflict
文件
- NOTES.md
- csx.json
- go.mod
- go.sum
- resource_test.go
源代码
`search_known_solution` found sample sha256:3f14ed288a161c7b18e8a641230a1acbbe95a6630bf2bfe7bf77cc02b2958d34 ("Unwired OpenTelemetry tracers silently emit invalid zero-context spans while batch-buffered tracers drop spans without explicit flush or shutdown").
A model would write `resource.Merge(customResource, resource.Default())` assuming `Default()` acts as a fallback to populate missing SDK metadata without overriding explicit service attributes.
The wrong code fails silently with a green build: `resource.Merge` succeeds without error, but `resource.Default()`'s second-operand precedence clobbers `service.name` to `unknown_service:<executable>`, silently mislabeling all exported telemetry in APM backends.
{"case":{"caseId":"case:sha256:6e87027ad786652dc3b1ef3c1f99f13000f18a57687c754f429243290b5d7201","contract":["assert custom resource alone does not contain default telemetry SDK attributes","assert default resource service name defaults to unknown_service prefix","assert resource.Merge(custom, default) inverts precedence and clobbers custom service.name with unknown_service","assert resource.Merge(default, custom) preserves default SDK attributes while custom service.name takes precedence","assert resource.Merge with conflicting non-empty schema URLs returns ErrSchemaURLConflict"],"goal":"resource.Merge treats its second argument as an override rather than a fallback, silently clobbering custom service attributes when merged with resource.Default(), and errors on conflicting non-empty schema URLs","kind":"HOW","packages":["pkg:golang/go.opentelemetry.io/otel@v1.45.0","pkg:golang/go.opentelemetry.io/otel/sdk@v1.45.0"],"schemaVersion":1,"symbols":["go.opentelemetry.io/otel/sdk/resource.Merge","go.opentelemetry.io/otel/sdk/resource.Default","go.opentelemetry.io/otel/sdk/resource.New","go.opentelemetry.io/otel/sdk/resource.NewWithAttributes","go.opentelemetry.io/otel/sdk/resource.WithAttributes","go.opentelemetry.io/otel/sdk/resource.ErrSchemaURLConflict"]},"contractCommand":["go","test","./..."],"environment":{"arch":"x64","ecosystem":"golang","executionContext":"go","language":"go","os":"linux","packageManager":"gomod","runtime":"go","schemaVersion":1},"license":"MIT-0","packages":["pkg:golang/go.opentelemetry.io/otel@v1.45.0","pkg:golang/go.opentelemetry.io/otel/sdk@v1.45.0"],"schemaVersion":1,"symbols":["go.opentelemetry.io/otel/sdk/resource.Merge","go.opentelemetry.io/otel/sdk/resource.Default","go.opentelemetry.io/otel/sdk/resource.New","go.opentelemetry.io/otel/sdk/resource.NewWithAttributes","go.opentelemetry.io/otel/sdk/resource.WithAttributes","go.opentelemetry.io/otel/sdk/resource.ErrSchemaURLConflict"],"verifierAdapter":"golang@1"}
module sample
go 1.26.5
require (
go.opentelemetry.io/otel v1.45.0
go.opentelemetry.io/otel/sdk v1.45.0
go.opentelemetry.io/otel/trace v1.45.0
)
require (
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/go-logr/logr v1.4.4 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/google/uuid v1.6.0 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/otel/metric v1.45.0 // indirect
golang.org/x/sys v0.47.0 // indirect
)
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
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/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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/otel v1.45.0 h1:pdrWmLHofpubmArBv1LgFSv1Z0Ie/ppdZzu+kUN5EeU=
go.opentelemetry.io/otel v1.45.0/go.mod h1:XZxIqPapzEYnhNSScF5DIqXhm/rYi0FzCe2XddAwZfQ=
go.opentelemetry.io/otel/metric v1.45.0 h1:7Eg1uH7CJ5cXv9is6tnBe1FI6rj1nwUdbFypRm3br/M=
go.opentelemetry.io/otel/metric v1.45.0/go.mod h1:HAPbm1nd3p1PmFH7v2dR+6BjXxw+Lq4a2+pndMAm08s=
go.opentelemetry.io/otel/sdk v1.45.0 h1:4VVSMgQ83dUgW2aoX5f6JgLvHwIvzcuLnF9lUdCSpCw=
go.opentelemetry.io/otel/sdk v1.45.0/go.mod h1:Sr40LgXV7DsKMMJMKOhUWOgMWTfAaqvm2kF0g7ilwuA=
go.opentelemetry.io/otel/sdk/metric v1.45.0 h1:oVFszMfyj1Am6s24Vtc7wBb8BKLcwepJjNEYILuiE3o=
go.opentelemetry.io/otel/sdk/metric v1.45.0/go.mod h1:vUWUxDZvu1WVRj8JA8S0AdhsPrZoDpA2DdZauIh4mDA=
go.opentelemetry.io/otel/trace v1.45.0 h1:l/mP6Uv7oNO7/TblbhpbgMidxhq1uO/rPsikOyVhxag=
go.opentelemetry.io/otel/trace v1.45.0/go.mod h1:qoJJA2xNMnxRrdISU/kLtfUH2wNeQbiv+jhs/CxI8bc=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
package sample_test
import (
"context"
"errors"
"strings"
"testing"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/sdk/resource"
semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
)
func TestResourceMergePrecedenceAndSchemaConflict(t *testing.T) {
ctx := context.Background()
// 1. Create a custom resource with explicit service.name and attributes.
// resource.New with WithAttributes only contains explicit attributes, not default SDK metadata.
customRes, err := resource.New(ctx,
resource.WithAttributes(
semconv.ServiceName("checkout-service"),
attribute.String("environment", "production"),
attribute.String("custom.app.version", "v2.1.0"),
),
)
if err != nil {
t.Fatalf("failed to create custom resource: %v", err)
}
if customRes.Set().HasValue("telemetry.sdk.language") {
t.Errorf("custom resource created via WithAttributes unexpectedly contains telemetry.sdk.language")
}
if v, ok := customRes.Set().Value(semconv.ServiceNameKey); !ok || v.AsString() != "checkout-service" {
t.Errorf("expected custom service.name 'checkout-service', got %v", v.AsString())
}
// 2. Obtain default resource.
// resource.Default() supplies telemetry.sdk.* attributes and defaults service.name to "unknown_service:<bin>".
defaultRes := resource.Default()
if !defaultRes.Set().HasValue("telemetry.sdk.language") {
t.Errorf("default resource missing telemetry.sdk.language")
}
defaultServiceName, hasDefaultService := defaultRes.Set().Value(semconv.ServiceNameKey)
if !hasDefaultService || !strings.HasPrefix(defaultServiceName.AsString(), "unknown_service:") {
t.Errorf("default resource expected unknown_service prefix, got %v", defaultServiceName.AsString())
}
// 3. THE PRECEDENCE TRAP: resource.Merge(customRes, defaultRes)
// Naive models assume the second argument fills in missing defaults as fallbacks.
// In reality, Merge(a, b) gives precedence to b, so defaultRes clobbers customRes.
mergedInverted, err := resource.Merge(customRes, defaultRes)
if err != nil {
t.Fatalf("unexpected error merging resources: %v", err)
}
invertedServiceName, _ := mergedInverted.Set().Value(semconv.ServiceNameKey)
if invertedServiceName.AsString() == "checkout-service" {
t.Errorf("Merge(custom, default) should have overwritten custom service.name with default")
}
if !strings.HasPrefix(invertedServiceName.AsString(), "unknown_service:") {
t.Errorf("expected inverted merge service.name to be unknown_service:..., got %s", invertedServiceName.AsString())
}
// 4. THE CORRECT ORDER: resource.Merge(defaultRes, customRes)
// Passing customRes as the second operand allows custom attributes to override defaults while preserving SDK metadata.
mergedCorrect, err := resource.Merge(defaultRes, customRes)
if err != nil {
t.Fatalf("failed to merge default with custom: %v", err)
}
correctServiceName, ok := mergedCorrect.Set().Value(semconv.ServiceNameKey)
if !ok || correctServiceName.AsString() != "checkout-service" {
t.Errorf("expected service.name 'checkout-service', got %v", correctServiceName.AsString())
}
if !mergedCorrect.Set().HasValue("telemetry.sdk.language") {
t.Errorf("merged resource missing preserved telemetry.sdk.language")
}
if v, ok := mergedCorrect.Set().Value(attribute.Key("environment")); !ok || v.AsString() != "production" {
t.Errorf("expected environment 'production', got %v", v.AsString())
}
// 5. THE SCHEMA URL CONFLICT TRAP:
// Merging resources with conflicting non-empty schema URLs returns ErrSchemaURLConflict.
resSchema1 := resource.NewWithAttributes("https://example.com/schemas/1.24.0",
attribute.String("k1", "v1"),
)
resSchema2 := resource.NewWithAttributes("https://example.com/schemas/1.26.0",
attribute.String("k2", "v2"),
)
_, conflictErr := resource.Merge(resSchema1, resSchema2)
if conflictErr == nil {
t.Fatalf("expected ErrSchemaURLConflict when merging resources with different non-empty schema URLs")
}
if !errors.Is(conflictErr, resource.ErrSchemaURLConflict) {
t.Errorf("expected error to match resource.ErrSchemaURLConflict, got: %v", conflictErr)
}
}