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.
- data/README.markdown +39 -32
- data/lib/tagged_logger/railtie.rb +16 -11
- data/lib/tagged_logger/tagged_logger.rb +75 -58
- data/test/test.rb +4 -6
- data/test/test_rails.rb +6 -4
- metadata +4 -4
data/README.markdown
CHANGED
@@ -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
|
58
|
-
It means, for example, that if no rules defined all these methods do nothing
|
59
|
-
reasons, I like to log a lot and I do not want calls like *#logger.debug()*
|
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.
|
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
|
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
|
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
|
127
|
-
|
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
|
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
|
-
|
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
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
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
|
-
|
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
|
156
|
-
#
|
167
|
+
debug /\.logsubscriber$/ do |level, tag, msg|
|
168
|
+
#your special logging
|
157
169
|
end
|
158
170
|
|
159
171
|
|
160
|
-
|
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
|
-
#
|
173
|
-
TaggedLogger.rules
|
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.
|
6
|
-
|
7
|
-
|
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.
|
11
|
-
|
12
|
-
|
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.
|
16
|
-
|
17
|
-
|
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.
|
21
|
-
|
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
|
-
@
|
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
|
-
|
14
|
-
|
15
|
-
|
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
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
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
|
52
|
-
|
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
|
data/test/test.rb
CHANGED
@@ -9,11 +9,11 @@ class TaggedLoggerTest < Test::Unit::TestCase
|
|
9
9
|
end
|
10
10
|
|
11
11
|
teardown do
|
12
|
-
TaggedLogger.
|
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.
|
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.
|
44
|
-
|
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
|
data/test/test_rails.rb
CHANGED
@@ -28,12 +28,13 @@ class TaggedLoggerRailsTest < Test::Unit::TestCase
|
|
28
28
|
end
|
29
29
|
|
30
30
|
teardown do
|
31
|
-
TaggedLogger.
|
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.
|
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.
|
47
|
+
TaggedLogger.config(:replace_existing_logger => true)
|
48
|
+
TaggedLogger.rules do
|
47
49
|
info(/.*/) {|level, tag, message|}
|
48
50
|
end
|
49
|
-
TaggedLogger.
|
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:
|
4
|
+
hash: 9
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 5
|
9
|
-
-
|
10
|
-
version: 0.5.
|
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-
|
18
|
+
date: 2010-10-30 00:00:00 -05:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|