production_log_analyzer 1.2.1 → 1.3.0
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/Manifest.txt +4 -1
- data/README +17 -12
- data/Rakefile +33 -32
- data/bin/action_grep +19 -0
- data/lib/production_log/action_grep.rb +39 -0
- data/lib/production_log/parser.rb +21 -3
- data/test/test.syslog.0.14.x.log +4 -0
- data/test/test_action_grep.rb +68 -0
- data/test/test_parser.rb +41 -2
- metadata +21 -5
- data/lib/production_log/syslog_logger.rb +0 -150
data/Manifest.txt
CHANGED
@@ -2,10 +2,13 @@ Rakefile
|
|
2
2
|
README
|
3
3
|
LICENSE
|
4
4
|
Manifest.txt
|
5
|
+
bin/action_grep
|
5
6
|
bin/pl_analyze
|
7
|
+
lib/production_log/action_grep.rb
|
6
8
|
lib/production_log/analyzer.rb
|
7
9
|
lib/production_log/parser.rb
|
8
|
-
|
10
|
+
test/test.syslog.0.14.x.log
|
9
11
|
test/test.syslog.log
|
12
|
+
test/test_action_grep.rb
|
10
13
|
test/test_analyzer.rb
|
11
14
|
test/test_parser.rb
|
data/README
CHANGED
@@ -6,19 +6,21 @@ http://rubyforge.org/projects/rails-analyzer
|
|
6
6
|
|
7
7
|
= About
|
8
8
|
|
9
|
-
The Production Analyzer lets you find out which pages on your site are
|
10
|
-
dragging you down. PL
|
11
|
-
because the default Logger doesn't give any way to
|
12
|
-
request.
|
9
|
+
The Production Log Analyzer lets you find out which pages on your site are
|
10
|
+
dragging you down. The PL Analyzer requires the use of SyslogLogger from
|
11
|
+
rails_analyzer_tools because the default Logger doesn't give any way to
|
12
|
+
associate lines logged to a request.
|
13
13
|
|
14
|
-
|
15
|
-
|
14
|
+
The PL Analyzer also includes action_grep which lets you grab lines from a log
|
15
|
+
that only match a single action.
|
16
|
+
|
17
|
+
action_grep RssController#uber /var/log/production.log
|
16
18
|
|
17
19
|
= Installing
|
18
20
|
|
19
21
|
== Download
|
20
22
|
|
21
|
-
Grab the gem (or tar.gz
|
23
|
+
Grab the gem (or tar.gz) from the RubyForge project:
|
22
24
|
|
23
25
|
http://rubyforge.org/frs/?group_id=586
|
24
26
|
|
@@ -27,8 +29,8 @@ http://rubyforge.org/frs/?group_id=586
|
|
27
29
|
Either:
|
28
30
|
|
29
31
|
A syslogd that doesn't suck. This means that syslog.conf(5) shows a
|
30
|
-
!
|
31
|
-
does.)
|
32
|
+
!program_name specification. (FreeBSD's syslogd doesn't suck, but OS X's
|
33
|
+
syslogd does.)
|
32
34
|
|
33
35
|
or:
|
34
36
|
|
@@ -40,13 +42,16 @@ submit patches with tests. (Patches without tests are useless to me.)
|
|
40
42
|
|
41
43
|
Either:
|
42
44
|
|
43
|
-
Use SyslogLogger according to directions on the SyslogLogger page,
|
44
|
-
setting up your non-sucky syslogd as directed.
|
45
|
+
Use SyslogLogger according to directions on the SyslogLogger RDoc page,
|
46
|
+
including setting up your non-sucky syslogd as directed. (SyslogLogger is
|
47
|
+
included via the rails_analyzer_tools gem.)
|
48
|
+
|
49
|
+
http://rails-analyzer.rubyforge.org/tools/classes/SyslogLogger.html
|
45
50
|
|
46
51
|
or:
|
47
52
|
|
48
53
|
Use your hacking skills and set up a logger that your hacked LogParser#parse
|
49
|
-
can deal with.
|
54
|
+
can deal with. (Then send my your patches for integration.)
|
50
55
|
|
51
56
|
Then:
|
52
57
|
|
data/Rakefile
CHANGED
@@ -8,55 +8,56 @@ require 'rake/contrib/sshpublisher'
|
|
8
8
|
$VERBOSE = nil
|
9
9
|
|
10
10
|
spec = Gem::Specification.new do |s|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
11
|
+
s.name = 'production_log_analyzer'
|
12
|
+
s.version = '1.3.0'
|
13
|
+
s.summary = 'Extracts statistics from Rails production logs'
|
14
|
+
s.author = 'Eric Hodel'
|
15
|
+
s.email = 'hodel@robotcoop.com'
|
16
|
+
|
17
|
+
s.has_rdoc = true
|
18
|
+
s.files = File.read('Manifest.txt').split($/)
|
19
|
+
s.require_path = 'lib'
|
20
|
+
s.executables = ['pl_analyze', 'action_grep']
|
21
|
+
s.default_executable = 'pl_analyze'
|
22
|
+
|
23
|
+
s.add_dependency 'rails_analyzer_tools', '>= 1.1.0'
|
22
24
|
end
|
23
25
|
|
24
|
-
desc
|
26
|
+
desc 'Run tests'
|
25
27
|
task :default => [ :test ]
|
26
28
|
|
27
|
-
Rake::TestTask.new(
|
28
|
-
|
29
|
-
|
30
|
-
|
29
|
+
Rake::TestTask.new('test') do |t|
|
30
|
+
t.libs << 'test'
|
31
|
+
t.pattern = 'test/test_*.rb'
|
32
|
+
t.verbose = true
|
31
33
|
end
|
32
34
|
|
33
|
-
desc
|
35
|
+
desc 'Generate RDoc'
|
34
36
|
Rake::RDocTask.new :rdoc do |rd|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
37
|
+
rd.rdoc_dir = 'doc'
|
38
|
+
rd.rdoc_files.add 'lib', 'README', 'LICENSE'
|
39
|
+
rd.main = 'README'
|
40
|
+
rd.options << '-d' if `which dot` =~ /\/dot/
|
39
41
|
end
|
40
42
|
|
41
|
-
desc
|
43
|
+
desc 'Build Gem'
|
42
44
|
Rake::GemPackageTask.new spec do |pkg|
|
43
|
-
|
44
|
-
pkg.need_tar = true
|
45
|
+
pkg.need_tar = true
|
45
46
|
end
|
46
47
|
|
47
|
-
desc
|
48
|
+
desc 'Sends RDoc to RubyForge'
|
48
49
|
task :send_rdoc => [ :rerdoc ] do
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
50
|
+
publisher = Rake::SshDirPublisher.new('drbrain@rubyforge.org',
|
51
|
+
'/var/www/gforge-projects/rails-analyzer/pl_analyze',
|
52
|
+
'doc')
|
53
|
+
publisher.upload
|
53
54
|
end
|
54
55
|
|
55
|
-
desc
|
56
|
+
desc 'Clean up'
|
56
57
|
task :clean => [ :clobber_rdoc, :clobber_package ]
|
57
58
|
|
58
|
-
desc
|
59
|
+
desc 'Clean up'
|
59
60
|
task :clobber => [ :clean ]
|
60
61
|
|
61
|
-
# vim:
|
62
|
+
# vim: syntax=Ruby
|
62
63
|
|
data/bin/action_grep
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
#!/usr/local/bin/ruby -w
|
2
|
+
|
3
|
+
require 'production_log/action_grep'
|
4
|
+
|
5
|
+
action_name = ARGV.shift
|
6
|
+
file_name = ARGV.shift
|
7
|
+
|
8
|
+
if action_name.nil? or file_name.nil? then
|
9
|
+
puts "Usage: #{$0} action_name file_name"
|
10
|
+
exit 1
|
11
|
+
end
|
12
|
+
|
13
|
+
begin
|
14
|
+
ActionGrep.grep action_name, file_name
|
15
|
+
rescue ArgumentError => e
|
16
|
+
puts e
|
17
|
+
exit 1
|
18
|
+
end
|
19
|
+
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module ActionGrep; end
|
2
|
+
|
3
|
+
class << ActionGrep
|
4
|
+
|
5
|
+
def grep(action_name, file_name)
|
6
|
+
unless action_name =~ /\A([A-Z][A-Za-z\d]*)(?:#([A-Za-z]\w*))?\Z/ then
|
7
|
+
raise ArgumentError, "Invalid action name #{action_name} expected something like FooController#uber"
|
8
|
+
end
|
9
|
+
|
10
|
+
unless File.file? file_name and File.readable? file_name then
|
11
|
+
raise ArgumentError, "Unable to read #{file_name}"
|
12
|
+
end
|
13
|
+
|
14
|
+
in_component = 0
|
15
|
+
buckets = Hash.new { |h,k| h[k] = [] }
|
16
|
+
File.open file_name do |fp|
|
17
|
+
fp.each_line do |line|
|
18
|
+
line =~ / ([^ ]+) ([^ ]+)\[(\d+)\]: /
|
19
|
+
bucket = [$1, $2, $3].join '-'
|
20
|
+
|
21
|
+
buckets[bucket] << line
|
22
|
+
|
23
|
+
case line
|
24
|
+
when /\]: Start rendering component / then
|
25
|
+
in_component += 1
|
26
|
+
when /\]: End of component rendering$/ then
|
27
|
+
in_component -= 1
|
28
|
+
when /\]: Completed/ then
|
29
|
+
next unless in_component == 0
|
30
|
+
action = buckets.delete bucket
|
31
|
+
next unless action.first =~ /#{action_name}/
|
32
|
+
puts action.join
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
@@ -61,6 +61,7 @@ module LogParser
|
|
61
61
|
@request_time = 0
|
62
62
|
@render_time = 0
|
63
63
|
@db_time = 0
|
64
|
+
@in_component = 0
|
64
65
|
|
65
66
|
parse entry
|
66
67
|
end
|
@@ -75,20 +76,28 @@ module LogParser
|
|
75
76
|
when /^Parameters/, /^Cookie set/, /^Rendering/,
|
76
77
|
/^Redirected/ then
|
77
78
|
# nothing
|
78
|
-
when /^Processing ([\S]+) \(for (.+) at (.*)\)
|
79
|
+
when /^Processing ([\S]+) \(for (.+) at (.*)\)/ then
|
80
|
+
next if @in_component > 0
|
79
81
|
@page = $1
|
80
82
|
@ip = $2
|
81
83
|
@time = $3
|
82
84
|
when /^Completed in ([\S]+) .+ Rendering: ([\S]+) .+ DB: ([\S]+)/ then
|
85
|
+
next if @in_component > 0
|
83
86
|
@request_time = $1.to_f
|
84
87
|
@render_time = $2.to_f
|
85
88
|
@db_time = $3.to_f
|
86
89
|
when /^Completed in ([\S]+) .+ DB: ([\S]+)/ then # Redirect
|
90
|
+
next if @in_component > 0
|
87
91
|
@request_time = $1.to_f
|
88
92
|
@render_time = 0
|
89
93
|
@db_time = $2.to_f
|
90
94
|
when /(.+?) \(([^)]+)\) / then
|
91
95
|
@queries << [$1, $2.to_f]
|
96
|
+
when /^Start rendering component / then
|
97
|
+
@in_component += 1
|
98
|
+
when /^End of component rendering$/ then
|
99
|
+
@in_component -= 1
|
100
|
+
when /^Fragment hit: / then
|
92
101
|
else
|
93
102
|
raise "Can't handle #{line.inspect}" if $TESTING
|
94
103
|
end
|
@@ -116,16 +125,25 @@ module LogParser
|
|
116
125
|
# the same process id through Completed.
|
117
126
|
|
118
127
|
def self.parse(stream) # :yields: log_entry
|
128
|
+
in_component = 0
|
119
129
|
buckets = Hash.new { |h,k| h[k] = [] }
|
130
|
+
comp_count = Hash.new 0
|
131
|
+
|
120
132
|
stream.each_line do |line|
|
121
133
|
line =~ / ([^ ]+) ([^ ]+)\[(\d+)\]: (.*)/
|
122
|
-
next if $2
|
134
|
+
next if $2.nil? or $2 == 'newsyslog'
|
123
135
|
bucket = "#{$1}-#{$3}"
|
124
136
|
data = $4
|
125
137
|
|
126
138
|
buckets[bucket] << data
|
127
139
|
|
128
|
-
|
140
|
+
case data
|
141
|
+
when /^Start rendering component / then
|
142
|
+
comp_count[bucket] += 1
|
143
|
+
when /^End of component rendering$/ then
|
144
|
+
comp_count[bucket] -= 1
|
145
|
+
when /^Completed/ then
|
146
|
+
next unless comp_count[bucket] == 0
|
129
147
|
entry = buckets.delete bucket
|
130
148
|
if entry.first =~ /^Processing/ then
|
131
149
|
yield LogEntry.new(entry)
|
@@ -0,0 +1,4 @@
|
|
1
|
+
Nov 7 12:14:02 192.168.1.71 43things[24950]: Processing RssController#entries (for 10.43.199.12 at 2005-11-07 12:14:02) [GET]
|
2
|
+
Nov 7 12:14:02 192.168.1.71 43things[24950]: Parameters: {"rss/entries/goal.html/entries/goal"=>nil, "action"=>"entries", "id"=>"goal", "controller"=>"rss", "goal_id"=>"86381"}
|
3
|
+
Nov 7 12:14:02 192.168.1.71 43things[24950]: Rendering rss/rss2.0
|
4
|
+
Nov 7 12:14:02 192.168.1.71 43things[24950]: Completed in 0.00860 (116 reqs/sec) | DB: 0.00328 (38%) | 200 OK [http://www.43things.com/rss/entries/goal?goal_id=86381]
|
@@ -0,0 +1,68 @@
|
|
1
|
+
#!/usr/local/bin/ruby -w
|
2
|
+
|
3
|
+
require 'stringio'
|
4
|
+
require 'tempfile'
|
5
|
+
require 'test/unit'
|
6
|
+
|
7
|
+
require 'production_log/action_grep'
|
8
|
+
|
9
|
+
class TestActionGrep < Test::Unit::TestCase
|
10
|
+
|
11
|
+
def setup
|
12
|
+
@syslog_file_name = File.expand_path(File.join(File.dirname(__FILE__),
|
13
|
+
'test.syslog.log'))
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_module_grep
|
17
|
+
old_stdout = $stdout.dup
|
18
|
+
stdout = StringIO.new
|
19
|
+
$stdout = stdout
|
20
|
+
|
21
|
+
ActionGrep.grep 'RssController', @syslog_file_name
|
22
|
+
|
23
|
+
stdout.rewind
|
24
|
+
|
25
|
+
lines = stdout.readlines
|
26
|
+
|
27
|
+
assert_equal 18, lines.length
|
28
|
+
|
29
|
+
ensure
|
30
|
+
$stdout = old_stdout
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_module_grep_arguments
|
34
|
+
file = Tempfile.new File.basename(__FILE__)
|
35
|
+
|
36
|
+
assert_raises ArgumentError do
|
37
|
+
ActionGrep.grep 'Foo_Controller', '/tmp/no_such_file/no_really/'
|
38
|
+
end
|
39
|
+
|
40
|
+
assert_raises ArgumentError do
|
41
|
+
ActionGrep.grep 'FooController#5', '/tmp/no_such_file/no_really/'
|
42
|
+
end
|
43
|
+
|
44
|
+
assert_raises ArgumentError do
|
45
|
+
ActionGrep.grep '5', '/tmp/no_such_file/no_really/'
|
46
|
+
end
|
47
|
+
|
48
|
+
assert_raises ArgumentError do
|
49
|
+
ActionGrep.grep 'FooController', '/tmp/no_such_file/no_really'
|
50
|
+
end
|
51
|
+
|
52
|
+
assert_nothing_raised do
|
53
|
+
ActionGrep.grep 'FooController', file.path
|
54
|
+
ActionGrep.grep 'FooController5', file.path
|
55
|
+
ActionGrep.grep 'FooController#action', file.path
|
56
|
+
ActionGrep.grep 'FooController#action_thingy', file.path
|
57
|
+
ActionGrep.grep 'FooController#action_thingy5', file.path
|
58
|
+
ActionGrep.grep 'FooController5#action', file.path
|
59
|
+
ActionGrep.grep 'FooController5#action_thingy', file.path
|
60
|
+
ActionGrep.grep 'FooController5#action_thingy5', file.path
|
61
|
+
end
|
62
|
+
|
63
|
+
ensure
|
64
|
+
file.close
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
data/test/test_parser.rb
CHANGED
@@ -92,7 +92,7 @@ end
|
|
92
92
|
class TestLogParser <Test::Unit::TestCase
|
93
93
|
|
94
94
|
def test_class_parse
|
95
|
-
log = StringIO.new
|
95
|
+
log = StringIO.new <<-EOF
|
96
96
|
Mar 7 00:00:25 online1 rails[59628]: Processing RssController#uber (for 67.18.200.5 at Mon Mar 07 00:00:25 CST 2005)
|
97
97
|
Mar 7 00:00:25 online1 rails[59628]: Parameters: {:id=>"author", :"rss/uber/author.html/uber/author"=>nil, :action=>"uber", :username=>"looch", :controller=>"rss"}
|
98
98
|
Mar 7 00:00:25 online1 rails[59628]: Cookie set: auth=dc%2FGUP20BwziF%2BApGecc0pXB0PF0obi55az63ubAFtsnOOdJPkhfJH2U09yuzQD3WtdmWnydLzFcRA78kwi7Gw%3D%3D; path=/; expires=Thu, 05 Mar 2015 06:00:25 GMT
|
@@ -102,7 +102,7 @@ Mar 7 00:00:25 online1 rails[59628]: Person Load (0.002445) SELECT * FROM peo
|
|
102
102
|
Mar 7 00:00:25 online1 rails[59628]: ProfileImage Load (0.001554) SELECT * FROM profile_images WHERE id = 2782 LIMIT 1
|
103
103
|
Mar 7 00:00:25 online1 rails[59628]: Rendering rss/rss2.0 (200 OK)
|
104
104
|
Mar 7 00:00:25 online1 rails[59628]: Completed in 0.034519 (28 reqs/sec) | Rendering: 0.011770 (34%) | DB: 0.007962 (23%)
|
105
|
-
EOF
|
105
|
+
EOF
|
106
106
|
|
107
107
|
entries = []
|
108
108
|
|
@@ -114,6 +114,36 @@ EOF
|
|
114
114
|
assert_equal 'RssController#uber', entries.first.page
|
115
115
|
end
|
116
116
|
|
117
|
+
def test_class_parse_components
|
118
|
+
log = StringIO.new <<-EOF
|
119
|
+
Jul 11 10:05:20 www rails[61243]: Processing ChatroomsController#launch (for 213.152.37.169 at Mon Jul 11 10:05:20 CDT 2005)
|
120
|
+
Jul 11 10:05:20 www rails[61243]: Start rendering component ({:action=>"online_count", :controller=>"members"}):
|
121
|
+
Jul 11 10:05:20 www rails[34216]: Processing ChatroomsController#launch (for 213.152.37.169 at Mon Jul 11 10:05:20 CDT 2005)
|
122
|
+
Jul 11 10:05:20 www rails[34216]: Start rendering component ({:action=>"online_count", :controller=>"members"}):
|
123
|
+
Jul 11 10:05:20 www rails[34216]: Processing MembersController#online_count (for 213.152.37.169 at Mon Jul 11 10:05:20 CDT 2005)
|
124
|
+
Jul 11 10:05:20 www rails[34216]: Completed in 0.00741 (135 reqs/sec) | DB: 0.00320 (43%)
|
125
|
+
Jul 11 10:05:20 www rails[34216]: End of component rendering
|
126
|
+
Jul 11 10:05:28 www rails[34216]: Completed in 8.65005 (0 reqs/sec) | Rendering: 8.64820 (99%) | DB: 0.00000 (0%)
|
127
|
+
Jul 11 10:05:20 www rails[34216]: Processing ChatroomsController#launch (for 213.152.37.169 at Mon Jul 11 10:05:20 CDT 2005)
|
128
|
+
Jul 11 10:05:20 www rails[34216]: Start rendering component ({:action=>"online_count", :controller=>"members"}):
|
129
|
+
Jul 11 10:05:20 www rails[34216]: Processing MembersController#online_count (for 213.152.37.169 at Mon Jul 11 10:05:20 CDT 2005)
|
130
|
+
Jul 11 10:05:20 www rails[34216]: Completed in 0.00741 (135 reqs/sec) | DB: 0.00320 (43%)
|
131
|
+
Jul 11 10:05:20 www rails[34216]: End of component rendering
|
132
|
+
Jul 11 10:05:28 www rails[34216]: Completed in 8.65005 (0 reqs/sec) | Rendering: 8.64820 (99%) | DB: 0.00000 (0%)
|
133
|
+
Jul 11 10:05:20 www rails[61243]: Processing MembersController#online_count (for 213.152.37.169 at Mon Jul 11 10:05:20 CDT 2005)
|
134
|
+
Jul 11 10:05:20 www rails[61243]: Completed in 0.00741 (135 reqs/sec) | DB: 0.00320 (43%)
|
135
|
+
Jul 11 10:05:20 www rails[61243]: End of component rendering
|
136
|
+
Jul 11 10:05:28 www rails[61243]: Completed in 8.65005 (0 reqs/sec) | Rendering: 8.64820 (99%) | DB: 0.00000 (0%)
|
137
|
+
EOF
|
138
|
+
|
139
|
+
entries = []
|
140
|
+
LogParser.parse(log) { |entry| entries << entry }
|
141
|
+
|
142
|
+
assert_equal 3, entries.length
|
143
|
+
assert_equal 'ChatroomsController#launch', entries.first.page
|
144
|
+
assert_equal 8.65005, entries.first.request_time
|
145
|
+
end
|
146
|
+
|
117
147
|
def test_class_parse_multi
|
118
148
|
entries = []
|
119
149
|
File.open 'test/test.syslog.log' do |fp|
|
@@ -134,6 +164,15 @@ EOF
|
|
134
164
|
assert_equal 0, last.request_time
|
135
165
|
end
|
136
166
|
|
167
|
+
def test_class_parse_0_14_x
|
168
|
+
entries = []
|
169
|
+
File.open 'test/test.syslog.0.14.x.log' do |fp|
|
170
|
+
LogParser.parse fp do |entry|
|
171
|
+
entries << entry
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
137
176
|
end
|
138
177
|
|
139
178
|
# vim: ts=4 sts=4 sw=4
|
metadata
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.8.
|
2
|
+
rubygems_version: 0.8.11
|
3
3
|
specification_version: 1
|
4
4
|
name: production_log_analyzer
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 1.
|
7
|
-
date: 2005-
|
6
|
+
version: 1.3.0
|
7
|
+
date: 2005-11-08 00:00:00 -08:00
|
8
8
|
summary: Extracts statistics from Rails production logs
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -24,6 +24,8 @@ required_ruby_version: !ruby/object:Gem::Version::Requirement
|
|
24
24
|
version: 0.0.0
|
25
25
|
version:
|
26
26
|
platform: ruby
|
27
|
+
signing_key:
|
28
|
+
cert_chain:
|
27
29
|
authors:
|
28
30
|
- Eric Hodel
|
29
31
|
files:
|
@@ -31,11 +33,14 @@ files:
|
|
31
33
|
- README
|
32
34
|
- LICENSE
|
33
35
|
- Manifest.txt
|
36
|
+
- bin/action_grep
|
34
37
|
- bin/pl_analyze
|
38
|
+
- lib/production_log/action_grep.rb
|
35
39
|
- lib/production_log/analyzer.rb
|
36
40
|
- lib/production_log/parser.rb
|
37
|
-
-
|
41
|
+
- test/test.syslog.0.14.x.log
|
38
42
|
- test/test.syslog.log
|
43
|
+
- test/test_action_grep.rb
|
39
44
|
- test/test_analyzer.rb
|
40
45
|
- test/test_parser.rb
|
41
46
|
test_files: []
|
@@ -43,6 +48,17 @@ rdoc_options: []
|
|
43
48
|
extra_rdoc_files: []
|
44
49
|
executables:
|
45
50
|
- pl_analyze
|
51
|
+
- action_grep
|
46
52
|
extensions: []
|
47
53
|
requirements: []
|
48
|
-
dependencies:
|
54
|
+
dependencies:
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rails_analyzer_tools
|
57
|
+
version_requirement:
|
58
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
59
|
+
requirements:
|
60
|
+
-
|
61
|
+
- ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: 1.1.0
|
64
|
+
version:
|
@@ -1,150 +0,0 @@
|
|
1
|
-
require 'syslog'
|
2
|
-
require 'logger'
|
3
|
-
|
4
|
-
##
|
5
|
-
# This Logger logs messages to syslogd. Add it to your production environment
|
6
|
-
# so you can run pl_analyze on your log files.
|
7
|
-
#
|
8
|
-
# SyslogLogger logs everything. Tweak your syslog.conf to throw away messages
|
9
|
-
# you don't want, SyslogLogger ignores any calls to #level=.
|
10
|
-
#
|
11
|
-
# SyslogLogger logs messages using the 'rails' facility.
|
12
|
-
#
|
13
|
-
# = Sample usage
|
14
|
-
#
|
15
|
-
# == config/environment/production.rb
|
16
|
-
#
|
17
|
-
# Add the following lines:
|
18
|
-
#
|
19
|
-
# require 'production_log/syslog_logger'
|
20
|
-
# RAILS_DEFAULT_LOGGER = SyslogLogger.new
|
21
|
-
#
|
22
|
-
# == config/environment.rb
|
23
|
-
#
|
24
|
-
# In 0.10.0, change this line:
|
25
|
-
#
|
26
|
-
# RAILS_DEFAULT_LOGGER = Logger.new("#{RAILS_ROOT}/log/#{RAILS_ENV}.log")
|
27
|
-
#
|
28
|
-
# to:
|
29
|
-
#
|
30
|
-
# RAILS_DEFAULT_LOGGER ||= Logger.new("#{RAILS_ROOT}/log/#{RAILS_ENV}.log")
|
31
|
-
#
|
32
|
-
# Other versions of Rails should have a similar change.
|
33
|
-
#
|
34
|
-
# == /etc/syslog.conf
|
35
|
-
#
|
36
|
-
# Add the following lines:
|
37
|
-
#
|
38
|
-
# !rails
|
39
|
-
# *.* /var/log/production.log
|
40
|
-
#
|
41
|
-
# Then touch /var/log/production.log and signal syslogd with a HUP
|
42
|
-
# (killall -HUP syslogd, on FreeBSD).
|
43
|
-
#
|
44
|
-
# == /etc/newsyslog.conf
|
45
|
-
#
|
46
|
-
# Add the following line:
|
47
|
-
#
|
48
|
-
# /var/log/production.log 640 7 * @T00 Z
|
49
|
-
#
|
50
|
-
# This creates a log file that is rotated every day at midnight, gzip'd, then
|
51
|
-
# kept for 7 days. Consult newsyslog.conf(5) for more details.
|
52
|
-
#
|
53
|
-
# Now restart your Rails app. Your production logs should now be showing up
|
54
|
-
# in /var/log/production.log. If you have mulitple machines, you can log them
|
55
|
-
# all to a central machine with remote syslog logging for analysis.
|
56
|
-
|
57
|
-
class SyslogLogger
|
58
|
-
|
59
|
-
##
|
60
|
-
# Log level for Logger compatibility.
|
61
|
-
|
62
|
-
attr_accessor :level
|
63
|
-
|
64
|
-
##
|
65
|
-
# Syslog is a module, so this constant holds our open logger.
|
66
|
-
|
67
|
-
SYSLOG = Syslog.open "rails"
|
68
|
-
|
69
|
-
##
|
70
|
-
# Maps Logger warning types to syslog(3) warning types.
|
71
|
-
|
72
|
-
LOGGER_MAP = {
|
73
|
-
:fatal => :err,
|
74
|
-
:error => :warning,
|
75
|
-
:warn => :notice,
|
76
|
-
:info => :info,
|
77
|
-
:debug => :debug,
|
78
|
-
}
|
79
|
-
|
80
|
-
##
|
81
|
-
# Maps Logger log levels to their values so we can silence.
|
82
|
-
|
83
|
-
LOGGER_LEVEL_MAP = {}
|
84
|
-
|
85
|
-
LOGGER_MAP.each_key do |key|
|
86
|
-
LOGGER_LEVEL_MAP[key] = Logger.const_get key.to_s.upcase
|
87
|
-
end
|
88
|
-
|
89
|
-
##
|
90
|
-
# Builds a logging method for level +meth+.
|
91
|
-
|
92
|
-
def self.log_method(meth)
|
93
|
-
eval <<-EOF
|
94
|
-
def #{meth}(message)
|
95
|
-
SYSLOG.#{LOGGER_MAP[meth]} clean(message) if #{LOGGER_LEVEL_MAP[meth]} >= @level
|
96
|
-
end
|
97
|
-
EOF
|
98
|
-
end
|
99
|
-
|
100
|
-
LOGGER_MAP.each_key do |level|
|
101
|
-
log_method level
|
102
|
-
end
|
103
|
-
|
104
|
-
##
|
105
|
-
# Fill in variables for Logger compatibility.
|
106
|
-
|
107
|
-
def initialize(*args)
|
108
|
-
@level = Logger::DEBUG
|
109
|
-
end
|
110
|
-
|
111
|
-
##
|
112
|
-
# Allows messages of a particular log level to be ignored temporarily.
|
113
|
-
#
|
114
|
-
# Can you say "Broken Windows"?
|
115
|
-
|
116
|
-
def silence(temporary_level = Logger::ERROR)
|
117
|
-
old_logger_level = @level
|
118
|
-
@level = temporary_level
|
119
|
-
yield
|
120
|
-
ensure
|
121
|
-
@level = old_logger_level
|
122
|
-
end
|
123
|
-
|
124
|
-
private
|
125
|
-
|
126
|
-
##
|
127
|
-
# Clean up messages so they're nice and pretty.
|
128
|
-
|
129
|
-
def clean(message)
|
130
|
-
message = message.dup
|
131
|
-
message.strip!
|
132
|
-
message.gsub!(/%/, '%%') # syslog(3) freaks on % (printf)
|
133
|
-
message.gsub!(/\e\[[^m]*m/, '') # remove useless ansi color codes
|
134
|
-
return message
|
135
|
-
end
|
136
|
-
|
137
|
-
end
|
138
|
-
|
139
|
-
if __FILE__ == $0 then
|
140
|
-
logger = SyslogLogger.new
|
141
|
-
|
142
|
-
message = "message from syslog_logger.rb logged using"
|
143
|
-
|
144
|
-
SyslogLogger::LOGGER_MAP.each do |logger_level, syslog_level|
|
145
|
-
logger.send logger_level, "#{logger_level} #{message} #{syslog_level}"
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
# vim: ts=4 sts=4 sw=4
|
150
|
-
|