Jolokia2 handles unordered mbean object name properties (#3504)
This commit is contained in:
parent
fb1edd5da3
commit
d9e2599de7
|
@ -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
|
||||
// returned by a Jolokia agent.
|
||||
func metricMatchesResponse(metric Metric, response ReadResponse) bool {
|
||||
|
||||
if metric.Mbean != response.RequestMbean {
|
||||
if !metric.MatchObjectName(response.RequestMbean) {
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -136,21 +135,11 @@ func metricMatchesResponse(metric Metric, response ReadResponse) bool {
|
|||
return len(response.RequestAttributes) == 0
|
||||
}
|
||||
|
||||
for _, fullPath := range metric.Paths {
|
||||
segments := strings.SplitN(fullPath, "/", 2)
|
||||
attribute := segments[0]
|
||||
|
||||
var path string
|
||||
if len(segments) == 2 {
|
||||
path = segments[1]
|
||||
}
|
||||
|
||||
for _, rattr := range response.RequestAttributes {
|
||||
if attribute == rattr && path == response.RequestPath {
|
||||
for _, attribute := range response.RequestAttributes {
|
||||
if metric.MatchAttributeAndPath(attribute, response.RequestPath) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
config := `
|
||||
[jolokia2_agent]
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package jolokia2
|
||||
|
||||
import "strings"
|
||||
|
||||
// A MetricConfig represents a TOML form of
|
||||
// a Metric with some optional fields.
|
||||
type MetricConfig struct {
|
||||
|
@ -25,6 +27,9 @@ type Metric struct {
|
|||
FieldSeparator string
|
||||
TagPrefix string
|
||||
TagKeys []string
|
||||
|
||||
mbeanDomain string
|
||||
mbeanProperties []string
|
||||
}
|
||||
|
||||
func NewMetric(config MetricConfig, defaultFieldPrefix, defaultFieldSeparator, defaultTagPrefix string) Metric {
|
||||
|
@ -57,5 +62,67 @@ func NewMetric(config MetricConfig, defaultFieldPrefix, defaultFieldSeparator, d
|
|||
metric.TagPrefix = *config.TagPrefix
|
||||
}
|
||||
|
||||
mbeanDomain, mbeanProperties := parseMbeanObjectName(config.Mbean)
|
||||
metric.mbeanDomain = mbeanDomain
|
||||
metric.mbeanProperties = mbeanProperties
|
||||
|
||||
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:], ",")
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue