lib/ntail/log_line.rb in ntail-0.0.11 vs lib/ntail/log_line.rb in ntail-0.0.12

- old
+ new

@@ -4,65 +4,102 @@ require 'rainbow' module NginxTail class LogLine - def self.component_to_module_name(component) - # this mimicks the ActiveSupport::Inflector.camelize() method in Rails... - component.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase } - end - - def self.component_to_ntail_module(component) - # this mimicks the ActiveSupport::Inflector.constantize() method in Rails... - NginxTail.const_get(self.component_to_module_name(component)) - end - attr_reader :raw_line attr_reader :parsable + attr_reader :filename + attr_reader :line_number - COMPONENTS = [ - :remote_addr, - :remote_user, - :time_local, - :request, - :status, - :body_bytes_sent, - :http_referer, - :http_user_agent, - :proxy_addresses, + COMPONENTS = [ # formatting token: + + # NGINX + + :remote_addr, # %a + :remote_user, # %u + :time_local, # %t + :request, # %r + :status, # %s + :body_bytes_sent, # %b + :http_referer, # %R + :http_user_agent, # %U + :proxy_addresses, # %p + + # APACHE + + :server_name, # %V + # :remote_addr, # %h + :remote_log_name, # %l + # :remote_user, # %u + # :time_local, # %t + # :request, # %r + # :status, # %s + # :body_bytes_sent, # %b + # :http_referer, # %%{Referer}i + # :http_user_agent, # %%{User-agent}i + :http_cookie, # %{Cookie}i + :time_taken, # %D + ] - + COMPONENTS.each do |symbol| attr_reader symbol - include component_to_ntail_module(symbol) + if (module_for_symbol = Inflections.component_to_ntail_module(symbol)) + include module_for_symbol + end end include KnownIpAddresses # module to identify known IP addresses include LocalIpAddresses # module to identify local IP addresses SUBCOMPONENTS = [ :http_method, :uri, :http_version, ] - + SUBCOMPONENTS.each do |symbol| attr_reader symbol - include component_to_ntail_module(symbol) + include Inflections.component_to_ntail_module(symbol) end # + # http://httpd.apache.org/docs/2.0/mod/mod_log_config.html - we currently only support the following custom log format... + # + # "%V %h %l %u %t \"%r\" %s %b \"%{Referer}i\" \"%{User-agent}i\" \"%{Cookie}i\" %I %O %D %{deflate_ratio}n%%" + # + + APACHE_LOG_PATTERN = Regexp.compile(/\A([\S]*) ([\S]+) ([\S]+|-) ([\S]+|-) \[([^\]]+)\] "(.*)" ([\d]+) ([\d]+|-) "(.*?)" "(.*?)" "(.*?)" [\d]+ [\d]+ ([\d]+) .*\Z/) + + # # http://wiki.nginx.org/NginxHttpLogModule#log_format - we currently only support the default "combined" log format... # NGINX_LOG_PATTERN = Regexp.compile(/\A(\S+) - (\S+) \[([^\]]+)\] "([^"]+)" (\S+) (\S+) "([^"]*?)" "([^"]*?)"( "([^"]*?)")?\Z/) + + # + # the actual pattern used for line matching, either nginx (default) or apache + # + + @@log_pattern = NGINX_LOG_PATTERN + + def self.set_log_pattern(nginx_format) + @@log_pattern = nginx_format ? NGINX_LOG_PATTERN : APACHE_LOG_PATTERN + end + NGINX_REQUEST_PATTERN = Regexp.compile(/\A(\S+) (.*?) (\S+)\Z/) NGINX_PROXY_PATTERN = Regexp.compile(/\A "([^"]*)"\Z/) - def initialize(line) - @parsable = if NGINX_LOG_PATTERN.match(@raw_line = line) - @remote_addr, @remote_user, @time_local, @request, @status, @body_bytes_sent, @http_referer, @http_user_agent, @proxy_addresses = $~.captures + def initialize(line, filename = nil, line_number = nil) + @filename = filename ; @line_number = line_number + @parsable = if @@log_pattern.match(@raw_line = line) + if @@log_pattern == NGINX_LOG_PATTERN + @remote_addr, @remote_user, @time_local, @request, @status, @body_bytes_sent, @http_referer, @http_user_agent, @proxy_addresses = $~.captures + elsif @@log_pattern == APACHE_LOG_PATTERN + @server_name, @remote_addr, @remote_log_name, @remote_user, @time_local, @request, @status, @body_bytes_sent, @http_referer, @http_user_agent, @http_cookie, @time_taken = $~.captures + end if NGINX_REQUEST_PATTERN.match(@request) # counter example (ie. HTTP request that cannot by parsed) # 91.203.96.51 - - [21/Dec/2010:05:26:53 +0000] "-" 400 0 "-" "-" @http_method, @uri, @http_version = $~.captures end @@ -72,37 +109,48 @@ true else false end end - + alias_method :remote_address, :remote_addr # a non-abbreviated alias, for convenience and readability... - + # for now, until we make it fancier... def method_missing(method, *params) raw_line.send method, *params end - + @@parser = FormattingParser.new - - def to_s() + + @@result = @@format = nil + + def self.format= format + unless @@result = @@parser.parse(@@format = format) + raise @@parser.terminal_failures.join("\n") + else + def @@result.value(log_line, color) + elements.map { |element| element.value(log_line, color) }.join + end + end + end + + self.format = "%t - %a - %s - %r - %U - %R" + + def to_s(options = {}) + # simple but boring: # raw_line.to_s - color = if redirect_status? + + # a bit less boring: + color = options[:color] && if redirect_status? :yellow elsif !success_status? :red else :default end - unless result = @@parser.parse("%d - %a - %s - %r - %u - %f") - raise @@parser.terminal_failures.join("\n") - else - def result.value(log_line, color) - elements.map { |element| element.value(log_line, color) }.join - end - end - result.value(self, color) + @@result.value(self, color) + end - + end # class LogLine end # module NginxTail