Skip to content

Commit 8b8e009

Browse files
committed
Adds append_dimensions to collectd, supporting custom metric dimensions
1 parent 1a4b2ce commit 8b8e009

3 files changed

Lines changed: 134 additions & 2 deletions

File tree

translator/config/schema.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,9 @@
286286
"type": "string",
287287
"minLength": 1,
288288
"maxLength": 4096
289+
},
290+
"append_dimensions": {
291+
"$ref": "#/definitions/generalAppendDimensionsDefinition"
289292
}
290293
},
291294
"additionalProperties": false

translator/translate/metrics/metrics_collect/collectd/collectd.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package collected
66
import (
77
"github.com/aws/amazon-cloudwatch-agent/translator"
88
parent "github.com/aws/amazon-cloudwatch-agent/translator/translate/metrics/metrics_collect"
9+
"github.com/aws/amazon-cloudwatch-agent/translator/translate/metrics/util"
910
)
1011

1112
//
@@ -49,8 +50,7 @@ func (obj *CollectD) ApplyRule(input interface{}) (returnKey string, returnVal i
4950
returnKey = ""
5051
returnVal = ""
5152
} else {
52-
//If exists, process it
53-
//Check if there are some config entry with rules applied
53+
util.ProcessAppendDimensions(m[SectionKey].(map[string]interface{}), SectionKey, result)
5454
result = translator.ProcessRuleToMergeAndApply(m[SectionKey], ChildRule, result)
5555
resArray = append(resArray, result)
5656
returnKey = SectionMappedKey

translator/translate/metrics/metrics_collect/collectd/collectd_test.go

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import (
88
"testing"
99

1010
"github.com/stretchr/testify/assert"
11+
12+
"github.com/aws/amazon-cloudwatch-agent/translator/translate/util"
1113
)
1214

1315
func TestCollectD_HappyCase(t *testing.T) {
@@ -62,3 +64,130 @@ func TestCollectD_MinimumConfig(t *testing.T) {
6264

6365
assert.Equal(t, expect, actual)
6466
}
67+
68+
func TestCollectD_WithAppendDimensions(t *testing.T) {
69+
// Mock EC2 metadata to avoid 6s IMDS timeout
70+
originalProvider := util.Ec2MetadataInfoProvider
71+
util.Ec2MetadataInfoProvider = func() *util.Metadata {
72+
return &util.Metadata{InstanceID: "i-1234567890abcdef0", InstanceType: "t3.medium"}
73+
}
74+
defer func() { util.Ec2MetadataInfoProvider = originalProvider }()
75+
76+
obj := new(CollectD)
77+
var input interface{}
78+
err := json.Unmarshal([]byte(`{"collectd": {
79+
"service_address": "udp://127.0.0.1:123",
80+
"append_dimensions": {
81+
"InstanceId": "${aws:InstanceId}",
82+
"CustomDimension": "CustomValue"
83+
}
84+
}}`), &input)
85+
assert.NoError(t, err)
86+
87+
_, actual := obj.ApplyRule(input)
88+
89+
actualMap := actual.([]interface{})[0].(map[string]interface{})
90+
tags := actualMap["tags"].(map[string]interface{})
91+
92+
assert.Equal(t, "60s", tags["aws:AggregationInterval"])
93+
assert.Equal(t, "CustomValue", tags["CustomDimension"])
94+
assert.Equal(t, "i-1234567890abcdef0", tags["InstanceId"])
95+
}
96+
97+
func TestCollectD_WithAppendDimensionsAndAggregationInterval(t *testing.T) {
98+
obj := new(CollectD)
99+
var input interface{}
100+
err := json.Unmarshal([]byte(`{"collectd": {
101+
"metrics_aggregation_interval": 30,
102+
"append_dimensions": {
103+
"Environment": "Production",
104+
"Team": "Infrastructure"
105+
}
106+
}}`), &input)
107+
assert.NoError(t, err)
108+
109+
_, actual := obj.ApplyRule(input)
110+
111+
expect := []interface{}{
112+
map[string]interface{}{
113+
"data_format": "collectd",
114+
"service_address": "udp://127.0.0.1:25826",
115+
"name_prefix": "collectd_",
116+
"collectd_auth_file": "/etc/collectd/auth_file",
117+
"collectd_security_level": "encrypt",
118+
"collectd_typesdb": []interface{}{"/usr/share/collectd/types.db"},
119+
"tags": map[string]interface{}{
120+
"aws:AggregationInterval": "30s",
121+
"Environment": "Production",
122+
"Team": "Infrastructure",
123+
},
124+
},
125+
}
126+
127+
assert.Equal(t, expect, actual)
128+
}
129+
130+
func TestCollectD_WithFullConfigAndAppendDimensions(t *testing.T) {
131+
// Mock EC2 metadata to avoid IMDS timeout
132+
originalProvider := util.Ec2MetadataInfoProvider
133+
util.Ec2MetadataInfoProvider = func() *util.Metadata {
134+
return &util.Metadata{InstanceID: "i-1234567890abcdef0", InstanceType: "t3.large", ImageID: "ami-12345678"}
135+
}
136+
defer func() { util.Ec2MetadataInfoProvider = originalProvider }()
137+
138+
obj := new(CollectD)
139+
var input interface{}
140+
err := json.Unmarshal([]byte(`{"collectd": {
141+
"service_address": "udp://127.0.0.1:123",
142+
"name_prefix": "collectd_prefix_",
143+
"collectd_auth_file": "/etc/collectd/_auth_file",
144+
"collectd_security_level": "none",
145+
"collectd_typesdb": ["/usr/share/collectd/types.db", "/custom_location/types.db"],
146+
"metrics_aggregation_interval": 30,
147+
"append_dimensions": {
148+
"InstanceId": "${aws:InstanceId}",
149+
"InstanceType": "${aws:InstanceType}",
150+
"ImageId": "${aws:ImageId}",
151+
"CustomTag": "MyValue"
152+
}
153+
}}`), &input)
154+
assert.NoError(t, err)
155+
156+
_, actual := obj.ApplyRule(input)
157+
158+
actualMap := actual.([]interface{})[0].(map[string]interface{})
159+
tags := actualMap["tags"].(map[string]interface{})
160+
161+
assert.Equal(t, "30s", tags["aws:AggregationInterval"])
162+
assert.Equal(t, "MyValue", tags["CustomTag"])
163+
assert.Equal(t, "i-1234567890abcdef0", tags["InstanceId"])
164+
assert.Equal(t, "t3.large", tags["InstanceType"])
165+
assert.Equal(t, "ami-12345678", tags["ImageId"])
166+
}
167+
168+
func TestCollectD_EmptyAppendDimensions(t *testing.T) {
169+
obj := new(CollectD)
170+
var input interface{}
171+
err := json.Unmarshal([]byte(`{"collectd": {
172+
"append_dimensions": {}
173+
}}`), &input)
174+
assert.NoError(t, err)
175+
176+
_, actual := obj.ApplyRule(input)
177+
178+
expect := []interface{}{
179+
map[string]interface{}{
180+
"data_format": "collectd",
181+
"service_address": "udp://127.0.0.1:25826",
182+
"name_prefix": "collectd_",
183+
"collectd_auth_file": "/etc/collectd/auth_file",
184+
"collectd_security_level": "encrypt",
185+
"collectd_typesdb": []interface{}{"/usr/share/collectd/types.db"},
186+
"tags": map[string]interface{}{
187+
"aws:AggregationInterval": "60s",
188+
},
189+
},
190+
}
191+
192+
assert.Equal(t, expect, actual)
193+
}

0 commit comments

Comments
 (0)