tagged_logger 0.5.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -54,14 +54,14 @@ the following will happen:
54
54
 
55
55
 
56
56
  The *#logger()* returns some object having methods: *#debug(), #info(), #warn(), #error() and #fatal()*.
57
- These methods have generated on first *#logger()* call and contain only necessary code to meet rules.
58
- It means, for example, that if no rules defined all these methods do nothing. It is done for performance
59
- reasons, I like to log a lot and I do not want calls like *#logger.debug()* slowing down production code.
57
+ These methods have generated on first *#logger()* call and contain only necessary code to satisfy rules conditions.
58
+ It means, for example, that if no rules defined all these methods do **nothing**. It is done for performance
59
+ reasons, I like to log a lot and I do not want calls like *#logger.debug()* to slow down production code.
60
60
 
61
61
 
62
62
  The simplest way to have a *#logger()* available everywhere without specifying any rules is:
63
63
 
64
- TaggedLogger.init
64
+ TaggedLogger.rules
65
65
 
66
66
  No rules specified, therefore whenever you call *logger.debug()* (or alike) you actually paying for just an empty method
67
67
  execution. You may specify rules later, now you may stay focused on code you are writing.
@@ -78,7 +78,7 @@ If you are wondering what the heck the 'tag' is - the answer is simple. The tag
78
78
  whose method calls *#logger()*. This is what allows to specify rules for classes or namespaces and this
79
79
  is what the *tagged_logger* plugin is named after.
80
80
 
81
- Lets see how you may use it. For example you want to have separate log files
81
+ Lets see how you may use it. For example, you want to have separate log files
82
82
  for classes *Network* and *Database*:
83
83
 
84
84
  TaggedLogger.rules do
@@ -92,7 +92,7 @@ In case you want to define common log for several classes:
92
92
  debug [Ftp, Http, Sockets], :to => Logger.new("network.log")
93
93
  end
94
94
 
95
- Or if you want to have all these classes showing up under common
95
+ Or if you want to have all these classes to show up under common
96
96
  tag *Network* in standard output:
97
97
 
98
98
  TaggedLogger.rules do
@@ -107,7 +107,7 @@ You may also use regular expressions in your rules:
107
107
  end
108
108
 
109
109
 
110
- There is more general form for rules, it accepts block with three params:
110
+ There is more general form for rules, it accepts block with three parameters:
111
111
 
112
112
  TaggedLogger.rules do
113
113
  info /Whatever/ do |level, tag, message|
@@ -117,14 +117,23 @@ There is more general form for rules, it accepts block with three params:
117
117
 
118
118
  As previously explained the *tag* is a class name the *#logger* is being called from (except when you override Rails instrumentation, see below)
119
119
 
120
- ## Integration with Rails (only Rails 3.0 supported at the moment, not completely tested):
120
+ ## Integration with Rails (only Rails 3.0 supported at the moment, not completely tested)
121
121
 
122
- Installation:
122
+ ### Installation
123
123
 
124
124
  $ gem install tagged_logger
125
125
 
126
- Rails has two facility for logging - *#logger* method injected in base classes such in ActiveRecord::Base and instrumentation. Instrumentation is somewhat which allows to issue an event upon execution of
127
- block, for example:
126
+ In Rails.root/config/application.rb:
127
+
128
+ TaggedLogger.config(:replace_existing_logger => true)
129
+
130
+ Without that original methods *ActionController::Base#logger*, *ActiveRecord::Base#logger* and alike will remain untouched, and they have to be patched if we want
131
+ redefine their behavior.
132
+
133
+ ### Logging in Rails
134
+
135
+ Rails has two facility for logging - *#logger* method injected in base classes (*ActiveRecord::Base*, *ActionController::Base*, etc.) and *instrumentation*.
136
+ Instrumentation in Rails allows to subscribe on event signaled upon block execution, for example:
128
137
 
129
138
  def sendfile(path, options={})
130
139
  ActiveSupport::Notifications.instrument("sendfile.action_controller") do
@@ -132,36 +141,35 @@ block, for example:
132
141
  end
133
142
  end
134
143
 
135
- The event *"sendfile.action_controller"* will be issued and one could subscribe to that event:
144
+ The event *"sendfile.action_controller"* will be signaled after actual work on sending file is done. One could subscribe to that event:
136
145
 
137
- ActiveSupport::Notifications.subscribe("sendfile.action_controller") do
138
- #do something, for example log an event
146
+ ActiveSupport::Notifications.subscribe("sendfile.action_controller") do |*args|
147
+ event = ActiveSupport::Notifications::Event.new(*args)
148
+ #do something, for example, log an event
139
149
  end
140
150
 
151
+ ### Overriding Rails logging
152
+ Logging inside Rails is done by log subscribers - their task to subscribe to instrumentation events, receive and log them.
153
+ *TaggedLogger* allows you to override how these subscribers work, for example,
154
+ you could redirect what is being logged in *ActionController* to some external logging service, like [Logworm](http://www.logworm.com/):
141
155
 
142
- Actually Rails subscribers - they are responsible for majority of logging in Rails.
143
- *TaggedLogger* allows you to override how those subscribers do actual logging, for example if you want to override it for *ActionController*:
144
-
145
- # "#{Rails.root}/config/initializers/tagged_logger.rb"
146
- TaggedLogger.rules(:override=>true) do
147
- debug "action_controller.instrumentation" do |level, tag, msg|
148
- puts "#{tag} {msg}" #msg formed by ActionController::LogSubscriber goes here, tag is 'action_controller.instrumentation'
156
+ # In Rails.root/config/initializers/tagged_logger.rb:
157
+ TaggedLogger.rules do
158
+ debug "action_controller.logsubscriber" do |level, tag, msg|
159
+ Logworm::Logger.log(:controllers, :level => level.to_s, :tag => tag.to_s, :message => msg.to_s )
149
160
  end
150
161
  end
151
162
 
152
- If you like to have a special logging not only for *ActionController*, but rather for everything logged by Rails via instrumentation mechanism, you could use a
163
+ You may also use *active_record.logsubscriber*, *action_mailer.logsubscriber*, *action_view.logsubscriber* and *rack.logsubscriber* tags.
164
+ If you'd like to have a special logging not only for *ActionController*, but rather for entire logging done in Rails (via instrumentation), you could use a
153
165
  rule with regular expression:
154
166
 
155
- debug /.*\.instrumentation$/ do |level, tag, msg|
156
- #you special logging
167
+ debug /\.logsubscriber$/ do |level, tag, msg|
168
+ #your special logging
157
169
  end
158
170
 
159
171
 
160
- Since *#logger* is defined by Rails for classes you inherits from (*ActionController::Base*, *ActiveRecord::Base*), you have to initialize *TaggedLogger* with
161
-
162
- :override => true
163
-
164
- option since by default *TaggedLogger* is trying to be safe and does not override existing *#logger* method:
172
+ You also could use *#logger* in your classes inherited from Rails bases and define your own logging rules, for example:
165
173
 
166
174
  class ApplicationController < ActionController::Base
167
175
  def welcome
@@ -169,15 +177,14 @@ Since *#logger* is defined by Rails for classes you inherits from (*ActionContro
169
177
  end
170
178
  end
171
179
 
172
- # "#{Rails.root}/config/initializers/tagged_logger.rb"
173
- TaggedLogger.rules(:override=>true) do
180
+ # Rails.root/config/initializers/tagged_logger.rb
181
+ TaggedLogger.rules do
174
182
  debug /.*Controller$/ do |level, tag, msg|
175
183
  puts "Here I dump whatever happens in controllers, including ApplicationController"
176
184
  end
177
185
  end
178
186
 
179
187
 
180
-
181
188
  ## License
182
189
  *TaggedLogger* is released under the MIT license.
183
190
 
@@ -2,24 +2,29 @@ if defined?(Rails::Railtie)
2
2
  module TaggedLogger
3
3
  class Railtie < Rails::Railtie
4
4
  ActiveSupport.on_load(:action_controller) do
5
- TaggedLogger.send(:inject_logger_method_in_call_chain, ActionController::Base)
6
- TaggedLogger.send(:inject_logger_method_in_call_chain, ActionController::LogSubscriber)
7
- TaggedLogger.rename [ActionController::LogSubscriber] => "action_controller.instrumentation"
5
+ TaggedLogger.patch_logger(ActionController::Base, TaggedLogger.options[:replace_existing_logger]).
6
+ patch_logger(ActionController::LogSubscriber, TaggedLogger.options[:replace_existing_logger]).
7
+ rename [ActionController::LogSubscriber] => "action_controller.logsubscriber"
8
8
  end
9
9
  ActiveSupport.on_load(:active_record) do
10
- TaggedLogger.send(:inject_logger_method_in_call_chain, ActiveRecord::Base)
11
- TaggedLogger.send(:inject_logger_method_in_call_chain, ActiveRecord::LogSubscriber)
12
- TaggedLogger.rename [ActiveRecord::LogSubscriber] => "active_record.instrumentation"
10
+ TaggedLogger.patch_logger(ActiveRecord::Base, TaggedLogger.options[:replace_existing_logger]).
11
+ patch_logger(ActiveRecord::LogSubscriber, TaggedLogger.options[:replace_existing_logger]).
12
+ rename [ActiveRecord::LogSubscriber] => "active_record.logsubscriber"
13
13
  end
14
14
  ActiveSupport.on_load(:action_mailer) do
15
- TaggedLogger.send(:inject_logger_method_in_call_chain, ActionMailer::Base)
16
- TaggedLogger.send(:inject_logger_method_in_call_chain, ActionMailer::LogSubscriber)
17
- TaggedLogger.rename [ActionMailer::LogSubscriber] => "action_mailer.instrumentation"
15
+ TaggedLogger.patch_logger(ActionMailer::Base, TaggedLogger.options[:replace_existing_logger]).
16
+ patch_logger(ActionMailer::LogSubscriber, TaggedLogger.options[:replace_existing_logger]).
17
+ rename [ActionMailer::LogSubscriber] => "action_mailer.logsubscriber"
18
18
  end
19
19
  ActiveSupport.on_load(:action_view) do
20
- TaggedLogger.send(:inject_logger_method_in_call_chain, ActionView::LogSubscriber)
21
- TaggedLogger.rename [ActionView::LogSubscriber] => "action_view.instrumentation"
20
+ TaggedLogger.patch_logger(ActionView::LogSubscriber, TaggedLogger.options[:replace_existing_logger]).
21
+ rename [ActionView::LogSubscriber] => "action_view.logsubscriber"
22
22
  end
23
+ ActiveSupport.on_load(:after_initialize) do
24
+ TaggedLogger.patch_logger(Rails::Rack::Logger, TaggedLogger.options[:replace_existing_logger]).
25
+ rename [Rails::Rack::Logger] => "rack.logsubscriber"
26
+ end
27
+
23
28
  end
24
29
  end
25
30
  end
@@ -2,42 +2,59 @@ require 'delegate'
2
2
  require 'hashery/dictionary'
3
3
 
4
4
  module TaggedLogger
5
+
5
6
  @rename_rules = Dictionary.new
6
7
  @tag_blocks = Dictionary.new
7
- @overridees = []
8
-
8
+ @patched = []
9
+ @formatter = nil
10
+ @config = {}
11
+
9
12
  class << self
13
+
14
+ #Supported options: :replace_existing_logger => true/false
15
+ def config(options)
16
+ @config = options
17
+ self
18
+ end
19
+
20
+ def options
21
+ @config
22
+ end
23
+
24
+ def rules(&block)
25
+ patch_logger(Object, options[:replace_existing_logger]) unless @patched.include?(Object)
26
+ instance_eval(&block) if block
27
+ self
28
+ end
29
+
10
30
  def reset
31
+ unpatch_all
11
32
  @rename_rules = Dictionary.new
12
33
  @tag_blocks = Dictionary.new
13
- ObjectSpace.each_object(ClassSpecificLogger) { |obj| obj.detach }
14
- init
15
- end
16
-
17
- def rules(options = {}, &block)
18
- @options = options
19
- @old_methods_restored = false
20
- inject_logger_method_in_call_chain(Object)
21
- instance_eval(&block)
34
+ @formatter = nil
35
+ @config = {}
36
+ self
22
37
  end
23
38
 
39
+ def init
40
+ puts "TaggedLogger#init() is deprecated. Use TaggedLogger.rules with no block."
41
+ end
42
+
24
43
  def klass_has_method?(klass, method)
25
44
  klass.instance_methods(false).include?(RUBY_VERSION >= '1.9' ? method.to_sym : method.to_s)
26
45
  end
27
46
 
28
- def restore_old_logger_methods
29
- return if @old_methods_restored
30
- @old_methods_restored = true
31
- @overridees.each do |klass|
32
- if klass_has_method?(klass, :tagged_logger_original_logger)
33
- klass.class_eval {alias_method :logger, :tagged_logger_original_logger}
34
- elsif klass_has_method?(klass, :logger)
35
- klass.class_eval {remove_method :logger}
36
- end
37
- end
38
- @overridees = []
47
+ def format(&block)
48
+ @formatter = block
49
+ self
50
+ end
51
+
52
+ def rename(renames)
53
+ renames.each { |from, to| @rename_rules[tag_matcher(from)] = to }
54
+ self
39
55
  end
40
56
 
57
+ # should private, but used by ClassSpecificLogger
41
58
  def blocks_for(level, tag)
42
59
  blocks = []
43
60
  tag_aliases(tag) do |tag_alias|
@@ -48,8 +65,42 @@ module TaggedLogger
48
65
  blocks
49
66
  end
50
67
 
51
- def init
52
- rules {}
68
+ def patch_logger(patchee, replace_existing_logger)
69
+ return self if @patched.include?(patchee)
70
+
71
+ if klass_has_method?(patchee, :logger)
72
+ return self if !replace_existing_logger
73
+ #so we could resurrect old :logger method if we need
74
+ patchee.class_eval { alias_method :tagged_logger_original_logger, :logger }
75
+ end
76
+
77
+ @patched << patchee
78
+
79
+ patchee.class_eval do
80
+ def logger
81
+ klass = self.class == Class ? self : self.class
82
+ result = klass.class_eval do
83
+ return @class_logger if @class_logger
84
+ @class_logger = ClassSpecificLogger.new(klass)
85
+ @class_logger
86
+ end
87
+ result
88
+ end
89
+ end
90
+ self
91
+ end
92
+
93
+ private
94
+ def unpatch_all
95
+ @patched.each do |klass|
96
+ if klass_has_method?(klass, :tagged_logger_original_logger)
97
+ klass.class_eval {alias_method :logger, :tagged_logger_original_logger}
98
+ elsif klass_has_method?(klass, :logger)
99
+ klass.class_eval {remove_method :logger}
100
+ end
101
+ end
102
+ @patched = []
103
+ ObjectSpace.each_object(ClassSpecificLogger) { |obj| obj.detach }
53
104
  end
54
105
 
55
106
  def debug(what, where = {}, &block) output(:debug, what, where, &block) end
@@ -62,21 +113,12 @@ module TaggedLogger
62
113
  output(level, what, where, &block)
63
114
  end
64
115
  end
65
-
66
- def format(&block)
67
- @formatter = block
68
- end
69
116
 
70
117
  def formatter
71
118
  @formatter = lambda { |level, tag, message| "#{message}\n"} unless @formatter
72
119
  @formatter
73
120
  end
74
121
 
75
- def rename(renames)
76
- renames.each { |from, to| @rename_rules[tag_matcher(from)] = to }
77
- end
78
-
79
- private
80
122
  def output(level, what, where, &block)
81
123
  logger = where[:to]
82
124
  code = nil
@@ -144,31 +186,6 @@ module TaggedLogger
144
186
  end
145
187
  end
146
188
 
147
- def inject_logger_method_in_call_chain(definee_klass)
148
- return if @overridees.include?(definee_klass)
149
-
150
- if klass_has_method?(definee_klass, :logger)
151
- return if !@options[:override]
152
- #so we could resurrect old :logger method if we need
153
- definee_klass.class_eval { alias_method :tagged_logger_original_logger, :logger }
154
- end
155
-
156
- @overridees << definee_klass
157
-
158
- definee_klass.class_eval do
159
- def logger
160
- klass = self.class == Class ? self : self.class
161
- result = klass.class_eval do
162
- return @class_logger if @class_logger
163
- @class_logger = ClassSpecificLogger.new(klass)
164
- @class_logger
165
- end
166
- result
167
- end
168
- end
169
-
170
- end
171
-
172
189
  end # class methods
173
190
 
174
191
  class ClassSpecificLogger
@@ -9,11 +9,11 @@ class TaggedLoggerTest < Test::Unit::TestCase
9
9
  end
10
10
 
11
11
  teardown do
12
- TaggedLogger.restore_old_logger_methods
12
+ TaggedLogger.reset
13
13
  end
14
14
 
15
15
  should "be able to intialize with minimal effort, without defining any rules" do
16
- TaggedLogger.init
16
+ TaggedLogger.rules
17
17
  dont_allow(@@stub_out).write
18
18
  logger_method = RUBY_VERSION >= '1.9' ? :logger : "logger"
19
19
  assert Class.new.methods.include? logger_method
@@ -27,7 +27,6 @@ class TaggedLoggerTest < Test::Unit::TestCase
27
27
  def foo; logger.write("debug"); end
28
28
  end
29
29
  TaggedLogger.rules do
30
- reset
31
30
  debug(/.*/) { |level, tag, msg| @@stub_out.write("hmmm, something new") }
32
31
  end
33
32
  mock(@@stub_out).write("debug")
@@ -40,8 +39,8 @@ class TaggedLoggerTest < Test::Unit::TestCase
40
39
  def logger; @logger ||= Logger.new('/dev/null'); end
41
40
  def foo; logger.debug("debug"); end
42
41
  end
43
- TaggedLogger.rules(:override => true) do
44
- reset
42
+ TaggedLogger.config(:replace_existing_logger => true)
43
+ TaggedLogger.rules do
45
44
  debug(/.*/) { |level, tag, msg| @@stub_out.write(msg) }
46
45
  end
47
46
  mock(@@stub_out).write("debug")
@@ -51,7 +50,6 @@ class TaggedLoggerTest < Test::Unit::TestCase
51
50
  context "everything gets logged to @@stub_out;" do
52
51
  setup do
53
52
  TaggedLogger.rules do
54
- reset
55
53
  format {|level, tag, msg| "#{tag}: #{msg}"}
56
54
  debug /.*/, :to => Logger.new(@@stub_out)
57
55
  end
@@ -28,12 +28,13 @@ class TaggedLoggerRailsTest < Test::Unit::TestCase
28
28
  end
29
29
 
30
30
  teardown do
31
- TaggedLogger.restore_old_logger_methods
31
+ TaggedLogger.reset
32
32
  end
33
33
 
34
34
  should "be able possible to initialize in the way to override Rails existing logger" do
35
35
  assert TestController.new.respond_to? :logger
36
- TaggedLogger.rules(:override=>true) do
36
+ TaggedLogger.config(:replace_existing_logger => true)
37
+ TaggedLogger.rules do
37
38
  info /.*/ do |level, tag, message|
38
39
  @@stub_out.write(tag.to_s)
39
40
  end
@@ -43,10 +44,11 @@ class TaggedLoggerRailsTest < Test::Unit::TestCase
43
44
  end
44
45
 
45
46
  should "be possible to restore old logger methods" do
46
- TaggedLogger.rules(:override=>true) do
47
+ TaggedLogger.config(:replace_existing_logger => true)
48
+ TaggedLogger.rules do
47
49
  info(/.*/) {|level, tag, message|}
48
50
  end
49
- TaggedLogger.restore_old_logger_methods
51
+ TaggedLogger.reset
50
52
  mock(Test.rails_log_device).write("hi\n")
51
53
  TestController.new.hi
52
54
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tagged_logger
3
3
  version: !ruby/object:Gem::Version
4
- hash: 11
4
+ hash: 9
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 5
9
- - 0
10
- version: 0.5.0
9
+ - 1
10
+ version: 0.5.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Aleksandr Furmanov
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-10-29 00:00:00 -05:00
18
+ date: 2010-10-30 00:00:00 -05:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency