Skip to content

Commit 9b4821a

Browse files
odubajDTAkhigbeEromo
authored andcommitted
[receiver/cloudfoundry]: move datapoint level attributes to resource level (open-telemetry#34905)
**Description:** <Describe what has changed.> Introduce a feature gate enable copying envelope tags to the metrics as resource attributes instead of datapoint attributes. **Link to tracking Issue:** open-telemetry#34824 --------- Signed-off-by: odubajDT <[email protected]>
1 parent da89566 commit 9b4821a

File tree

8 files changed

+1061
-95
lines changed

8 files changed

+1061
-95
lines changed

.chloggen/move-attributes.yaml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: breaking
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
7+
component: cloudfoundryreceiver
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Introduce a feature gate enable copying envelope tags to the metrics as resource attributes instead of datapoint attributes.
11+
12+
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
13+
issues: [34824]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext:
19+
20+
# If your change doesn't affect end users or the exported elements of any package,
21+
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
22+
# Optional: The change log or logs in which this entry should be included.
23+
# e.g. '[user]' or '[user, api]'
24+
# Include 'user' if the change is relevant to end users.
25+
# Include 'api' if there is a change to a library API.
26+
# Default: '[user]'
27+
change_logs: []

receiver/cloudfoundryreceiver/README.md

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,4 +132,35 @@ The receiver maps the envelope attribute tags to the following OpenTelemetry att
132132
* `instance_id` - numerical index of the origin. If origin is `rep` (`source_type` is `APP`) this is the application index. However, for other cases this is the instance index.
133133
* `process_id` - process ID (GUID)
134134
* `process_instance_id` - unique ID of a process instance, should be treated as an opaque string
135-
* `process_type` - process type. Each application has exactly one process of type `web`, but many have any number of other processes
135+
* `process_type` - process type. Each application has exactly one process of type `web`, but many have any number of other processes
136+
137+
## Feature Gate
138+
139+
### `cloudfoundry.resourceAttributes.allow`
140+
141+
#### Purpose
142+
143+
The `cloudfoundry.resourceAttributes.allow` [feature gate](https://github.com/open-telemetry/opentelemetry-collector/blob/main/featuregate/README.md#collector-feature-gates) allows the envelope tags being copied to the metrics as resource attributes instead of datapoint attributes (default `false`).
144+
Therefore all `org.cloudfoundry.*` datapoint attributes won't be present anymore on metrics datapoint level, but on resource level instead, since the attributes describe the resource and not the datapoints itself.
145+
146+
The `cloudfoundry.resourceAttributes.allow` feature gate is available since version `v0.117.0` and will be held at least for 2 versions (`v0.119.0`) until promoting to `beta` and another 2 vesions (`v0.121.0`) until promoting to `stable`.
147+
148+
Below you can see the list of attributes that are present the resource level instead of datapoint level (when `cloudfoundry.resourceAttributes.allow` feature gate is enabled):
149+
150+
```
151+
- org.cloudfoundry.index
152+
- org.cloudfoundry.ip
153+
- org.cloudfoundry.deployment
154+
- org.cloudfoundry.id
155+
- org.cloudfoundry.job
156+
- org.cloudfoundry.product
157+
- org.cloudfoundry.instance_group
158+
- org.cloudfoundry.instance_id
159+
- org.cloudfoundry.origin
160+
- org.cloudfoundry.system_domain
161+
- org.cloudfoundry.source_id
162+
- org.cloudfoundry.source_type
163+
- org.cloudfoundry.process_type
164+
- org.cloudfoundry.process_id
165+
- org.cloudfoundry.process_instance_id
166+
```

receiver/cloudfoundryreceiver/converter.go

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ package cloudfoundryreceiver // import "github.com/open-telemetry/opentelemetry-
55

66
import (
77
"fmt"
8+
"slices"
89
"time"
910

1011
"code.cloudfoundry.org/go-loggregator/rpc/loggregator_v2"
12+
"go.opentelemetry.io/collector/featuregate"
1113
"go.opentelemetry.io/collector/pdata/pcommon"
1214
"go.opentelemetry.io/collector/pdata/plog"
1315
"go.opentelemetry.io/collector/pdata/pmetric"
@@ -17,6 +19,31 @@ const (
1719
attributeNamePrefix = "org.cloudfoundry."
1820
)
1921

22+
var ResourceAttributesKeys = []string{
23+
"index",
24+
"ip",
25+
"deployment",
26+
"id",
27+
"job",
28+
"product",
29+
"instance_group",
30+
"instance_id",
31+
"origin",
32+
"system_domain",
33+
"source_id",
34+
"source_type",
35+
"process_type",
36+
"process_id",
37+
"process_instance_id",
38+
}
39+
40+
var allowResourceAttributes = featuregate.GlobalRegistry().MustRegister(
41+
"cloudfoundry.resourceAttributes.allow",
42+
featuregate.StageAlpha,
43+
featuregate.WithRegisterDescription("When enabled, envelope tags are copied to the metrics as resource attributes instead of datapoint attributes"),
44+
featuregate.WithRegisterFromVersion("v0.117.0"),
45+
)
46+
2047
func convertEnvelopeToMetrics(envelope *loggregator_v2.Envelope, metricSlice pmetric.MetricSlice, startTime time.Time) {
2148
namePrefix := envelope.Tags["origin"] + "."
2249

@@ -28,7 +55,12 @@ func convertEnvelopeToMetrics(envelope *loggregator_v2.Envelope, metricSlice pme
2855
dataPoint.SetDoubleValue(float64(message.Counter.GetTotal()))
2956
dataPoint.SetTimestamp(pcommon.Timestamp(envelope.GetTimestamp()))
3057
dataPoint.SetStartTimestamp(pcommon.NewTimestampFromTime(startTime))
31-
copyEnvelopeAttributes(dataPoint.Attributes(), envelope)
58+
if allowResourceAttributes.IsEnabled() {
59+
attrs := getEnvelopeDataAttributes(envelope)
60+
attrs.CopyTo(dataPoint.Attributes())
61+
} else {
62+
copyEnvelopeAttributes(dataPoint.Attributes(), envelope)
63+
}
3264
case *loggregator_v2.Envelope_Gauge:
3365
for name, value := range message.Gauge.GetMetrics() {
3466
metric := metricSlice.AppendEmpty()
@@ -37,7 +69,12 @@ func convertEnvelopeToMetrics(envelope *loggregator_v2.Envelope, metricSlice pme
3769
dataPoint.SetDoubleValue(value.Value)
3870
dataPoint.SetTimestamp(pcommon.Timestamp(envelope.GetTimestamp()))
3971
dataPoint.SetStartTimestamp(pcommon.NewTimestampFromTime(startTime))
40-
copyEnvelopeAttributes(dataPoint.Attributes(), envelope)
72+
if allowResourceAttributes.IsEnabled() {
73+
attrs := getEnvelopeDataAttributes(envelope)
74+
attrs.CopyTo(dataPoint.Attributes())
75+
} else {
76+
copyEnvelopeAttributes(dataPoint.Attributes(), envelope)
77+
}
4178
}
4279
}
4380
}
@@ -59,7 +96,12 @@ func convertEnvelopeToLogs(envelope *loggregator_v2.Envelope, logSlice plog.LogR
5996
default:
6097
return fmt.Errorf("unsupported envelope log type: %s", envelope.GetLog().GetType())
6198
}
62-
copyEnvelopeAttributes(log.Attributes(), envelope)
99+
if allowResourceAttributes.IsEnabled() {
100+
attrs := getEnvelopeDataAttributes(envelope)
101+
attrs.CopyTo(log.Attributes())
102+
} else {
103+
copyEnvelopeAttributes(log.Attributes(), envelope)
104+
}
63105
return nil
64106
}
65107

@@ -74,3 +116,29 @@ func copyEnvelopeAttributes(attributes pcommon.Map, envelope *loggregator_v2.Env
74116
attributes.PutStr(attributeNamePrefix+"instance_id", envelope.InstanceId)
75117
}
76118
}
119+
120+
func getEnvelopeDataAttributes(envelope *loggregator_v2.Envelope) pcommon.Map {
121+
attrs := pcommon.NewMap()
122+
for key, value := range envelope.Tags {
123+
if !slices.Contains(ResourceAttributesKeys, key) {
124+
attrs.PutStr(attributeNamePrefix+key, value)
125+
}
126+
}
127+
return attrs
128+
}
129+
130+
func getEnvelopeResourceAttributes(envelope *loggregator_v2.Envelope) pcommon.Map {
131+
attrs := pcommon.NewMap()
132+
for key, value := range envelope.Tags {
133+
if slices.Contains(ResourceAttributesKeys, key) {
134+
attrs.PutStr(attributeNamePrefix+key, value)
135+
}
136+
}
137+
if envelope.SourceId != "" {
138+
attrs.PutStr(attributeNamePrefix+"source_id", envelope.SourceId)
139+
}
140+
if envelope.InstanceId != "" {
141+
attrs.PutStr(attributeNamePrefix+"instance_id", envelope.InstanceId)
142+
}
143+
return attrs
144+
}

0 commit comments

Comments
 (0)