Skip to content

Commit 39435da

Browse files
zeitlingerChrsMark
authored andcommitted
[processor/k8sattributes] Automatic resource attributes - annotation prefix (open-telemetry#38825)
This is the first part of open-telemetry#37114 - the ability to use an annotation prefix to define a resource attribute --------- Co-authored-by: Christos Markou <[email protected]>
1 parent f31f451 commit 39435da

File tree

6 files changed

+84
-4
lines changed

6 files changed

+84
-4
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
change_type: enhancement
2+
3+
component: k8sattributesprocessor
4+
5+
note: Add option to configure automatic resource attributes - with annotation prefix
6+
7+
issues: [37114]
8+
9+
subtext: |
10+
Implements [Specify resource attributes using Kubernetes annotations](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/non-normative/k8s-attributes.md#specify-resource-attributes-using-kubernetes-annotations).
11+
12+
If you are using the file log receiver, you can now create the same resource attributes as traces (via OTLP) received
13+
from an application instrumented with the OpenTelemetry Operator -
14+
simply by adding the `extract: { otel_annotations: true }` configuration to the `k8sattributesprocessor` processor.
15+
See the [documentation](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/processor/k8sattributesprocessor/README.md#config-example) for more details.

processor/k8sattributesprocessor/README.md

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,18 @@ extract:
251251
from: node
252252
```
253253
254+
## Configuring recommended resource attributes
255+
256+
The processor can be configured to set the
257+
[recommended resource attributes](https://opentelemetry.io/docs/specs/semconv/non-normative/k8s-attributes/):
258+
259+
- `otel_annotations` will translate `resource.opentelemetry.io/foo` to the `foo` resource attribute, etc.
260+
261+
```yaml
262+
extract:
263+
otel_annotations: true
264+
```
265+
254266
### Config example
255267

256268
```yaml
@@ -271,10 +283,11 @@ k8sattributes/2:
271283
- k8s.node.name
272284
- k8s.pod.start_time
273285
labels:
274-
# This label extraction rule takes the value 'app.kubernetes.io/component' label and maps it to the 'app.label.component' attribute which will be added to the associated resources
275-
- tag_name: app.label.component
276-
key: app.kubernetes.io/component
277-
from: pod
286+
# This label extraction rule takes the value 'app.kubernetes.io/component' label and maps it to the 'app.label.component' attribute which will be added to the associated resources
287+
- tag_name: app.label.component
288+
key: app.kubernetes.io/component
289+
from: pod
290+
otel_annotations: true
278291
pod_association:
279292
- sources:
280293
# This rule associates all resources containing the 'k8s.pod.ip' attribute with the matching pods. If this attribute is not present in the resource, this rule will not be able to find the matching pod.

processor/k8sattributesprocessor/config.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,10 @@ type ExtractConfig struct {
166166
// It is a list of FieldExtractConfig type. See FieldExtractConfig
167167
// documentation for more details.
168168
Labels []FieldExtractConfig `mapstructure:"labels"`
169+
170+
// OtelAnnotations extracts all pod annotations with the prefix "resource.opentelemetry.io" as resource attributes
171+
// E.g. "resource.opentelemetry.io/foo" becomes "foo"
172+
OtelAnnotations bool `mapstructure:"otel_annotations"`
169173
}
170174

171175
// FieldExtractConfig allows specifying an extraction rule to extract a resource attribute from pod (or namespace)

processor/k8sattributesprocessor/factory.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ func createProcessorOpts(cfg component.Config) []option {
192192
opts = append(opts, withExtractMetadata(oCfg.Extract.Metadata...))
193193
opts = append(opts, withExtractLabels(oCfg.Extract.Labels...))
194194
opts = append(opts, withExtractAnnotations(oCfg.Extract.Annotations...))
195+
opts = append(opts, withOtelAnnotations(oCfg.Extract.OtelAnnotations))
195196

196197
// filters
197198
opts = append(opts, withFilterNode(oCfg.Filter.Node, oCfg.Filter.NodeFromEnvVar))

processor/k8sattributesprocessor/options.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,20 @@ func withExtractMetadata(fields ...string) option {
198198
}
199199
}
200200

201+
func withOtelAnnotations(enabled bool) option {
202+
return func(p *kubernetesprocessor) error {
203+
if enabled {
204+
p.rules.Annotations = append(p.rules.Annotations, kube.FieldExtractionRule{
205+
Name: "$1",
206+
KeyRegex: regexp.MustCompile(`^resource\.opentelemetry\.io/(.+)$`),
207+
HasKeyRegexReference: true,
208+
From: kube.MetadataFromPod,
209+
})
210+
}
211+
return nil
212+
}
213+
}
214+
201215
// withExtractLabels allows specifying options to control extraction of pod labels.
202216
func withExtractLabels(labels ...FieldExtractConfig) option {
203217
return func(p *kubernetesprocessor) error {

processor/k8sattributesprocessor/options_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,3 +746,36 @@ func TestWithExcludes(t *testing.T) {
746746
})
747747
}
748748
}
749+
750+
func TestOtelAnnotations(t *testing.T) {
751+
tests := []struct {
752+
name string
753+
enabled bool
754+
wantAnnotations []kube.FieldExtractionRule
755+
}{
756+
{
757+
name: "no automatic rules",
758+
},
759+
{
760+
name: "default automatic rules",
761+
enabled: true,
762+
wantAnnotations: []kube.FieldExtractionRule{
763+
{
764+
Name: "$1",
765+
KeyRegex: regexp.MustCompile(`^resource\.opentelemetry\.io/(.+)$`),
766+
HasKeyRegexReference: true,
767+
From: kube.MetadataFromPod,
768+
},
769+
},
770+
},
771+
}
772+
for _, tt := range tests {
773+
t.Run(tt.name, func(t *testing.T) {
774+
p := kubernetesprocessor{}
775+
rules := withOtelAnnotations(tt.enabled)
776+
err := rules(&p)
777+
assert.NoError(t, err)
778+
assert.Equal(t, tt.wantAnnotations, p.rules.Annotations)
779+
})
780+
}
781+
}

0 commit comments

Comments
 (0)