clarity 0.9.2 → 0.9.5
Sign up to get free protection for your applications and to get access to all the features.
- data/Manifest.txt +1 -3
- data/README.rdoc +1 -1
- data/Rakefile +8 -14
- data/lib/clarity.rb +1 -1
- data/lib/clarity/cli.rb +15 -6
- data/lib/clarity/grep_renderer.rb +17 -17
- data/lib/clarity/process_tree.rb +23 -0
- data/lib/clarity/renderers/log_renderer.rb +22 -33
- data/lib/clarity/server.rb +11 -27
- data/lib/clarity/server/chunk_http.rb +2 -0
- data/test/commands/command_builder_test.rb +10 -11
- data/test/commands/tail_command_builder_test.rb +1 -2
- data/test/parsers/hostname_parser_test.rb +1 -2
- data/test/parsers/shop_parser_test.rb +1 -2
- data/test/parsers/time_parser_test.rb +1 -2
- data/test/test_helper.rb +3 -2
- data/test/test_string_scanner.rb +1 -2
- data/views/_toolbar.html.erb +3 -3
- metadata +8 -7
- data/lib/clarity/parsers/hostname_parser.rb +0 -43
- data/lib/clarity/parsers/shop_parser.rb +0 -48
- data/lib/clarity/parsers/time_parser.rb +0 -93
data/Manifest.txt
CHANGED
@@ -10,9 +10,7 @@ lib/clarity/cli.rb
|
|
10
10
|
lib/clarity/commands/command_builder.rb
|
11
11
|
lib/clarity/commands/tail_command_builder.rb
|
12
12
|
lib/clarity/grep_renderer.rb
|
13
|
-
lib/clarity/
|
14
|
-
lib/clarity/parsers/shop_parser.rb
|
15
|
-
lib/clarity/parsers/time_parser.rb
|
13
|
+
lib/clarity/process_tree.rb
|
16
14
|
lib/clarity/renderers/log_renderer.rb
|
17
15
|
lib/clarity/server.rb
|
18
16
|
lib/clarity/server/basic_auth.rb
|
data/README.rdoc
CHANGED
data/Rakefile
CHANGED
@@ -1,27 +1,21 @@
|
|
1
|
+
$LOAD_PATH.unshift File.join(File.dirname(__FILE__), "lib")
|
2
|
+
|
1
3
|
require 'rubygems'
|
2
4
|
gem 'hoe', '>= 2.1.0'
|
5
|
+
gem 'newgem'
|
6
|
+
|
3
7
|
require 'hoe'
|
4
|
-
require '
|
5
|
-
require './lib/clarity'
|
8
|
+
require 'clarity'
|
6
9
|
|
7
10
|
Hoe.plugin :newgem
|
8
|
-
# Hoe.plugin :website
|
9
|
-
# Hoe.plugin :cucumberfeatures
|
10
11
|
|
11
|
-
# Generate all the Rake tasks
|
12
|
-
# Run 'rake -T' to see list of generated tasks (from gem root directory)
|
13
12
|
$hoe = Hoe.spec 'clarity' do
|
14
13
|
self.developer 'Tobias Lütke', 'tobi@shopify.com'
|
15
14
|
self.developer 'John Tajima', 'john@shopify.com'
|
16
|
-
self.post_install_message = 'PostInstall.txt'
|
17
|
-
# self.rubyforge_name = self.name # TODO this is default value
|
18
|
-
|
15
|
+
self.post_install_message = 'PostInstall.txt'
|
19
16
|
self.extra_deps = [['eventmachine','>= 0.12.10'], ['eventmachine_httpserver','>= 0.2.0']]
|
17
|
+
self.test_globs = ['test/**/*_test.rb']
|
20
18
|
end
|
21
19
|
|
22
20
|
require 'newgem/tasks'
|
23
|
-
Dir['tasks/**/*.rake'].each { |t| load t }
|
24
|
-
|
25
|
-
# TODO - want other tests/tasks run by default? Add them to the list
|
26
|
-
# remove_task :default
|
27
|
-
# task :default => [:spec, :features]
|
21
|
+
Dir['tasks/**/*.rake'].each { |t| load t }
|
data/lib/clarity.rb
CHANGED
data/lib/clarity/cli.rb
CHANGED
@@ -1,6 +1,4 @@
|
|
1
1
|
require 'optparse'
|
2
|
-
#require File.dirname(__FILE__) + '/../clarity'
|
3
|
-
|
4
2
|
|
5
3
|
module Clarity
|
6
4
|
class CLI
|
@@ -9,9 +7,11 @@ module Clarity
|
|
9
7
|
options = {
|
10
8
|
:username => nil,
|
11
9
|
:password => nil,
|
12
|
-
:log_files =>
|
10
|
+
:log_files => nil,
|
13
11
|
:port => 8080,
|
14
|
-
:address => "0.0.0.0"
|
12
|
+
:address => "0.0.0.0",
|
13
|
+
:user => nil,
|
14
|
+
:group => nil
|
15
15
|
}
|
16
16
|
|
17
17
|
mandatory_options = %w( )
|
@@ -23,7 +23,10 @@ module Clarity
|
|
23
23
|
opts.separator "Specific options:"
|
24
24
|
|
25
25
|
opts.on( "-f", "--config=FILE", String, "Config file (yml)" ) do |opt|
|
26
|
-
|
26
|
+
config = YAML.load_file( opt )
|
27
|
+
config.keys.each do |key|
|
28
|
+
options[key.to_sym] = config[key]
|
29
|
+
end
|
27
30
|
end
|
28
31
|
|
29
32
|
opts.on( "-p", "--port=PORT", Integer, "Port to listen on" ) do |opt|
|
@@ -38,7 +41,11 @@ module Clarity
|
|
38
41
|
options[:log_files] ||= []
|
39
42
|
options[:log_files] += opt
|
40
43
|
end
|
41
|
-
|
44
|
+
|
45
|
+
opts.on( "--user=USER", String, "User to run as" ) do |opt|
|
46
|
+
options[:user] = opt
|
47
|
+
end
|
48
|
+
|
42
49
|
opts.separator " "
|
43
50
|
opts.separator "Password protection:"
|
44
51
|
|
@@ -67,6 +74,8 @@ module Clarity
|
|
67
74
|
Dir.chdir(arguments.first)
|
68
75
|
end
|
69
76
|
|
77
|
+
options[:log_files] ||= ['**/*.log*']
|
78
|
+
|
70
79
|
::Clarity::Server.run(options)
|
71
80
|
|
72
81
|
#rescue
|
@@ -1,10 +1,7 @@
|
|
1
1
|
module Clarity
|
2
|
-
module GrepRenderer
|
3
|
-
attr_accessor :response
|
4
|
-
|
5
|
-
def parser
|
6
|
-
@parser ||= TimeParser.new( HostnameParser.new(ShopParser.new), params)
|
7
|
-
end
|
2
|
+
module GrepRenderer
|
3
|
+
attr_accessor :response
|
4
|
+
attr_writer :renderer
|
8
5
|
|
9
6
|
def renderer
|
10
7
|
@renderer ||= LogRenderer.new
|
@@ -15,22 +12,25 @@ module Clarity
|
|
15
12
|
@buffer ||= StringScanner.new("")
|
16
13
|
@buffer << data
|
17
14
|
|
18
|
-
html = ""
|
19
15
|
while line = @buffer.scan_until(/\n/)
|
20
|
-
|
21
|
-
|
22
|
-
end
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
response.chunk html
|
16
|
+
response.chunk renderer.render(line)
|
17
|
+
flush
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def flush
|
27
22
|
response.send_chunks
|
28
23
|
end
|
24
|
+
|
25
|
+
def close
|
26
|
+
ProcessTree.kill(get_status.pid)
|
27
|
+
end
|
29
28
|
|
30
|
-
def unbind
|
31
|
-
response.chunk
|
29
|
+
def unbind
|
30
|
+
response.chunk renderer.finalize
|
32
31
|
response.chunk ''
|
33
|
-
|
32
|
+
close
|
33
|
+
flush
|
34
34
|
puts 'Done'
|
35
35
|
end
|
36
36
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module ProcessTree
|
2
|
+
|
3
|
+
def self.kill(ppid)
|
4
|
+
return if ppid.nil?
|
5
|
+
all_pids = [ppid] + child_pids_of(ppid).flatten.uniq.compact
|
6
|
+
all_pids.each do |pid|
|
7
|
+
Process.kill('TERM',pid.to_i) rescue nil
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.child_pids_of(ppid)
|
12
|
+
out = `ps -opid,ppid | grep #{ppid.to_s}`
|
13
|
+
ids = out.split("\n").map {|line| $1 if line =~ /^\s*([0-9]+)\s.*/ }.compact
|
14
|
+
ids.delete(ppid.to_s)
|
15
|
+
if ids.empty?
|
16
|
+
ids
|
17
|
+
else
|
18
|
+
ids << ids.map {|id| child_pids_of(id) }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
end
|
@@ -1,47 +1,36 @@
|
|
1
|
-
require 'action_view'
|
2
1
|
require 'uri'
|
2
|
+
require 'erb'
|
3
3
|
|
4
|
-
class LogRenderer
|
5
|
-
include ActionView::Helpers::TagHelper
|
6
|
-
include ActionView::Helpers::UrlHelper
|
4
|
+
class LogRenderer
|
7
5
|
|
6
|
+
# Thank you to http://daringfireball.net/2009/11/liberal_regex_for_matching_urls
|
7
|
+
#
|
8
|
+
UrlParser = %r{\b(([\w-]+://?|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))}
|
8
9
|
Prefix = ""
|
9
10
|
Suffix = "<br/>\n"
|
10
|
-
TagOrder = [ :timestamp, :shop, :labels, :line ]
|
11
|
-
MarkTime = 60 * 5 # 5 minutes
|
12
|
-
|
13
|
-
def initialize()
|
14
|
-
@last_timestamp = nil
|
15
|
-
end
|
16
|
-
|
17
|
-
def render(elements = {})
|
18
|
-
@elements = elements
|
19
|
-
@tags = []
|
20
|
-
TagOrder.each do |tag|
|
21
|
-
if content = @elements.fetch(tag, nil)
|
22
|
-
method = ("tag_"+tag.to_s).to_sym
|
23
|
-
@tags << self.send(method, content)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
@tags.empty? ? "" : Prefix + @tags.join(" ").to_s + Suffix
|
28
|
-
end
|
29
11
|
|
12
|
+
def render(line = {})
|
13
|
+
# Escape
|
14
|
+
output = ERB::Util.h(line)
|
30
15
|
|
31
|
-
|
32
|
-
|
16
|
+
# Transform urls into html links
|
17
|
+
output.gsub!(UrlParser) do |match|
|
18
|
+
html_link(match)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Return with formatting
|
22
|
+
"#{Prefix}#{output}#{Suffix}"
|
33
23
|
end
|
34
24
|
|
35
|
-
def
|
36
|
-
|
25
|
+
def finalize
|
26
|
+
'</div><hr><p id="done">Done</p></body></html>'
|
37
27
|
end
|
38
28
|
|
39
|
-
|
40
|
-
|
29
|
+
private
|
30
|
+
|
31
|
+
def html_link(url)
|
32
|
+
uri = URI.parse(url)
|
33
|
+
"<a href='#{uri}'>#{url}</a>"
|
41
34
|
end
|
42
35
|
|
43
|
-
def tag_labels(content, options = {})
|
44
|
-
"[#{content}]"
|
45
|
-
end
|
46
|
-
|
47
36
|
end
|
data/lib/clarity/server.rb
CHANGED
@@ -3,6 +3,7 @@ require File.dirname(__FILE__) + '/server/basic_auth'
|
|
3
3
|
require File.dirname(__FILE__) + '/server/mime_types'
|
4
4
|
require File.dirname(__FILE__) + '/server/chunk_http'
|
5
5
|
require File.dirname(__FILE__) + '/grep_renderer'
|
6
|
+
require File.dirname(__FILE__) + '/process_tree'
|
6
7
|
|
7
8
|
module Clarity
|
8
9
|
class NotFoundError < StandardError; end
|
@@ -18,6 +19,7 @@ module Clarity
|
|
18
19
|
attr_accessor :log_files
|
19
20
|
|
20
21
|
def self.run(options)
|
22
|
+
|
21
23
|
EventMachine::run do
|
22
24
|
EventMachine.epoll
|
23
25
|
EventMachine::start_server(options[:address], options[:port], self) do |a|
|
@@ -25,7 +27,14 @@ module Clarity
|
|
25
27
|
a.required_username = options[:username]
|
26
28
|
a.required_password = options[:password]
|
27
29
|
end
|
30
|
+
|
28
31
|
STDERR.puts "Listening #{options[:address]}:#{options[:port]}..."
|
32
|
+
|
33
|
+
if options[:user]
|
34
|
+
STDERR.puts "Running as user #{options[:user]}"
|
35
|
+
EventMachine.set_effective_user(options[:user])
|
36
|
+
end
|
37
|
+
|
29
38
|
STDERR.puts "Adding log files: #{options[:log_files].inspect}"
|
30
39
|
end
|
31
40
|
end
|
@@ -54,10 +63,9 @@ module Clarity
|
|
54
63
|
response.chunk results_page # display page header
|
55
64
|
|
56
65
|
puts "Running: #{command}"
|
66
|
+
|
57
67
|
EventMachine::popen(command, GrepRenderer) do |grepper|
|
58
68
|
@grepper = grepper
|
59
|
-
@grepper.marker = 0
|
60
|
-
@grepper.params = params
|
61
69
|
@grepper.response = response
|
62
70
|
end
|
63
71
|
end
|
@@ -97,34 +105,10 @@ module Clarity
|
|
97
105
|
end
|
98
106
|
|
99
107
|
def unbind
|
100
|
-
|
101
|
-
kill_processes(@grepper.get_status.pid)
|
108
|
+
@grepper.close_connection if @grepper
|
102
109
|
close_connection
|
103
110
|
end
|
104
111
|
|
105
|
-
def kill_processes(ppid)
|
106
|
-
return if ppid.nil?
|
107
|
-
all_pids = [ppid] + get_child_pids(ppid).flatten.uniq.compact
|
108
|
-
puts "=== pids are #{all_pids.inspect}"
|
109
|
-
all_pids.each do |pid|
|
110
|
-
Process.kill('TERM',pid.to_i)
|
111
|
-
puts "=== killing #{pid}"
|
112
|
-
end
|
113
|
-
rescue Exception => e
|
114
|
-
puts "!Error killing processes: #{e}"
|
115
|
-
end
|
116
|
-
|
117
|
-
def get_child_pids(ppid)
|
118
|
-
out = `ps -opid,ppid | grep #{ppid.to_s}`
|
119
|
-
ids = out.split("\n").map {|line| $1 if line =~ /^\s*([0-9]+)\s.*/ }.compact
|
120
|
-
ids.delete(ppid.to_s)
|
121
|
-
if ids.empty?
|
122
|
-
ids
|
123
|
-
else
|
124
|
-
ids << ids.map {|id| get_child_pids(id) }
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
112
|
private
|
129
113
|
|
130
114
|
def authenticate!
|
@@ -1,5 +1,4 @@
|
|
1
|
-
require
|
2
|
-
require File.dirname(__FILE__) + "/../../lib/commands/command_builder.rb"
|
1
|
+
require 'test_helper'
|
3
2
|
|
4
3
|
class CommandBuilderTest < Test::Unit::TestCase
|
5
4
|
|
@@ -29,35 +28,35 @@ class CommandBuilderTest < Test::Unit::TestCase
|
|
29
28
|
def test_exec_functions_for_log
|
30
29
|
command = CommandBuilder.new(@params)
|
31
30
|
assert_equal 1, command.exec_functions.size
|
32
|
-
assert_match
|
31
|
+
assert_match(/^grep/, command.exec_functions.first)
|
33
32
|
end
|
34
33
|
|
35
34
|
def test_exec_functions_with_multiple_terms_for_log
|
36
35
|
command = CommandBuilder.new(@params.merge("term2" => "bar", "term3" => "baz"))
|
37
36
|
assert_equal 3, command.exec_functions.size
|
38
|
-
assert_match
|
39
|
-
assert_match
|
40
|
-
assert_match
|
37
|
+
assert_match(/^grep/, command.exec_functions[0])
|
38
|
+
assert_match(/^grep/, command.exec_functions[1])
|
39
|
+
assert_match(/^grep/, command.exec_functions[2])
|
41
40
|
end
|
42
41
|
|
43
42
|
def test_exec_function_with_no_terms_for_log
|
44
43
|
command = CommandBuilder.new(@params.merge("term1" => nil))
|
45
44
|
assert_equal 1, command.exec_functions.size
|
46
|
-
assert_match
|
45
|
+
assert_match(/^cat/, command.exec_functions[0])
|
47
46
|
end
|
48
47
|
|
49
48
|
def test_exec_funcations_for_gzip
|
50
49
|
command = CommandBuilder.new(@params.merge("file" => "testfile.gz"))
|
51
50
|
assert_equal 1, command.exec_functions.size
|
52
|
-
assert_match
|
51
|
+
assert_match(/^zgrep/, command.exec_functions.first)
|
53
52
|
end
|
54
53
|
|
55
54
|
def test_exec_functions_with_multiple_terms_for_gzip
|
56
55
|
command = CommandBuilder.new(@params.merge("file" => "testfile.gz", "term2" => "bar", "term3" => "baz"))
|
57
56
|
assert_equal 3, command.exec_functions.size
|
58
|
-
assert_match
|
59
|
-
assert_match
|
60
|
-
assert_match
|
57
|
+
assert_match(/^zgrep/, command.exec_functions[0])
|
58
|
+
assert_match(/^grep/, command.exec_functions[1])
|
59
|
+
assert_match(/^grep/, command.exec_functions[2])
|
61
60
|
end
|
62
61
|
|
63
62
|
def test_exec_function_with_no_terms_for_gzip
|
data/test/test_helper.rb
CHANGED
data/test/test_string_scanner.rb
CHANGED
data/views/_toolbar.html.erb
CHANGED
@@ -81,9 +81,9 @@
|
|
81
81
|
</div>
|
82
82
|
|
83
83
|
<script>
|
84
|
-
Search.init({ 'grep': <%= logfiles.map {|f| f }.
|
85
|
-
'tail': <%= logfiles.map {|f| f if f =~ /log$/ }.compact.
|
86
|
-
<%= params.empty? ?
|
84
|
+
Search.init({ 'grep': <%= logfiles.map {|f| f }.inspect %>,
|
85
|
+
'tail': <%= logfiles.map {|f| f if f =~ /log$/ }.compact.inspect %> },
|
86
|
+
<%= params.empty? ? 'null' : params.inspect %> );
|
87
87
|
|
88
88
|
|
89
89
|
</script>
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: clarity
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- "Tobias L\xC3\xBCtke"
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2009-
|
13
|
+
date: 2009-12-04 00:00:00 -05:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -77,9 +77,7 @@ files:
|
|
77
77
|
- lib/clarity/commands/command_builder.rb
|
78
78
|
- lib/clarity/commands/tail_command_builder.rb
|
79
79
|
- lib/clarity/grep_renderer.rb
|
80
|
-
- lib/clarity/
|
81
|
-
- lib/clarity/parsers/shop_parser.rb
|
82
|
-
- lib/clarity/parsers/time_parser.rb
|
80
|
+
- lib/clarity/process_tree.rb
|
83
81
|
- lib/clarity/renderers/log_renderer.rb
|
84
82
|
- lib/clarity/server.rb
|
85
83
|
- lib/clarity/server/basic_auth.rb
|
@@ -133,5 +131,8 @@ signing_key:
|
|
133
131
|
specification_version: 3
|
134
132
|
summary: "Clarity - a log search tool By John Tajima & Tobi L\xC3\xBCtke Clarity is a Splunk like web interface for your server log files"
|
135
133
|
test_files:
|
136
|
-
- test/
|
137
|
-
- test/
|
134
|
+
- test/commands/command_builder_test.rb
|
135
|
+
- test/commands/tail_command_builder_test.rb
|
136
|
+
- test/parsers/hostname_parser_test.rb
|
137
|
+
- test/parsers/shop_parser_test.rb
|
138
|
+
- test/parsers/time_parser_test.rb
|
@@ -1,43 +0,0 @@
|
|
1
|
-
|
2
|
-
class HostnameParser
|
3
|
-
|
4
|
-
# given a string in format:
|
5
|
-
#
|
6
|
-
# app3 rails.shopify[9855]: [wadedemt.myshopify.com] Processing ShopController#products (for 192.168.1.230 at 2009-07-24 14:58:21) [GET]
|
7
|
-
# 129.123.2.1 rails.shopify[9855]: [wadedemt.myshopify.com] Processing ShopController#products (for 192.168.1.230 at 2009-07-24 14:58:21) [GET]
|
8
|
-
#
|
9
|
-
# strips out the hostname/IP and appname
|
10
|
-
#
|
11
|
-
# result => [wadedemt.myshopify.com] Processing ShopController#products (for 192.168.1.230 at 2009-07-24 14:58:21) [GET]
|
12
|
-
|
13
|
-
|
14
|
-
LineRegexp = /^([\w-]+|\d+\.\d+\.\d+\.\d+)\s([^:]*):\s*(.*)/
|
15
|
-
|
16
|
-
attr_accessor :elements, :next_parser
|
17
|
-
|
18
|
-
def initialize(next_renderer = nil)
|
19
|
-
@next_renderer = next_renderer
|
20
|
-
end
|
21
|
-
|
22
|
-
def parse(line, elements = {})
|
23
|
-
@elements = elements
|
24
|
-
# parse line into elements and put into element
|
25
|
-
next_line = parse_line(line)
|
26
|
-
if @next_renderer && next_line
|
27
|
-
@elements = @next_renderer.parse(next_line, @elements)
|
28
|
-
end
|
29
|
-
@elements
|
30
|
-
end
|
31
|
-
|
32
|
-
# parse line and break into pieces
|
33
|
-
def parse_line(line)
|
34
|
-
results = LineRegexp.match(line)
|
35
|
-
if results
|
36
|
-
@elements[:line] = results[-1]
|
37
|
-
results[-1] # remaining line
|
38
|
-
else
|
39
|
-
@elements[:line] = line
|
40
|
-
line
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
@@ -1,48 +0,0 @@
|
|
1
|
-
class ShopParser
|
2
|
-
|
3
|
-
# given a string in format:
|
4
|
-
#
|
5
|
-
# [wadedemt.myshopify.com] Processing ShopController#products (for 192.168.1.230 at 2009-07-24 14:58:21) [GET]
|
6
|
-
#
|
7
|
-
# strips out the shop name
|
8
|
-
#
|
9
|
-
# result => :shop => wadedemt.myshopify.com
|
10
|
-
# :line => Processing ShopController#products (for 192.168.1.230 at 2009-07-24 14:58:21) [GET]
|
11
|
-
|
12
|
-
|
13
|
-
LineRegexp = /^\s*\[([a-zA-Z0-9\-.]+)\]\s*(.*)/
|
14
|
-
|
15
|
-
attr_accessor :elements
|
16
|
-
|
17
|
-
def initialize(next_renderer = nil)
|
18
|
-
@next_renderer = next_renderer
|
19
|
-
end
|
20
|
-
|
21
|
-
def parse(line, elements = {})
|
22
|
-
@elements = elements
|
23
|
-
# parse line into elements and put into element
|
24
|
-
next_line = parse_line(line)
|
25
|
-
if @next_renderer && next_line
|
26
|
-
@elements = @next_renderer.parse(next_line, @elements)
|
27
|
-
end
|
28
|
-
@elements
|
29
|
-
end
|
30
|
-
|
31
|
-
# parse line and break into pieces
|
32
|
-
def parse_line(line)
|
33
|
-
results = LineRegexp.match(line)
|
34
|
-
if results
|
35
|
-
if results[1] =~ /\./
|
36
|
-
@elements[:shop] = results[1]
|
37
|
-
@elements[:line] = results[-1]
|
38
|
-
results[-1]
|
39
|
-
else
|
40
|
-
@elements[:line] = line
|
41
|
-
line
|
42
|
-
end
|
43
|
-
else
|
44
|
-
@elements[:line] = line
|
45
|
-
line
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
@@ -1,93 +0,0 @@
|
|
1
|
-
|
2
|
-
class TimeParser
|
3
|
-
|
4
|
-
# strips out timestamp and if start/end times are defined, will reject lines that don't fall within proper time periods
|
5
|
-
#
|
6
|
-
# entry format:
|
7
|
-
# Jul 24 14:58:21 app3 rails.shopify[9855]: [wadedemt.myshopify.com] Processing ShopController#products (for 192.168.1.230 at 2009-07-24 14:58:21) [GET]
|
8
|
-
#
|
9
|
-
# params = {
|
10
|
-
# 'sh' => start hour
|
11
|
-
# 'sm' => start minute
|
12
|
-
# 'ss' => start second
|
13
|
-
# 'eh' => end hour
|
14
|
-
# 'em' => end minute
|
15
|
-
# 'es' => end second
|
16
|
-
# }
|
17
|
-
#
|
18
|
-
# if 'sh' is defined, reject any lines where timestamp is earlier than start time
|
19
|
-
# if 'eh' is defined, reject any lines where timestamp is later than end time
|
20
|
-
# if 'sh' && 'eh' is defined, reject any lines where timestamp is not between start time and end time
|
21
|
-
|
22
|
-
LineRegexp = /^(\w+\s+\d+\s\d\d:\d\d:\d\d)\s(.*)/
|
23
|
-
|
24
|
-
attr_accessor :elements, :params
|
25
|
-
|
26
|
-
def initialize(next_renderer = nil, params = {})
|
27
|
-
@next_renderer = next_renderer
|
28
|
-
@params = params
|
29
|
-
end
|
30
|
-
|
31
|
-
def parse(line, elements = {})
|
32
|
-
@elements = elements
|
33
|
-
next_line = parse_line(line)
|
34
|
-
|
35
|
-
# reject line if we filter by time
|
36
|
-
if check_time?
|
37
|
-
if !start_time_valid? || !end_time_valid?
|
38
|
-
# reject this entry
|
39
|
-
@elements = {}
|
40
|
-
return @elements
|
41
|
-
end
|
42
|
-
else
|
43
|
-
if @next_renderer && next_line
|
44
|
-
@elements = @next_renderer.parse(next_line, @elements)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
@elements
|
48
|
-
end
|
49
|
-
|
50
|
-
def check_time?
|
51
|
-
(params['sh'] && !params['sh'].empty?) || (params['eh'] && !params['eh'].empty?)
|
52
|
-
end
|
53
|
-
|
54
|
-
# check if current line's time is >= start time, if it was set
|
55
|
-
def start_time_valid?
|
56
|
-
line_time = parse_time_from_string(@elements[:timestamp])
|
57
|
-
start_time = Time.utc(line_time.year, line_time.month, line_time.day, params.fetch('sh',0).to_i, params.fetch('sm', 0).to_i, params.fetch('ss', 0).to_i )
|
58
|
-
line_time >= start_time ? true : false
|
59
|
-
rescue Exception => e
|
60
|
-
puts "Error! #{e}"
|
61
|
-
end
|
62
|
-
|
63
|
-
def end_time_valid?
|
64
|
-
line_time = parse_time_from_string(@elements[:timestamp])
|
65
|
-
end_time = Time.utc(line_time.year, line_time.month, line_time.day, params.fetch('eh',23).to_i, params.fetch('em', 59).to_i, params.fetch('es', 59).to_i )
|
66
|
-
line_time <= end_time ? true : false
|
67
|
-
rescue Exception => e
|
68
|
-
puts "Error! #{e}"
|
69
|
-
end
|
70
|
-
|
71
|
-
def parse_time_from_string(text)
|
72
|
-
# Jul 24 14:58:21
|
73
|
-
time = nil
|
74
|
-
if text =~ /(\w+)\s+(\d+)\s+(\d+):(\d+):(\d+)/
|
75
|
-
time = Time.utc(Time.now.year, $1, $2, $3, $4, $5)
|
76
|
-
end
|
77
|
-
time
|
78
|
-
end
|
79
|
-
|
80
|
-
# parse line and break into pieces
|
81
|
-
def parse_line(line)
|
82
|
-
results = LineRegexp.match(line)
|
83
|
-
if results
|
84
|
-
@elements[:timestamp] = results[1]
|
85
|
-
@elements[:line] = results[-1]
|
86
|
-
results[-1] # remaining line
|
87
|
-
else
|
88
|
-
@elements[:line] = line
|
89
|
-
line
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
end
|