Class: NginxTail::LogLine

Inherits:
Object
  • Object
show all
Includes:
KnownIpAddresses, LocalIpAddresses
Defined in:
lib/ntail/log_line.rb

Constant Summary collapse

COMPONENTS =
[
  :remote_addr,
  :remote_user,
  :time_local,
  :request,
  :status,
  :body_bytes_sent,
  :http_referer,
  :http_user_agent,
  :proxy_addresses,
]
SUBCOMPONENTS =
[
  :http_method,
  :uri,
  :http_version,
]
NGINX_LOG_PATTERN =

wiki.nginx.org/NginxHttpLogModule#log_format - we currently only support the default “combined” log format…

Regexp.compile(/\A(\S+) - (\S+) \[([^\]]+)\] "([^"]+)" (\S+) (\S+) "([^"]*?)" "([^"]*?)"( "([^"]*?)")?\Z/)
NGINX_REQUEST_PATTERN =
Regexp.compile(/\A(\S+) (.*?) (\S+)\Z/)
NGINX_PROXY_PATTERN =
Regexp.compile(/\A "([^"]*)"\Z/)
CONVERSIONS =
[
  
  :to_date,
  :to_date_s,
  
  :to_agent,
  :to_agent_s,

  :to_host_name,
  :to_refering_website,
  
  :to_country_s,
  :to_city_s,

]
AUTOMATED_REQUESTS =

“GET /xd_receiver.html HTTP/1.1” “GET /crossdomain.xml HTTP/1.1” “GET /favicon.ico HTTP/1.1” “GET /robots.txt HTTP/1.0”

[
  Regexp.compile('^[A-Z]+ \/xd_receiver.html'),
  Regexp.compile('^[A-Z]+ \/crossdomain.xml'),
  Regexp.compile('^[A-Z]+ \/favicon.ico'),
  Regexp.compile('^[A-Z]+ \/robots.txt'),
  nil
].compact!
STATIC_REPOS =

subdirectories of the “public” folder in the web root, which - in a typical Rails setup - are served by nginx

%w{
  flash
  html
  images
  javascripts
  movies
  newsletters
  pictures
  stylesheets
  xml
}
STATIC_URIS =
STATIC_REPOS.map { |repo| Regexp.compile("^\/#{repo}\/") }
STATIC_REQUESTS =
STATIC_REPOS.map { |repo| Regexp.compile("^[A-Z]+ \/#{repo}\/") }

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from LocalIpAddresses

included, #local_ip_address?

Methods included from KnownIpAddresses

included, #known_ip_address?

Constructor Details

#initialize(line) ⇒ LogLine

Returns a new instance of LogLine.



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/ntail/log_line.rb', line 61

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
    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
    if @proxy_addresses and NGINX_PROXY_PATTERN.match(@proxy_addresses)
      @proxy_addresses = $~.captures.first.split(/, /)
    end
    true
  else
    false
  end
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *params) ⇒ Object

for now, until we make it fancier…



81
82
83
# File 'lib/ntail/log_line.rb', line 81

def method_missing(method, *params)
  raw_line.send method, *params
end

Instance Attribute Details

#parsableObject (readonly)

Returns the value of attribute parsable.



20
21
22
# File 'lib/ntail/log_line.rb', line 20

def parsable
  @parsable
end

#raw_lineObject (readonly)

Returns the value of attribute raw_line.



19
20
21
# File 'lib/ntail/log_line.rb', line 19

def raw_line
  @raw_line
end

Class Method Details

.automated_request?(request) ⇒ Boolean

Returns:

  • (Boolean)


201
# File 'lib/ntail/log_line.rb', line 201

def self.automated_request?(request) !AUTOMATED_REQUESTS.detect { |automated_request_regexp| request.match(automated_request_regexp) }.nil? end

.component_to_module_name(component) ⇒ Object



9
10
11
12
# File 'lib/ntail/log_line.rb', line 9

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

.component_to_ntail_module(component) ⇒ Object



14
15
16
17
# File 'lib/ntail/log_line.rb', line 14

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

.log_component?(component) ⇒ Boolean

Returns:

  • (Boolean)


126
127
128
129
# File 'lib/ntail/log_line.rb', line 126

def self.log_component?(component)
  # TODO replace with some clever meta-programming...
  COMPONENTS.include?(component)
end

.log_conversion?(conversion) ⇒ Boolean

Returns:

  • (Boolean)


131
132
133
134
# File 'lib/ntail/log_line.rb', line 131

def self.log_conversion?(conversion)
  # TODO replace with some clever meta-programming...
  CONVERSIONS.include?(conversion)
end

.log_directive?(directive) ⇒ Boolean

Returns:

  • (Boolean)


136
137
138
# File 'lib/ntail/log_line.rb', line 136

def self.log_directive?(directive)
  (directive == :full) or log_conversion?(directive) or log_component?(directive) or log_subcomponent?(directive)
end

.log_subcomponent?(subcomponent) ⇒ Boolean

Returns:

  • (Boolean)


121
122
123
124
# File 'lib/ntail/log_line.rb', line 121

def self.log_subcomponent?(subcomponent)
  # TODO replace with some clever meta-programming...
  SUBCOMPONENTS.include?(subcomponent)
end

.regexp_for_http_referer(http_referer) ⇒ Object



156
157
158
# File 'lib/ntail/log_line.rb', line 156

def self.regexp_for_http_referer(http_referer)
  Regexp.compile(/" .* "([^"]*#{http_referer}[^"]*)" "/)
end

.regexp_for_http_user_agent(http_user_agent) ⇒ Object



160
161
162
# File 'lib/ntail/log_line.rb', line 160

def self.regexp_for_http_user_agent(http_user_agent)
  Regexp.compile(/ "([^"]*#{http_user_agent}[^"]*)"$/)
end

.regexp_for_remote_address(remote_address) ⇒ Object

extraction filters for log line components



144
145
146
# File 'lib/ntail/log_line.rb', line 144

def self.regexp_for_remote_address(remote_address)
  Regexp.compile(/^(#{remote_address}) /)
end

.regexp_for_request(request) ⇒ Object



148
149
150
# File 'lib/ntail/log_line.rb', line 148

def self.regexp_for_request(request)
  Regexp.compile(/^([^"]+) "([^"]*#{request}[^"]*)" /)
end

.regexp_for_status(status) ⇒ Object



152
153
154
# File 'lib/ntail/log_line.rb', line 152

def self.regexp_for_status(status)
  Regexp.compile(/ "([^"]+)" (#{status}) /)
end

.static_request?(request) ⇒ Boolean

Returns:

  • (Boolean)


228
# File 'lib/ntail/log_line.rb', line 228

def self.static_request?(request) !STATIC_REQUESTS.detect { |static_request_regexp| request.match(static_request_regexp) }.nil? end

.static_uri?(uri) ⇒ Boolean

Returns:

  • (Boolean)


223
# File 'lib/ntail/log_line.rb', line 223

def self.static_uri?(uri) !STATIC_URIS.detect { |static_uri_regexp| uri.match(static_uri_regexp) }.nil? end

.valid_referer?(referer) ⇒ Boolean

Returns:

  • (Boolean)


183
# File 'lib/ntail/log_line.rb', line 183

def self.valid_referer?(referer) true ; end

.valid_request?(request) ⇒ Boolean

Returns:

  • (Boolean)


182
# File 'lib/ntail/log_line.rb', line 182

def self.valid_request?(request) true ; end

.valid_status?(status) ⇒ Boolean

validation of log line components

Returns:

  • (Boolean)


168
169
170
171
172
173
# File 'lib/ntail/log_line.rb', line 168

def self.valid_status?(status)
  if /\A(\d{1,3})\Z/ =~ status
    return $~.captures.all? { |i| 100 <= i.to_i and i.to_i < 600 }
  end
  return false
end

.valid_user_agent?(user_agent) ⇒ Boolean

Returns:

  • (Boolean)


184
# File 'lib/ntail/log_line.rb', line 184

def self.valid_user_agent?(user_agent) true ; end

.valid_v4?(addr) ⇒ Boolean

Returns:

  • (Boolean)


175
176
177
178
179
180
# File 'lib/ntail/log_line.rb', line 175

def self.valid_v4?(addr)
  if /\A(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\Z/ =~ addr
    return $~.captures.all? {|i| i.to_i < 256}
  end
  return false
end

Instance Method Details

#automated_request?Boolean

Returns:

  • (Boolean)


202
# File 'lib/ntail/log_line.rb', line 202

def      automated_request?()        self.class.automated_request?(self.request) ; end

#static_request?Boolean

Returns:

  • (Boolean)


229
# File 'lib/ntail/log_line.rb', line 229

def      static_request?()        self.class.static_request?(self.request) ; end

#static_uri?Boolean

Returns:

  • (Boolean)


224
# File 'lib/ntail/log_line.rb', line 224

def      static_uri?()    self.class.static_uri?(self.uri); end

#to_sObject



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/ntail/log_line.rb', line 85

def to_s()
  # simple but boring:
  # raw_line.to_s
  color = if redirect_status?
    :yellow
  elsif !success_status?
    :red
  else
    :default
  end
  "%s - %#{Sickill::Rainbow.enabled ? 15 + 9 : 15}s - %s - %s - %s - %s" % [
    to_date_s.foreground(color),
    remote_address.foreground(color),
    status.foreground(color),
    to_request_s.foreground(color),
    to_agent_s.foreground(color),
    to_referer_s.foreground(color).inverse
  ]
end