loggr 1.0.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/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ *.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in loggr.gemspec
4
+ gemspec
data/LICENSES.md ADDED
@@ -0,0 +1,15 @@
1
+ Simple Logging Facade for Java (SLF4J)
2
+ --------------------------------------
3
+
4
+ - License: http://www.slf4j.org/license.html, MIT license, (c) by QOS.ch
5
+ - File: lib/slf4j-api-1.6.1.jar
6
+ - URL: http://www.slf4j.org/
7
+ - Source: https://github.com/ceki/slf4j
8
+
9
+ Logback
10
+ -------
11
+
12
+ - License: http://logback.qos.ch/license.html, EPL 1.0, (c) by QOS.ch
13
+ - Files: lib/logback-classic-0.9.29.jar, lib/logback-core-0.9.29.jar
14
+ - URL: http://logback.qos.ch/
15
+ - Source: https://github.com/ceki/logback
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Lukas Westermann, at-point ag
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,230 @@
1
+ Loggr
2
+ =====
3
+
4
+ Loggr provides a factory for creating logger instances. It:
5
+
6
+ - Provides a wrapper for SLF4J (on JRuby)
7
+ - Has adapters for Stdlib Logger and ActiveSupport::BufferedLogger
8
+ - Supports Rails
9
+ - Handles using a Mapped Diagnostic Context (MDC)
10
+
11
+ **So, why should I use a logger factory instead of just `Logger.new('out.log')`
12
+ or `Rails.logger`?** Deploying the same application to different environments,
13
+ with different logging requirements, might make such a step necessary. Or when
14
+ trying to take advante of SLF4J-only features like the MDC or markers.
15
+
16
+ Information
17
+ -----------
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
+ **Bug Reports** No software is without bugs, if you discover a problem please report the issue.
25
+
26
+ https://github.com/at-point/loggr/issues
27
+
28
+ **Documentation** The latest RDocs are available on rubydoc.info.
29
+
30
+ http://rubydoc.info/github/at-point/loggr/master/frames
31
+
32
+ Installation
33
+ ------------
34
+
35
+ Like any gem, just add it to the Gemfile:
36
+
37
+ # stable version
38
+ gem 'loggr', '~> 1.0.0'
39
+
40
+ # latest development version
41
+ gem 'loggr', :git => 'git://github.com/at-point/loggr.git'
42
+
43
+ Getting started
44
+ ===============
45
+
46
+ Guides through creating some sample Logger instances and integration with Rails, if interested
47
+ in using the SLF4J Logger directly (without the factory), skip to _The SLF4J Wrapper_.
48
+
49
+ An example, application runs in development on MRI and production in a Jetty container
50
+ (Java/JRuby), lets assume you want to log there SQL using a logger named `jruby.rails.ActiveRecord`.
51
+
52
+ # config/initializers/logging.rb:
53
+ LoggerFactory.adapter = Rails.env.production? ? :slf4j : :rails
54
+ ActiveRecord::Base.logger = LoggerFactory.logger 'jruby.rails.ActiveRecord'
55
+
56
+ Once an adapter has been specified new logger instances can be easily created using:
57
+
58
+ def logger
59
+ @logger ||= LoggerFactory.logger 'my.app.SomeClass', :marker => "WORKER"
60
+ end
61
+
62
+ The adapter then handles creating new logger instances and uses features like the ability
63
+ to set markers (if supported), or setting a logger name. Based on the adapter a new logger
64
+ will be returned with all things defined like the marker, or a custom logger name - if the
65
+ adapter supports it, else it just tries to return a logger which has an API compatible with
66
+ those found by Stdlibs Logger.
67
+
68
+ The LoggerFactory
69
+ ------------------
70
+
71
+ Yap, is responsible for creating new loggers, a logger factory has an adapter, the adapter
72
+ defines how logger instances are really created.
73
+
74
+ ### Creating new loggers
75
+
76
+ LoggerFactory.logger 'app' # create a logger with named app
77
+ LoggerFactory.logger 'app', :to => 'debug.out' # write to debug.out
78
+ LoggerFactory.logger 'app', :to => $stderr # write to stderr
79
+
80
+ **Note:** not all adapters support all options, so some adapters might just ignore certain
81
+ options, but this is intended :)
82
+
83
+ ### Bundled Adapters
84
+
85
+ **<code>LoggerFactory.adapter = :base</code>**
86
+
87
+ The base adapter creates ruby stdlib `Logger` instances. Supported options for
88
+ `LoggerFactory.logger(name, options = {})` are:
89
+
90
+ - `: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`)
92
+
93
+ **<code>LoggerFactory.adapter = :buffered</code>**
94
+
95
+ Creates `ActiveSupport::BufferedLogger` instances and supports the same options
96
+ as the `:base` adapter.
97
+
98
+ **<code>LoggerFactory.adapter = :rails</code>**
99
+
100
+ This adapter alwasy returns the `Rails.logger`, which is very useful e.g. in development
101
+ environments or testing, where we just care that it's somewhere in our `logs/development.log`.
102
+ *Note:* Rails is automatically detected and the rails adapter is the default adapter when
103
+ `::Rails` is present - else the base adapter is the default.
104
+
105
+ **<code>LoggerFactory.adapter = :slf4j</code>**
106
+
107
+ SLF4J only works with JRuby (because it's Java) and you are responsible for a) having an
108
+ SLF4J implementation on the classpath and it's configuration. Furthermore slf4j supports
109
+ these options for `LoggerFactory.logger(name, options = {})`:
110
+
111
+ - `:marker`, String, additional marker logged with each statement (default: `nil`)
112
+
113
+ ### Using the Mapped Diagnostic Context (MDC)
114
+
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
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):
120
+
121
+ # app/controllers/application_controller.rb
122
+ class ApplicationController < ActionController::Base
123
+ around_filter :push_ip_to_mdc
124
+
125
+ private
126
+ def push_ip_to_mdc
127
+ LoggerFactory.mdc[:ip] = request.ip
128
+ yield
129
+ ensure
130
+ LoggerFactory.mdc.delete(:ip)
131
+ end
132
+ end
133
+
134
+ When using SLF4J all statements would now be annotated with the IP from where the request
135
+ was made from.
136
+
137
+ The _SLF4J_ Wrapper
138
+ ===================
139
+
140
+ Apart from the logger factory, this gem provides a ruby wrapper for logging using SLF4J and
141
+ taking advantage of:
142
+
143
+ - Same API as exposed by Stdlib Logger or AS::BufferedLogger
144
+ - SLF4J markers
145
+ - The Mapped Diagnostic Context (MDC)
146
+ - Access to SLF4J & Logback implementation JARs
147
+
148
+ The Logger
149
+ ----------
150
+
151
+ Creating a new logger is as simple as creating instances of `Loggr::SLF4J::Logger`:
152
+
153
+ # logger named "my.package.App"
154
+ @logger = Loggr::SLF4J::Logger.new 'my.package.App'
155
+
156
+ # logger named "some.sample.Application" => classes are converted to java notation
157
+ @logger = Loggr::SLF4J::Logger.new Some::Sample::Application
158
+
159
+ # logger with a default marker named "APP"
160
+ @logger = Loggr::SLF4J::Logger.new 'my.package.App', :marker => 'APP'
161
+
162
+ Logging events is like using Stdlib Logger:
163
+
164
+ # log with level INFO
165
+ @logger.info "some info message"
166
+
167
+ # log with level DEBUG, if enabled
168
+ @logger.debug "verbose information" if @logger.debug?
169
+
170
+ # log with level DEBUG and marker "QUEUE" (masking as progname)
171
+ @logger.debug "do something", "QUEUE"
172
+
173
+ The MDC
174
+ -------
175
+
176
+ A wrapper hash for SLF4Js Mapped Diagnostic Context is available using `Loggr::SLF4J::MDC`
177
+ like a hash:
178
+
179
+ begin
180
+ Loggr::SLF4J::MDC[:user] = username
181
+ do_some_stuff
182
+ ensure
183
+ Loggr::SLF4J::MDC.delete(:user)
184
+ end
185
+
186
+ It's a good practice to wrap MDC set/get into begin/ensure blocks to ensure the value
187
+ is cleared afterwards, even in case of errors. The user is responsible for getting rid
188
+ of these values. To just clear all values use `Loggr::SLF4J::MDC.clear`
189
+
190
+ Extending & Contributing
191
+ ========================
192
+
193
+ Of course any custom adapters (e.g. for log4r or the logging gem) are greatly appreciated.
194
+ To write a custom adapter just do something like:
195
+
196
+ class MyModule::MyCustomAdapter < Loggr::Adpater::AbstractAdapter
197
+ def logger(name, options = {})
198
+ # build logger instances and return it
199
+ end
200
+ end
201
+
202
+ # use custom adapter
203
+ LoggerFactory.adapter = MyModule::MyCustomAdapter.new
204
+
205
+ Extending from `Loggr::Adapter::AbstractAdapter` provides the adapter with a default
206
+ MDC implementation (backed by a hash stored in a thread local).
207
+
208
+ Similar to ActiveModel there are also Lint tests available to verify if your adapter
209
+ and the logger and mdc returned adhere to the API.
210
+
211
+ class MyModule::MyCustomAdapterTest < Test::Unit::TestCase
212
+ include Loggr::Lint::Tests
213
+
214
+ def setup
215
+ # required, so the Lint Tests can pick it up
216
+ @adapter = MyModule::MyCustomAdapter.new
217
+ end
218
+ end
219
+
220
+ Contribute
221
+ ----------
222
+
223
+ 1. Fork this project and hack away
224
+ 2. Ensure that the changes are well tested
225
+ 3. Send pull request
226
+
227
+ License & Copyright
228
+ -------------------
229
+
230
+ Loggr is licensed under the MIT License, (c) 2011 by at-point ag.
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ require 'bundler'
2
+ require 'rake/testtask'
3
+
4
+ # to fix warnings
5
+ include Rake::DSL
6
+
7
+ Bundler::GemHelper.install_tasks
8
+
9
+ desc 'Test the loggr gem.'
10
+ Rake::TestTask.new(:test) do |t|
11
+ t.libs << 'test'
12
+ t.pattern = 'test/**/*_test.rb'
13
+ t.verbose = true
14
+ end
Binary file
Binary file
data/lib/loggr.rb ADDED
@@ -0,0 +1,38 @@
1
+ #--
2
+ # Copyright (c) 2011 Lukas Westermann, at-point ag
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #++
23
+
24
+ module Loggr
25
+ autoload :Adapter, 'loggr/adapter'
26
+ autoload :Severity, 'loggr/severity'
27
+ autoload :Lint, 'loggr/lint'
28
+
29
+ autoload :SLF4J, 'loggr/slf4j'
30
+
31
+ autoload :VERSION, 'loggr/version'
32
+
33
+ # Ensure we've got the Log Levels covered
34
+ include Loggr::Severity
35
+ end
36
+
37
+ # Autoloading the factory into the root.
38
+ autoload :LoggerFactory, 'loggr/factory'
@@ -0,0 +1,114 @@
1
+ module Loggr
2
+
3
+ # The factory is responsible for getting Logger instances from
4
+ # the adapters.
5
+ #
6
+ # It delegates both the `logger` and `mdc` calls to the current
7
+ # adpater.
8
+ #
9
+ # The adpater can be changed by setting `adpater = ...`:
10
+ #
11
+ # Loggr.adapter = Loggr::Adapter::SLF4J
12
+ #
13
+ # @see #logger, #mdc
14
+ module Adapter
15
+
16
+ # An abstract base class, which provides a simple MDC implementation
17
+ autoload :AbstractAdapter, 'loggr/adapter/abstract'
18
+
19
+ # Adapter for Ruby Stdlib Logger
20
+ autoload :Base, 'loggr/adapter/base'
21
+
22
+ # Adapter for ActiveSupport::BufferedLogger, requires AS
23
+ autoload :Buffered, 'loggr/adapter/buffered'
24
+
25
+ # Adapter which uses Rails.logger
26
+ autoload :Rails, 'loggr/adapter/rails'
27
+
28
+ # Adpater for SLF4J
29
+ autoload :SLF4J, 'loggr/adapter/slf4j'
30
+
31
+ # Get the backend, if no backend is defined uses the default backend.
32
+ #
33
+ # If running in a rails environment, automatically chooses the rails
34
+ # adapter as a default, else base is used.
35
+ def adapter
36
+ @adapter ||= Object.const_defined?(:Rails) ? Loggr::Adapter::Rails : Loggr::Adapter::Base
37
+ end
38
+
39
+ # Set a new adapter, either as string, class or whatever :)
40
+ #
41
+ def adapter=(new_adapter)
42
+ @adapter = get_adapter(new_adapter)
43
+ end
44
+
45
+ # Get a new logger instance for supplied named logger or class name.
46
+ #
47
+ # All adapters must ensure that they provide the same API for creating
48
+ # new loggers. Each logger has a name, further possible options are:
49
+ #
50
+ # - `:to`, filename or IO, where to write the output to
51
+ # - `:level`, Fixnum, starting log level, @see `Loggr::Severity`
52
+ # - `:marker`, String, name of the category/marker
53
+ #
54
+ # If an adapter does not support setting a specific option, just
55
+ # ignore it.
56
+ def logger(name, options = {}, &block)
57
+ use_adapter = options.key?(:adapter) ? get_adapter(options.delete(:adapter)) : self.adapter
58
+ use_adapter.logger(name, options).tap do |logger|
59
+ yield(logger) if block_given?
60
+ end
61
+ end
62
+
63
+ # The Mapped Diagnostic Context is a basically a hash where values
64
+ # can be stored for certain keys, the context must be stored per thread.
65
+ #
66
+ # The most basic MDC implementation is `Thread.local['my_simple_mdc'] ||= Hash.new`.
67
+ #
68
+ # If a adapter provides a native MDC implementation ensure it does expose
69
+ # these methods:
70
+ #
71
+ # - `def []=(key, value)`, set a property in the MDC
72
+ # - `def [](key)`, get a property from the MDC
73
+ # - `def delete(key)`, delete a property in the MDC
74
+ # - `def clear()`, deletes all properties from the MDC
75
+ # - `def to_hash`, access MDC as standard ruby hash (might be clone, though!)
76
+ #
77
+ # Well it should basically behave like a Ruby Hash, eventhough not with all
78
+ # options.
79
+ def mdc
80
+ self.adapter.mdc
81
+ end
82
+
83
+ protected
84
+
85
+ # Try to get adapter class from Symbol, String or use Object as-is.
86
+ #
87
+ def get_adapter(adp)
88
+ adp = Loggr::Adapter::SLF4J if adp == :slf4j # okay, this is only because we can't camelize it :)
89
+
90
+ # Code adapter from ActiveSupport::Inflector#camelize
91
+ # https://github.com/rails/rails/blob/v3.0.9/activesupport/lib/active_support/inflector/methods.rb#L30
92
+ adp = adp.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase } if adp.is_a?(Symbol)
93
+
94
+ clazz = adp
95
+
96
+ if adp.respond_to?(:to_str)
97
+ const = begin Loggr::Adapter.const_get(adp.to_s) rescue nil end
98
+ unless const
99
+ # code adapter from ActiveSupport::Inflector#constantize
100
+ # https://github.com/rails/rails/blob/v3.0.9/activesupport/lib/active_support/inflector/methods.rb#L107
101
+ names = adp.to_s.split('::')
102
+ names.shift if names.empty? || names.first.empty?
103
+
104
+ const = ::Object
105
+ names.each { |n| const = const.const_get(n) }
106
+ end
107
+ clazz = const
108
+ end
109
+
110
+ raise "#{clazz}: an adapter must implement #logger and #mdc" unless clazz.respond_to?(:logger) && clazz.respond_to?(:mdc)
111
+ clazz
112
+ end
113
+ end
114
+ end