Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support in jolokia get response for single value #11075

Merged
merged 5 commits into from
Mar 6, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.next.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ https://github.com/elastic/beats/compare/v7.0.0-alpha2...master[Check the HEAD d
- Migrate docker autodiscover to ECS. {issue}10757[10757] {pull}10862[10862]
- Fix issue in kubernetes module preventing usage percentages to be properly calculated. {pull}10946[10946]
- Fix for not reusable http client leading to connection leaks in Jolokia module {pull}11014[11014]
- Fix parsing error using GET in Jolokia module. {pull}11075[11075] {issue}11071[11071]

*Packetbeat*

Expand Down
35 changes: 18 additions & 17 deletions metricbeat/module/jolokia/jmx/_meta/data.json
Original file line number Diff line number Diff line change
@@ -1,33 +1,34 @@
{
"@timestamp": "2017-10-12T08:05:34.853Z",
"beat": {
"hostname": "host.example.com",
"name": "host.example.com"
"event": {
"dataset": "jolokia.testnamespace",
"duration": 115000,
"module": "jolokia"
},
"jolokia": {
"testnamespace": {
"memory": {
"heap_usage": {
"committed": 112721920,
"init": 64673792,
"max": 921174016,
"used": 81023984
"committed": 514850816,
"init": 536870912,
"max": 7635730432,
"used": 133286280
},
"non_heap_usage": {
"committed": 24576000,
"init": 24576000,
"max": 224395264,
"used": 17684240
"committed": 32702464,
"init": 2555904,
"max": -1,
"used": 31349800
}
},
"uptime": 580487
"uptime": 56281839
}
},
"metricset": {
"host": "jolokia:8778",
"module": "jolokia",
"name": "jmx",
"namespace": "testnamespace",
"rtt": 115
"name": "jmx"
},
"service": {
"address": "127.0.0.1:8080",
"type": "jolokia"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"request":{
"mbean":"java.lang:type=Runtime",
"attribute":"Uptime",
"type":"read"
},
"value":88622,
"timestamp":1551739190,
"status":200
}
94 changes: 67 additions & 27 deletions metricbeat/module/jolokia/jmx/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,10 @@ const (

type Entry struct {
Request struct {
Mbean string `json:"mbean"`
Mbean string `json:"mbean"`
Attribute interface{} `json:"attribute"`
jsoriano marked this conversation as resolved.
Show resolved Hide resolved
}
Value map[string]interface{}
Value interface{}
}

// Map responseBody to common.MapStr
Expand Down Expand Up @@ -90,7 +91,22 @@ type Entry struct {
// "timestamp": 1519409583
// "status": 200,
// }
// }
// ]
//
// A response with single value
//
// [
// {
// "request": {
// "mbean":"java.lang:type=Runtime",
// "attribute":"Uptime",
// "type":"read"
// },
// "value":88622,
// "timestamp":1551739190,
// "status":200
// }
// ]
jsoriano marked this conversation as resolved.
Show resolved Hide resolved
type eventKey struct {
mbean, event string
}
Expand All @@ -103,32 +119,24 @@ func eventMapping(entries []Entry, mapping AttributeMapping) ([]common.MapStr, e
var errs multierror.Errors

for _, v := range entries {
hasWildcard := strings.Contains(v.Request.Mbean, "*")
for attribute, value := range v.Value {
if !hasWildcard {
err := parseResponseEntry(v.Request.Mbean, v.Request.Mbean, attribute, value, mbeanEvents, mapping)
if err != nil {
errs = append(errs, err)
}
continue
}

// If there was a wildcard, we are going to have an additional
// nesting level in response values, and attribute here is going
// to be actually the matching mbean name
values, ok := value.(map[string]interface{})
if !ok {
errs = append(errs, errors.Errorf("expected map of values for %s", v.Request.Mbean))
continue
}
if v.Value == nil || v.Request.Attribute == nil {
continue
}

responseMbean := attribute
for attribute, value := range values {
err := parseResponseEntry(v.Request.Mbean, responseMbean, attribute, value, mbeanEvents, mapping)
switch attribute := v.Request.Attribute.(type) {
case string:
switch entryValues := v.Value.(type) {
case float64:
err := parseResponseEntry(v.Request.Mbean, v.Request.Mbean, attribute, entryValues, mbeanEvents, mapping)
if err != nil {
errs = append(errs, err)
}
case map[string]interface{}:
constructEvents(entryValues, v, mbeanEvents, mapping, errs)
}
case []interface{}:
entryValues := v.Value.(map[string]interface{})
constructEvents(entryValues, v, mbeanEvents, mapping, errs)
kaiyan-sheng marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand All @@ -140,6 +148,36 @@ func eventMapping(entries []Entry, mapping AttributeMapping) ([]common.MapStr, e
return events, errs.Err()
}

func constructEvents(entryValues map[string]interface{}, v Entry, mbeanEvents map[eventKey]common.MapStr, mapping AttributeMapping, errs multierror.Errors) {
kaiyan-sheng marked this conversation as resolved.
Show resolved Hide resolved
hasWildcard := strings.Contains(v.Request.Mbean, "*")
for attribute, value := range entryValues {
if !hasWildcard {
err := parseResponseEntry(v.Request.Mbean, v.Request.Mbean, attribute, value, mbeanEvents, mapping)
if err != nil {
errs = append(errs, err)
}
continue
}

// If there was a wildcard, we are going to have an additional
// nesting level in response values, and attribute here is going
// to be actually the matching mbean name
values, ok := value.(map[string]interface{})
if !ok {
errs = append(errs, errors.Errorf("expected map of values for %s", v.Request.Mbean))
continue
}

responseMbean := attribute
for attribute, value := range values {
err := parseResponseEntry(v.Request.Mbean, responseMbean, attribute, value, mbeanEvents, mapping)
if err != nil {
errs = append(errs, err)
}
}
}
}

func selectEvent(events map[eventKey]common.MapStr, key eventKey) common.MapStr {
event, found := events[key]
if !found {
Expand Down Expand Up @@ -177,13 +215,15 @@ func parseResponseEntry(

// In case the attributeValue is a map the keys are dedotted
data := attributeValue
c, ok := data.(map[string]interface{})
if ok {
switch aValue := attributeValue.(type) {
case map[string]interface{}:
newData := map[string]interface{}{}
for k, v := range c {
for k, v := range aValue {
newData[common.DeDot(k)] = v
}
data = newData
case float64:
data = aValue
}
_, err := event.Put(field.Field, data)
return err
Expand Down
Loading