From 27994abcb5a5bfb34204273d18f695575c6f9b63 Mon Sep 17 00:00:00 2001 From: Dylan Meissner Date: Mon, 27 Nov 2017 13:43:19 -0800 Subject: [PATCH] Jolokia2 handles unordered mbean object name properties (#3504) --- plugins/inputs/jolokia2/gatherer.go | 19 +---- plugins/inputs/jolokia2/jolokia_test.go | 108 ++++++++++++++++++++++++ plugins/inputs/jolokia2/metric.go | 67 +++++++++++++++ 3 files changed, 179 insertions(+), 15 deletions(-) diff --git a/plugins/inputs/jolokia2/gatherer.go b/plugins/inputs/jolokia2/gatherer.go index 3cc2e1217..5005e8225 100644 --- a/plugins/inputs/jolokia2/gatherer.go +++ b/plugins/inputs/jolokia2/gatherer.go @@ -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,19 +135,9 @@ 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 { - return true - } + for _, attribute := range response.RequestAttributes { + if metric.MatchAttributeAndPath(attribute, response.RequestPath) { + return true } } diff --git a/plugins/inputs/jolokia2/jolokia_test.go b/plugins/inputs/jolokia2/jolokia_test.go index dfdc4bef9..f94606ae6 100644 --- a/plugins/inputs/jolokia2/jolokia_test.go +++ b/plugins/inputs/jolokia2/jolokia_test.go @@ -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] diff --git a/plugins/inputs/jolokia2/metric.go b/plugins/inputs/jolokia2/metric.go index 03baea124..0f438b3c0 100644 --- a/plugins/inputs/jolokia2/metric.go +++ b/plugins/inputs/jolokia2/metric.go @@ -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:], ",") +}