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