Flatten recursively a JSON to Logstash in Ruby

Hello,
I have the following JSON to parse in Logstash :

"payload": [
					{
							"route":"/v1/things",
							"method":"PUT",
							"status":200,
							"content-type":"json",
							"body":{
									"licencePlate":"ZZ123ZZ"
							}
					},
					{
							"route":"/v2",
							"method":"DEL",
							"status":400,
							"content-type":"html",
							"body": [{
										"plate":"67S8DFSDF125V-952",
										"infos":"diverse"
							},{
								"plate":"DZEC12CD-856"
						}]
					}
				]

This JSON contains arrays and can contains any values ( There is no template or no modele ).
In this example, my JSON ( payload ) contains an array with 2 object and one of this object contains an other array, we can imagine, in an other context, this array can contain an other array and ....

I found a ruby script which flatten the JSON at the first level ( payload ) but I don't know how to do it recursively in ruby :

def filter(event)
			payload = event.get("payload")
			if payload.is_a?(Array) then
				payload.each_index { |i|
					event.set("payload-#{i}", payload[i])
				}
			end
			event.delete("payload")
	return []
end

Thank you for your time and your help.

I cannot think of a way to do what you want. The problem is that you want to replace an array with additional hash entries. That appears to require knowing where you are in the event although it is conceivable there is a way to do a merge into the parent field.

The closest I can get is this

def register(params)
    @field = params['field']
end

def processArray(a)
    newHash = {}
    a.each_index { |x|
        newHash["entry#{x}"] = processObject(a[x])
    }
    newHash
end

def processHash(h)
    newHash = {}
    h.each { |k, v|
        newHash[k] = processObject(v)
    }
    newHash
end

def processObject(v)
    if v.kind_of?(Array)
        processArray(v)
    elsif v.kind_of?(Hash)
        processHash(v)
    else
        v
    end
end

def filter(event)
    v = event.get(@field)
    if v
        event.remove(@field)
        event.set(@field, processObject(v))
    end
    [event]
end

which you would invoke using

    ruby {
        path => "/home/user/Ruby/FlattenArrays.rb"
        script_params => { "field" => "payload" }
    }

and it will produce

   "payload" => {
    "entry0" => {
               "route" => "/v1/things",
              "method" => "PUT",
        "content-type" => "json",
                "body" => {
            "licencePlate" => "ZZ123ZZ"
        },
              "status" => 200
    },
    "entry1" => {
               "route" => "/v2",
              "method" => "DEL",
        "content-type" => "html",
                "body" => {
            "entry0" => {
                "plate" => "67S8DFSDF125V-952",
                "infos" => "diverse"
            },
            "entry1" => {
                "plate" => "DZEC12CD-856"
            }
        },
              "status" => 400
    }
},
1 Like

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