production_log_analyzer 1.2.1 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
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
- lib/production_log/syslog_logger.rb
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 Analyze requires the use of SyslogLogger (included)
11
- because the default Logger doesn't give any way to associate lines logged to a
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
- SyslogLogger gives you many other advantages, such as the ability to combine
15
- logs from multiple machines.
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 or .zip) from the RubyForge project:
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
- !prog specification. (FreeBSD's syslogd doesn't suck, but OS X's syslogd
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, including
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
- s.name = "production_log_analyzer"
12
- s.version = "1.2.1"
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"]
21
- s.default_executable = "pl_analyze"
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 "Run tests"
26
+ desc 'Run tests'
25
27
  task :default => [ :test ]
26
28
 
27
- Rake::TestTask.new("test") do |t|
28
- t.libs << "test"
29
- t.pattern = "test/test_*.rb"
30
- t.verbose = true
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 "Generate RDoc"
35
+ desc 'Generate RDoc'
34
36
  Rake::RDocTask.new :rdoc do |rd|
35
- rd.rdoc_dir = "doc"
36
- rd.rdoc_files.add "lib", "README", "LICENSE"
37
- rd.main = "README"
38
- rd.options << "-d" if `which dot` =~ /\/dot/
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 "Build Gem"
43
+ desc 'Build Gem'
42
44
  Rake::GemPackageTask.new spec do |pkg|
43
- pkg.need_zip = true
44
- pkg.need_tar = true
45
+ pkg.need_tar = true
45
46
  end
46
47
 
47
- desc "Sends RDoc to RubyForge"
48
+ desc 'Sends RDoc to RubyForge'
48
49
  task :send_rdoc => [ :rerdoc ] do
49
- publisher = Rake::SshDirPublisher.new('drbrain@rubyforge.org',
50
- '/var/www/gforge-projects/rails-analyzer',
51
- 'doc')
52
- publisher.upload
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 "Clean up"
56
+ desc 'Clean up'
56
57
  task :clean => [ :clobber_rdoc, :clobber_package ]
57
58
 
58
- desc "Clean up"
59
+ desc 'Clean up'
59
60
  task :clobber => [ :clean ]
60
61
 
61
- # vim: ts=4 sts=4 sw=4 syntax=Ruby
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 (.*)\)$/ then
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 != 'rails'
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
- if data =~ /^Completed/ then
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 <<EOF
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.10
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.2.1
7
- date: 2005-05-16
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
- - lib/production_log/syslog_logger.rb
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
-