Skip to content

Commit

Permalink
Jolokia2 handles unordered mbean object name properties (influxdata#3504
Browse files Browse the repository at this point in the history
)
  • Loading branch information
dylanmei authored and danielnelson committed Nov 27, 2017
1 parent a9ada5f commit 27994ab
Show file tree
Hide file tree
Showing 3 changed files with 179 additions and 15 deletions.
19 changes: 4 additions & 15 deletions plugins/inputs/jolokia2/gatherer.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,28 +127,17 @@ 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
}

if len(metric.Paths) == 0 {
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 {
return true
}
for _, attribute := range response.RequestAttributes {
if metric.MatchAttributeAndPath(attribute, response.RequestPath) {
return true
}
}

Expand Down
108 changes: 108 additions & 0 deletions plugins/inputs/jolokia2/jolokia_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
67 changes: 67 additions & 0 deletions plugins/inputs/jolokia2/metric.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package jolokia2

import "strings"

// A MetricConfig represents a TOML form of
// a Metric with some optional fields.
type MetricConfig struct {
Expand All @@ -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 {
Expand Down Expand Up @@ -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:], ",")
}

0 comments on commit 27994ab

Please sign in to comment.