How can I add this ruby code?

Hi,

I have GPS coordinates in DMS (degree minute second) that I need to convert to DD (decimal degrees) so they can be used in Elastic as geo points.

I already wrote I probably not very good filter to convert South and West values to negatives.

if [gps_lat] =~ /[SW]$/ {
 mutate {
      gsub => [
      "gps_lat", "\D", " "
    ]
      strip => ["gps_lat"]
      #add_field => { "gps_lat2" => "-%{gps_lat}" }

Output:
11 22 33
Or
-11 22 33

Now I need a way to perform the following calculations to convert the values.

North/East

deg + (min / 60.0) + (sec / 3600.0)

South/West

deg - (min / 60.0) - (sec / 3600.0)

I found this ruby code online but simply copy/pasting it to a ruby code block doesn't work. No surprise. How can I get logstash to perform the calculation on the gps fields?

   @to_decimal = lambda do |str|
     deg, min, sec = str.split(" ").map(&:to_f)
     if deg >= 0
       output = deg + (min / 60.0) + (sec / 3600.0)
     elsif deg <  #HARD EARNED KNOWLEDGE HERE
       output = deg - (min / 60.0) - (sec / 3600.0)
     end
     raise "something is wrong" if output.abs > 180
     output
   end

Source: https://stackoverflow.com/questions/1774781/how-do-i-convert-coordinates-to-google-friendly-coordinates

Hi Sjaak,

Did you try to put it in a ruby file like explain in the doc ?

For instance you set your ruby plugin like this :

filter {
  ruby {
    path => "/usr/share/logstash/dms2dd.rb"
    script_params => { "gps_lat" => #{gps_lat2} }
  }
}

And you create the /usr/share/logstash/dms2dd.rb ruby file :

# the value of `params` is the value of the hash passed to `script_params`
# in the logstash configuration
def register(params)
    @str = params["gps_lat"]
end

# the filter method receives an event and must return a list of events.
# Dropping an event means not including it in the return array,
# while creating new ones only requires you to add a new instance of
# LogStash::Event to the returned array
def filter(event)
    deg, min, sec = @str.split(" ").map(&:to_f)
    if deg >= 0
        output = deg + (min / 60.0) + (sec / 3600.0)
    elsif deg <  #HARD EARNED KNOWLEDGE HERE
        output = deg - (min / 60.0) - (sec / 3600.0)
    end
    raise "something is wrong" if output.abs > 180
    event.set("dd", output)
    return [event]
end

You should have your converted coordinates in the "dd" field.

Thanks @OphyTe, but unfortunately I can't get it working.

script_params => { "gps_lat" => #{gps_lat2} }

Causes configuration errors. If I change it to "gps_lat2" then the ruby filter fails with

Could not process event: undefined method `/' for nil:NilClass

Looks like somehow it can't get the gps_lat value? I tried looking at some examples and read the docs but there isn't much information about what is what.

I did manage to make a very ugly version myself by using a if conditional to check the location (N/E/S/W), then apply a grok filter to slice up the value in three fields, use a ruby calculation on each field, and finally a mutate to put it all back together.

It works but the whole thing is like 150 lines... Would much rather get it working through this .rb.

Hi Sjaak,

You're probably right, it should be script_params => { "gps_lat" => gps_lat2 }.

For the next issue, I'm not a ruby master and I'm really not comfortable with the first lines syntax of the code block you gave in your first message. I've just copied it . Have you tried something really simple like

def register(params)
    @str = params["gps_lat"]
end

def filter(event)
    puts "str = @str"
    return [event]
end

And then if it works, try to put you logic in it ...
For the record I would have written it like this :blush: :

 def register(params)
    @str = params["gps_lat"]
end

def filter(event)
    ddArray = @str.split(" ").map(&:to_f)
    deg = ddArray[0]
    min = ddArray[1]
    sec = ddArray[2]
    if deg >= 0
        output = deg + (min / 60.0) + (sec / 3600.0)
    else
        output = deg - (min / 60.0) - (sec / 3600.0)
    end
    raise "something is wrong" if output.abs > 180
    event.set("dd", output)
    return [event]
end
1 Like

Thanks, I will try it out.

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