Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Change resource.New() to use functional options; add builtin attributes for (host.*, telemetry.sdk.*) #1235

Merged
merged 16 commits into from
Oct 31, 2020
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm

### Added

- Support for `resource.NewConfig()` to configure a Resource with
automatic values for builtin semantic `telemetry.sdk.*` and
`host.name` conventions. (#1235)
- `EventOption` and the related `NewEventConfig` function are added to the `go.opentelemetry.io/otel` package to configure Span events. (#1254)
- A `TextMapPropagator` and associated `TextMapCarrier` are added to the `go.opentelemetry.io/otel/oteltest` package to test TextMap type propagators and their use. (#1259)

Expand Down
2 changes: 1 addition & 1 deletion sdk/metric/benchmark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
45 changes: 0 additions & 45 deletions sdk/metric/config.go

This file was deleted.

2 changes: 1 addition & 1 deletion sdk/metric/controller/pull/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion sdk/metric/controller/push/push.go
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
2 changes: 1 addition & 1 deletion sdk/metric/correct_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 1 addition & 3 deletions sdk/metric/processor/processortest/test_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.New(label.String("R", "V")),
)
meter := otel.WrapMeterImpl(accum, "testing")

Expand Down
8 changes: 2 additions & 6 deletions sdk/metric/processor/reducer/reducer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.New(label.String("R", "V")),
)
generateData(accum)

Expand All @@ -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.New(label.String("R", "V")),
)
exporter := processorTest.NewExporter(basicProc, label.DefaultEncoder())

Expand Down
9 changes: 2 additions & 7 deletions sdk/metric/sdk.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
jmacd marked this conversation as resolved.
Show resolved Hide resolved
return &Accumulator{
processor: processor,
asyncInstruments: internal.NewAsyncInstrumentState(),
resource: c.Resource,
resource: resource,
}
}

Expand Down
3 changes: 2 additions & 1 deletion sdk/metric/stress_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
3 changes: 3 additions & 0 deletions sdk/resource/auto.go
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand Down
81 changes: 81 additions & 0 deletions sdk/resource/builtin.go
Original file line number Diff line number Diff line change
@@ -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) {
jmacd marked this conversation as resolved.
Show resolved Hide resolved
return New(
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) {
jmacd marked this conversation as resolved.
Show resolved Hide resolved
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 {
jmacd marked this conversation as resolved.
Show resolved Hide resolved
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 New(sd.K.String(value)), nil
}
59 changes: 59 additions & 0 deletions sdk/resource/builtin_test.go
Original file line number Diff line number Diff line change
@@ -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.NewConfig(
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)
}
Loading