ntail 0.0.6 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +1 -0
- data/Gemfile.lock +2 -0
- data/README.rdoc +1 -1
- data/VERSION +1 -1
- data/lib/ntail.rb +24 -1
- data/lib/ntail/application.rb +60 -28
- data/lib/ntail/body_bytes_sent.rb +14 -0
- data/lib/ntail/http_method.rb +34 -0
- data/lib/ntail/http_referer.rb +81 -0
- data/lib/ntail/http_user_agent.rb +122 -0
- data/lib/ntail/http_version.rb +22 -0
- data/lib/ntail/known_ip_addresses.rb +44 -0
- data/lib/ntail/local_ip_addresses.rb +44 -0
- data/lib/ntail/log_line.rb +75 -222
- data/lib/ntail/proxy_addresses.rb +14 -0
- data/lib/ntail/remote_addr.rb +56 -0
- data/lib/ntail/remote_user.rb +63 -0
- data/lib/ntail/request.rb +33 -0
- data/lib/ntail/status.rb +68 -0
- data/lib/ntail/time_local.rb +38 -0
- data/lib/ntail/uri.rb +22 -0
- data/ntail.gemspec +41 -2
- data/test/helper.rb +73 -0
- data/test/ntail/test_http_method.rb +50 -0
- data/test/ntail/test_http_referer.rb +77 -0
- data/test/ntail/test_http_user_agent.rb +29 -0
- data/test/ntail/test_known_ip_addresses.rb +45 -0
- data/test/ntail/test_local_ip_addresses.rb +45 -0
- data/test/ntail/test_log_line.rb +51 -0
- data/test/ntail/test_remote_addr.rb +38 -0
- data/test/ntail/test_remote_user.rb +65 -0
- data/test/ntail/test_request.rb +26 -0
- data/test/ntail/test_status.rb +26 -0
- data/test/ntail/test_time_local.rb +30 -0
- data/test/test_ntail.rb +9 -2
- metadata +59 -9
@@ -0,0 +1,14 @@
|
|
1
|
+
module NginxTail
|
2
|
+
module ProxyAddresses
|
3
|
+
|
4
|
+
def self.included(base) # :nodoc:
|
5
|
+
base.class_eval do
|
6
|
+
|
7
|
+
# this ensures the below module methods actually make sense...
|
8
|
+
raise "Class #{base.name} should implement instance method 'proxy_addresses'" unless base.instance_methods.include? 'proxy_addresses'
|
9
|
+
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'socket'
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'geoip'
|
5
|
+
rescue LoadError
|
6
|
+
# NOOP (optional dependency)
|
7
|
+
end
|
8
|
+
|
9
|
+
module NginxTail
|
10
|
+
module RemoteAddr
|
11
|
+
|
12
|
+
def self.included(base) # :nodoc:
|
13
|
+
base.class_eval do
|
14
|
+
|
15
|
+
def self.to_host_s(remote_addr)
|
16
|
+
Socket::getaddrinfo(remote_addr, nil)[0][2]
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.to_country_s(remote_addr)
|
20
|
+
record = if defined? GeoIP # ie. if the optional GeoIP gem is installed
|
21
|
+
if File.exists?('/usr/share/GeoIP/GeoIP.dat') # ie. if the GeoIP country database is installed
|
22
|
+
GeoIP.new('/usr/share/GeoIP/GeoIP.dat').country(remote_addr)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
record ? record[5] : 'N/A'
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.to_city_s(remote_addr)
|
29
|
+
record = if defined? GeoIP # ie. if the optional GeoIP gem is installed
|
30
|
+
if File.exists?('/usr/share/GeoIP/GeoIPCity.dat') # ie. if the GeoIP city database is installed
|
31
|
+
GeoIP.new('/usr/share/GeoIP/GeoIPCity.dat').city(remote_addr)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
record ? record[7] : 'N/A'
|
35
|
+
end
|
36
|
+
|
37
|
+
# this ensures the below module methods actually make sense...
|
38
|
+
raise "Class #{base.name} should implement instance method 'remote_addr'" unless base.instance_methods.include? 'remote_addr'
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_host_s()
|
44
|
+
self.class.to_host_s(self.remote_addr)
|
45
|
+
end
|
46
|
+
|
47
|
+
def to_country_s()
|
48
|
+
self.class.to_country_s(self.remote_addr)
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_city_s()
|
52
|
+
self.class.to_city_s(self.remote_addr)
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module NginxTail
|
2
|
+
module RemoteUser
|
3
|
+
|
4
|
+
#
|
5
|
+
# to easily identify remote and authenticated users, for filtering and formatting purposes
|
6
|
+
#
|
7
|
+
# e.g. add all employees as authenticated remote users (from your webserver's .htaccess file)
|
8
|
+
#
|
9
|
+
|
10
|
+
UNKNOWN_REMOTE_USER = "-".freeze # the 'default' nginx value for the $remote_user variable
|
11
|
+
|
12
|
+
def self.included(base) # :nodoc:
|
13
|
+
base.class_eval do
|
14
|
+
|
15
|
+
@@authenticated_users = []
|
16
|
+
|
17
|
+
# mainly (solely?) for testing purposes...
|
18
|
+
def self.reset_authenticated_users
|
19
|
+
while !@@authenticated_users.empty? ; @@authenticated_users.pop ; end
|
20
|
+
end
|
21
|
+
|
22
|
+
# mainly (solely?) for testing purposes...
|
23
|
+
def self.authenticated_users
|
24
|
+
@@authenticated_users.dup
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.add_authenticated_user(authenticated_user)
|
28
|
+
raise "Cannot add unkown remote user" if self.unknown_remote_user? authenticated_user
|
29
|
+
(@@authenticated_users << authenticated_user).uniq!
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.unknown_remote_user?(remote_user)
|
33
|
+
remote_user == UNKNOWN_REMOTE_USER
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.remote_user?(remote_user)
|
37
|
+
!self.unknown_remote_user?(remote_user)
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.authenticated_user?(remote_user)
|
41
|
+
self.remote_user?(remote_user) && @@authenticated_users.include?(remote_user)
|
42
|
+
end
|
43
|
+
|
44
|
+
# this ensures the below module methods actually make sense...
|
45
|
+
raise "Class #{base.name} should implement instance method 'remote_user'" unless base.instance_methods.include? 'remote_user'
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def unknown_remote_user?
|
51
|
+
self.class.unknown_remote_user?(self.remote_user)
|
52
|
+
end
|
53
|
+
|
54
|
+
def remote_user?
|
55
|
+
self.class.remote_user?(self.remote_user)
|
56
|
+
end
|
57
|
+
|
58
|
+
def authenticated_user?
|
59
|
+
self.class.authenticated_user?(self.remote_user)
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module NginxTail
|
2
|
+
module Request
|
3
|
+
|
4
|
+
UNKNOWN_REQUEST = "-".freeze # the 'default' nginx value for $request variable
|
5
|
+
|
6
|
+
def self.included(base) # :nodoc:
|
7
|
+
base.class_eval do
|
8
|
+
|
9
|
+
def self.unknown_request?(request)
|
10
|
+
request == UNKNOWN_REQUEST
|
11
|
+
end
|
12
|
+
|
13
|
+
# this ensures the below module methods actually make sense...
|
14
|
+
raise "Class #{base.name} should implement instance method 'request'" unless base.instance_methods.include? 'request'
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def unknown_request?
|
20
|
+
self.class.unknown_request?(self.request)
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_request_s
|
24
|
+
if self.unknown_request?
|
25
|
+
self.request
|
26
|
+
else
|
27
|
+
# note: we exclude the HTTP version info...
|
28
|
+
"%s %s" % [self.to_http_method_s, self.to_uri_s]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
data/lib/ntail/status.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
module NginxTail
|
2
|
+
module Status
|
3
|
+
|
4
|
+
NGINX_MAGIC_STATUS = '499' # ex-standard HTTP response code specific to nginx, in addition to http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
|
5
|
+
|
6
|
+
def self.included(base) # :nodoc:
|
7
|
+
base.class_eval do
|
8
|
+
|
9
|
+
# Informational 1xx
|
10
|
+
def self.information_status?(status)
|
11
|
+
# (status.to_s != NGINX_MAGIC_STATUS) and Net::HTTPResponse::CODE_TO_OBJ[status.to_s] <= Net::HTTPInformation
|
12
|
+
(status.to_s != NGINX_MAGIC_STATUS) and Net::HTTPResponse::CODE_CLASS_TO_OBJ[(status.to_i / 100).to_s] == Net::HTTPInformation
|
13
|
+
end
|
14
|
+
|
15
|
+
# Successful 2xx
|
16
|
+
def self.success_status?(status)
|
17
|
+
# (status.to_s != NGINX_MAGIC_STATUS) and Net::HTTPResponse::CODE_TO_OBJ[status.to_s] <= Net::HTTPSuccess
|
18
|
+
(status.to_s != NGINX_MAGIC_STATUS) and Net::HTTPResponse::CODE_CLASS_TO_OBJ[(status.to_i / 100).to_s] == Net::HTTPSuccess
|
19
|
+
end
|
20
|
+
|
21
|
+
# Redirection 3xx
|
22
|
+
def self.redirect_status?(status)
|
23
|
+
# (status.to_s != NGINX_MAGIC_STATUS) and Net::HTTPResponse::CODE_TO_OBJ[status.to_s] <= Net::HTTPRedirection
|
24
|
+
(status.to_s != NGINX_MAGIC_STATUS) and Net::HTTPResponse::CODE_CLASS_TO_OBJ[(status.to_i / 100).to_s] == Net::HTTPRedirection
|
25
|
+
end
|
26
|
+
|
27
|
+
# Client Error 4xx
|
28
|
+
def self.client_error_status?(status)
|
29
|
+
# (status.to_s != NGINX_MAGIC_STATUS) and Net::HTTPResponse::CODE_TO_OBJ[status.to_s] <= Net::HTTPClientError
|
30
|
+
(status.to_s != NGINX_MAGIC_STATUS) and Net::HTTPResponse::CODE_CLASS_TO_OBJ[(status.to_i / 100).to_s] == Net::HTTPClientError
|
31
|
+
end
|
32
|
+
|
33
|
+
# Internal Server Error 5xx
|
34
|
+
def self.server_error_status?(status)
|
35
|
+
# (status.to_s != NGINX_MAGIC_STATUS) and Net::HTTPResponse::CODE_TO_OBJ[status.to_s] <= Net::HTTPServerError
|
36
|
+
(status.to_s != NGINX_MAGIC_STATUS) and Net::HTTPResponse::CODE_CLASS_TO_OBJ[(status.to_i / 100).to_s] == Net::HTTPServerError
|
37
|
+
end
|
38
|
+
|
39
|
+
# this ensures the below module methods actually make sense...
|
40
|
+
raise "Class #{base.name} should implement instance method 'status'" unless base.instance_methods.include? 'status'
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def information_status?
|
46
|
+
self.class.information_status?(self.status)
|
47
|
+
end
|
48
|
+
|
49
|
+
def success_status?
|
50
|
+
self.class.success_status?(self.status)
|
51
|
+
end
|
52
|
+
|
53
|
+
def redirect_status?
|
54
|
+
self.class.redirect_status?(self.status)
|
55
|
+
end
|
56
|
+
|
57
|
+
def client_error_status?
|
58
|
+
self.class.client_error_status?(self.status)
|
59
|
+
end
|
60
|
+
|
61
|
+
def server_error_status?
|
62
|
+
self.class.server_error_status?(self.status)
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
module NginxTail
|
4
|
+
module TimeLocal
|
5
|
+
|
6
|
+
def self.included(base) # :nodoc:
|
7
|
+
base.class_eval do
|
8
|
+
|
9
|
+
# >> DateTime.strptime("13/Apr/2010:04:45:51 +0100", '%d/%b/%Y:%T %z').to_s
|
10
|
+
# => "2010-04-13T04:45:51+01:00"
|
11
|
+
# >> DateTime.strptime("13/Apr/2010:04:45:51 +0100", '%d/%b/%Y:%H:%M:%S %z').to_s
|
12
|
+
# => "2010-04-13T04:45:51+01:00"
|
13
|
+
# >> _
|
14
|
+
|
15
|
+
def self.to_date(time_local)
|
16
|
+
DateTime.strptime(time_local, '%d/%b/%Y:%T %z')
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.to_date_s(time_local, format = "%Y-%m-%d %X")
|
20
|
+
self.to_date(time_local).strftime(format)
|
21
|
+
end
|
22
|
+
|
23
|
+
# this ensures the below module methods actually make sense...
|
24
|
+
raise "Class #{base.name} should implement instance method 'time_local'" unless base.instance_methods.include? 'time_local'
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_date
|
30
|
+
self.class.to_date(self.time_local)
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_date_s
|
34
|
+
self.class.to_date_s(self.time_local)
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
data/lib/ntail/uri.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
module NginxTail
|
2
|
+
module Uri
|
3
|
+
|
4
|
+
def self.included(base) # :nodoc:
|
5
|
+
base.class_eval do
|
6
|
+
|
7
|
+
def self.to_uri_s(uri)
|
8
|
+
uri || "-" # will be nil if $request == "-" (ie. "dodgy" HTTP requests)
|
9
|
+
end
|
10
|
+
|
11
|
+
# this ensures the below module methods actually make sense...
|
12
|
+
raise "Class #{base.name} should implement instance method 'uri'" unless base.instance_methods.include? 'uri'
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_uri_s
|
18
|
+
self.class.to_uri_s(self.uri)
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
data/ntail.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{ntail}
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.7"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Peter Vandenberk"]
|
12
|
-
s.date = %q{
|
12
|
+
s.date = %q{2011-01-06}
|
13
13
|
s.default_executable = %q{ntail}
|
14
14
|
s.description = %q{A tail(1)-like utility for nginx log files. It supports parsing, filtering and formatting individual log lines.}
|
15
15
|
s.email = %q{pvandenberk@mac.com}
|
@@ -29,9 +29,34 @@ Gem::Specification.new do |s|
|
|
29
29
|
"bin/ntail",
|
30
30
|
"lib/ntail.rb",
|
31
31
|
"lib/ntail/application.rb",
|
32
|
+
"lib/ntail/body_bytes_sent.rb",
|
33
|
+
"lib/ntail/http_method.rb",
|
34
|
+
"lib/ntail/http_referer.rb",
|
35
|
+
"lib/ntail/http_user_agent.rb",
|
36
|
+
"lib/ntail/http_version.rb",
|
37
|
+
"lib/ntail/known_ip_addresses.rb",
|
38
|
+
"lib/ntail/local_ip_addresses.rb",
|
32
39
|
"lib/ntail/log_line.rb",
|
40
|
+
"lib/ntail/proxy_addresses.rb",
|
41
|
+
"lib/ntail/remote_addr.rb",
|
42
|
+
"lib/ntail/remote_user.rb",
|
43
|
+
"lib/ntail/request.rb",
|
44
|
+
"lib/ntail/status.rb",
|
45
|
+
"lib/ntail/time_local.rb",
|
46
|
+
"lib/ntail/uri.rb",
|
33
47
|
"ntail.gemspec",
|
34
48
|
"test/helper.rb",
|
49
|
+
"test/ntail/test_http_method.rb",
|
50
|
+
"test/ntail/test_http_referer.rb",
|
51
|
+
"test/ntail/test_http_user_agent.rb",
|
52
|
+
"test/ntail/test_known_ip_addresses.rb",
|
53
|
+
"test/ntail/test_local_ip_addresses.rb",
|
54
|
+
"test/ntail/test_log_line.rb",
|
55
|
+
"test/ntail/test_remote_addr.rb",
|
56
|
+
"test/ntail/test_remote_user.rb",
|
57
|
+
"test/ntail/test_request.rb",
|
58
|
+
"test/ntail/test_status.rb",
|
59
|
+
"test/ntail/test_time_local.rb",
|
35
60
|
"test/test_ntail.rb"
|
36
61
|
]
|
37
62
|
s.homepage = %q{http://github.com/pvdb/ntail}
|
@@ -41,6 +66,17 @@ Gem::Specification.new do |s|
|
|
41
66
|
s.summary = %q{A tail(1)-like utility for nginx log files}
|
42
67
|
s.test_files = [
|
43
68
|
"test/helper.rb",
|
69
|
+
"test/ntail/test_http_method.rb",
|
70
|
+
"test/ntail/test_http_referer.rb",
|
71
|
+
"test/ntail/test_http_user_agent.rb",
|
72
|
+
"test/ntail/test_known_ip_addresses.rb",
|
73
|
+
"test/ntail/test_local_ip_addresses.rb",
|
74
|
+
"test/ntail/test_log_line.rb",
|
75
|
+
"test/ntail/test_remote_addr.rb",
|
76
|
+
"test/ntail/test_remote_user.rb",
|
77
|
+
"test/ntail/test_request.rb",
|
78
|
+
"test/ntail/test_status.rb",
|
79
|
+
"test/ntail/test_time_local.rb",
|
44
80
|
"test/test_ntail.rb"
|
45
81
|
]
|
46
82
|
|
@@ -55,6 +91,7 @@ Gem::Specification.new do |s|
|
|
55
91
|
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
56
92
|
s.add_development_dependency(%q<jeweler>, ["~> 1.5.1"])
|
57
93
|
s.add_development_dependency(%q<rcov>, [">= 0"])
|
94
|
+
s.add_development_dependency(%q<geoip>, [">= 0"])
|
58
95
|
else
|
59
96
|
s.add_dependency(%q<rainbow>, [">= 0"])
|
60
97
|
s.add_dependency(%q<user-agent>, [">= 0"])
|
@@ -62,6 +99,7 @@ Gem::Specification.new do |s|
|
|
62
99
|
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
63
100
|
s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
|
64
101
|
s.add_dependency(%q<rcov>, [">= 0"])
|
102
|
+
s.add_dependency(%q<geoip>, [">= 0"])
|
65
103
|
end
|
66
104
|
else
|
67
105
|
s.add_dependency(%q<rainbow>, [">= 0"])
|
@@ -70,6 +108,7 @@ Gem::Specification.new do |s|
|
|
70
108
|
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
71
109
|
s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
|
72
110
|
s.add_dependency(%q<rcov>, [">= 0"])
|
111
|
+
s.add_dependency(%q<geoip>, [">= 0"])
|
73
112
|
end
|
74
113
|
end
|
75
114
|
|
data/test/helper.rb
CHANGED
@@ -15,4 +15,77 @@ $LOAD_PATH.unshift(File.dirname(__FILE__))
|
|
15
15
|
require 'ntail'
|
16
16
|
|
17
17
|
class Test::Unit::TestCase
|
18
|
+
|
19
|
+
def random_ip_address
|
20
|
+
((1..4).map { Kernel.rand(256) }).join('.')
|
21
|
+
end
|
22
|
+
|
23
|
+
def local_ip_address
|
24
|
+
# http://en.wikipedia.org/wiki/IP_address#IPv4_private_addresses
|
25
|
+
(['192', '168'] + (1..2).map { Kernel.rand(256) }).join('.')
|
26
|
+
end
|
27
|
+
|
28
|
+
#
|
29
|
+
# http://wiki.nginx.org/NginxHttpLogModule#log_format
|
30
|
+
#
|
31
|
+
# There is a predefined log format called "combined":
|
32
|
+
#
|
33
|
+
# log_format combined '$remote_addr - $remote_user [$time_local] '
|
34
|
+
# '"$request" $status $body_bytes_sent '
|
35
|
+
# '"$http_referer" "$http_user_agent"';
|
36
|
+
#
|
37
|
+
|
38
|
+
LOG_FORMAT_COMBINED = '%s - %s [%s] ' \
|
39
|
+
'"%s" %d %d ' \
|
40
|
+
'"%s" "%s"'
|
41
|
+
|
42
|
+
DEFAULT_VALUES = {
|
43
|
+
:remote_addr => '72.46.130.42',
|
44
|
+
:remote_user => '-',
|
45
|
+
:time_local => '01/Jan/2010:04:00:29 +0000',
|
46
|
+
# :request => 'GET /index.html HTTP/1.1',
|
47
|
+
:http_method => 'GET',
|
48
|
+
:uri => '/index.html',
|
49
|
+
:http_version => 'HTTP/1.1',
|
50
|
+
:status => 200,
|
51
|
+
:body_bytes_sent => 6918,
|
52
|
+
:http_referer => 'http://www.google.com/search?q=example',
|
53
|
+
:http_user_agent => 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.224 Safari/534.10'
|
54
|
+
}
|
55
|
+
|
56
|
+
REQUEST_FORMAT = '%s %s %s'
|
57
|
+
|
58
|
+
def random_raw_line(options = {})
|
59
|
+
options = DEFAULT_VALUES.merge options
|
60
|
+
options[:request] ||= REQUEST_FORMAT % [
|
61
|
+
options[:http_method],
|
62
|
+
options[:uri],
|
63
|
+
options[:http_version]
|
64
|
+
]
|
65
|
+
LOG_FORMAT_COMBINED % [
|
66
|
+
options[:remote_addr],
|
67
|
+
options[:remote_user],
|
68
|
+
options[:time_local],
|
69
|
+
options[:request],
|
70
|
+
options[:status],
|
71
|
+
options[:body_bytes_sent],
|
72
|
+
options[:http_referer],
|
73
|
+
options[:http_user_agent],
|
74
|
+
]
|
75
|
+
end
|
76
|
+
|
77
|
+
def random_log_line(options = {})
|
78
|
+
NginxTail::LogLine.new(random_raw_line(options))
|
79
|
+
end
|
80
|
+
|
81
|
+
def bad_request_raw_line
|
82
|
+
# a "bad request", resulting in a 400 status, is logged by nginx as follows:
|
83
|
+
# 121.8.101.138 - - [28/Dec/2010:23:50:58 +0000] "-" 400 0 "-" "-"
|
84
|
+
'121.8.101.138 - - [28/Dec/2010:23:50:58 +0000] "-" 400 0 "-" "-"'
|
85
|
+
end
|
86
|
+
|
87
|
+
def bad_request_log_line
|
88
|
+
NginxTail::LogLine.new(bad_request_raw_line)
|
89
|
+
end
|
90
|
+
|
18
91
|
end
|