rails-log-sorter 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "rails-log-sorter"
4
+
5
+ file = ARGV[0]
6
+ action = ARGV[1]
7
+ limit = (ARGV[2] || 0).to_f
8
+
9
+ log = RailsLogSorter::Log.new_with_file(file)
10
+
11
+ reqs = log.find_slowest(action, limit)
12
+ reqs.each {|req|
13
+ req.lines.each {|line| puts line.original_line}
14
+ puts ""
15
+ puts "*" * 50
16
+ puts ""
17
+ }
@@ -0,0 +1,93 @@
1
+ module RailsLogSorter
2
+ class Log
3
+ def self.new_with_file(file)
4
+ new(File.read(file))
5
+ end
6
+
7
+ attr_reader :requests
8
+
9
+ def initialize(log)
10
+ @requests = []
11
+
12
+ current_requests = {}
13
+
14
+ log.split("\n").each {|line|
15
+ begin
16
+ line = Line.new(line)
17
+
18
+ request = current_requests[line.pid]
19
+
20
+ case line.type
21
+ when :started
22
+ current_requests[line.pid] = request = Request.new
23
+ request.lines << line
24
+ @requests << request
25
+ when :processing
26
+ if request
27
+ request.action = line.action
28
+ request.lines << line
29
+ end
30
+ when :completed
31
+ if request
32
+ request.runtime = line.runtime
33
+ request.lines << line
34
+ end
35
+ current_requests[line.pid] = nil
36
+ else
37
+ request.lines << line if request
38
+ end
39
+
40
+ rescue
41
+ p line
42
+ raise
43
+ end
44
+ }
45
+ end
46
+
47
+ def find(action)
48
+ @requests.select {|r| r.action == action}
49
+ end
50
+
51
+ def find_slowest(action, limit=5)
52
+ find(action).sort_by {|r| r.runtime}.reverse[0..(limit - 1)]
53
+ end
54
+ end
55
+
56
+ class Request
57
+ attr_accessor :lines, :action, :runtime
58
+
59
+ def initialize
60
+ @lines = []
61
+ end
62
+ end
63
+
64
+ class Line
65
+ FORMAT = /\A(?<timestamp>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}) \[(?<loglevel>.*)\] (?<message>.*) \(pid:(?<pid>\d+)\)/
66
+
67
+ attr_reader :message, :pid, :type, :action, :runtime, :original_line
68
+
69
+ def initialize(line)
70
+ @original_line = line
71
+ match = line.match(FORMAT)
72
+ if !match
73
+ @type = :unknown
74
+ else
75
+ @message = match[:message]
76
+ @pid = match[:pid]
77
+
78
+ @type = case @message
79
+ when /\AStarted (GET|POST|PUT|DELETE)/
80
+ :started
81
+ when /\AProcessing by (\S+) as/
82
+ @action = $1
83
+ :processing
84
+ when /Completed \d{3} .* in (\d+\.\d+)ms/
85
+ @runtime = $1.to_f
86
+ :completed
87
+ else
88
+ :log
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,12 @@
1
+ 2014-03-04 10:00:00.100 [INFO ] Started GET "/" for 127.0.0.1 at 2014-03-04 10:26:45 +0100 (pid:1)
2
+ 2014-03-04 10:00:00.100 [INFO ] Started GET "/123" for 127.0.0.1 at 2014-03-04 10:26:45 +0100 (pid:2)
3
+ 2014-03-04 10:00:00.200 [INFO ] Processing by BlogController#index as HTML (pid:1)
4
+ 2014-03-04 10:00:00.200 [INFO ] Processing by BlogController#show as HTML (pid:2)
5
+ 2014-03-04 10:00:00.300 [DEBUG ] We are probably serving up some blogs now. (pid:1)
6
+ 2014-03-04 10:00:00.300 [DEBUG ] Serving the single blog alright (pid:2)
7
+ 2014-03-04 10:00:00.400 [INFO ] Completed 200 OK in 100.2ms (pid:1)
8
+ 2014-03-04 10:00:00.400 [INFO ] Completed 200 OK in 200.18ms (pid:2)
9
+ 2014-03-04 10:00:00.100 [INFO ] Started GET "/" for 127.0.0.1 at 2014-03-04 10:26:45 +0100 (pid:1)
10
+ 2014-03-04 10:00:00.200 [INFO ] Processing by BlogController#index as HTML (pid:1)
11
+ 2014-03-04 10:00:00.300 [DEBUG ] We are probably serving up some blogs now. (pid:1)
12
+ 2014-03-04 10:00:00.400 [INFO ] Completed 200 OK in 300.3ms (pid:1)
@@ -0,0 +1,3 @@
1
+ require "rails-log-sorter"
2
+ require "minitest/unit"
3
+ require "minitest/autorun"
@@ -0,0 +1,50 @@
1
+ require "test_helper"
2
+
3
+ class TestLine < MiniTest::Unit::TestCase
4
+ include RailsLogSorter
5
+
6
+ def test_started_line
7
+ line = Line.new('2014-03-04 10:00:00.100 [INFO ] Started GET "/" (pid:1)')
8
+
9
+ assert_equal 'Started GET "/"', line.message
10
+ assert_equal '1', line.pid
11
+ assert_equal :started, line.type
12
+ end
13
+
14
+ def test_processing_line
15
+ line = Line.new('2014-03-04 10:00:00.100 [INFO ] Processing by FooController#index as HTML (pid:1)')
16
+
17
+ assert_equal '1', line.pid
18
+ assert_equal :processing, line.type
19
+ assert_equal "FooController#index", line.action
20
+ end
21
+
22
+ def test_completed_line
23
+ line = Line.new('2014-03-04 10:00:00.100 [INFO ] Completed 200 OK in 50.1ms (pid:1)')
24
+
25
+ assert_equal '1', line.pid
26
+ assert_equal :completed, line.type
27
+ assert_equal 50.1, line.runtime
28
+ end
29
+
30
+ def test_completed_line_with_breakdown
31
+ line = Line.new('2014-03-04 10:26:47.736 [INFO ] Completed 200 OK in 1837.5ms (Views: 1808.8ms | ActiveRecord: 5.1ms) (pid:18269)')
32
+
33
+ assert_equal '18269', line.pid
34
+ assert_equal :completed, line.type
35
+ assert_equal 1837.5, line.runtime
36
+ end
37
+
38
+ def test_log_line
39
+ line = Line.new('2014-03-04 10:00:00.100 [INFO ] This is a log (pid:1)')
40
+
41
+ assert_equal '1', line.pid
42
+ assert_equal :log, line.type
43
+ end
44
+
45
+ def test_unknown_line
46
+ line = Line.new('Connecting to database')
47
+
48
+ assert_equal :unknown, line.type
49
+ end
50
+ end
@@ -0,0 +1,32 @@
1
+ require "test_helper"
2
+
3
+ class TestLog < MiniTest::Unit::TestCase
4
+ include RailsLogSorter
5
+
6
+ def test_parsing_log_file
7
+ log = Log.new_with_file("test/example.log")
8
+
9
+ r1 = log.requests[0]
10
+ assert_equal "BlogController#index", r1.action
11
+ assert_equal 100.2, r1.runtime
12
+
13
+ r2 = log.requests[1]
14
+ assert_equal "BlogController#show", r2.action
15
+ assert_equal 200.18, r2.runtime
16
+
17
+ r3 = log.requests[2]
18
+ assert_equal "BlogController#index", r3.action
19
+ assert_equal 300.3, r3.runtime
20
+ end
21
+
22
+ def test_find_slowest
23
+ log = Log.new_with_file("test/example.log")
24
+
25
+ slow = log.find_slowest("BlogController#index")
26
+
27
+ assert_equal 2, slow.size
28
+
29
+ assert_equal 300.3, slow[0].runtime
30
+ assert_equal 100.2, slow[1].runtime
31
+ end
32
+ end
metadata ADDED
@@ -0,0 +1,57 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rails-log-sorter
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Harry Vangberg
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-04-15 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: Sort log files
15
+ email:
16
+ - hv@firmafon.dk
17
+ executables:
18
+ - rails-log-sorter
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - lib/rails-log-sorter.rb
23
+ - test/test_helper.rb
24
+ - test/test_log.rb
25
+ - test/example.log
26
+ - test/test_line.rb
27
+ - bin/rails-log-sorter
28
+ homepage: https://github.com/firmafon/rails-log-sorter
29
+ licenses: []
30
+ post_install_message:
31
+ rdoc_options: []
32
+ require_paths:
33
+ - lib
34
+ required_ruby_version: !ruby/object:Gem::Requirement
35
+ none: false
36
+ requirements:
37
+ - - ! '>='
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ required_rubygems_version: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ requirements: []
47
+ rubyforge_project:
48
+ rubygems_version: 1.8.23
49
+ signing_key:
50
+ specification_version: 3
51
+ summary: Sort log files
52
+ test_files:
53
+ - test/test_helper.rb
54
+ - test/test_log.rb
55
+ - test/example.log
56
+ - test/test_line.rb
57
+ has_rdoc: