How can I add this ruby code?


(Sjaak) #1

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


#2

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.


(Sjaak) #3

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.


#4

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

(Sjaak) #5

Thanks, I will try it out.


(system) #6

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