loggr 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,5 +1,6 @@
1
1
  *.gem
2
+ *.rbc
2
3
  .bundle
3
- Gemfile.lock
4
+ *.lock
4
5
  pkg/*
5
6
  *.log
@@ -0,0 +1,12 @@
1
+ rvm:
2
+ - 1.8.7
3
+ - 1.9.2
4
+ - 1.9.3
5
+ - jruby
6
+ - rbx
7
+ - rbx-2.0
8
+ - ree
9
+
10
+ notifications:
11
+ recipients:
12
+ - lukas@at-point.ch
@@ -0,0 +1,11 @@
1
+ appraise "activesupport-3.0.x" do
2
+ gem 'activesupport', '~> 3.0.9'
3
+ end
4
+
5
+ appraise "activesupport-3.1" do
6
+ gem 'activesupport', '~> 3.1.0'
7
+ end
8
+
9
+ appraise "activesupport-head" do
10
+ gem 'activesupport', :path => '../../rails/activesupport/'
11
+ end
data/README.md CHANGED
@@ -5,7 +5,7 @@ Loggr provides a factory for creating logger instances. It:
5
5
 
6
6
  - Provides a wrapper for SLF4J (on JRuby)
7
7
  - Has adapters for Stdlib Logger and ActiveSupport::BufferedLogger
8
- - Supports Rails
8
+ - Supports Rails, including the new `tagged` method
9
9
  - Handles using a Mapped Diagnostic Context (MDC)
10
10
 
11
11
  **So, why should I use a logger factory instead of just `Logger.new('out.log')`
@@ -16,11 +16,6 @@ trying to take advante of SLF4J-only features like the MDC or markers.
16
16
  Information
17
17
  -----------
18
18
 
19
- **Wiki** The Loggr Wiki will hopefully soon be filled with how-to articles and
20
- frequently asked questions.
21
-
22
- https://github.com/at-point/loggr/wiki
23
-
24
19
  **Bug Reports** No software is without bugs, if you discover a problem please report the issue.
25
20
 
26
21
  https://github.com/at-point/loggr/issues
@@ -29,17 +24,21 @@ https://github.com/at-point/loggr/issues
29
24
 
30
25
  http://rubydoc.info/github/at-point/loggr/master/frames
31
26
 
27
+ **Gem** The latest stable gem is always on rubygems.org.
28
+
29
+ http://rubygems.org/gems/loggr
30
+
32
31
  Installation
33
32
  ------------
34
33
 
35
34
  Like any gem, just add it to the Gemfile:
36
35
 
37
36
  # stable version
38
- gem 'loggr', '~> 1.0.0'
39
-
37
+ gem 'loggr', '~> 1.1.0'
38
+
40
39
  # latest development version
41
40
  gem 'loggr', :git => 'git://github.com/at-point/loggr.git'
42
-
41
+
43
42
  Getting started
44
43
  ===============
45
44
 
@@ -58,7 +57,7 @@ Once an adapter has been specified new logger instances can be easily created us
58
57
  def logger
59
58
  @logger ||= LoggerFactory.logger 'my.app.SomeClass', :marker => "WORKER"
60
59
  end
61
-
60
+
62
61
  The adapter then handles creating new logger instances and uses features like the ability
63
62
  to set markers (if supported), or setting a logger name. Based on the adapter a new logger
64
63
  will be returned with all things defined like the marker, or a custom logger name - if the
@@ -76,33 +75,33 @@ defines how logger instances are really created.
76
75
  LoggerFactory.logger 'app' # create a logger with named app
77
76
  LoggerFactory.logger 'app', :to => 'debug.out' # write to debug.out
78
77
  LoggerFactory.logger 'app', :to => $stderr # write to stderr
79
-
78
+
80
79
  **Note:** not all adapters support all options, so some adapters might just ignore certain
81
80
  options, but this is intended :)
82
81
 
83
82
  ### Bundled Adapters
84
83
 
85
- **<code>LoggerFactory.adapter = :base</code>**
84
+ **LoggerFactory.adapter = :base**
86
85
 
87
86
  The base adapter creates ruby stdlib `Logger` instances. Supported options for
88
87
  `LoggerFactory.logger(name, options = {})` are:
89
88
 
90
89
  - `:to`, String or IO, where to log should be written to (default: `"#{name}.log"`)
91
- - `:level`, Fixnum, one of `Logger::Severity`, the minimum severity to log (default: `Logger::Severity::DEBUG`)
90
+ - `:level`, Fixnum, one of `Logger::Severity`, the minimum severity to log (default: `Logger::Severity::INFO`)
92
91
 
93
- **<code>LoggerFactory.adapter = :buffered</code>**
92
+ **LoggerFactory.adapter = :buffered**
94
93
 
95
94
  Creates `ActiveSupport::BufferedLogger` instances and supports the same options
96
95
  as the `:base` adapter.
97
96
 
98
- **<code>LoggerFactory.adapter = :rails</code>**
97
+ **LoggerFactory.adapter = :rails**
99
98
 
100
99
  This adapter alwasy returns the `Rails.logger`, which is very useful e.g. in development
101
100
  environments or testing, where we just care that it's somewhere in our `logs/development.log`.
102
101
  *Note:* Rails is automatically detected and the rails adapter is the default adapter when
103
102
  `::Rails` is present - else the base adapter is the default.
104
103
 
105
- **<code>LoggerFactory.adapter = :slf4j</code>**
104
+ **LoggerFactory.adapter = :slf4j**
106
105
 
107
106
  SLF4J only works with JRuby (because it's Java) and you are responsible for a) having an
108
107
  SLF4J implementation on the classpath and it's configuration. Furthermore slf4j supports
@@ -112,38 +111,42 @@ these options for `LoggerFactory.logger(name, options = {})`:
112
111
 
113
112
  ### Using the Mapped Diagnostic Context (MDC)
114
113
 
115
- Some loggers provide a MDC (or mapped diagnostic context), which can be used to annotate
116
- log outputs with additional bits of information. At the moment only SLF4J really can make
114
+ Some loggers provide a MDC (or mapped diagnostic context) or a similar feature like
115
+ ActiveSupport 3.2s `TaggedLogging#tagged` which can be used to annotate log outputs with
116
+ additional bits of information. At the moment only SLF4J and ActiveSupport 3.2 can make
117
117
  use of this. Though, to provide a clean and consistent API all adapters _must_ provide
118
- access to an MDC, so the MDC can be used in code no matter the adapter, a sample use case
119
- (in Rails):
118
+ access to an MDC and each logger _must_ respond to both `tagged` and `mapped`, so these
119
+ features can be used in code no matter the adapter.
120
+
121
+ A sample use case:
120
122
 
121
123
  # app/controllers/application_controller.rb
122
124
  class ApplicationController < ActionController::Base
123
125
  around_filter :push_ip_to_mdc
124
-
125
- private
126
+ def logger; @logger ||= LoggerFactory.logger('sample') end
127
+
128
+ private
126
129
  def push_ip_to_mdc
127
- LoggerFactory.mdc[:ip] = request.ip
128
- yield
129
- ensure
130
- LoggerFactory.mdc.delete(:ip)
130
+ logger.mapped(:ip => request.ip) do
131
+ yield
132
+ end
131
133
  end
132
134
  end
133
-
135
+
134
136
  When using SLF4J all statements would now be annotated with the IP from where the request
135
- was made from.
137
+ was made from, when using Rails 3.2 it would use it's support for `tagged` and add a tag
138
+ named `ip=....`.
136
139
 
137
- The _SLF4J_ Wrapper
138
- ===================
140
+ The SLF4J Wrapper
141
+ =================
139
142
 
140
143
  Apart from the logger factory, this gem provides a ruby wrapper for logging using SLF4J and
141
144
  taking advantage of:
142
145
 
143
- - Same API as exposed by Stdlib Logger or AS::BufferedLogger
146
+ - Same API as exposed by Stdlib Logger, AS::BufferedLogger and AS::TaggedLogging
144
147
  - SLF4J markers
145
148
  - The Mapped Diagnostic Context (MDC)
146
- - Access to SLF4J & Logback implementation JARs
149
+ - Access to SLF4J & Logback implementation JARs
147
150
 
148
151
  The Logger
149
152
  ----------
@@ -152,21 +155,21 @@ Creating a new logger is as simple as creating instances of `Loggr::SLF4J::Logge
152
155
 
153
156
  # logger named "my.package.App"
154
157
  @logger = Loggr::SLF4J::Logger.new 'my.package.App'
155
-
158
+
156
159
  # logger named "some.sample.Application" => classes are converted to java notation
157
160
  @logger = Loggr::SLF4J::Logger.new Some::Sample::Application
158
-
161
+
159
162
  # logger with a default marker named "APP"
160
163
  @logger = Loggr::SLF4J::Logger.new 'my.package.App', :marker => 'APP'
161
-
164
+
162
165
  Logging events is like using Stdlib Logger:
163
166
 
164
167
  # log with level INFO
165
168
  @logger.info "some info message"
166
-
169
+
167
170
  # log with level DEBUG, if enabled
168
171
  @logger.debug "verbose information" if @logger.debug?
169
-
172
+
170
173
  # log with level DEBUG and marker "QUEUE" (masking as progname)
171
174
  @logger.debug "do something", "QUEUE"
172
175
 
@@ -187,21 +190,42 @@ It's a good practice to wrap MDC set/get into begin/ensure blocks to ensure the
187
190
  is cleared afterwards, even in case of errors. The user is responsible for getting rid
188
191
  of these values. To just clear all values use `Loggr::SLF4J::MDC.clear`
189
192
 
193
+ Tagging and mapping
194
+ -------------------
195
+
196
+ As an alternative to using the MDC directly, each logger exposes a method which is more
197
+ ruby-like than setting the MDC and having to handle the `ensure` all by itself.
198
+
199
+ logger.mapped(:user => username) do
200
+ do_some_stuff
201
+ end
202
+
203
+ This ensures that the key is cleared at the end, these calls can also be easily nested.
204
+ Starting with ActiveSupport 3.2 there's support for `TaggedLogging`, SLF4J mimics this
205
+ behaviour by using the mapped diagnostic context:
206
+
207
+ logger.tagged("some", "values") do
208
+ do_some_stuff
209
+ end
210
+
211
+ Within the block the MDC has been assigned `some, values` to the key `:tags`. Nested values
212
+ are just appended to this key.
213
+
190
214
  Extending & Contributing
191
215
  ========================
192
216
 
193
217
  Of course any custom adapters (e.g. for log4r or the logging gem) are greatly appreciated.
194
218
  To write a custom adapter just do something like:
195
219
 
196
- class MyModule::MyCustomAdapter < Loggr::Adpater::AbstractAdapter
220
+ class MyModule::MyCustomAdapter < Loggr::Adpater::AbstractAdapter
197
221
  def logger(name, options = {})
198
222
  # build logger instances and return it
199
- end
223
+ end
200
224
  end
201
-
225
+
202
226
  # use custom adapter
203
227
  LoggerFactory.adapter = MyModule::MyCustomAdapter.new
204
-
228
+
205
229
  Extending from `Loggr::Adapter::AbstractAdapter` provides the adapter with a default
206
230
  MDC implementation (backed by a hash stored in a thread local).
207
231
 
@@ -210,7 +234,7 @@ and the logger and mdc returned adhere to the API.
210
234
 
211
235
  class MyModule::MyCustomAdapterTest < Test::Unit::TestCase
212
236
  include Loggr::Lint::Tests
213
-
237
+
214
238
  def setup
215
239
  # required, so the Lint Tests can pick it up
216
240
  @adapter = MyModule::MyCustomAdapter.new
data/Rakefile CHANGED
@@ -1,11 +1,13 @@
1
+ require 'rubygems'
1
2
  require 'bundler'
3
+ require 'appraisal'
2
4
  require 'rake/testtask'
3
5
 
4
- # to fix warnings
5
- include Rake::DSL
6
-
7
6
  Bundler::GemHelper.install_tasks
8
7
 
8
+ desc 'Default: run unit tests.'
9
+ task :default => :test
10
+
9
11
  desc 'Test the loggr gem.'
10
12
  Rake::TestTask.new(:test) do |t|
11
13
  t.libs << 'test'
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "http://rubygems.org"
4
+
5
+ gem "activesupport", "~> 3.0.9"
6
+
7
+ gemspec :path=>"../"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "http://rubygems.org"
4
+
5
+ gem "activesupport", "~> 3.1.0"
6
+
7
+ gemspec :path=>"../"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "http://rubygems.org"
4
+
5
+ gem "activesupport", :path=>"../../rails/activesupport/"
6
+
7
+ gemspec :path=>"../"
@@ -8,10 +8,10 @@
8
8
  # distribute, sublicense, and/or sell copies of the Software, and to
9
9
  # permit persons to whom the Software is furnished to do so, subject to
10
10
  # the following conditions:
11
- #
11
+ #
12
12
  # The above copyright notice and this permission notice shall be
13
13
  # included in all copies or substantial portions of the Software.
14
- #
14
+ #
15
15
  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
16
  # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
17
  # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@@ -22,16 +22,16 @@
22
22
  #++
23
23
 
24
24
  module Loggr
25
- autoload :Adapter, 'loggr/adapter'
25
+ autoload :Adapter, 'loggr/adapter'
26
26
  autoload :Severity, 'loggr/severity'
27
27
  autoload :Lint, 'loggr/lint'
28
-
28
+
29
29
  autoload :SLF4J, 'loggr/slf4j'
30
-
31
- autoload :VERSION, 'loggr/version'
32
-
30
+
31
+ autoload :GEM_VERSION, 'loggr/version'
32
+
33
33
  # Ensure we've got the Log Levels covered
34
- include Loggr::Severity
34
+ include Loggr::Severity
35
35
  end
36
36
 
37
37
  # Autoloading the factory into the root.
@@ -85,7 +85,8 @@ module Loggr
85
85
  # Try to get adapter class from Symbol, String or use Object as-is.
86
86
  #
87
87
  def get_adapter(adp)
88
- adp = Loggr::Adapter::SLF4J if adp == :slf4j # okay, this is only because we can't camelize it :)
88
+ # okay, this is only because we can't camelize it :)
89
+ adp = Loggr::Adapter::NOP if !adp
89
90
 
90
91
  # Code adapter from ActiveSupport::Inflector#camelize
91
92
  # https://github.com/rails/rails/blob/v3.0.9/activesupport/lib/active_support/inflector/methods.rb#L30
@@ -94,7 +95,7 @@ module Loggr
94
95
  clazz = adp
95
96
 
96
97
  if adp.respond_to?(:to_str)
97
- const = begin Loggr::Adapter.const_get(adp.to_s) rescue nil end
98
+ const = begin Loggr::Adapter.const_get(adp.to_s) rescue begin Loggr::Adapter.const_get(adp.to_s.upcase) rescue nil end end
98
99
  unless const
99
100
  # code adapter from ActiveSupport::Inflector#constantize
100
101
  # https://github.com/rails/rails/blob/v3.0.9/activesupport/lib/active_support/inflector/methods.rb#L107
@@ -1,25 +1,25 @@
1
1
  module Loggr
2
2
  module Adapter
3
-
3
+
4
4
  # A basically abstract base class for logger backend
5
5
  # implementations, provides a default implementation for MDC (hash & thread local based).
6
6
  #
7
7
  # Ensure to implement `#logger`.
8
- #
8
+ #
9
9
  class AbstractAdapter
10
-
10
+
11
11
  # Implement which creates a new instance of a logger.
12
12
  def logger(name, options = {})
13
13
  raise "#{self.class.name}#logger is declared `abstract': implement #logger method"
14
14
  end
15
-
15
+
16
16
  # Use a simple thread local hash as fake MDC, because it's
17
17
  # not supported by the logger anyway - but it should be available
18
18
  # for consistency and usage.
19
19
  def mdc
20
20
  mdc_key = "#{self.class.name}.mdc"
21
21
  Thread.current[mdc_key] ||= Hash.new
22
- end
22
+ end
23
23
  end
24
24
  end
25
25
  end
@@ -1,33 +1,34 @@
1
1
  require 'loggr/adapter/abstract'
2
- require 'logger'
2
+ require 'loggr/support/annotations'
3
3
 
4
4
  module Loggr
5
5
  module Adapter
6
-
6
+
7
7
  # Default backend which is backed Rubys Stdlib Logger.
8
8
  #
9
9
  class BaseAdapter < AbstractAdapter
10
-
11
- #
10
+
11
+ #
12
12
  #
13
13
  def logger(name, options = {})
14
14
  name = normalize_name(name)
15
15
  @loggers ||= {}
16
16
  @loggers[name] ||= build_new_logger(name, options)
17
17
  end
18
-
18
+
19
19
  protected
20
20
  # Constructs a new logger instance for the supplied options, is called
21
21
  # by `#loggers` when no logger with this name already exists - instead of
22
22
  # creating a new logger...
23
23
  #
24
24
  def build_new_logger(name, options = {})
25
- ::Logger.new(options[:to] || "#{name.to_s.gsub(/[:\s\/]+/, '_')}.log").tap do |logger|
25
+ logger = ::Logger.new(options[:to] || "#{name.to_s.gsub(/[:\s\/]+/, '_')}.log").tap do |logger|
26
26
  logger.level = options[:level] || Logger::INFO
27
27
  logger.progname = name
28
- end
28
+ end
29
+ Loggr::Support::Annotations.enhance(logger)
29
30
  end
30
-
31
+
31
32
  # Because we should also allow using class names, or objects
32
33
  # to construct new loggers (like in SLF4J), it makes sense to
33
34
  # have a method which normalizes some input, be it a string or
@@ -45,9 +46,9 @@ module Loggr
45
46
  when Module then name.name.to_s
46
47
  else name.class.name.to_s
47
48
  end
48
- end
49
+ end
49
50
  end
50
-
51
+
51
52
  # Okay, basically a singleton thus create instance
52
53
  Base = BaseAdapter.new
53
54
  end