mirror of
https://github.com/open-telemetry/opentelemetry-go.git
synced 2024-12-04 09:43:23 +02:00
OT resource detector (#939)
* first * all included * constant * res keys * env detector * Update sdk/detect/env.go Co-authored-by: Anthony Mirabella <a9@aneurysm9.com> * new test cases and strings operation to handle labels * solved conflict * typo * corrected comments * deleted env var handling * push again * rerun * restructuring * new way to aggregate errors * all in resources package and verbose comments * solved merge conflicts * included new error types * improved error handling * updated changelog.md * updated changelog * updated changelog.md * updated changelog * Update CHANGELOG.md Co-authored-by: Anthony Mirabella <a9@aneurysm9.com> Co-authored-by: Liz Fong-Jones <lizf@honeycomb.io> Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com>
This commit is contained in:
parent
b2b23e15e5
commit
99c299877d
@ -10,6 +10,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
||||
|
||||
### Added
|
||||
|
||||
- Define a general Resources Detector Interface and allow resources to be detected from environment variables. (#939)
|
||||
- Github action to generate protobuf Go bindings locally in `internal/opentelemetry-proto-gen`. (#938)
|
||||
- OTLP .proto files from `open-telemetry/opentelemetry-proto` imported as a git submodule under `internal/opentelemetry-proto`.
|
||||
References to `github.com/open-telemetry/opentelemetry-proto` changed to `go.opentelemetry.io/otel/internal/opentelemetry-proto-gen`. (#942)
|
||||
|
67
sdk/resource/auto.go
Normal file
67
sdk/resource/auto.go
Normal file
@ -0,0 +1,67 @@
|
||||
// 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"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrMissingResource is returned by a detector when source information
|
||||
// is unavailable for a Resource.
|
||||
ErrMissingResource = errors.New("missing resource")
|
||||
// ErrPartialResource is returned by a detector when complete source
|
||||
// information for a Resource is unavailable or the source information
|
||||
// contains invalid values that are omitted from the returned Resource.
|
||||
ErrPartialResource = errors.New("partial resource")
|
||||
)
|
||||
|
||||
// Detector detects OpenTelemetry resource information
|
||||
type Detector interface {
|
||||
// Detect returns an initialized Resource based on gathered information.
|
||||
// If source information to construct a Resource is inaccessible, an
|
||||
// uninitialized Resource is returned with an appropriately wrapped
|
||||
// ErrMissingResource error is returned. If the source information to
|
||||
// construct a Resource contains invalid values, a Resource is returned
|
||||
// with the valid parts of the source information used for
|
||||
// initialization along with an appropriately wrapped ErrPartialResource
|
||||
// error.
|
||||
Detect(ctx context.Context) (*Resource, error)
|
||||
}
|
||||
|
||||
// Detect calls all input detectors sequentially and merges each result with the previous one.
|
||||
// It returns the merged error too.
|
||||
func Detect(ctx context.Context, detectors ...Detector) (*Resource, error) {
|
||||
var autoDetectedRes *Resource
|
||||
var errInfo []string
|
||||
for _, detector := range detectors {
|
||||
res, err := detector.Detect(ctx)
|
||||
if err != nil {
|
||||
errInfo = append(errInfo, err.Error())
|
||||
if !errors.Is(err, ErrPartialResource) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
autoDetectedRes = Merge(autoDetectedRes, res)
|
||||
}
|
||||
|
||||
var aggregatedError error
|
||||
if len(errInfo) > 0 {
|
||||
aggregatedError = fmt.Errorf("detecting resources: %s", errInfo)
|
||||
}
|
||||
return autoDetectedRes, aggregatedError
|
||||
}
|
28
sdk/resource/doc.go
Normal file
28
sdk/resource/doc.go
Normal file
@ -0,0 +1,28 @@
|
||||
// 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 provides detecting and representing resources.
|
||||
//
|
||||
// The fundamental struct is a Resource which holds identifying information
|
||||
// about the entities for which telemetry is exported.
|
||||
//
|
||||
// To automatically construct Resources from an environment a Detector
|
||||
// interface is defined. Implementations of this interface can be passed to
|
||||
// the Detect function to generate a Resource from the merged information.
|
||||
//
|
||||
// To load a user defined Resource from the environment variable
|
||||
// OTEL_RESOURCE_LABELS the FromEnv Detector can be used. It will interpret
|
||||
// the value as a list of comma delimited key/value pairs
|
||||
// (e.g. `<key1>=<value1>,<key2>=<value2>,...`).
|
||||
package resource
|
69
sdk/resource/env.go
Normal file
69
sdk/resource/env.go
Normal file
@ -0,0 +1,69 @@
|
||||
// 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"
|
||||
"strings"
|
||||
|
||||
"go.opentelemetry.io/otel/api/kv"
|
||||
)
|
||||
|
||||
// envVar is the environment variable name OpenTelemetry Resource information can be assigned to.
|
||||
const envVar = "OTEL_RESOURCE_LABELS"
|
||||
|
||||
var (
|
||||
//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
|
||||
type FromEnv struct{}
|
||||
|
||||
// compile time assertion that FromEnv implements Detector interface
|
||||
var _ Detector = (*FromEnv)(nil)
|
||||
|
||||
// Detect collects resources from environment
|
||||
func (d *FromEnv) Detect(context.Context) (*Resource, error) {
|
||||
labels := strings.TrimSpace(os.Getenv(envVar))
|
||||
|
||||
if labels == "" {
|
||||
return Empty(), ErrMissingResource
|
||||
}
|
||||
return constructOTResources(labels)
|
||||
}
|
||||
|
||||
func constructOTResources(s string) (*Resource, error) {
|
||||
pairs := strings.Split(s, ",")
|
||||
labels := []kv.KeyValue{}
|
||||
var invalid []string
|
||||
for _, p := range pairs {
|
||||
field := strings.SplitN(p, "=", 2)
|
||||
if len(field) != 2 {
|
||||
invalid = append(invalid, p)
|
||||
continue
|
||||
}
|
||||
k, v := strings.TrimSpace(field[0]), strings.TrimSpace(field[1])
|
||||
labels = append(labels, kv.String(k, v))
|
||||
}
|
||||
var err error
|
||||
if len(invalid) > 0 {
|
||||
err = fmt.Errorf("%w: %v", errMissingValue, invalid)
|
||||
}
|
||||
return New(labels...), err
|
||||
}
|
73
sdk/resource/env_test.go
Normal file
73
sdk/resource/env_test.go
Normal file
@ -0,0 +1,73 @@
|
||||
// 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"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"go.opentelemetry.io/otel/api/kv"
|
||||
)
|
||||
|
||||
func TestDetectOnePair(t *testing.T) {
|
||||
os.Setenv(envVar, "key=value")
|
||||
|
||||
detector := &FromEnv{}
|
||||
res, err := detector.Detect(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, New(kv.String("key", "value")), res)
|
||||
}
|
||||
|
||||
func TestDetectMultiPairs(t *testing.T) {
|
||||
os.Setenv("x", "1")
|
||||
os.Setenv(envVar, "key=value, k = v , a= x, a=z")
|
||||
|
||||
detector := &FromEnv{}
|
||||
res, err := detector.Detect(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, res, New(
|
||||
kv.String("key", "value"),
|
||||
kv.String("k", "v"),
|
||||
kv.String("a", "x"),
|
||||
kv.String("a", "z"),
|
||||
))
|
||||
}
|
||||
|
||||
func TestEmpty(t *testing.T) {
|
||||
os.Setenv(envVar, "")
|
||||
|
||||
detector := &FromEnv{}
|
||||
res, err := detector.Detect(context.Background())
|
||||
require.Error(t, err)
|
||||
assert.Equal(t, err, ErrMissingResource)
|
||||
assert.Equal(t, Empty(), res)
|
||||
}
|
||||
|
||||
func TestMissingKeyError(t *testing.T) {
|
||||
os.Setenv(envVar, "key=value,key")
|
||||
|
||||
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(
|
||||
kv.String("key", "value"),
|
||||
))
|
||||
}
|
@ -12,8 +12,6 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package resource provides functionality for resource, which capture
|
||||
// identifying information about the entities for which signals are exported.
|
||||
package resource
|
||||
|
||||
import (
|
||||
@ -34,7 +32,7 @@ type Resource struct {
|
||||
|
||||
var emptyResource Resource
|
||||
|
||||
// Key creates a resource from a set of attributes. If there are
|
||||
// New 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 ...kv.KeyValue) *Resource {
|
||||
|
Loading…
Reference in New Issue
Block a user