mirror of
https://github.com/open-telemetry/opentelemetry-go.git
synced 2025-02-05 13:15:41 +02:00
Change resource.New() to use functional options; add builtin attributes for (host.*, telemetry.sdk.*) (#1235)
* Add a resource.Configure() with functional options
* Add a changelog
* Add tests for builtin resources
* Rename to WithoutBuiltin
* Add new test; restore environment after tests
* Apply feedback
* Apply suggestions from code review
❤️
Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com>
* Comment edits
* Rename New, former method NewFromAttributes
* NewFromAttributes->NewWithAttributes
Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com>
This commit is contained in:
parent
034195692a
commit
187adeb251
@ -35,6 +35,8 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
||||
- Move the `go.opentelemetry.io/otel/api/global` package to `go.opentelemetry.io/otel/global`. (#1262)
|
||||
- Rename correlation context header from `"otcorrelations"` to `"baggage"` to match the OpenTelemetry specification. (#1267)
|
||||
- Fix `Code.UnmarshalJSON` to work with valid json only. (#1276)
|
||||
- The `resource.New()` method changes signature to support builtin attributes and functional options, including `telemetry.sdk.*` and
|
||||
`host.name` semantic conventions; the former method is renamed `resource.NewWithAttributes`. (#1235)
|
||||
|
||||
### Removed
|
||||
|
||||
|
@ -41,6 +41,7 @@ import (
|
||||
// Initializes an OTLP exporter, and configures the corresponding trace and
|
||||
// metric providers.
|
||||
func initProvider() func() {
|
||||
ctx := context.Background()
|
||||
|
||||
// If the OpenTelemetry Collector is running on a local cluster (minikube or
|
||||
// microk8s), it should be accessible through the NodePort service at the
|
||||
@ -54,13 +55,18 @@ func initProvider() func() {
|
||||
)
|
||||
handleErr(err, "failed to create exporter")
|
||||
|
||||
res, err := resource.New(ctx,
|
||||
resource.WithAttributes(
|
||||
// the service name used to display traces in backends
|
||||
semconv.ServiceNameKey.String("test-service"),
|
||||
),
|
||||
)
|
||||
handleErr(err, "failed to create resource")
|
||||
|
||||
bsp := sdktrace.NewBatchSpanProcessor(exp)
|
||||
tracerProvider := sdktrace.NewTracerProvider(
|
||||
sdktrace.WithConfig(sdktrace.Config{DefaultSampler: sdktrace.AlwaysSample()}),
|
||||
sdktrace.WithResource(resource.New(
|
||||
// the service name used to display traces in backends
|
||||
semconv.ServiceNameKey.String("test-service"),
|
||||
)),
|
||||
sdktrace.WithResource(res),
|
||||
sdktrace.WithSpanProcessor(bsp),
|
||||
)
|
||||
|
||||
@ -80,7 +86,6 @@ func initProvider() func() {
|
||||
pusher.Start()
|
||||
|
||||
return func() {
|
||||
ctx := context.Background()
|
||||
handleErr(tracerProvider.Shutdown(ctx), "failed to shutdown provider")
|
||||
handleErr(exp.Shutdown(ctx), "failed to stop exporter")
|
||||
pusher.Stop() // pushes any last exports to the receiver
|
||||
|
@ -37,10 +37,20 @@ import (
|
||||
// TODO: Address this issue.
|
||||
|
||||
func ExampleNewExportPipeline() {
|
||||
// Create a resource, with builtin attributes plus R=V.
|
||||
res, err := resource.New(
|
||||
context.Background(),
|
||||
resource.WithoutBuiltin(), // Test-only!
|
||||
resource.WithAttributes(label.String("R", "V")),
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Create a meter
|
||||
exporter, err := prometheus.NewExportPipeline(
|
||||
prometheus.Config{},
|
||||
pull.WithResource(resource.New(label.String("R", "V"))),
|
||||
pull.WithResource(res),
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -39,7 +39,7 @@ func TestPrometheusExporter(t *testing.T) {
|
||||
DefaultHistogramBoundaries: []float64{-0.5, 1},
|
||||
},
|
||||
pull.WithCachePeriod(0),
|
||||
pull.WithResource(resource.New(label.String("R", "V"))),
|
||||
pull.WithResource(resource.NewWithAttributes(label.String("R", "V"))),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
|
@ -320,7 +320,7 @@ func TestRecordAggregatorIncompatibleErrors(t *testing.T) {
|
||||
makeMpb := func(kind aggregation.Kind, agg aggregation.Aggregation) (*metricpb.Metric, error) {
|
||||
desc := otel.NewDescriptor("things", otel.CounterInstrumentKind, otel.Int64NumberKind)
|
||||
labels := label.NewSet()
|
||||
res := resource.New()
|
||||
res := resource.Empty()
|
||||
test := &testAgg{
|
||||
kind: kind,
|
||||
agg: agg,
|
||||
@ -357,7 +357,7 @@ func TestRecordAggregatorUnexpectedErrors(t *testing.T) {
|
||||
makeMpb := func(kind aggregation.Kind, agg aggregation.Aggregation) (*metricpb.Metric, error) {
|
||||
desc := otel.NewDescriptor("things", otel.CounterInstrumentKind, otel.Int64NumberKind)
|
||||
labels := label.NewSet()
|
||||
res := resource.New()
|
||||
res := resource.Empty()
|
||||
return Record(export.NewRecord(&desc, &labels, res, agg, intervalStart, intervalEnd))
|
||||
}
|
||||
|
||||
|
@ -40,7 +40,7 @@ func TestEmptyResource(t *testing.T) {
|
||||
func TestResourceAttributes(t *testing.T) {
|
||||
attrs := []label.KeyValue{label.Int("one", 1), label.Int("two", 2)}
|
||||
|
||||
got := Resource(resource.New(attrs...)).GetAttributes()
|
||||
got := Resource(resource.NewWithAttributes(attrs...)).GetAttributes()
|
||||
if !assert.Len(t, attrs, 2) {
|
||||
return
|
||||
}
|
||||
|
@ -252,7 +252,7 @@ func TestSpanData(t *testing.T) {
|
||||
DroppedAttributeCount: 1,
|
||||
DroppedMessageEventCount: 2,
|
||||
DroppedLinkCount: 3,
|
||||
Resource: resource.New(label.String("rk1", "rv1"), label.Int64("rk2", 5)),
|
||||
Resource: resource.NewWithAttributes(label.String("rk1", "rv1"), label.Int64("rk2", 5)),
|
||||
InstrumentationLibrary: instrumentation.Library{
|
||||
Name: "go.opentelemetry.io/test/otel",
|
||||
Version: "v0.0.1",
|
||||
|
@ -94,13 +94,13 @@ func newExporterEndToEndTest(t *testing.T, additionalOpts []otlp.ExporterOption)
|
||||
),
|
||||
}
|
||||
tp1 := sdktrace.NewTracerProvider(append(pOpts,
|
||||
sdktrace.WithResource(resource.New(
|
||||
sdktrace.WithResource(resource.NewWithAttributes(
|
||||
label.String("rk1", "rv11)"),
|
||||
label.Int64("rk2", 5),
|
||||
)))...)
|
||||
|
||||
tp2 := sdktrace.NewTracerProvider(append(pOpts,
|
||||
sdktrace.WithResource(resource.New(
|
||||
sdktrace.WithResource(resource.NewWithAttributes(
|
||||
label.String("rk1", "rv12)"),
|
||||
label.Float32("rk3", 6.5),
|
||||
)))...)
|
||||
|
@ -104,8 +104,8 @@ var (
|
||||
baseKeyValues = []label.KeyValue{label.String("host", "test.com")}
|
||||
cpuKey = label.Key("CPU")
|
||||
|
||||
testInstA = resource.New(label.String("instance", "tester-a"))
|
||||
testInstB = resource.New(label.String("instance", "tester-b"))
|
||||
testInstA = resource.NewWithAttributes(label.String("instance", "tester-a"))
|
||||
testInstB = resource.NewWithAttributes(label.String("instance", "tester-b"))
|
||||
|
||||
testHistogramBoundaries = []float64{2.0, 4.0, 8.0}
|
||||
|
||||
|
@ -97,7 +97,7 @@ func TestExportSpans(t *testing.T) {
|
||||
},
|
||||
StatusCode: codes.Ok,
|
||||
StatusMessage: "Ok",
|
||||
Resource: resource.New(label.String("instance", "tester-a")),
|
||||
Resource: resource.NewWithAttributes(label.String("instance", "tester-a")),
|
||||
InstrumentationLibrary: instrumentation.Library{
|
||||
Name: "lib-a",
|
||||
Version: "v0.1.0",
|
||||
@ -119,7 +119,7 @@ func TestExportSpans(t *testing.T) {
|
||||
},
|
||||
StatusCode: codes.Ok,
|
||||
StatusMessage: "Ok",
|
||||
Resource: resource.New(label.String("instance", "tester-a")),
|
||||
Resource: resource.NewWithAttributes(label.String("instance", "tester-a")),
|
||||
InstrumentationLibrary: instrumentation.Library{
|
||||
Name: "lib-b",
|
||||
Version: "v0.1.0",
|
||||
@ -142,7 +142,7 @@ func TestExportSpans(t *testing.T) {
|
||||
},
|
||||
StatusCode: codes.Ok,
|
||||
StatusMessage: "Ok",
|
||||
Resource: resource.New(label.String("instance", "tester-a")),
|
||||
Resource: resource.NewWithAttributes(label.String("instance", "tester-a")),
|
||||
InstrumentationLibrary: instrumentation.Library{
|
||||
Name: "lib-a",
|
||||
Version: "v0.1.0",
|
||||
@ -164,7 +164,7 @@ func TestExportSpans(t *testing.T) {
|
||||
},
|
||||
StatusCode: codes.Error,
|
||||
StatusMessage: "Unauthenticated",
|
||||
Resource: resource.New(label.String("instance", "tester-b")),
|
||||
Resource: resource.NewWithAttributes(label.String("instance", "tester-b")),
|
||||
InstrumentationLibrary: instrumentation.Library{
|
||||
Name: "lib-a",
|
||||
Version: "v1.1.0",
|
||||
|
@ -48,7 +48,7 @@ type testFixture struct {
|
||||
output *bytes.Buffer
|
||||
}
|
||||
|
||||
var testResource = resource.New(label.String("R", "V"))
|
||||
var testResource = resource.NewWithAttributes(label.String("R", "V"))
|
||||
|
||||
func newFixture(t *testing.T, opts ...stdout.Option) testFixture {
|
||||
buf := &bytes.Buffer{}
|
||||
@ -290,11 +290,11 @@ func TestStdoutResource(t *testing.T) {
|
||||
}
|
||||
testCases := []testCase{
|
||||
newCase("R1=V1,R2=V2,A=B,C=D",
|
||||
resource.New(label.String("R1", "V1"), label.String("R2", "V2")),
|
||||
resource.NewWithAttributes(label.String("R1", "V1"), label.String("R2", "V2")),
|
||||
label.String("A", "B"),
|
||||
label.String("C", "D")),
|
||||
newCase("R1=V1,R2=V2",
|
||||
resource.New(label.String("R1", "V1"), label.String("R2", "V2")),
|
||||
resource.NewWithAttributes(label.String("R1", "V1"), label.String("R2", "V2")),
|
||||
),
|
||||
newCase("A=B,C=D",
|
||||
nil,
|
||||
@ -304,7 +304,7 @@ func TestStdoutResource(t *testing.T) {
|
||||
// We explicitly do not de-duplicate between resources
|
||||
// and metric labels in this exporter.
|
||||
newCase("R1=V1,R2=V2,R1=V3,R2=V4",
|
||||
resource.New(label.String("R1", "V1"), label.String("R2", "V2")),
|
||||
resource.NewWithAttributes(label.String("R1", "V1"), label.String("R2", "V2")),
|
||||
label.String("R1", "V3"),
|
||||
label.String("R2", "V4")),
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ func TestExporter_ExportSpan(t *testing.T) {
|
||||
spanID, _ := otel.SpanIDFromHex("0102030405060708")
|
||||
keyValue := "value"
|
||||
doubleValue := 123.456
|
||||
resource := resource.New(label.String("rk1", "rv11"))
|
||||
resource := resource.NewWithAttributes(label.String("rk1", "rv11"))
|
||||
|
||||
testSpan := &export.SpanData{
|
||||
SpanContext: otel.SpanContext{
|
||||
|
@ -409,7 +409,7 @@ func Test_spanDataToThrift(t *testing.T) {
|
||||
StatusCode: codes.Error,
|
||||
StatusMessage: statusMessage,
|
||||
SpanKind: otel.SpanKindClient,
|
||||
Resource: resource.New(label.String("rk1", rv1), label.Int64("rk2", rv2)),
|
||||
Resource: resource.NewWithAttributes(label.String("rk1", rv1), label.Int64("rk2", rv2)),
|
||||
InstrumentationLibrary: instrumentation.Library{
|
||||
Name: instrLibName,
|
||||
Version: instrLibVersion,
|
||||
|
@ -42,7 +42,7 @@ func newFixture(b *testing.B) *benchFixture {
|
||||
AggregatorSelector: processortest.AggregatorSelector(),
|
||||
}
|
||||
|
||||
bf.accumulator = sdk.NewAccumulator(bf)
|
||||
bf.accumulator = sdk.NewAccumulator(bf, nil)
|
||||
bf.meter = otel.WrapMeterImpl(bf.accumulator, "benchmarks")
|
||||
return bf
|
||||
}
|
||||
|
@ -1,45 +0,0 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package metric
|
||||
|
||||
import (
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
)
|
||||
|
||||
// Config contains configuration for an SDK.
|
||||
type Config struct {
|
||||
// Resource describes all the metric records processed by the
|
||||
// Accumulator.
|
||||
Resource *resource.Resource
|
||||
}
|
||||
|
||||
// Option is the interface that applies the value to a configuration option.
|
||||
type Option interface {
|
||||
// Apply sets the Option value of a Config.
|
||||
Apply(*Config)
|
||||
}
|
||||
|
||||
// WithResource sets the Resource configuration option of a Config.
|
||||
func WithResource(res *resource.Resource) Option {
|
||||
return resourceOption{res}
|
||||
}
|
||||
|
||||
type resourceOption struct {
|
||||
*resource.Resource
|
||||
}
|
||||
|
||||
func (o resourceOption) Apply(config *Config) {
|
||||
config.Resource = o.Resource
|
||||
}
|
@ -60,7 +60,7 @@ func New(checkpointer export.Checkpointer, options ...Option) *Controller {
|
||||
}
|
||||
accum := sdk.NewAccumulator(
|
||||
checkpointer,
|
||||
sdk.WithResource(config.Resource),
|
||||
config.Resource,
|
||||
)
|
||||
return &Controller{
|
||||
accumulator: accum,
|
||||
|
@ -24,7 +24,7 @@ import (
|
||||
)
|
||||
|
||||
func TestWithResource(t *testing.T) {
|
||||
r := resource.New(label.String("A", "a"))
|
||||
r := resource.NewWithAttributes(label.String("A", "a"))
|
||||
|
||||
c := &Config{}
|
||||
WithResource(r).Apply(c)
|
||||
|
@ -61,7 +61,7 @@ func New(checkpointer export.Checkpointer, exporter export.Exporter, opts ...Opt
|
||||
|
||||
impl := sdk.NewAccumulator(
|
||||
checkpointer,
|
||||
sdk.WithResource(c.Resource),
|
||||
c.Resource,
|
||||
)
|
||||
return &Controller{
|
||||
provider: registry.NewMeterProvider(impl),
|
||||
|
@ -36,7 +36,7 @@ import (
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
)
|
||||
|
||||
var testResource = resource.New(label.String("R", "V"))
|
||||
var testResource = resource.NewWithAttributes(label.String("R", "V"))
|
||||
|
||||
type handler struct {
|
||||
sync.Mutex
|
||||
|
@ -34,7 +34,7 @@ import (
|
||||
)
|
||||
|
||||
var Must = otel.Must
|
||||
var testResource = resource.New(label.String("R", "V"))
|
||||
var testResource = resource.NewWithAttributes(label.String("R", "V"))
|
||||
|
||||
type handler struct {
|
||||
sync.Mutex
|
||||
@ -96,7 +96,7 @@ func newSDK(t *testing.T) (otel.Meter, *metricsdk.Accumulator, *correctnessProce
|
||||
}
|
||||
accum := metricsdk.NewAccumulator(
|
||||
processor,
|
||||
metricsdk.WithResource(testResource),
|
||||
testResource,
|
||||
)
|
||||
meter := otel.WrapMeterImpl(accum, "test")
|
||||
return meter, accum, processor
|
||||
|
@ -121,7 +121,7 @@ func testProcessor(
|
||||
// Note: this selector uses the instrument name to dictate
|
||||
// aggregation kind.
|
||||
selector := processorTest.AggregatorSelector()
|
||||
res := resource.New(label.String("R", "V"))
|
||||
res := resource.NewWithAttributes(label.String("R", "V"))
|
||||
|
||||
labs1 := []label.KeyValue{label.String("L1", "V")}
|
||||
labs2 := []label.KeyValue{label.String("L2", "V")}
|
||||
@ -361,7 +361,7 @@ func TestBasicTimestamps(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestStatefulNoMemoryCumulative(t *testing.T) {
|
||||
res := resource.New(label.String("R", "V"))
|
||||
res := resource.NewWithAttributes(label.String("R", "V"))
|
||||
ekind := export.CumulativeExporter
|
||||
|
||||
desc := otel.NewDescriptor("inst.sum", otel.CounterInstrumentKind, otel.Int64NumberKind)
|
||||
@ -395,7 +395,7 @@ func TestStatefulNoMemoryCumulative(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestStatefulNoMemoryDelta(t *testing.T) {
|
||||
res := resource.New(label.String("R", "V"))
|
||||
res := resource.NewWithAttributes(label.String("R", "V"))
|
||||
ekind := export.DeltaExporter
|
||||
|
||||
desc := otel.NewDescriptor("inst.sum", otel.SumObserverInstrumentKind, otel.Int64NumberKind)
|
||||
@ -435,7 +435,7 @@ func TestMultiObserverSum(t *testing.T) {
|
||||
export.DeltaExporter,
|
||||
} {
|
||||
|
||||
res := resource.New(label.String("R", "V"))
|
||||
res := resource.NewWithAttributes(label.String("R", "V"))
|
||||
desc := otel.NewDescriptor("observe.sum", otel.SumObserverInstrumentKind, otel.Int64NumberKind)
|
||||
selector := processorTest.AggregatorSelector()
|
||||
|
||||
|
@ -32,9 +32,7 @@ func generateTestData(proc export.Processor) {
|
||||
ctx := context.Background()
|
||||
accum := metricsdk.NewAccumulator(
|
||||
proc,
|
||||
metricsdk.WithResource(
|
||||
resource.New(label.String("R", "V")),
|
||||
),
|
||||
resource.NewWithAttributes(label.String("R", "V")),
|
||||
)
|
||||
meter := otel.WrapMeterImpl(accum, "testing")
|
||||
|
||||
|
@ -75,9 +75,7 @@ func TestFilterProcessor(t *testing.T) {
|
||||
)
|
||||
accum := metricsdk.NewAccumulator(
|
||||
reducer.New(testFilter{}, processorTest.Checkpointer(testProc)),
|
||||
metricsdk.WithResource(
|
||||
resource.New(label.String("R", "V")),
|
||||
),
|
||||
resource.NewWithAttributes(label.String("R", "V")),
|
||||
)
|
||||
generateData(accum)
|
||||
|
||||
@ -94,9 +92,7 @@ func TestFilterBasicProcessor(t *testing.T) {
|
||||
basicProc := basic.New(processorTest.AggregatorSelector(), export.CumulativeExporter)
|
||||
accum := metricsdk.NewAccumulator(
|
||||
reducer.New(testFilter{}, basicProc),
|
||||
metricsdk.WithResource(
|
||||
resource.New(label.String("R", "V")),
|
||||
),
|
||||
resource.NewWithAttributes(label.String("R", "V")),
|
||||
)
|
||||
exporter := processorTest.NewExporter(basicProc, label.DefaultEncoder())
|
||||
|
||||
|
@ -305,16 +305,11 @@ func (s *syncInstrument) RecordOne(ctx context.Context, number api.Number, kvs [
|
||||
// processor will call Collect() when it receives a request to scrape
|
||||
// current metric values. A push-based processor should configure its
|
||||
// own periodic collection.
|
||||
func NewAccumulator(processor export.Processor, opts ...Option) *Accumulator {
|
||||
c := &Config{}
|
||||
for _, opt := range opts {
|
||||
opt.Apply(c)
|
||||
}
|
||||
|
||||
func NewAccumulator(processor export.Processor, resource *resource.Resource) *Accumulator {
|
||||
return &Accumulator{
|
||||
processor: processor,
|
||||
asyncInstruments: internal.NewAsyncInstrumentState(),
|
||||
resource: c.Resource,
|
||||
resource: resource,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -292,7 +292,8 @@ func stressTest(t *testing.T, impl testImpl) {
|
||||
AggregatorSelector: processortest.AggregatorSelector(),
|
||||
}
|
||||
cc := concurrency()
|
||||
sdk := NewAccumulator(fixture)
|
||||
|
||||
sdk := NewAccumulator(fixture, nil)
|
||||
meter := otel.WrapMeterImpl(sdk, "stress_test")
|
||||
fixture.wg.Add(cc + 1)
|
||||
|
||||
|
@ -43,6 +43,9 @@ func Detect(ctx context.Context, detectors ...Detector) (*Resource, error) {
|
||||
var autoDetectedRes *Resource
|
||||
var errInfo []string
|
||||
for _, detector := range detectors {
|
||||
if detector == nil {
|
||||
continue
|
||||
}
|
||||
res, err := detector.Detect(ctx)
|
||||
if err != nil {
|
||||
errInfo = append(errInfo, err.Error())
|
||||
|
@ -47,7 +47,7 @@ func makeLabels(n int) (_, _ *resource.Resource) {
|
||||
}
|
||||
|
||||
}
|
||||
return resource.New(l1...), resource.New(l2...)
|
||||
return resource.NewWithAttributes(l1...), resource.NewWithAttributes(l2...)
|
||||
}
|
||||
|
||||
func benchmarkMergeResource(b *testing.B, size int) {
|
||||
|
81
sdk/resource/builtin.go
Normal file
81
sdk/resource/builtin.go
Normal file
@ -0,0 +1,81 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package resource
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"go.opentelemetry.io/otel/label"
|
||||
opentelemetry "go.opentelemetry.io/otel/sdk"
|
||||
"go.opentelemetry.io/otel/semconv"
|
||||
)
|
||||
|
||||
type (
|
||||
// TelemetrySDK is a Detector that provides information about
|
||||
// the OpenTelemetry SDK used. This Detector is included as a
|
||||
// builtin. If these resource attributes are not wanted, use
|
||||
// the WithTelemetrySDK(nil) or WithoutBuiltin() options to
|
||||
// explicitly disable them.
|
||||
TelemetrySDK struct{}
|
||||
|
||||
// Host is a Detector that provides information about the host
|
||||
// being run on. This Detector is included as a builtin. If
|
||||
// these resource attributes are not wanted, use the
|
||||
// WithHost(nil) or WithoutBuiltin() options to explicitly
|
||||
// disable them.
|
||||
Host struct{}
|
||||
|
||||
stringDetector struct {
|
||||
K label.Key
|
||||
F func() (string, error)
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
_ Detector = TelemetrySDK{}
|
||||
_ Detector = Host{}
|
||||
_ Detector = stringDetector{}
|
||||
)
|
||||
|
||||
// Detect returns a *Resource that describes the OpenTelemetry SDK used.
|
||||
func (TelemetrySDK) Detect(context.Context) (*Resource, error) {
|
||||
return NewWithAttributes(
|
||||
semconv.TelemetrySDKNameKey.String("opentelemetry-go"),
|
||||
semconv.TelemetrySDKLanguageKey.String("go"),
|
||||
semconv.TelemetrySDKVersionKey.String(opentelemetry.Version()),
|
||||
), nil
|
||||
}
|
||||
|
||||
// Detect returns a *Resource that describes the host being run on.
|
||||
func (Host) Detect(ctx context.Context) (*Resource, error) {
|
||||
return StringDetector(semconv.HostNameKey, os.Hostname).Detect(ctx)
|
||||
}
|
||||
|
||||
// StringDetector returns a Detector that will produce a *Resource
|
||||
// containing the string as a value corresponding to k.
|
||||
func StringDetector(k label.Key, f func() (string, error)) Detector {
|
||||
return stringDetector{K: k, F: f}
|
||||
}
|
||||
|
||||
// Detect implements Detector.
|
||||
func (sd stringDetector) Detect(ctx context.Context) (*Resource, error) {
|
||||
value, err := sd.F()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: %w", string(sd.K), err)
|
||||
}
|
||||
return NewWithAttributes(sd.K.String(value)), nil
|
||||
}
|
59
sdk/resource/builtin_test.go
Normal file
59
sdk/resource/builtin_test.go
Normal file
@ -0,0 +1,59 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package resource_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"go.opentelemetry.io/otel/label"
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
)
|
||||
|
||||
func TestBuiltinStringDetector(t *testing.T) {
|
||||
E := fmt.Errorf("no K")
|
||||
res, err := resource.StringDetector(label.Key("K"), func() (string, error) {
|
||||
return "", E
|
||||
}).Detect(context.Background())
|
||||
require.True(t, errors.Is(err, E))
|
||||
require.NotEqual(t, E, err)
|
||||
require.Nil(t, res)
|
||||
}
|
||||
|
||||
func TestBuiltinStringConfig(t *testing.T) {
|
||||
res, err := resource.New(
|
||||
context.Background(),
|
||||
resource.WithoutBuiltin(),
|
||||
resource.WithAttributes(label.String("A", "B")),
|
||||
resource.WithDetectors(resource.StringDetector(label.Key("K"), func() (string, error) {
|
||||
return "", fmt.Errorf("K-IS-MISSING")
|
||||
})),
|
||||
)
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "K-IS-MISSING")
|
||||
require.NotNil(t, res)
|
||||
|
||||
m := map[string]string{}
|
||||
for _, kv := range res.Attributes() {
|
||||
m[string(kv.Key)] = kv.Value.Emit()
|
||||
}
|
||||
require.EqualValues(t, map[string]string{
|
||||
"A": "B",
|
||||
}, m)
|
||||
}
|
150
sdk/resource/config.go
Normal file
150
sdk/resource/config.go
Normal file
@ -0,0 +1,150 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package resource
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.opentelemetry.io/otel/label"
|
||||
)
|
||||
|
||||
// config contains configuration for Resource creation.
|
||||
type config struct {
|
||||
// detectors that will be evaluated.
|
||||
detectors []Detector
|
||||
|
||||
// telemetrySDK is used to specify non-default
|
||||
// `telemetry.sdk.*` attributes.
|
||||
telemetrySDK Detector
|
||||
|
||||
// HostResource is used to specify non-default `host.*`
|
||||
// attributes.
|
||||
host Detector
|
||||
|
||||
// FromEnv is used to specify non-default OTEL_RESOURCE_ATTRIBUTES
|
||||
// attributes.
|
||||
fromEnv Detector
|
||||
}
|
||||
|
||||
// Option is the interface that applies a configuration option.
|
||||
type Option interface {
|
||||
// Apply sets the Option value of a config.
|
||||
Apply(*config)
|
||||
}
|
||||
|
||||
// WithAttributes adds attributes to the configured Resource.
|
||||
func WithAttributes(attributes ...label.KeyValue) Option {
|
||||
return WithDetectors(detectAttributes{attributes})
|
||||
}
|
||||
|
||||
type detectAttributes struct {
|
||||
attributes []label.KeyValue
|
||||
}
|
||||
|
||||
func (d detectAttributes) Detect(context.Context) (*Resource, error) {
|
||||
return NewWithAttributes(d.attributes...), nil
|
||||
}
|
||||
|
||||
// WithDetectors adds detectors to be evaluated for the configured resource.
|
||||
func WithDetectors(detectors ...Detector) Option {
|
||||
return detectorsOption{detectors}
|
||||
}
|
||||
|
||||
type detectorsOption struct {
|
||||
detectors []Detector
|
||||
}
|
||||
|
||||
// Apply implements Option.
|
||||
func (o detectorsOption) Apply(cfg *config) {
|
||||
cfg.detectors = append(cfg.detectors, o.detectors...)
|
||||
}
|
||||
|
||||
// WithTelemetrySDK overrides the builtin `telemetry.sdk.*`
|
||||
// attributes. Use nil to disable these attributes entirely.
|
||||
func WithTelemetrySDK(d Detector) Option {
|
||||
return telemetrySDKOption{d}
|
||||
}
|
||||
|
||||
type telemetrySDKOption struct {
|
||||
Detector
|
||||
}
|
||||
|
||||
// Apply implements Option.
|
||||
func (o telemetrySDKOption) Apply(cfg *config) {
|
||||
cfg.telemetrySDK = o.Detector
|
||||
}
|
||||
|
||||
// WithHost overrides the builtin `host.*` attributes. Use nil to
|
||||
// disable these attributes entirely.
|
||||
func WithHost(d Detector) Option {
|
||||
return hostOption{d}
|
||||
}
|
||||
|
||||
type hostOption struct {
|
||||
Detector
|
||||
}
|
||||
|
||||
// Apply implements Option.
|
||||
func (o hostOption) Apply(cfg *config) {
|
||||
cfg.host = o.Detector
|
||||
}
|
||||
|
||||
// WithFromEnv overrides the builtin detector for
|
||||
// OTEL_RESOURCE_ATTRIBUTES. Use nil to disable environment checking.
|
||||
func WithFromEnv(d Detector) Option {
|
||||
return fromEnvOption{d}
|
||||
}
|
||||
|
||||
type fromEnvOption struct {
|
||||
Detector
|
||||
}
|
||||
|
||||
// Apply implements Option.
|
||||
func (o fromEnvOption) Apply(cfg *config) {
|
||||
cfg.fromEnv = o.Detector
|
||||
}
|
||||
|
||||
// WithoutBuiltin disables all the builtin detectors, including the
|
||||
// telemetry.sdk.*, host.*, and the environment detector.
|
||||
func WithoutBuiltin() Option {
|
||||
return noBuiltinOption{}
|
||||
}
|
||||
|
||||
type noBuiltinOption struct{}
|
||||
|
||||
// Apply implements Option.
|
||||
func (o noBuiltinOption) Apply(cfg *config) {
|
||||
cfg.host = nil
|
||||
cfg.telemetrySDK = nil
|
||||
cfg.fromEnv = nil
|
||||
}
|
||||
|
||||
// New returns a Resource combined from the provided attributes,
|
||||
// user-provided detectors and builtin detectors.
|
||||
func New(ctx context.Context, opts ...Option) (*Resource, error) {
|
||||
cfg := config{
|
||||
telemetrySDK: TelemetrySDK{},
|
||||
host: Host{},
|
||||
fromEnv: FromEnv{},
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt.Apply(&cfg)
|
||||
}
|
||||
detectors := append(
|
||||
[]Detector{cfg.telemetrySDK, cfg.host, cfg.fromEnv},
|
||||
cfg.detectors...,
|
||||
)
|
||||
return Detect(ctx, detectors...)
|
||||
}
|
139
sdk/resource/config_test.go
Normal file
139
sdk/resource/config_test.go
Normal file
@ -0,0 +1,139 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package resource_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
ottest "go.opentelemetry.io/otel/internal/testing"
|
||||
"go.opentelemetry.io/otel/label"
|
||||
opentelemetry "go.opentelemetry.io/otel/sdk"
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
)
|
||||
|
||||
const envVar = "OTEL_RESOURCE_ATTRIBUTES"
|
||||
|
||||
func TestDefaultConfig(t *testing.T) {
|
||||
store, err := ottest.SetEnvVariables(map[string]string{
|
||||
envVar: "",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
defer func() { require.NoError(t, store.Restore()) }()
|
||||
|
||||
ctx := context.Background()
|
||||
res, err := resource.New(ctx)
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, map[string]string{
|
||||
"host.name": hostname(),
|
||||
"telemetry.sdk.name": "opentelemetry-go",
|
||||
"telemetry.sdk.language": "go",
|
||||
"telemetry.sdk.version": opentelemetry.Version(),
|
||||
}, toMap(res))
|
||||
}
|
||||
|
||||
func TestDefaultConfigNoHost(t *testing.T) {
|
||||
store, err := ottest.SetEnvVariables(map[string]string{
|
||||
envVar: "",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
defer func() { require.NoError(t, store.Restore()) }()
|
||||
|
||||
ctx := context.Background()
|
||||
res, err := resource.New(ctx, resource.WithHost(nil))
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, map[string]string{
|
||||
"telemetry.sdk.name": "opentelemetry-go",
|
||||
"telemetry.sdk.language": "go",
|
||||
"telemetry.sdk.version": opentelemetry.Version(),
|
||||
}, toMap(res))
|
||||
}
|
||||
|
||||
func TestDefaultConfigNoEnv(t *testing.T) {
|
||||
store, err := ottest.SetEnvVariables(map[string]string{
|
||||
envVar: "from=here",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
defer func() { require.NoError(t, store.Restore()) }()
|
||||
|
||||
ctx := context.Background()
|
||||
res, err := resource.New(ctx, resource.WithFromEnv(nil))
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, map[string]string{
|
||||
"host.name": hostname(),
|
||||
"telemetry.sdk.name": "opentelemetry-go",
|
||||
"telemetry.sdk.language": "go",
|
||||
"telemetry.sdk.version": opentelemetry.Version(),
|
||||
}, toMap(res))
|
||||
}
|
||||
|
||||
func TestDefaultConfigWithEnv(t *testing.T) {
|
||||
store, err := ottest.SetEnvVariables(map[string]string{
|
||||
envVar: "key=value,other=attr",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
defer func() { require.NoError(t, store.Restore()) }()
|
||||
|
||||
ctx := context.Background()
|
||||
res, err := resource.New(ctx)
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, map[string]string{
|
||||
"key": "value",
|
||||
"other": "attr",
|
||||
"host.name": hostname(),
|
||||
"telemetry.sdk.name": "opentelemetry-go",
|
||||
"telemetry.sdk.language": "go",
|
||||
"telemetry.sdk.version": opentelemetry.Version(),
|
||||
}, toMap(res))
|
||||
}
|
||||
|
||||
func TestWithoutBuiltin(t *testing.T) {
|
||||
store, err := ottest.SetEnvVariables(map[string]string{
|
||||
envVar: "key=value,other=attr",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
defer func() { require.NoError(t, store.Restore()) }()
|
||||
|
||||
ctx := context.Background()
|
||||
res, err := resource.New(
|
||||
ctx,
|
||||
resource.WithoutBuiltin(),
|
||||
resource.WithAttributes(label.String("hello", "collector")),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, map[string]string{
|
||||
"hello": "collector",
|
||||
}, toMap(res))
|
||||
}
|
||||
|
||||
func toMap(res *resource.Resource) map[string]string {
|
||||
m := map[string]string{}
|
||||
for _, attr := range res.Attributes() {
|
||||
m[string(attr.Key)] = attr.Value.Emit()
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func hostname() string {
|
||||
hn, err := os.Hostname()
|
||||
if err != nil {
|
||||
return fmt.Sprintf("hostname(%s)", err)
|
||||
}
|
||||
return hn
|
||||
}
|
@ -27,19 +27,22 @@ import (
|
||||
const envVar = "OTEL_RESOURCE_ATTRIBUTES"
|
||||
|
||||
var (
|
||||
//errMissingValue is returned when a resource value is missing.
|
||||
// errMissingValue is returned when a resource value is missing.
|
||||
errMissingValue = fmt.Errorf("%w: missing value", ErrPartialResource)
|
||||
)
|
||||
|
||||
// FromEnv is a detector that implements the Detector and collects resources
|
||||
// from environment
|
||||
// FromEnv is a Detector that implements the Detector and collects
|
||||
// resources from environment. This Detector is included as a
|
||||
// builtin. If these resource attributes are not wanted, use the
|
||||
// WithFromEnv(nil) or WithoutBuiltin() options to explicitly disable
|
||||
// them.
|
||||
type FromEnv struct{}
|
||||
|
||||
// compile time assertion that FromEnv implements Detector interface
|
||||
var _ Detector = (*FromEnv)(nil)
|
||||
var _ Detector = FromEnv{}
|
||||
|
||||
// Detect collects resources from environment
|
||||
func (d *FromEnv) Detect(context.Context) (*Resource, error) {
|
||||
func (FromEnv) Detect(context.Context) (*Resource, error) {
|
||||
labels := strings.TrimSpace(os.Getenv(envVar))
|
||||
|
||||
if labels == "" {
|
||||
@ -65,5 +68,5 @@ func constructOTResources(s string) (*Resource, error) {
|
||||
if len(invalid) > 0 {
|
||||
err = fmt.Errorf("%w: %v", errMissingValue, invalid)
|
||||
}
|
||||
return New(labels...), err
|
||||
return NewWithAttributes(labels...), err
|
||||
}
|
||||
|
@ -17,32 +17,40 @@ package resource
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
ottest "go.opentelemetry.io/otel/internal/testing"
|
||||
"go.opentelemetry.io/otel/label"
|
||||
)
|
||||
|
||||
func TestDetectOnePair(t *testing.T) {
|
||||
os.Setenv(envVar, "key=value")
|
||||
store, err := ottest.SetEnvVariables(map[string]string{
|
||||
envVar: "key=value",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
defer func() { require.NoError(t, store.Restore()) }()
|
||||
|
||||
detector := &FromEnv{}
|
||||
res, err := detector.Detect(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, New(label.String("key", "value")), res)
|
||||
assert.Equal(t, NewWithAttributes(label.String("key", "value")), res)
|
||||
}
|
||||
|
||||
func TestDetectMultiPairs(t *testing.T) {
|
||||
os.Setenv("x", "1")
|
||||
os.Setenv(envVar, "key=value, k = v , a= x, a=z")
|
||||
store, err := ottest.SetEnvVariables(map[string]string{
|
||||
"x": "1",
|
||||
envVar: "key=value, k = v , a= x, a=z",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
defer func() { require.NoError(t, store.Restore()) }()
|
||||
|
||||
detector := &FromEnv{}
|
||||
res, err := detector.Detect(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, res, New(
|
||||
assert.Equal(t, res, NewWithAttributes(
|
||||
label.String("key", "value"),
|
||||
label.String("k", "v"),
|
||||
label.String("a", "x"),
|
||||
@ -51,7 +59,11 @@ func TestDetectMultiPairs(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestEmpty(t *testing.T) {
|
||||
os.Setenv(envVar, " ")
|
||||
store, err := ottest.SetEnvVariables(map[string]string{
|
||||
envVar: " ",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
defer func() { require.NoError(t, store.Restore()) }()
|
||||
|
||||
detector := &FromEnv{}
|
||||
res, err := detector.Detect(context.Background())
|
||||
@ -60,13 +72,17 @@ func TestEmpty(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMissingKeyError(t *testing.T) {
|
||||
os.Setenv(envVar, "key=value,key")
|
||||
store, err := ottest.SetEnvVariables(map[string]string{
|
||||
envVar: "key=value,key",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
defer func() { require.NoError(t, store.Restore()) }()
|
||||
|
||||
detector := &FromEnv{}
|
||||
res, err := detector.Detect(context.Background())
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, err, fmt.Errorf("%w: %v", errMissingValue, "[key]"))
|
||||
assert.Equal(t, res, New(
|
||||
assert.Equal(t, res, NewWithAttributes(
|
||||
label.String("key", "value"),
|
||||
))
|
||||
}
|
||||
|
@ -31,10 +31,10 @@ type Resource struct {
|
||||
|
||||
var emptyResource Resource
|
||||
|
||||
// New creates a resource from a set of attributes. If there are
|
||||
// NewWithAttributes creates a resource from a set of attributes. If there are
|
||||
// duplicate keys present in the list of attributes, then the last
|
||||
// value found for the key is preserved.
|
||||
func New(kvs ...label.KeyValue) *Resource {
|
||||
func NewWithAttributes(kvs ...label.KeyValue) *Resource {
|
||||
return &Resource{
|
||||
labels: label.NewSet(kvs...),
|
||||
}
|
||||
@ -103,7 +103,7 @@ func Merge(a, b *Resource) *Resource {
|
||||
for mi.Next() {
|
||||
combine = append(combine, mi.Label())
|
||||
}
|
||||
return New(combine...)
|
||||
return NewWithAttributes(combine...)
|
||||
}
|
||||
|
||||
// Empty returns an instance of Resource with no attributes. It is
|
||||
|
@ -58,7 +58,7 @@ func TestNew(t *testing.T) {
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(fmt.Sprintf("case-%s", c.name), func(t *testing.T) {
|
||||
res := resource.New(c.in...)
|
||||
res := resource.NewWithAttributes(c.in...)
|
||||
if diff := cmp.Diff(
|
||||
res.Attributes(),
|
||||
c.want,
|
||||
@ -77,61 +77,61 @@ func TestMerge(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
name: "Merge with no overlap, no nil",
|
||||
a: resource.New(kv11, kv31),
|
||||
b: resource.New(kv21, kv41),
|
||||
a: resource.NewWithAttributes(kv11, kv31),
|
||||
b: resource.NewWithAttributes(kv21, kv41),
|
||||
want: []label.KeyValue{kv11, kv21, kv31, kv41},
|
||||
},
|
||||
{
|
||||
name: "Merge with no overlap, no nil, not interleaved",
|
||||
a: resource.New(kv11, kv21),
|
||||
b: resource.New(kv31, kv41),
|
||||
a: resource.NewWithAttributes(kv11, kv21),
|
||||
b: resource.NewWithAttributes(kv31, kv41),
|
||||
want: []label.KeyValue{kv11, kv21, kv31, kv41},
|
||||
},
|
||||
{
|
||||
name: "Merge with common key order1",
|
||||
a: resource.New(kv11),
|
||||
b: resource.New(kv12, kv21),
|
||||
a: resource.NewWithAttributes(kv11),
|
||||
b: resource.NewWithAttributes(kv12, kv21),
|
||||
want: []label.KeyValue{kv11, kv21},
|
||||
},
|
||||
{
|
||||
name: "Merge with common key order2",
|
||||
a: resource.New(kv12, kv21),
|
||||
b: resource.New(kv11),
|
||||
a: resource.NewWithAttributes(kv12, kv21),
|
||||
b: resource.NewWithAttributes(kv11),
|
||||
want: []label.KeyValue{kv12, kv21},
|
||||
},
|
||||
{
|
||||
name: "Merge with common key order4",
|
||||
a: resource.New(kv11, kv21, kv41),
|
||||
b: resource.New(kv31, kv41),
|
||||
a: resource.NewWithAttributes(kv11, kv21, kv41),
|
||||
b: resource.NewWithAttributes(kv31, kv41),
|
||||
want: []label.KeyValue{kv11, kv21, kv31, kv41},
|
||||
},
|
||||
{
|
||||
name: "Merge with no keys",
|
||||
a: resource.New(),
|
||||
b: resource.New(),
|
||||
a: resource.NewWithAttributes(),
|
||||
b: resource.NewWithAttributes(),
|
||||
want: nil,
|
||||
},
|
||||
{
|
||||
name: "Merge with first resource no keys",
|
||||
a: resource.New(),
|
||||
b: resource.New(kv21),
|
||||
a: resource.NewWithAttributes(),
|
||||
b: resource.NewWithAttributes(kv21),
|
||||
want: []label.KeyValue{kv21},
|
||||
},
|
||||
{
|
||||
name: "Merge with second resource no keys",
|
||||
a: resource.New(kv11),
|
||||
b: resource.New(),
|
||||
a: resource.NewWithAttributes(kv11),
|
||||
b: resource.NewWithAttributes(),
|
||||
want: []label.KeyValue{kv11},
|
||||
},
|
||||
{
|
||||
name: "Merge with first resource nil",
|
||||
a: nil,
|
||||
b: resource.New(kv21),
|
||||
b: resource.NewWithAttributes(kv21),
|
||||
want: []label.KeyValue{kv21},
|
||||
},
|
||||
{
|
||||
name: "Merge with second resource nil",
|
||||
a: resource.New(kv11),
|
||||
a: resource.NewWithAttributes(kv11),
|
||||
b: nil,
|
||||
want: []label.KeyValue{kv11},
|
||||
},
|
||||
@ -207,14 +207,14 @@ func TestString(t *testing.T) {
|
||||
want: `A\=a\\\,B=b`,
|
||||
},
|
||||
} {
|
||||
if got := resource.New(test.kvs...).String(); got != test.want {
|
||||
if got := resource.NewWithAttributes(test.kvs...).String(); got != test.want {
|
||||
t.Errorf("Resource(%v).String() = %q, want %q", test.kvs, got, test.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalJSON(t *testing.T) {
|
||||
r := resource.New(label.Int64("A", 1), label.String("C", "D"))
|
||||
r := resource.NewWithAttributes(label.Int64("A", 1), label.String("C", "D"))
|
||||
data, err := json.Marshal(r)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t,
|
||||
|
@ -1169,7 +1169,7 @@ func TestWithResource(t *testing.T) {
|
||||
te := NewTestExporter()
|
||||
tp := NewTracerProvider(WithSyncer(te),
|
||||
WithConfig(Config{DefaultSampler: AlwaysSample()}),
|
||||
WithResource(resource.New(label.String("rk1", "rv1"), label.Int64("rk2", 5))))
|
||||
WithResource(resource.NewWithAttributes(label.String("rk1", "rv1"), label.Int64("rk2", 5))))
|
||||
span := startSpan(tp, "WithResource")
|
||||
span.SetAttributes(label.String("key1", "value1"))
|
||||
got, err := endSpan(te, span)
|
||||
@ -1189,7 +1189,7 @@ func TestWithResource(t *testing.T) {
|
||||
},
|
||||
SpanKind: otel.SpanKindInternal,
|
||||
HasRemoteParent: true,
|
||||
Resource: resource.New(label.String("rk1", "rv1"), label.Int64("rk2", 5)),
|
||||
Resource: resource.NewWithAttributes(label.String("rk1", "rv1"), label.Int64("rk2", 5)),
|
||||
InstrumentationLibrary: instrumentation.Library{Name: "WithResource"},
|
||||
}
|
||||
if diff := cmpDiff(got, want); diff != "" {
|
||||
|
Loading…
x
Reference in New Issue
Block a user