forked from open-telemetry/opentelemetry-collector-contrib
-
Notifications
You must be signed in to change notification settings - Fork 0
/
metadata.go
156 lines (133 loc) · 4.85 KB
/
metadata.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
// 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:https://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 collection
import (
"fmt"
"strings"
"time"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/open-telemetry/opentelemetry-collector-contrib/internal/common/metrics"
"github.com/open-telemetry/opentelemetry-collector-contrib/internal/common/testing/util"
)
const (
// Keys for K8s metadata
k8sKeyWorkLoadKind = "k8s.workload.kind"
k8sKeyWorkLoadName = "k8s.workload.name"
)
// KubernetesMetadata associates a resource to a set of properties.
type KubernetesMetadata struct {
// resourceIDKey is the label key of UID label for the resource.
resourceIDKey string
// resourceID is the Kubernetes UID of the resource. In case of
// containers, this value is the container id.
resourceID metrics.ResourceID
// metadata is a set of key-value pairs that describe a resource.
metadata map[string]string
}
// getGenericMetadata is responsible for collecting metadata from K8s resources that
// live on v1.ObjectMeta.
func getGenericMetadata(om *v1.ObjectMeta, resourceType string) *KubernetesMetadata {
rType := strings.ToLower(resourceType)
metadata := util.MergeStringMaps(map[string]string{}, om.Labels)
metadata[k8sKeyWorkLoadKind] = resourceType
metadata[k8sKeyWorkLoadName] = om.Name
metadata[fmt.Sprintf("%s.creation_timestamp",
rType)] = om.GetCreationTimestamp().Format(time.RFC3339)
for _, or := range om.OwnerReferences {
metadata[strings.ToLower(or.Kind)] = or.Name
metadata[strings.ToLower(or.Kind)+"_uid"] = string(or.UID)
}
return &KubernetesMetadata{
resourceIDKey: getResourceIDKey(rType),
resourceID: metrics.ResourceID(om.UID),
metadata: metadata,
}
}
func getResourceIDKey(rType string) string {
return fmt.Sprintf("k8s.%s.uid", rType)
}
// mergeKubernetesMetadataMaps merges maps of string (resource id) to
// KubernetesMetadata into a single map.
func mergeKubernetesMetadataMaps(maps ...map[metrics.ResourceID]*KubernetesMetadata) map[metrics.ResourceID]*KubernetesMetadata {
out := map[metrics.ResourceID]*KubernetesMetadata{}
for _, m := range maps {
for id, km := range m {
out[id] = km
}
}
return out
}
// GetMetadataUpdate processes metadata updates and returns
// a map of a delta of metadata mapped to each resource.
func GetMetadataUpdate(old, new map[metrics.ResourceID]*KubernetesMetadata) []*metrics.MetadataUpdate {
var out []*metrics.MetadataUpdate
for id, oldMetadata := range old {
// if an object with the same id has a previous revision, take a delta
// of the metadata.
if newMetadata, ok := new[id]; ok {
if metadataDelta := getMetadataDelta(oldMetadata.metadata, newMetadata.metadata); metadataDelta != nil {
out = append(out, &metrics.MetadataUpdate{
ResourceIDKey: oldMetadata.resourceIDKey,
ResourceID: id,
MetadataDelta: *metadataDelta,
})
}
}
}
// In case there are resources in the current revision, that was not in the
// previous revision, collect metadata to be added
for id, km := range new {
// if an id is seen for the first time, all metadata need to be added.
if _, ok := old[id]; !ok {
out = append(out, &metrics.MetadataUpdate{
ResourceIDKey: km.resourceIDKey,
ResourceID: id,
MetadataDelta: metrics.MetadataDelta{MetadataToAdd: km.metadata},
})
}
}
return out
}
// getMetadataDelta returns MetadataDelta between two sets for properties.
// If the delta between old (oldProps) and new (newProps) revisions of a
// resource end up being empty, nil is returned.
func getMetadataDelta(oldProps, newProps map[string]string) *metrics.MetadataDelta {
toAdd, toRemove, toUpdate := map[string]string{}, map[string]string{}, map[string]string{}
// If metadata exist in the previous revision as well, collect if
// the new values are different. Otherwise, the property is a new value
// and has to be added.
for key, newVal := range newProps {
if oldVal, ok := oldProps[key]; ok {
if oldVal != newVal {
toUpdate[key] = newVal
}
} else {
toAdd[key] = newVal
}
}
// Properties that don't exist in the latest revision should be removed
for key, val := range oldProps {
if _, ok := newProps[key]; !ok {
toRemove[key] = val
}
}
if len(toAdd) > 0 || len(toRemove) > 0 || len(toUpdate) > 0 {
return &metrics.MetadataDelta{
MetadataToAdd: toAdd,
MetadataToRemove: toRemove,
MetadataToUpdate: toUpdate,
}
}
return nil
}