require "rubygems" require "ffi" class Grok < FFI::Struct module CGrok extend FFI::Library ffi_lib "libgrok" attach_function :grok_new, [], :pointer attach_function :grok_compilen, [:pointer, :pointer, :int], :int attach_function :grok_pattern_add, [:pointer, :pointer, :int, :pointer, :int], :int attach_function :grok_patterns_import_from_file, [:pointer, :pointer], :int attach_function :grok_execn, [:pointer, :pointer, :int, :pointer], :int end include CGrok layout :pattern, :string, :pattern_len, :int, :full_pattern, :string, :full_pattern_len, :int, :__patterns, :pointer, # TCTREE*, technically :__re, :pointer, # pcre* :__pcre_capture_vector, :pointer, # int* :__pcre_num_captures, :int, :__captures_by_id, :pointer, # TCTREE* :__captures_by_name, :pointer, # TCTREE* :__captures_by_subname, :pointer, # TCTREE* :__captures_by_capture_number, :pointer, # TCTREE* :__max_capture_num, :int, :pcre_errptr, :string, :pcre_erroffset, :int, :pcre_errno, :int, :logmask, :uint, :logdepth, :uint, :errstr, :string GROK_OK = 0 GROK_ERROR_FILE_NOT_ACCESSIBLE = 1 GROK_ERROR_PATTERN_NOT_FOUND = 2 GROK_ERROR_UNEXPECTED_READ_SIZE = 3 GROK_ERROR_COMPILE_FAILED = 4 GROK_ERROR_UNINITIALIZED = 5 GROK_ERROR_PCRE_ERROR = 6 GROK_ERROR_NOMATCH = 7 public def initialize super(grok_new) end public def add_pattern(name, pattern) name_c = FFI::MemoryPointer.from_string(name) pattern_c = FFI::MemoryPointer.from_string(pattern) grok_pattern_add(self, name_c, name.length, pattern_c, pattern.length) return nil end public def add_patterns_from_file(path) path_c = FFI::MemoryPointer.from_string(path) ret = grok_patterns_import_from_file(self, path_c) if ret != GROK_OK raise ArgumentError, "Failed to add patterns from file #{path}" end return nil end public def pattern return self[:pattern] end public def expanded_pattern return self[:full_pattern] end public def compile(pattern) pattern_c = FFI::MemoryPointer.from_string(pattern) ret = grok_compilen(self, pattern_c, pattern.length) if ret != GROK_OK raise ArgumentError, "Compile failed: #{self[:errstr]})" end return ret end public def match(text) match = Grok::Match.new text_c = FFI::MemoryPointer.from_string(text) rc = grok_execn(self, text_c, text.size, match) case rc when GROK_OK # Give the Grok::Match object a reference to the 'text_c' # object which is also Grok::Match#subject string; # this will prevent Ruby from garbage collecting it until # the match object is garbage collectd. # # If we don't do this, then 'text_c' will fall out of # scope at the end of this function and become a candidate # for garbage collection, causing Grok::Match#subject to become # corrupt and any captures to point to those corrupt portions. # http://code.google.com/p/logstash/issues/detail?id=47 match.subject_memorypointer = text_c return match when GROK_ERROR_NOMATCH return false end raise ValueError, "unknown return from grok_execn: #{rc}" end public def discover(input) init_discover if @discover == nil return @discover.discover(input) end private def init_discover @discover = GrokDiscover.new(self) @discover.logmask = logmask end end # Grok require "grok/match" require "grok/pile"