Skip to content

Commit a5e28d6

Browse files
authored
[connector/count] Support all attribute types (#43768)
#### Description The count connector currently implements its own parsing and copying logic for attributes. This means that attributes with non-supported types (e.g. booleans) are converted to the empty string. We replace this custom logic with a more standard `CopyTo` and `FromRaw`. #### Testing All existing tests pass unchanged. There is a new test that asserts common attribute types (string, int, double, bool) can be copied.
1 parent 07e3552 commit a5e28d6

File tree

6 files changed

+139
-25
lines changed

6 files changed

+139
-25
lines changed
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: enhancement
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. receiver/filelog)
7+
component: connector/count
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Support all attribute types in the count connector
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: [43768]
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: [user]

connector/countconnector/config.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
"go.opentelemetry.io/collector/component"
1111
"go.opentelemetry.io/collector/confmap"
12+
"go.opentelemetry.io/collector/pdata/pcommon"
1213
"go.uber.org/zap"
1314

1415
"github.com/open-telemetry/opentelemetry-collector-contrib/internal/filter/filterottl"
@@ -134,10 +135,16 @@ func (c *Config) Validate() error {
134135
}
135136

136137
func (i *MetricInfo) validateAttributes() error {
138+
tmp := pcommon.NewValueEmpty()
139+
137140
for _, attr := range i.Attributes {
138141
if attr.Key == "" {
139142
return errors.New("attribute key missing")
140143
}
144+
145+
if err := tmp.FromRaw(attr.DefaultValue); err != nil {
146+
return fmt.Errorf("invalid default value specified for attribute %s", attr.Key)
147+
}
141148
}
142149
return nil
143150
}

connector/countconnector/config_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,10 @@ func TestLoadConfig(t *testing.T) {
422422
Key: "request_success",
423423
DefaultValue: float64(0.85),
424424
},
425+
{
426+
Key: "cache_hit",
427+
DefaultValue: bool(true),
428+
},
425429
},
426430
},
427431
},

connector/countconnector/counter.go

Lines changed: 5 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -45,22 +45,9 @@ func (c *counter[K]) update(ctx context.Context, attrs, scopeAttrs, resourceAttr
4545
Name: attr.Key,
4646
Value: func() *pcommon.Value {
4747
if attr.DefaultValue != nil {
48-
switch v := attr.DefaultValue.(type) {
49-
case string:
50-
if v != "" {
51-
strV := pcommon.NewValueStr(v)
52-
return &strV
53-
}
54-
case int:
55-
if v != 0 {
56-
intV := pcommon.NewValueInt(int64(v))
57-
return &intV
58-
}
59-
case float64:
60-
if v != 0 {
61-
floatV := pcommon.NewValueDouble(v)
62-
return &floatV
63-
}
48+
val := pcommon.NewValueEmpty()
49+
if err := val.FromRaw(attr.DefaultValue); err == nil {
50+
return &val
6451
}
6552
}
6653

@@ -69,14 +56,8 @@ func (c *counter[K]) update(ctx context.Context, attrs, scopeAttrs, resourceAttr
6956
}
7057
value, ok := utilattri.GetDimensionValue(dimension, attrs, scopeAttrs, resourceAttrs)
7158
if ok {
72-
switch value.Type() {
73-
case pcommon.ValueTypeInt:
74-
countAttrs.PutInt(attr.Key, value.Int())
75-
case pcommon.ValueTypeDouble:
76-
countAttrs.PutDouble(attr.Key, value.Double())
77-
default:
78-
countAttrs.PutStr(attr.Key, value.Str())
79-
}
59+
countValue, _ := countAttrs.GetOrPutEmpty(attr.Key)
60+
value.CopyTo(countValue)
8061
}
8162
}
8263

connector/countconnector/counter_test.go

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import (
1313
"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil"
1414
)
1515

16-
func Test_update_attributes(t *testing.T) {
16+
func Test_update_attribute_inheritance(t *testing.T) {
1717
spanMetricDefs := make(map[string]metricDef[ottlspan.TransformContext])
1818
spanMetricDefs[defaultMetricNameSpans] = metricDef[ottlspan.TransformContext]{
1919
desc: defaultMetricDescSpans,
@@ -141,3 +141,96 @@ func Test_update_attributes(t *testing.T) {
141141
})
142142
}
143143
}
144+
145+
func Test_update_attributes_types(t *testing.T) {
146+
tests := []struct {
147+
name string
148+
config []AttributeConfig
149+
inputAttr pcommon.Map
150+
expectedAttr pcommon.Map
151+
}{
152+
{
153+
name: "attributes from DefaultValue",
154+
config: []AttributeConfig{
155+
{
156+
Key: "string",
157+
DefaultValue: "default-string",
158+
},
159+
{
160+
Key: "int",
161+
DefaultValue: 123,
162+
},
163+
{
164+
Key: "double",
165+
DefaultValue: 321.0,
166+
},
167+
{
168+
Key: "bool",
169+
DefaultValue: true,
170+
},
171+
},
172+
inputAttr: pcommon.NewMap(),
173+
expectedAttr: func() pcommon.Map {
174+
res := pcommon.NewMap()
175+
res.PutStr("string", "default-string")
176+
res.PutInt("int", 123)
177+
res.PutDouble("double", 321.0)
178+
res.PutBool("bool", true)
179+
return res
180+
}(),
181+
},
182+
{
183+
name: "attributes from resource",
184+
config: []AttributeConfig{
185+
{
186+
Key: "string",
187+
},
188+
{
189+
Key: "int",
190+
},
191+
{
192+
Key: "double",
193+
},
194+
{
195+
Key: "bool",
196+
},
197+
},
198+
inputAttr: func() pcommon.Map {
199+
res := pcommon.NewMap()
200+
res.PutStr("string", "default-string")
201+
res.PutInt("int", 123)
202+
res.PutDouble("double", 321.0)
203+
res.PutBool("bool", true)
204+
return res
205+
}(),
206+
expectedAttr: func() pcommon.Map {
207+
res := pcommon.NewMap()
208+
res.PutStr("string", "default-string")
209+
res.PutInt("int", 123)
210+
res.PutDouble("double", 321.0)
211+
res.PutBool("bool", true)
212+
return res
213+
}(),
214+
},
215+
}
216+
217+
for _, tt := range tests {
218+
spanMetricDefs := make(map[string]metricDef[ottlspan.TransformContext])
219+
spanMetricDefs[defaultMetricNameSpans] = metricDef[ottlspan.TransformContext]{
220+
desc: defaultMetricDescSpans,
221+
attrs: tt.config,
222+
}
223+
224+
t.Run(tt.name, func(t *testing.T) {
225+
spansCounter := newCounter(spanMetricDefs)
226+
err := spansCounter.update(t.Context(), pcommon.NewMap(), pcommon.NewMap(), tt.inputAttr, ottlspan.TransformContext{})
227+
require.NoError(t, err)
228+
require.NotNil(t, spansCounter)
229+
m := spansCounter.counts[defaultMetricNameSpans]
230+
expectKey := pdatautil.MapHash(tt.expectedAttr)
231+
attrCount, ok := m[expectKey]
232+
require.True(t, ok)
233+
require.NotNil(t, attrCount)
234+
})
235+
}
236+
}

connector/countconnector/testdata/config.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,3 +211,5 @@
211211
default_value: 200
212212
- key: request_success
213213
default_value: 0.85
214+
- key: cache_hit
215+
default_value: true

0 commit comments

Comments
 (0)