Digging values out of embedded hashes


(Jason Brooks) #1

Hello,

I have spent all day trying to do this, but I am pretty sure that a) not knowing enough ruby and b) not being familiar enough wth logstash is killing me.

I am running logstash 6.1 on ubuntu 16.04LTS server.

I have the following json data fragment

{    "events": [{
    "attributes": [{
        "name": "messageId",
        "value": "30797758",
        "type": "number",
        "isSync": false
    }, {
        "name": "reportId",
        "value": "1142603714",
        "type": "number",
        "isSync": false
}]
}] 
}

I wish to produce something more like this:

"attributes" => {
   "messageId" => 30797758,
   "reportId" => 1142603714
}

Note how I transpose for each element of "attributes" that "name" becomes the key and "value" becomes the value of the key "name".

I am trying to do it with a ruby filter using the logstash config:

input { codec=>json } 
filter{ 
    json { source=>"message" 
    ruby {
        code=>'
            things=event.get("[events][0][attributes]")
            newhash={}
            if things.is_a?(Array)
                things.each{ |attr| newhash[attr["name"] => attr["value"]]}
            end
    event.set("[newhash]", newhash )
    '
} 
output { codec => rubydebug } 

the trouble is newhash doesn't show anything:

"newhash"  => {},

instead of the things.each line, I have tried various versions of:

	    things.each{ |attr| event.set{[attributes2][#{attr["name"]}], attr["value"]  } }

but here I just get an error.

I am not at wits end, but I thought I would give it a go before I wrote here.

Does anyone have any suggestions?

Thanks in advance...

--jason


(Jason Brooks) #2

Wait: I think I got it!

things=event.get("[events][0][attributes]")
newhash={}
if things.is_a?(Array)
    things.each{ |xx| newhash["#{xx["name"]}"] = xx["value"]  }
end
event.set("[newhash]", newhash )

please feel free to critique me! :slight_smile:


(Guy Boertje) #3

Marked up the error:

input { codec=>json } 
filter{ 
    json { source=>"message" 
    ruby {
        code=>'
            things=event.get("[events][0][attributes]")
            newhash={}
            if things.is_a?(Array)
                #                                      move this bracket⤵
                things.each{ |attr| newhash[attr["name"] => attr["value"]]}
                #                               to here⤴ ▲this > is not needed.
            end
    event.set("[newhash]", newhash )
    '
} 
output { codec => rubydebug } 

should be:
things.each{ |attr| newhash[attr["name"]] = attr["value"]}


(Jason Brooks) #4

Ooh: I will compare this to my solution...

Thank you!


(Jason Brooks) #5

Hello @guyboertje,

I just tried your solution, and it works perfectly.

I compared it to mine, which also appears to work.

your line followed by mine:

things.each{ |attr| newhash[attr["name"]] = attr["value"]}
things.each{ |attr| newhash["#{attr["name"]}"] = attr["value"] }

Of course, I can't now recall why I used #{attr["name"]}" rather than just attr["name"], and I imagine my code just goes through more gyrations than yours... But I am fairly pleased how close they are!

Thank you for your help! I really appreciate it!


(system) #6

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.