tagged_logger 0.5.0 → 0.5.1

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