Jolokia2 handles unordered mbean object name properties (#3504)

This commit is contained in:
Dylan Meissner 2017-11-27 13:43:19 -08:00 committed by Daniel Nelson
parent fb1edd5da3
commit d9e2599de7
3 changed files with 179 additions and 15 deletions

View File

@ -127,8 +127,7 @@ func mergeTags(metricTags, outerTags map[string]string) map[string]string {
// of a Metric match the corresponding elements in a ReadResponse object // of a Metric match the corresponding elements in a ReadResponse object
// returned by a Jolokia agent. // returned by a Jolokia agent.
func metricMatchesResponse(metric Metric, response ReadResponse) bool { func metricMatchesResponse(metric Metric, response ReadResponse) bool {
if !metric.MatchObjectName(response.RequestMbean) {
if metric.Mbean != response.RequestMbean {
return false return false
} }
@ -136,19 +135,9 @@ func metricMatchesResponse(metric Metric, response ReadResponse) bool {
return len(response.RequestAttributes) == 0 return len(response.RequestAttributes) == 0
} }
for _, fullPath := range metric.Paths { for _, attribute := range response.RequestAttributes {
segments := strings.SplitN(fullPath, "/", 2) if metric.MatchAttributeAndPath(attribute, response.RequestPath) {
attribute := segments[0] return true
var path string
if len(segments) == 2 {
path = segments[1]
}
for _, rattr := range response.RequestAttributes {
if attribute == rattr && path == response.RequestPath {
return true
}
} }
} }

View File

@ -481,6 +481,114 @@ func TestJolokia2_FieldRenaming(t *testing.T) {
}) })
} }
func TestJolokia2_MetricMbeanMatching(t *testing.T) {
config := `
[jolokia2_agent]
urls = ["%s"]
[[jolokia2_agent.metric]]
name = "mbean_name_and_object_keys"
mbean = "test1:foo=bar,fizz=buzz"
[[jolokia2_agent.metric]]
name = "mbean_name_and_unordered_object_keys"
mbean = "test2:fizz=buzz,foo=bar"
[[jolokia2_agent.metric]]
name = "mbean_name_and_attributes"
mbean = "test3"
paths = ["foo", "bar"]
[[jolokia2_agent.metric]]
name = "mbean_name_and_attribute_with_paths"
mbean = "test4"
paths = ["flavor/chocolate", "flavor/strawberry"]
`
response := `[{
"request": {
"mbean": "test1:foo=bar,fizz=buzz",
"type": "read"
},
"value": 123,
"status": 200
}, {
"request": {
"mbean": "test2:foo=bar,fizz=buzz",
"type": "read"
},
"value": 123,
"status": 200
}, {
"request": {
"mbean": "test3",
"attribute": "foo",
"type": "read"
},
"value": 123,
"status": 200
}, {
"request": {
"mbean": "test3",
"attribute": "bar",
"type": "read"
},
"value": 456,
"status": 200
}, {
"request": {
"mbean": "test4",
"attribute": "flavor",
"path": "chocolate",
"type": "read"
},
"value": 123,
"status": 200
}, {
"request": {
"mbean": "test4",
"attribute": "flavor",
"path": "strawberry",
"type": "read"
},
"value": 456,
"status": 200
}]`
server := setupServer(http.StatusOK, response)
defer server.Close()
plugin := setupPlugin(t, fmt.Sprintf(config, server.URL))
var acc testutil.Accumulator
assert.NoError(t, plugin.Gather(&acc))
acc.AssertContainsTaggedFields(t, "mbean_name_and_object_keys", map[string]interface{}{
"value": 123.0,
}, map[string]string{
"jolokia_agent_url": server.URL,
})
acc.AssertContainsTaggedFields(t, "mbean_name_and_unordered_object_keys", map[string]interface{}{
"value": 123.0,
}, map[string]string{
"jolokia_agent_url": server.URL,
})
acc.AssertContainsTaggedFields(t, "mbean_name_and_attributes", map[string]interface{}{
"foo": 123.0,
"bar": 456.0,
}, map[string]string{
"jolokia_agent_url": server.URL,
})
acc.AssertContainsTaggedFields(t, "mbean_name_and_attribute_with_paths", map[string]interface{}{
"flavor.chocolate": 123.0,
"flavor.strawberry": 456.0,
}, map[string]string{
"jolokia_agent_url": server.URL,
})
}
func TestJolokia2_MetricCompaction(t *testing.T) { func TestJolokia2_MetricCompaction(t *testing.T) {
config := ` config := `
[jolokia2_agent] [jolokia2_agent]

View File

@ -1,5 +1,7 @@
package jolokia2 package jolokia2
import "strings"
// A MetricConfig represents a TOML form of // A MetricConfig represents a TOML form of
// a Metric with some optional fields. // a Metric with some optional fields.
type MetricConfig struct { type MetricConfig struct {
@ -25,6 +27,9 @@ type Metric struct {
FieldSeparator string FieldSeparator string
TagPrefix string TagPrefix string
TagKeys []string TagKeys []string
mbeanDomain string
mbeanProperties []string
} }
func NewMetric(config MetricConfig, defaultFieldPrefix, defaultFieldSeparator, defaultTagPrefix string) Metric { func NewMetric(config MetricConfig, defaultFieldPrefix, defaultFieldSeparator, defaultTagPrefix string) Metric {
@ -57,5 +62,67 @@ func NewMetric(config MetricConfig, defaultFieldPrefix, defaultFieldSeparator, d
metric.TagPrefix = *config.TagPrefix metric.TagPrefix = *config.TagPrefix
} }
mbeanDomain, mbeanProperties := parseMbeanObjectName(config.Mbean)
metric.mbeanDomain = mbeanDomain
metric.mbeanProperties = mbeanProperties
return metric return metric
} }
func (m Metric) MatchObjectName(name string) bool {
if name == m.Mbean {
return true
}
mbeanDomain, mbeanProperties := parseMbeanObjectName(name)
if mbeanDomain != m.mbeanDomain {
return false
}
if len(mbeanProperties) != len(m.mbeanProperties) {
return false
}
NEXT_PROPERTY:
for _, mbeanProperty := range m.mbeanProperties {
for i := range mbeanProperties {
if mbeanProperties[i] == mbeanProperty {
continue NEXT_PROPERTY
}
}
return false
}
return true
}
func (m Metric) MatchAttributeAndPath(attribute, innerPath string) bool {
path := attribute
if innerPath != "" {
path = path + "/" + innerPath
}
for i := range m.Paths {
if path == m.Paths[i] {
return true
}
}
return false
}
func parseMbeanObjectName(name string) (string, []string) {
index := strings.Index(name, ":")
if index == -1 {
return name, []string{}
}
domain := name[:index]
if index+1 > len(name) {
return domain, []string{}
}
return domain, strings.Split(name[index+1:], ",")
}