You've already forked opentelemetry-go
mirror of
https://github.com/open-telemetry/opentelemetry-go.git
synced 2025-08-10 22:31:50 +02:00
add resource type. (#528)
* add resource type. * sort attributes in test to fix ci. * add resource keys and update test.
This commit is contained in:
72
sdk/resource/resource.go
Normal file
72
sdk/resource/resource.go
Normal file
@@ -0,0 +1,72 @@
|
||||
// Copyright 2020, 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 functionality for resource, which capture
|
||||
// identifying information about the entities for which signals are exported.
|
||||
package resource
|
||||
|
||||
import (
|
||||
"go.opentelemetry.io/otel/api/core"
|
||||
)
|
||||
|
||||
// Resource describes an entity about which identifying information and metadata is exposed.
|
||||
type Resource struct {
|
||||
labels map[core.Key]core.Value
|
||||
}
|
||||
|
||||
// New creates a resource from a set of attributes.
|
||||
// If there are duplicates keys then the first value of the key is preserved.
|
||||
func New(kvs ...core.KeyValue) *Resource {
|
||||
res := &Resource{
|
||||
labels: map[core.Key]core.Value{},
|
||||
}
|
||||
for _, kv := range kvs {
|
||||
if _, ok := res.labels[kv.Key]; !ok {
|
||||
res.labels[kv.Key] = kv.Value
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// Merge creates a new resource by combining resource a and b.
|
||||
// If there are common key between resource a and b then value from resource a is preserved.
|
||||
// If one of the resources is nil then the other resource is returned without creating a new one.
|
||||
func Merge(a, b *Resource) *Resource {
|
||||
if a == nil {
|
||||
return b
|
||||
}
|
||||
if b == nil {
|
||||
return a
|
||||
}
|
||||
res := &Resource{
|
||||
labels: map[core.Key]core.Value{},
|
||||
}
|
||||
for k, v := range b.labels {
|
||||
res.labels[k] = v
|
||||
}
|
||||
// labels from resource a overwrite labels from resource b.
|
||||
for k, v := range a.labels {
|
||||
res.labels[k] = v
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// Attributes returns a copy of attributes from the resource.
|
||||
func (r Resource) Attributes() []core.KeyValue {
|
||||
attrs := make([]core.KeyValue, 0, len(r.labels))
|
||||
for k, v := range r.labels {
|
||||
attrs = append(attrs, core.KeyValue{Key: k, Value: v})
|
||||
}
|
||||
return attrs
|
||||
}
|
126
sdk/resource/resource_test.go
Normal file
126
sdk/resource/resource_test.go
Normal file
@@ -0,0 +1,126 @@
|
||||
// Copyright 2020, 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 (
|
||||
"fmt"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
||||
"go.opentelemetry.io/otel/api/core"
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
)
|
||||
|
||||
var (
|
||||
kv11 = core.Key("k1").String("v11")
|
||||
kv12 = core.Key("k1").String("v12")
|
||||
kv21 = core.Key("k2").String("v21")
|
||||
kv31 = core.Key("k3").String("v31")
|
||||
kv41 = core.Key("k4").String("v41")
|
||||
)
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
in []core.KeyValue
|
||||
want []core.KeyValue
|
||||
}{
|
||||
{
|
||||
name: "New with common key order1",
|
||||
in: []core.KeyValue{kv11, kv12, kv21},
|
||||
want: []core.KeyValue{kv11, kv21},
|
||||
},
|
||||
{
|
||||
name: "New with common key order2",
|
||||
in: []core.KeyValue{kv12, kv11, kv21},
|
||||
want: []core.KeyValue{kv12, kv21},
|
||||
},
|
||||
{
|
||||
name: "New with nil",
|
||||
in: nil,
|
||||
want: []core.KeyValue{},
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(fmt.Sprintf("case-%s", c.name), func(t *testing.T) {
|
||||
res := resource.New(c.in...)
|
||||
if diff := cmp.Diff(
|
||||
sortedAttributes(res.Attributes()),
|
||||
sortedAttributes(c.want),
|
||||
cmp.AllowUnexported(core.Value{})); diff != "" {
|
||||
t.Fatalf("unwanted result: diff %+v,", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMerge(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
a, b *resource.Resource
|
||||
want []core.KeyValue
|
||||
}{
|
||||
{
|
||||
name: "Merge with no overlap, no nil",
|
||||
a: resource.New(kv11, kv31),
|
||||
b: resource.New(kv21, kv41),
|
||||
want: []core.KeyValue{kv11, kv21, kv31, kv41},
|
||||
},
|
||||
{
|
||||
name: "Merge with common key order1",
|
||||
a: resource.New(kv11),
|
||||
b: resource.New(kv12, kv21),
|
||||
want: []core.KeyValue{kv21, kv11},
|
||||
},
|
||||
{
|
||||
name: "Merge with common key order2",
|
||||
a: resource.New(kv12, kv21),
|
||||
b: resource.New(kv11),
|
||||
want: []core.KeyValue{kv12, kv21},
|
||||
},
|
||||
{
|
||||
name: "Merge with first resource nil",
|
||||
a: nil,
|
||||
b: resource.New(kv21),
|
||||
want: []core.KeyValue{kv21},
|
||||
},
|
||||
{
|
||||
name: "Merge with second resource nil",
|
||||
a: resource.New(kv11),
|
||||
b: nil,
|
||||
want: []core.KeyValue{kv11},
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(fmt.Sprintf("case-%s", c.name), func(t *testing.T) {
|
||||
res := resource.Merge(c.a, c.b)
|
||||
if diff := cmp.Diff(
|
||||
sortedAttributes(res.Attributes()),
|
||||
sortedAttributes(c.want),
|
||||
cmp.AllowUnexported(core.Value{})); diff != "" {
|
||||
t.Fatalf("unwanted result: diff %+v,", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func sortedAttributes(attrs []core.KeyValue) []core.KeyValue {
|
||||
sort.Slice(attrs[:], func(i, j int) bool {
|
||||
return attrs[i].Key < attrs[j].Key
|
||||
})
|
||||
return attrs
|
||||
}
|
80
sdk/resource/resourcekeys/const.go
Normal file
80
sdk/resource/resourcekeys/const.go
Normal file
@@ -0,0 +1,80 @@
|
||||
// Copyright 2020, 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 resourcekeys contains well known type and label keys for resources.
|
||||
package resourcekeys // import "go.opentelemetry.io/otel/sdk/resource/resourcekeys"
|
||||
|
||||
// Constants for Service resources.
|
||||
const (
|
||||
// A uniquely identifying name for a Service.
|
||||
ServiceKeyName = "service.name"
|
||||
ServiceKeyNamespace = "service.namespace"
|
||||
ServiceKeyInstanceID = "service.instance.id"
|
||||
ServiceKeyVersion = "service.version"
|
||||
)
|
||||
|
||||
// Constants for Library resources.
|
||||
const (
|
||||
// A uniquely identifying name for a Library.
|
||||
LibraryKeyName = "library.name"
|
||||
LibraryKeyLanguage = "library.language"
|
||||
LibraryKeyVersion = "library.version"
|
||||
)
|
||||
|
||||
// Constants for Kubernetes resources.
|
||||
const (
|
||||
// A uniquely identifying name for the Kubernetes cluster. Kubernetes
|
||||
// does not have cluster names as an internal concept so this may be
|
||||
// set to any meaningful value within the environment. For example,
|
||||
// GKE clusters have a name which can be used for this label.
|
||||
K8SKeyClusterName = "k8s.cluster.name"
|
||||
K8SKeyNamespaceName = "k8s.namespace.name"
|
||||
K8SKeyPodName = "k8s.pod.name"
|
||||
K8SKeyDeploymentName = "k8s.deployment.name"
|
||||
)
|
||||
|
||||
// Constants for Container resources.
|
||||
const (
|
||||
// A uniquely identifying name for the Container.
|
||||
ContainerKeyName = "container.name"
|
||||
ContainerKeyImageName = "container.image.name"
|
||||
ContainerKeyImageTag = "container.image.tag"
|
||||
)
|
||||
|
||||
// Constants for Cloud resources.
|
||||
const (
|
||||
CloudKeyProvider = "cloud.provider"
|
||||
CloudKeyAccountID = "cloud.account.id"
|
||||
CloudKeyRegion = "cloud.region"
|
||||
CloudKeyZone = "cloud.zone"
|
||||
|
||||
// Cloud Providers
|
||||
CloudProviderAWS = "aws"
|
||||
CloudProviderGCP = "gcp"
|
||||
CloudProviderAZURE = "azure"
|
||||
)
|
||||
|
||||
// Constants for Host resources.
|
||||
const (
|
||||
// A uniquely identifying name for the host.
|
||||
HostKeyName = "host.name"
|
||||
|
||||
// A hostname as returned by the 'hostname' command on host machine.
|
||||
HostKeyHostName = "host.hostname"
|
||||
HostKeyID = "host.id"
|
||||
HostKeyType = "host.type"
|
||||
HostKeyImageName = "host.image.name"
|
||||
HostKeyImageID = "host.image.id"
|
||||
HostKeyImageVersion = "host.image.version"
|
||||
)
|
Reference in New Issue
Block a user