Skip to content

Commit 9351351

Browse files
lisguojefchien
andauthored
[Bugfix] Fix merging logic to append multiple jvm/otlp configurations (#1870)
Co-authored-by: Jeffrey Chien <chienjef@amazon.com>
1 parent f33102f commit 9351351

2 files changed

Lines changed: 409 additions & 4 deletions

File tree

translator/jsonconfig/mergeJsonUtil/util.go

Lines changed: 80 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ import (
1313

1414
var MergeRuleMap = map[string]mergeJsonRule.MergeRule{}
1515

16+
var ArrayOrObjectKeys = map[string]bool{
17+
"jmx": true,
18+
"otlp": true,
19+
}
20+
1621
func MergeMap(source map[string]interface{}, result map[string]interface{}, sectionKey string,
1722
mergeRuleMap map[string]mergeJsonRule.MergeRule, path string) {
1823
subMapSource, exists := GetSubMap(source, sectionKey)
@@ -32,16 +37,24 @@ func MergeMap(source map[string]interface{}, result map[string]interface{}, sect
3237

3338
func mergeMap(sourceMap map[string]interface{}, resultMap map[string]interface{}, mergeRuleMap map[string]mergeJsonRule.MergeRule, path string) {
3439
for key, value := range sourceMap {
35-
if rule, ok := mergeRuleMap[key]; ok {
40+
rule, hasRule := mergeRuleMap[key]
41+
existingValue, hasExisting := resultMap[key]
42+
43+
switch {
44+
case hasRule:
3645
rule.Merge(sourceMap, resultMap)
37-
} else if existingValue, ok := resultMap[key]; !ok {
46+
case ArrayOrObjectKeys[key]:
47+
// Special handling for configurations that can be array or object according to schema
48+
mergeArrayOrObjectConfiguration(sourceMap, resultMap, key, path)
49+
case !hasExisting:
3850
// only one defines the value
3951
resultMap[key] = value
40-
} else if !reflect.DeepEqual(existingValue, value) {
52+
case !reflect.DeepEqual(existingValue, value):
4153
// fail if different values are defined
4254
translator.AddErrorMessages(fmt.Sprintf("%s%s", path, key), fmt.Sprintf("Different values are specified for %v", key))
55+
default:
56+
// the same value is defined by multiple sources - no action needed
4357
}
44-
// the same value is defined by multiple sources
4558
}
4659
}
4760

@@ -103,3 +116,66 @@ func GetSubList(sourceMap map[string]interface{}, subKey string) []interface{} {
103116
}
104117
return resultList
105118
}
119+
120+
func mergeArrayOrObjectConfiguration(sourceMap map[string]interface{}, resultMap map[string]interface{}, key string, path string) {
121+
sourceValue, sourceExists := sourceMap[key]
122+
if !sourceExists {
123+
return
124+
}
125+
126+
resultValue, resultExists := resultMap[key]
127+
if !resultExists {
128+
resultMap[key] = sourceValue
129+
return
130+
}
131+
132+
switch sourceValue.(type) {
133+
case []interface{}:
134+
mergeArrayConfiguration(sourceValue, resultValue, resultMap, key, path)
135+
case map[string]interface{}:
136+
mergeObjectConfiguration(sourceValue, resultValue, resultMap, key, path)
137+
default:
138+
translator.AddErrorMessages(fmt.Sprintf("%s%s", path, key),
139+
fmt.Sprintf("Unsupported configuration source type: %T", sourceValue))
140+
}
141+
}
142+
143+
func mergeArrayConfiguration(sourceValue, resultValue interface{}, resultMap map[string]interface{}, key string, path string) {
144+
sourceList := sourceValue.([]interface{})
145+
146+
switch rv := resultValue.(type) {
147+
case []interface{}:
148+
// Array + Array: use existing mergeList function
149+
resultMap[key] = mergeList(sourceList, rv)
150+
case map[string]interface{}:
151+
// Array + Object: convert object to array and merge
152+
resultMap[key] = mergeList(sourceList, []interface{}{rv})
153+
default:
154+
translator.AddErrorMessages(fmt.Sprintf("%s%s", path, key),
155+
fmt.Sprintf("Unsupported configuration type: %T", resultValue))
156+
}
157+
}
158+
159+
func mergeObjectConfiguration(sourceValue, resultValue interface{}, resultMap map[string]interface{}, key string, path string) {
160+
sourceObj := sourceValue.(map[string]interface{})
161+
162+
switch rv := resultValue.(type) {
163+
case []interface{}:
164+
// Object + Array: use existing mergeList function with single-item array
165+
resultMap[key] = mergeList([]interface{}{sourceObj}, rv)
166+
case map[string]interface{}:
167+
// Object + Object: merge objects
168+
resultMap[key] = mergeObjects(rv, sourceObj)
169+
default:
170+
translator.AddErrorMessages(fmt.Sprintf("%s%s", path, key),
171+
fmt.Sprintf("Unsupported configuration type: %T", resultValue))
172+
}
173+
}
174+
175+
// mergeObjects merges two objects, converting to array if they differ
176+
func mergeObjects(result, source map[string]interface{}) interface{} {
177+
if reflect.DeepEqual(result, source) {
178+
return result
179+
}
180+
return []interface{}{result, source}
181+
}

0 commit comments

Comments
 (0)