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 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
-