Skip to content

Instantly share code, notes, and snippets.

@danslimmon
Created July 8, 2011 13:10
Show Gist options
  • Save danslimmon/1071789 to your computer and use it in GitHub Desktop.
Save danslimmon/1071789 to your computer and use it in GitHub Desktop.
Factory/Dictionary solution to log grammar
class LogFormatElement
@_caster = nil
attr_accessor :abbrev, :name, :regex
# Class variables that determine the _default_ for abbrev, name, and regex in an instance.
# That is, an instance will initialize with these values for the instance variables @abbrev,
# @name, and @regex.
class << self; attr_accessor :abbrev, :name, :regex end
# Additionally we need to access this from within the instance:
class << self; attr_accessor :_caster end
def initialize
@abbrev = self.class.abbrev
@name = self.class.name
@regex = self.class.regex
end
# Casts a string found in the log to the correct type, using the class's @@_caster attribute.
def cast(string_value)
...
end
# Derives any other element values that we can, given the parsed value for the deriving element.
def derived_values(our_own_value)
{}
end
end
class RemoteHostElement < LogFormatElement
@abbrev = "%h"
@name = "remote_host"
@regex = %q![A-Za-z0-9.-]+!
end
class LogNameElement < LogFormatElement
@abbrev = "%l"
@name = "log_name"
@regex = %q!\S+!
end
class RemoteUserElement < LogFormatElement
@abbrev = "%u"
@name = "remote_user"
@regex = %q![^:]+!
end
# Finds log format elements given information about them.
class ElementDictionary
@@_ELEMENTS = [
RemoteHostElement,
LogNameElement,
RemoteUserElement,
]
# Returns the LogFormatElement subclass with the given format-string abbreviation.
#
# If none exists, returns nil.
def self.find_by_abbrev(abbrev)
@@_ELEMENTS.each do |element|
if element.abbrev == abbrev
return element
end
end
nil
end
end
# Generates LogFormatElement instances.
#
# This class does the work of figuring out which LogFormatElement subclass to make and makes it.
class LogFormatElementFactory
# Takes an Apache log format abbreviation and returns a corresponding LogFormatElement
def from_abbrev(abbrev)
element_cls = ElementDictionary.find_by_abbrev(abbrev)
if element_cls
# We found it in the dictionary, so just return an instance
return element_cls.new
elsif abbrev =~ /^%\{([A-Za-z0-9-]+)\}i/
# HTTP request header
return _reqheader_element(abbrev, $1)
elsif abbrev =~ /^%\{(.*?):([^}]+)\}r/
# Arbitrary regex
return _regex_element(abbrev, $1, $2)
end
raise "Unknown element format '#{abbrev}'"
end
# Returns a format element based on an HTTP header
def _reqheader_element(abbrev, header_name)
...
end
# Returns a format element based on an arbitrary regex
def _regex_element(abbrev, regex_name, regex)
...
end
# Lowercases header name and turns hyphens into underscores
def _header_name_to_element_name(header_name)
...
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment