class LogStash::Filters::Javascript

Constants

JEvent

Public Class Methods

new(*params) click to toggle source
Flag for add exception message to tag_on_exception

config :tag_with_exception_message, :type => :boolean, :default => false

Calls superclass method
# File lib/logstash/filters/javascript.rb, line 46
def initialize(*params)
  super(*params)
  @script = Script.new(nil, init_parameters, logger)
  @script.js_eval @init if @init
  @js_filter = nil
end

Public Instance Methods

filter(event, &block) click to toggle source
# File lib/logstash/filters/javascript.rb, line 84
def filter(event, &block)
  java_event = event.to_java
  begin
    js_return = @script.js_call(@js_filter, java_event)
    filter_matched(event)
  rescue => e
    @logger.error("could not process event due:", error_details(e))
    tag_exception(event, e)
    return event
  end
  event.cancel unless filter_results(java_event, js_return, &block)
end
register() click to toggle source
# File lib/logstash/filters/javascript.rb, line 53
def register
  @js_filter = nil # TODO: devutils' sample helper causes plugin.register to happen twice

  if @path
    @path.each { |path| @script.js_eval(::File.read(path), path: path) }
    @js_filter = @script.get('filter') # `expecting a `function filter(event) {}`
    if @js_filter.nil?
      raise ScriptError, "script at '#{@path}' does not define a filter(event) function" if @code.nil?
    else
      if @js_filter.is_a?(ScriptObjectMirror)
        unless @js_filter.isFunction
          raise ScriptError, "script at '#{@path}' defines a 'filter' property that isn't a function (got type: #{@js_filter.getClassName})"
        end
      else
        raise ScriptError, "script at '#{@path}' defines a 'filter' property that isn't a function (got value: #{@js_filter.inspect})"
      end
    end
  end

  if @code
    if @js_filter
      msg = "Script(s) provided by 'path' defined a filter function while 'code' => ... is also set, this is ambiguous!"
      @logger.error(msg); raise LogStash::ConfigurationError.new(msg)
    end

    @js_filter = @script.js_eval(@code) { "(function filter(event) {\n#{@code} } )" } # jdk.nashorn.api.scripting.JSObject
  end

  @script.verify
end

Private Instance Methods

error_details(e) click to toggle source
# File lib/logstash/filters/javascript.rb, line 151
def error_details(e)
  details = { :exception => e.class, :message => e.message }
  if e.is_a?(NashornException)
    details[:message] = e.toString
    details[:backtrace] = e.backtrace if logger.debug?
    js_error = e.getEcmaError
    js_error = js_error.toString if js_error.is_a?(ScriptObjectMirror)
    details[:javascript_error] = js_error
    details[:javascript_file] = e.getFileName # '<eval>' for incline code
    details[:javascript_line] = e.getLineNumber # inline code lines are +1
    details[:javascript_column] = e.getColumnNumber
    details[:javascript_trace] = NashornException.getScriptFrames(e)
  else
    details[:backtrace] = e.backtrace
  end
  details
end
filter_results(event, js_return) { |wrap_event(evt)| ... } click to toggle source

@param results (JS array) in a `jdk.nashorn.api.scripting.ScriptObjectMirror`

# File lib/logstash/filters/javascript.rb, line 100
def filter_results(event, js_return)
  if js_return.nil? # explicit `return null`
    # drop event (return false)
  elsif ScriptObjectMirror.isUndefined(js_return) # jdk.nashorn.internal.runtime.Undefined
    return true # do not drop (assume it's been dealt with e.g. `event.cancel()`)
  elsif js_return.is_a?(ScriptObjectMirror)
    if js_return.isArray
      i = 0; returned_original = false
      while i < js_return.size
        evt = js_return.getSlot(i)
        if event.equal?(evt)
          returned_original = true
        else
          yield wrap_event(evt)
        end
        i += 1
      end
      return returned_original
    else
      begin
        evt = wrap_event(js_return) # JSObject implement Map interface
      rescue => e
        raise e # TODO we should attempt to provide a better exception here if we can not convert the JS (map) object
        # raise ScriptError, "javascript did not return an event/array (or null) from 'filter', got: #{js_return.getClassName}"
      else
        yield evt
      end
    end
  elsif js_return.is_a?(JEvent) || js_return.is_a?(Map)
    return true if event.equal?(js_return)
    yield wrap_event(js_return)
  else
    raise ScriptError, "javascript did not return an event/array (or null) from 'filter', got: #{js_return.inspect}"
  end
  false # script did not return original event
end
tag_exception(event, e) click to toggle source
# File lib/logstash/filters/javascript.rb, line 144
def tag_exception(event, e)
  if @tag_with_exception_message && e.message
    event.tag("#{@tag_on_exception}: #{e.message}")
  end
  event.tag(@tag_on_exception) if @tag_on_exception
end
wrap_event(js_event) click to toggle source

NOTE: JS code is expected to work with Java event API @param js_event a org.logstash.Event or simply a plain-old (map-like) JS object

# File lib/logstash/filters/javascript.rb, line 139
def wrap_event(js_event)
  js_event = JEvent.new(js_event) unless js_event.is_a?(JEvent)
  Event.new(js_event)
end