ntail 0.0.11 → 0.0.12
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +5 -0
- data/Gemfile.lock +37 -4
- data/README.md +158 -0
- data/Rakefile +24 -11
- data/VERSION +1 -1
- data/bin/ntail +1 -1
- data/lib/ntail/application.rb +74 -97
- data/lib/ntail/body_bytes_sent.rb +2 -2
- data/lib/ntail/formatting.rb +157 -44
- data/lib/ntail/formatting.treetop +44 -15
- data/lib/ntail/http_method.rb +2 -2
- data/lib/ntail/http_referer.rb +2 -2
- data/lib/ntail/http_user_agent.rb +3 -1
- data/lib/ntail/http_version.rb +20 -5
- data/lib/ntail/known_ip_addresses.rb +2 -2
- data/lib/ntail/local_ip_addresses.rb +2 -2
- data/lib/ntail/log_line.rb +90 -42
- data/lib/ntail/node.rb +3 -0
- data/lib/ntail/options.rb +82 -0
- data/lib/ntail/proxy_addresses.rb +2 -2
- data/lib/ntail/remote_addr.rb +2 -2
- data/lib/ntail/remote_user.rb +2 -2
- data/lib/ntail/request.rb +2 -2
- data/lib/ntail/status.rb +1 -1
- data/lib/ntail/time_local.rb +2 -2
- data/lib/ntail/uri.rb +8 -1
- data/lib/ntail.rb +18 -3
- data/ntail.gemspec +29 -6
- data/spec/application_spec.rb +23 -0
- data/spec/spec_helper.rb +9 -0
- data/test/helper.rb +4 -1
- data/test/ntail/test_formatting.rb +72 -0
- data/test/ntail/test_http_version.rb +36 -0
- data/test/ntail/test_log_line.rb +5 -4
- data/test/ntail/test_remote_addr.rb +25 -3
- data/test/test_ntail.rb +7 -0
- metadata +125 -43
- data/README.rdoc +0 -99
data/Gemfile
CHANGED
@@ -5,13 +5,18 @@ source "http://rubygems.org"
|
|
5
5
|
gem "rainbow", ">= 0"
|
6
6
|
gem "user-agent", ">= 0"
|
7
7
|
gem "treetop", "~> 1.4.9"
|
8
|
+
gem 'sequel'
|
9
|
+
gem 'mongoid'
|
10
|
+
gem 'sqlite3-ruby', :require => 'sqlite3'
|
8
11
|
|
9
12
|
# Add dependencies to develop your gem here.
|
10
13
|
# Include everything needed to run rake, tests, features, etc.
|
11
14
|
group :development do
|
15
|
+
gem "rake", ">= 0.9.2"
|
12
16
|
gem "shoulda", ">= 0"
|
13
17
|
gem "bundler", "~> 1.0.0"
|
14
18
|
gem "jeweler", "~> 1.5.1"
|
15
19
|
gem "rcov", ">= 0"
|
16
20
|
gem "geoip", ">= 0"
|
21
|
+
gem "rspec", ">= 2.5"
|
17
22
|
end
|
data/Gemfile.lock
CHANGED
@@ -1,19 +1,47 @@
|
|
1
1
|
GEM
|
2
2
|
remote: http://rubygems.org/
|
3
3
|
specs:
|
4
|
-
|
4
|
+
activemodel (3.0.9)
|
5
|
+
activesupport (= 3.0.9)
|
6
|
+
builder (~> 2.1.2)
|
7
|
+
i18n (~> 0.5.0)
|
8
|
+
activesupport (3.0.9)
|
9
|
+
bson (1.3.1)
|
10
|
+
builder (2.1.2)
|
11
|
+
diff-lcs (1.1.2)
|
12
|
+
geoip (1.0.0)
|
5
13
|
git (1.2.5)
|
6
|
-
|
14
|
+
i18n (0.5.0)
|
15
|
+
jeweler (1.5.2)
|
7
16
|
bundler (~> 1.0.0)
|
8
17
|
git (>= 1.2.5)
|
9
18
|
rake
|
19
|
+
mongo (1.3.1)
|
20
|
+
bson (>= 1.3.1)
|
21
|
+
mongoid (2.1.2)
|
22
|
+
activemodel (~> 3.0)
|
23
|
+
mongo (~> 1.3)
|
24
|
+
tzinfo (~> 0.3.22)
|
10
25
|
polyglot (0.3.1)
|
11
|
-
rainbow (1.1)
|
12
|
-
rake (0.
|
26
|
+
rainbow (1.1.1)
|
27
|
+
rake (0.9.2)
|
13
28
|
rcov (0.9.9)
|
29
|
+
rspec (2.5.0)
|
30
|
+
rspec-core (~> 2.5.0)
|
31
|
+
rspec-expectations (~> 2.5.0)
|
32
|
+
rspec-mocks (~> 2.5.0)
|
33
|
+
rspec-core (2.5.1)
|
34
|
+
rspec-expectations (2.5.0)
|
35
|
+
diff-lcs (~> 1.1.2)
|
36
|
+
rspec-mocks (2.5.0)
|
37
|
+
sequel (3.25.0)
|
14
38
|
shoulda (2.11.3)
|
39
|
+
sqlite3 (1.3.4)
|
40
|
+
sqlite3-ruby (1.3.3)
|
41
|
+
sqlite3 (>= 1.3.3)
|
15
42
|
treetop (1.4.9)
|
16
43
|
polyglot (>= 0.3.1)
|
44
|
+
tzinfo (0.3.29)
|
17
45
|
user-agent (1.0.0)
|
18
46
|
|
19
47
|
PLATFORMS
|
@@ -23,8 +51,13 @@ DEPENDENCIES
|
|
23
51
|
bundler (~> 1.0.0)
|
24
52
|
geoip
|
25
53
|
jeweler (~> 1.5.1)
|
54
|
+
mongoid
|
26
55
|
rainbow
|
56
|
+
rake (>= 0.9.2)
|
27
57
|
rcov
|
58
|
+
rspec (>= 2.5)
|
59
|
+
sequel
|
28
60
|
shoulda
|
61
|
+
sqlite3-ruby
|
29
62
|
treetop (~> 1.4.9)
|
30
63
|
user-agent
|
data/README.md
ADDED
@@ -0,0 +1,158 @@
|
|
1
|
+
ntail
|
2
|
+
=====
|
3
|
+
|
4
|
+
A `tail(1)`-like utility for nginx log files that supports parsing, filtering and formatting of individual
|
5
|
+
log lines (in nginx's so-called ["combined" log format](http://wiki.nginx.org/NginxHttpLogModule#log_format)).
|
6
|
+
|
7
|
+
<a name="intro"/>
|
8
|
+
|
9
|
+
Check it out, yo!
|
10
|
+
-----------------
|
11
|
+
|
12
|
+
Instead of this...
|
13
|
+
|
14
|
+
<pre style="background-color: black; color: white; padding: 15px; width: 1100px; overflow: hidden; text-overflow: ellipsis;">
|
15
|
+
<span style="color:white;">$ tail -f /var/log/nginx/access.log</span>
|
16
|
+
<span style="color: green;">192.0.32.10 - - [21/Jan/2011:14:07:34 +0000] "GET / HTTP/1.1" 200 3700 "-" "Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.237 Safari/534.10" "-"</span>
|
17
|
+
<span style="color: green;">192.0.32.10 - - [21/Jan/2011:14:07:34 +0000] "GET /nginx-logo.png HTTP/1.1" 200 370 "http://localhost/" "Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.237 Safari/534.10" "-"</span>
|
18
|
+
<span style="color: green;">192.0.32.10 - - [21/Jan/2011:14:07:34 +0000] "GET /poweredby.png HTTP/1.1" 200 3034 "http://localhost/" "Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.237 Safari/534.10" "-"</span>
|
19
|
+
<span style="color: green;">192.0.32.10 - - [21/Jan/2011:14:07:34 +0000] "GET /favicon.ico HTTP/1.1" 404 3650 "-" "Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.237 Safari/534.10" "-"</span>
|
20
|
+
<span style="color: green;">192.0.32.10 - - [21/Jan/2011:14:19:04 +0000] "GET /nginx-logo.png HTTP/1.1" 304 0 "-" "Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.237 Safari/534.10" "-"</span>
|
21
|
+
<span style="color:white;">$ _</span>
|
22
|
+
</pre>
|
23
|
+
|
24
|
+
... you get this:
|
25
|
+
|
26
|
+
<pre style="background-color: black; padding: 15px; width: 800px;">
|
27
|
+
<span style="color:white;">$ tail -f /var/log/nginx/access.log <strong>| ntail</strong></span>
|
28
|
+
<span style="color: green;">2011-01-21 14:07:34 - 192.0.32.10 - 200 - GET / - (Chrome, Linux) - -</span>
|
29
|
+
<span style="color: green;">2011-01-21 14:07:34 - 192.0.32.10 - 200 - GET /nginx-logo.png - (Chrome, Linux) - localhost</span>
|
30
|
+
<span style="color: green;">2011-01-21 14:07:34 - 192.0.32.10 - 200 - GET /spanoweredby.png - (Chrome, Linux) - localhost</span>
|
31
|
+
<span style="color: red;">2011-01-21 14:07:34 - 192.0.32.10 - 404 - GET /favicon.ico - (Chrome, Linux) - -</span>
|
32
|
+
<span style="color: orange;">2011-01-21 14:19:04 - 192.0.32.10 - 304 - GET /nginx-logo.png - (Chrome, Linux) - -</span>
|
33
|
+
<span style="color:white;">$ _</span>
|
34
|
+
</pre>
|
35
|
+
|
36
|
+
<a name="installation"/>
|
37
|
+
|
38
|
+
Installation
|
39
|
+
------------
|
40
|
+
|
41
|
+
Installing the gem also installs the `ntail` executable, typically as `/usr/bin/ntail` or `/usr/local/bin/ntail`:
|
42
|
+
|
43
|
+
$ gem install ntail
|
44
|
+
|
45
|
+
To ensure easy execution of the `ntail` script, add the actual installation directory to your shell's `$PATH` variable.
|
46
|
+
|
47
|
+
<a name="basic"/>
|
48
|
+
|
49
|
+
Basic Usage
|
50
|
+
-----------
|
51
|
+
|
52
|
+
* process an entire nginx log file and print each parsed and formatted line to STDOUT
|
53
|
+
|
54
|
+
$ ntail /var/log/nginx/access.log
|
55
|
+
|
56
|
+
* tail an "active" nginx log file and print each new line to STDOUT _(stop with ^C)_
|
57
|
+
|
58
|
+
$ tail -f /var/log/nginx/access.log | ntail
|
59
|
+
|
60
|
+
<a name="advanced"/>
|
61
|
+
|
62
|
+
Advanced Examples
|
63
|
+
-----------------
|
64
|
+
|
65
|
+
* read from STDIN and print each line to STDOUT _(stop with ^D)_
|
66
|
+
|
67
|
+
$ ntail
|
68
|
+
|
69
|
+
* read from STDIN and print out the length of each line _(to illustrate -e option)_
|
70
|
+
|
71
|
+
$ ntail -e 'puts size'
|
72
|
+
|
73
|
+
* read from STDIN but only print out non-empty lines _(to illustrate -f option)_
|
74
|
+
|
75
|
+
$ ntail -f 'size != 0'
|
76
|
+
|
77
|
+
* the following invocations behave exactly the same _(to illustrate -e and -f options)_
|
78
|
+
|
79
|
+
$ ntail
|
80
|
+
$ ntail -f 'true' -e 'puts self'
|
81
|
+
|
82
|
+
* print out all HTTP requests that are coming from a given IP address
|
83
|
+
|
84
|
+
$ ntail -f 'remote_address == "208.67.222.222"' /var/log/nginx/access.log
|
85
|
+
|
86
|
+
* find all HTTP requests that resulted in a '5xx' HTTP error/status code _(e.g. Rails 500 errors)_
|
87
|
+
|
88
|
+
$ gunzip -S .gz -c access.log-20101216.gz | ntail -f 'server_error_status?'
|
89
|
+
|
90
|
+
* generate a summary report of HTTP status codes, for all non-200 HTTP requests
|
91
|
+
|
92
|
+
$ ntail -f 'status != "200"' -e 'puts status' access.log | sort | uniq -c
|
93
|
+
76 301
|
94
|
+
16 302
|
95
|
+
2 304
|
96
|
+
1 406
|
97
|
+
|
98
|
+
* print out GeoIP country and city information for each HTTP request _(depends on the optional `geoip` gem)_
|
99
|
+
|
100
|
+
$ ntail -e 'puts [to_country_s, to_city_s].join("\t")' /var/log/nginx/access.log
|
101
|
+
United States Los Angeles
|
102
|
+
United States Houston
|
103
|
+
Germany Berlin
|
104
|
+
United Kingdom London
|
105
|
+
|
106
|
+
* print out the IP address and the corresponding host name for each HTTP request _(slows things down considerably, due to `nslookup` call)_
|
107
|
+
|
108
|
+
$ ntail -e 'puts [remote_address, to_host_s].join("\t")' /var/log/nginx/access.log
|
109
|
+
66.249.72.196 crawl-66-249-72-196.googlebot.com
|
110
|
+
67.192.120.134 s402.pingdom.com
|
111
|
+
75.31.109.144 adsl-75-31-109-144.dsl.irvnca.sbcglobal.net
|
112
|
+
|
113
|
+
* parse an access log file, and pipe its raw output (indirectly - via the `parsed.log` file) into the `gltail` realtime logfile visualizer
|
114
|
+
|
115
|
+
$ ntail -v --raw --sleep 0.1 /var/log/nginx/access.log > parsed.log
|
116
|
+
|
117
|
+
<a name="todo"/>
|
118
|
+
|
119
|
+
TODO
|
120
|
+
----
|
121
|
+
|
122
|
+
* implement a native `"-f"` option for ntail, similar to that of `tail(1)`, using e.g. flori's [file-tail gem](https://github.com/flori/file-tail)
|
123
|
+
* implement a `"-i"` option ("ignore exceptions"/"continue processing"), if handling a single line raises an exception
|
124
|
+
* or indeed a reverse `"-r"` option ("re-raise exception"), to immediately stop processing and raising the exception for investigation
|
125
|
+
* implement (better) support for custom nginx log formats, in addition to [nginx's default "combined" log format](http://wiki.nginx.org/NginxHttpLogModule#log_format).
|
126
|
+
|
127
|
+
<a name="acknowledgements"/>
|
128
|
+
|
129
|
+
Acknowledgements
|
130
|
+
----------------
|
131
|
+
|
132
|
+
* ntail's parsing feature is inspired by an nginx log parser written by [Richard Taylor (moomerman)](https://github.com/moomerman)
|
133
|
+
* parsing and expanding ntail's formatting string is done using nathansobo's quite brilliant [treetop gem](https://github.com/nathansobo/treetop)
|
134
|
+
* ntail's raw line output is compatible with Fudge's fun and useful [gltail gem](https://github.com/Fudge/gltail)
|
135
|
+
* Kudos to [Ed James (edjames)](https://github.com/edjames) for recommending the use of [instance_eval][eval] to clean up the DSL
|
136
|
+
|
137
|
+
[eval]: https://github.com/pvdb/ntail/commit/b0f40522012b9858c433808cd1f5c21cb455fadd "use instance_eval to simplify the DSL"
|
138
|
+
|
139
|
+
<a name="contributing"/>
|
140
|
+
|
141
|
+
Contributing to ntail
|
142
|
+
---------------------
|
143
|
+
|
144
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
145
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
146
|
+
* Fork the project
|
147
|
+
* Start a feature/bugfix branch
|
148
|
+
* Commit and push until you are happy with your contribution
|
149
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
150
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
151
|
+
|
152
|
+
<a name="copyright"/>
|
153
|
+
|
154
|
+
Copyright
|
155
|
+
---------
|
156
|
+
|
157
|
+
Copyright (c) 2011 Peter Vandenberk. See LICENSE.txt for further details.
|
158
|
+
|
data/Rakefile
CHANGED
@@ -26,6 +26,16 @@ Jeweler::Tasks.new do |gem|
|
|
26
26
|
end
|
27
27
|
Jeweler::RubygemsDotOrgTasks.new
|
28
28
|
|
29
|
+
require 'rake/rdoctask'
|
30
|
+
Rake::RDocTask.new do |rdoc|
|
31
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
32
|
+
|
33
|
+
rdoc.rdoc_dir = 'rdoc'
|
34
|
+
rdoc.title = "ntail #{version}"
|
35
|
+
rdoc.rdoc_files.include('README*')
|
36
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
37
|
+
end
|
38
|
+
|
29
39
|
require 'rake/testtask'
|
30
40
|
Rake::TestTask.new(:test) do |test|
|
31
41
|
test.libs << 'lib' << 'test'
|
@@ -33,21 +43,24 @@ Rake::TestTask.new(:test) do |test|
|
|
33
43
|
test.verbose = true
|
34
44
|
end
|
35
45
|
|
46
|
+
require 'rspec/core/rake_task'
|
47
|
+
RSpec::Core::RakeTask.new(:spec) do |test|
|
48
|
+
test.verbose = true
|
49
|
+
end
|
50
|
+
|
36
51
|
require 'rcov/rcovtask'
|
37
|
-
Rcov::RcovTask.new do |test|
|
52
|
+
Rcov::RcovTask.new(:test_rcov) do |test|
|
38
53
|
test.libs << 'test'
|
39
54
|
test.pattern = 'test/**/test_*.rb'
|
55
|
+
test.rcov_opts = %w{--exclude test\/,spec\/ -T}
|
56
|
+
test.verbose = true
|
57
|
+
end
|
58
|
+
Rcov::RcovTask.new(:spec_rcov) do |test|
|
59
|
+
test.libs << 'spec'
|
60
|
+
test.pattern = 'spec/**/*_spec.rb'
|
61
|
+
test.rcov_opts = %w{--exclude test\/,spec\/ -T}
|
40
62
|
test.verbose = true
|
41
63
|
end
|
42
64
|
|
43
|
-
task :default => :test
|
44
|
-
|
45
|
-
require 'rake/rdoctask'
|
46
|
-
Rake::RDocTask.new do |rdoc|
|
47
|
-
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
65
|
+
task :default => [:test, :spec]
|
48
66
|
|
49
|
-
rdoc.rdoc_dir = 'rdoc'
|
50
|
-
rdoc.title = "ntail #{version}"
|
51
|
-
rdoc.rdoc_files.include('README*')
|
52
|
-
rdoc.rdoc_files.include('lib/**/*.rb')
|
53
|
-
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.12
|
data/bin/ntail
CHANGED
data/lib/ntail/application.rb
CHANGED
@@ -3,145 +3,122 @@ require 'optparse'
|
|
3
3
|
|
4
4
|
module NginxTail
|
5
5
|
class Application
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
self.options.dry_run = true
|
23
|
-
}
|
24
|
-
],
|
25
|
-
['--parse-only', '-p', "Parse only: parse all lines, but don't actually process them",
|
26
|
-
lambda { |value|
|
27
|
-
self.options.parse_only = true
|
28
|
-
}
|
29
|
-
],
|
30
|
-
['--version', '-V', "Display the program version.",
|
31
|
-
lambda { |value|
|
32
|
-
puts "#{NTAIL_NAME}, version #{NTAIL_VERSION}"
|
33
|
-
self.options.running = false
|
34
|
-
}
|
35
|
-
],
|
36
|
-
['--line-number', '-l LINE_NUMBER', "Only process the line with the given line number",
|
37
|
-
lambda { |value|
|
38
|
-
self.options.line_number = value.to_i
|
39
|
-
}
|
40
|
-
],
|
41
|
-
['--filter', '-f CODE', "Ruby code block for filtering (parsed) lines - needs to return true or false.",
|
42
|
-
lambda { |value|
|
43
|
-
self.options.filter = eval "Proc.new #{value}"
|
44
|
-
}
|
45
|
-
],
|
46
|
-
['--execute', '-e CODE', "Ruby code block for processing each (parsed) line.",
|
47
|
-
lambda { |value|
|
48
|
-
self.options.code = eval "Proc.new #{value}"
|
49
|
-
}
|
50
|
-
],
|
51
|
-
]
|
6
|
+
|
7
|
+
include NginxTail::Options
|
8
|
+
|
9
|
+
# default application options...
|
10
|
+
DEFAULT_OPTIONS = {
|
11
|
+
:interrupted => false,
|
12
|
+
:running => true,
|
13
|
+
:nginx => true,
|
14
|
+
:exit => 0,
|
15
|
+
}
|
16
|
+
|
17
|
+
# parsed application options...
|
18
|
+
@options = nil
|
19
|
+
|
20
|
+
def respond_to?(symbol, include_private = false)
|
21
|
+
@options.respond_to?(symbol) || super
|
52
22
|
end
|
53
23
|
|
54
|
-
def
|
55
|
-
|
56
|
-
|
57
|
-
self.options.interrupted = false
|
58
|
-
self.options.running = true
|
59
|
-
self.options.exit = 0
|
60
|
-
|
61
|
-
OptionParser.new do |opts|
|
62
|
-
opts.banner = "ntail {options} {file(s)} ..."
|
63
|
-
opts.separator ""
|
64
|
-
opts.separator "Options are ..."
|
65
|
-
|
66
|
-
opts.on_tail("-h", "--help", "-H", "Display this help message.") do
|
67
|
-
puts opts
|
68
|
-
self.options.running = false
|
69
|
-
end
|
24
|
+
def method_missing(methodId)
|
25
|
+
respond_to?(methodId) ? @options.send(methodId.to_sym) : super
|
26
|
+
end
|
70
27
|
|
71
|
-
|
72
|
-
|
28
|
+
def initialize(argv = [])
|
29
|
+
@options = parse_options(argv, DEFAULT_OPTIONS)
|
73
30
|
end
|
74
|
-
|
75
|
-
def
|
76
|
-
|
77
|
-
|
78
|
-
|
31
|
+
|
32
|
+
def run!
|
33
|
+
|
34
|
+
LogLine.set_log_pattern(@options.nginx)
|
35
|
+
|
79
36
|
['TERM', 'INT'].each do |signal|
|
80
37
|
Signal.trap(signal) do
|
81
|
-
|
38
|
+
@options.running = false ; @options.interrupted = true
|
82
39
|
$stdin.close if ARGF.file == $stdin # ie. reading from STDIN
|
83
40
|
end
|
84
41
|
end
|
85
|
-
|
42
|
+
|
86
43
|
files_read = lines_read = lines_processed = lines_ignored = parsable_lines = unparsable_lines = 0
|
87
|
-
|
88
|
-
|
44
|
+
|
45
|
+
current_filename = nil ; current_line_number = 0 ; file_count = ARGV.count
|
46
|
+
|
47
|
+
while @options.running and ARGF.gets
|
89
48
|
if ARGF.file.lineno == 1
|
49
|
+
current_filename = ARGF.filename ; current_line_number = 0
|
90
50
|
files_read += 1
|
91
|
-
if
|
51
|
+
if @options.verbose
|
92
52
|
$stderr.puts "[INFO] now processing file #{ARGF.filename}"
|
93
53
|
end
|
94
54
|
end
|
95
|
-
raw_line = $_.chomp ; lines_read += 1
|
96
|
-
unless
|
97
|
-
if
|
55
|
+
raw_line = $_.chomp ; lines_read += 1 ; current_line_number += 1
|
56
|
+
unless @options.dry_run
|
57
|
+
if !@options.line_number or @options.line_number == ARGF.lineno
|
98
58
|
begin
|
99
|
-
log_line = NginxTail::LogLine.new(raw_line)
|
59
|
+
log_line = NginxTail::LogLine.new(raw_line, current_filename, current_line_number)
|
100
60
|
if log_line.parsable
|
101
61
|
parsable_lines += 1
|
102
|
-
unless
|
103
|
-
if
|
62
|
+
unless @options.parse_only
|
63
|
+
if !@options.filter || log_line.instance_eval(@options.filter)
|
104
64
|
lines_processed += 1
|
105
|
-
if
|
106
|
-
|
65
|
+
if @options.code
|
66
|
+
log_line.instance_eval(@options.code)
|
67
|
+
elsif @options.raw
|
68
|
+
$stdout.puts raw_line
|
69
|
+
sleep @options.sleep if @options.sleep
|
107
70
|
else
|
108
|
-
puts log_line
|
71
|
+
puts log_line.to_s(:color => true)
|
109
72
|
end
|
110
73
|
else
|
111
74
|
lines_ignored += 1
|
112
|
-
if
|
75
|
+
if @options.verbose
|
113
76
|
$stderr.puts "[WARNING] ignoring line ##{lines_read}"
|
114
77
|
end
|
115
78
|
end
|
116
79
|
end
|
117
80
|
else
|
118
81
|
unparsable_lines += 1
|
119
|
-
if
|
82
|
+
if @options.verbose
|
120
83
|
$stderr.puts "[ERROR] cannot parse '#{raw_line}'"
|
121
84
|
end
|
122
85
|
end
|
123
86
|
rescue
|
124
87
|
$stderr.puts "[ERROR] processing line #{ARGF.file.lineno} of file #{ARGF.filename} resulted in #{$!.message}"
|
125
88
|
$stderr.puts "[ERROR] " + raw_line
|
126
|
-
|
127
|
-
|
89
|
+
@options.exit = -1
|
90
|
+
@options.running = false
|
128
91
|
raise $! # TODO if the "re-raise exceptions" option has been set...
|
129
92
|
end
|
130
93
|
end
|
131
94
|
end
|
95
|
+
if @options.progress
|
96
|
+
progress_line = [
|
97
|
+
" Processing file ".inverse + (" %d/%d" % [files_read, file_count]),
|
98
|
+
" Current filename ".inverse + " " + current_filename.to_s,
|
99
|
+
" Line number ".inverse + " " + current_line_number.to_s,
|
100
|
+
" Lines processed ".inverse + " " + lines_read.to_s
|
101
|
+
].join(" \342\200\242 ")
|
102
|
+
max_length = [max_length || 0, progress_line.size].max
|
103
|
+
$stderr.print progress_line
|
104
|
+
$stderr.print " " * (max_length - progress_line.size)
|
105
|
+
$stderr.print "\r"
|
106
|
+
end
|
132
107
|
end
|
133
|
-
|
134
|
-
if
|
135
|
-
|
136
|
-
|
137
|
-
$stderr.
|
108
|
+
|
109
|
+
$stderr.puts if @options.progress
|
110
|
+
|
111
|
+
if @options.verbose
|
112
|
+
$stderr.puts if @options.interrupted
|
113
|
+
$stderr.print "[INFO] read #{lines_read} line(s) in #{files_read} file(s)"
|
114
|
+
$stderr.print " (interrupted)" if @options.interrupted ; $stderr.puts
|
138
115
|
$stderr.puts "[INFO] #{parsable_lines} parsable lines, #{unparsable_lines} unparsable lines"
|
139
116
|
$stderr.puts "[INFO] processed #{lines_processed} lines, ignored #{lines_ignored} lines"
|
140
117
|
end
|
141
|
-
|
142
|
-
return
|
143
|
-
|
144
|
-
end
|
145
|
-
|
118
|
+
|
119
|
+
return @options.exit
|
120
|
+
|
121
|
+
end
|
122
|
+
|
146
123
|
end
|
147
124
|
end
|
@@ -5,10 +5,10 @@ module NginxTail
|
|
5
5
|
base.class_eval do
|
6
6
|
|
7
7
|
# this ensures the below module methods actually make sense...
|
8
|
-
raise "Class #{base.name} should implement instance method 'body_bytes_sent'" unless base.instance_methods.include? 'body_bytes_sent'
|
8
|
+
raise "Class #{base.name} should implement instance method 'body_bytes_sent'" unless base.instance_methods.map(&:to_s).include? 'body_bytes_sent'
|
9
9
|
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
13
|
end
|
14
|
-
end
|
14
|
+
end
|