loggr 1.0.0 → 1.1.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 +2 -1
- data/.travis.yml +12 -0
- data/Appraisals +11 -0
- data/README.md +66 -42
- data/Rakefile +5 -3
- data/gemfiles/activesupport-3.0.x.gemfile +7 -0
- data/gemfiles/activesupport-3.1.gemfile +7 -0
- data/gemfiles/activesupport-head.gemfile +7 -0
- data/lib/loggr.rb +8 -8
- data/lib/loggr/adapter.rb +3 -2
- data/lib/loggr/adapter/abstract.rb +5 -5
- data/lib/loggr/adapter/base.rb +11 -10
- data/lib/loggr/adapter/buffered.rb +6 -4
- data/lib/loggr/adapter/nop.rb +10 -6
- data/lib/loggr/lint.rb +35 -21
- data/lib/loggr/slf4j/logger.rb +39 -16
- data/lib/loggr/slf4j/mdc.rb +9 -9
- data/lib/loggr/support/annotations.rb +40 -0
- data/lib/loggr/version.rb +2 -1
- data/loggr.gemspec +4 -2
- data/test/test_helper.rb +16 -10
- data/test/unit/adapter/base_test.rb +14 -14
- data/test/unit/adapter/buffered_test.rb +11 -11
- data/test/unit/adapter/rails_test.rb +4 -6
- data/test/unit/factory_test.rb +26 -11
- data/test/unit/slf4j/logger_test.rb +62 -26
- metadata +112 -109
@@ -1,24 +1,26 @@
|
|
1
1
|
require 'loggr/adapter/base'
|
2
|
+
require 'loggr/support/annotations'
|
2
3
|
require 'active_support/buffered_logger'
|
3
4
|
|
4
5
|
module Loggr
|
5
6
|
module Adapter
|
6
|
-
|
7
|
+
|
7
8
|
# Backend for `ActiveSupport::BufferedLogger`.
|
8
9
|
#
|
9
10
|
class BufferedAdapter < BaseAdapter
|
10
|
-
|
11
|
+
|
11
12
|
protected
|
12
13
|
# Creates a new `AS::BufferedLogger` instance, note that BufferedLogger has
|
13
14
|
# no support for setting a default progname, so `name` is basically ignored.
|
14
15
|
#
|
15
16
|
def build_new_logger(name, options = {})
|
16
|
-
ActiveSupport::BufferedLogger.new(options[:to] || "#{name.to_s.gsub(/[\s\/]+/, '_')}.log").tap do |logger|
|
17
|
+
logger = ActiveSupport::BufferedLogger.new(options[:to] || "#{name.to_s.gsub(/[\s\/]+/, '_')}.log").tap do |logger|
|
17
18
|
logger.level = options[:level] || ActiveSupport::BufferedLogger::INFO
|
18
19
|
end
|
20
|
+
Loggr::Support::Annotations.enhance(logger)
|
19
21
|
end
|
20
22
|
end
|
21
|
-
|
23
|
+
|
22
24
|
# THE instance
|
23
25
|
Buffered = BufferedAdapter.new
|
24
26
|
end
|
data/lib/loggr/adapter/nop.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'loggr/adapter/abstract'
|
2
|
+
require 'loggr/support/annotations'
|
2
3
|
|
3
4
|
module Loggr
|
4
5
|
module Adapter
|
@@ -6,14 +7,17 @@ module Loggr
|
|
6
7
|
# Silences all logging operations, nothing is written at all.
|
7
8
|
#
|
8
9
|
class NOPAdapter < AbstractAdapter
|
9
|
-
|
10
|
+
|
10
11
|
class NOPLogger
|
11
12
|
# Has no impact anyway :)
|
12
13
|
attr_accessor :level
|
13
|
-
|
14
|
+
|
14
15
|
# Just to ensure compatiability with AS::BufferedLogger
|
15
16
|
attr_reader :auto_flushing, :flush, :close
|
16
|
-
|
17
|
+
|
18
|
+
# Support fuer Annotations wie `tagged` und `mapped`.
|
19
|
+
include Loggr::Support::Annotations::NOPSupport
|
20
|
+
|
17
21
|
# Yields empty implementations for all severities
|
18
22
|
%w{trace debug info warn error fatal}.each do |severity|
|
19
23
|
class_eval <<-EOT, __FILE__, __LINE__ + 1
|
@@ -26,13 +30,13 @@ module Loggr
|
|
26
30
|
EOT
|
27
31
|
end
|
28
32
|
end
|
29
|
-
|
33
|
+
|
30
34
|
# Get single NOPLogger instance
|
31
35
|
def logger(name, options = {})
|
32
36
|
@logger ||= NOPLogger.new
|
33
|
-
end
|
37
|
+
end
|
34
38
|
end
|
35
|
-
|
39
|
+
|
36
40
|
# THE instance
|
37
41
|
NOP = NOPAdapter.new
|
38
42
|
end
|
data/lib/loggr/lint.rb
CHANGED
@@ -2,27 +2,51 @@ require 'tempfile'
|
|
2
2
|
|
3
3
|
module Loggr
|
4
4
|
module Lint
|
5
|
-
|
5
|
+
|
6
6
|
# == Adapter and Logger Lint Tests
|
7
7
|
#
|
8
8
|
# You can test whether an object provides a compliant adapter and logger
|
9
9
|
# by including <tt>Logger::Lint::Tests</tt>
|
10
10
|
# in your tests.
|
11
11
|
#
|
12
|
-
# Ensure you set the instance variable <tt>@adapter</tt> to
|
12
|
+
# Ensure you set the instance variable <tt>@adapter</tt> to the adapter to lint.
|
13
13
|
#
|
14
14
|
module Tests
|
15
|
+
|
16
|
+
# Verifies `adapter#logger`, it checks that:
|
17
|
+
#
|
18
|
+
# - the factory method named #logger exists
|
19
|
+
# - that it accepts two arguments, name and options hash
|
20
|
+
# - the returned instnace responds to debug, info, warn, error and fatal
|
21
|
+
# - responds to tagged and mapped
|
22
|
+
#
|
15
23
|
def test_adapter_logger
|
16
24
|
assert adapter.respond_to?(:logger), "The adapter should respond to #logger"
|
17
|
-
assert adapter.method('logger').arity == -2, "The adapter should accept two parameters for #logger, name and options hash"
|
25
|
+
assert adapter.method('logger').arity == -2, "The adapter should accept two parameters for #logger, name and options hash"
|
26
|
+
|
27
|
+
@tempfile = Tempfile.new('lint')
|
28
|
+
logger = adapter.logger('lint', :to => @tempfile.path)
|
29
|
+
%w{debug info warn error fatal}.each do |level|
|
30
|
+
assert logger.respond_to?(level), "The logger should respond to ##{level}"
|
31
|
+
#assert logger.respond_to?("#{level}?"), "The logger should respond to ##{level}?"
|
32
|
+
end
|
33
|
+
|
34
|
+
assert logger.respond_to?(:tagged), "The logger should respond to #tagged"
|
35
|
+
assert logger.respond_to?(:mapped), "The logger should respond to #mapped"
|
36
|
+
ensure
|
37
|
+
@tempfile.unlink if @tempfile
|
18
38
|
end
|
19
|
-
|
39
|
+
|
40
|
+
# Verifies `adapter#mdc`, it checks that:
|
41
|
+
#
|
42
|
+
# - the factory method named #mdc exists
|
43
|
+
# - it accepts no arguments
|
44
|
+
# - the returned mdc responds to []=, [], delete, clear and to_hash
|
45
|
+
#
|
20
46
|
def test_adapter_mdc
|
21
47
|
assert adapter.respond_to?(:mdc), "The adapter should respond to #mdc"
|
22
48
|
assert adapter.method('mdc').arity == 0, "The adapter should accept no parameters for #mdc"
|
23
|
-
|
24
|
-
|
25
|
-
def test_mdc_methods
|
49
|
+
|
26
50
|
mdc = adapter.mdc
|
27
51
|
assert mdc.respond_to?(:[]=), "The mdc should respond to #[]="
|
28
52
|
assert mdc.respond_to?(:[]), "The mdc should respond to #[]"
|
@@ -30,21 +54,11 @@ module Loggr
|
|
30
54
|
assert mdc.respond_to?(:clear), "The mdc should respond to #clear"
|
31
55
|
assert mdc.respond_to?(:to_hash), "The mdc should respond to #to_hash"
|
32
56
|
end
|
33
|
-
|
34
|
-
def test_logger_methods
|
35
|
-
tempfile = Tempfile.new('lint')
|
36
|
-
logger = adapter.logger('lint', :to => tempfile.path)
|
37
|
-
%w{debug info warn error fatal}.each do |level|
|
38
|
-
assert logger.respond_to?(level), "The logger should respond to ##{level}"
|
39
|
-
assert logger.respond_to?("#{level}?"), "The logger should respond to ##{level}?"
|
40
|
-
end
|
41
|
-
ensure
|
42
|
-
tempfile.unlink
|
43
|
-
end
|
44
|
-
|
57
|
+
|
45
58
|
protected
|
46
|
-
|
47
|
-
# Access the adapter, defined
|
59
|
+
|
60
|
+
# Access the adapter, must be defined <tt>@adapter</tt> in the
|
61
|
+
# `setup` method.
|
48
62
|
def adapter
|
49
63
|
assert !!@adapter, "An adapter must be defined"
|
50
64
|
@adapter
|
data/lib/loggr/slf4j/logger.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
require 'loggr/severity'
|
2
|
+
require 'loggr/slf4j/mdc'
|
2
3
|
|
3
4
|
module Loggr
|
4
5
|
module SLF4J
|
5
|
-
|
6
|
+
|
6
7
|
# Simple marker factory which uses `org.slf4j.MarkerFactory`, but
|
7
8
|
# caches the result in a local ruby hash, by name.
|
8
9
|
class MarkerFactory
|
9
|
-
|
10
|
+
|
10
11
|
# Get marker for any non-empty string.
|
11
12
|
def self.[](name)
|
12
13
|
name = name.to_s.strip
|
@@ -15,35 +16,36 @@ module Loggr
|
|
15
16
|
@markers[name] ||= Java::OrgSlf4j::MarkerFactory.getMarker(name)
|
16
17
|
end
|
17
18
|
end
|
18
|
-
|
19
|
+
|
19
20
|
# A logger which is backed by SLF4J, thus only useable in a JRuby environment.
|
20
21
|
#
|
21
22
|
class Logger
|
22
|
-
|
23
|
+
|
23
24
|
# Get severities
|
24
25
|
include Loggr::Severity
|
25
|
-
|
26
|
+
|
26
27
|
# Basically has *no* impact, because is handled by SLF4J
|
27
28
|
attr_accessor :level
|
28
|
-
|
29
|
+
|
29
30
|
# Just to ensure compatiability with AS::BufferedLogger
|
30
31
|
attr_reader :auto_flushing, :flush, :close
|
31
|
-
|
32
|
+
|
32
33
|
# Access raw SLF4J logger & marker instances
|
33
|
-
attr_reader :java_logger, :java_marker
|
34
|
-
|
34
|
+
attr_reader :java_logger, :java_marker, :java_mdc
|
35
|
+
|
35
36
|
# Create a new Logger instance for the given name
|
36
37
|
#
|
37
38
|
def initialize(name, options = {})
|
38
39
|
name = self.class.in_java_notation(name)
|
39
40
|
@java_logger = Java::OrgSlf4j::LoggerFactory.getLogger(name.to_s)
|
40
41
|
@java_marker = MarkerFactory[options[:marker]]
|
41
|
-
|
42
|
+
@java_mdc = options[:mdc] || Loggr::SLF4J::MDC
|
43
|
+
|
42
44
|
# seriously, this is handled by slf4j and pretty dynamic
|
43
45
|
@level = Logger::UNKNOWN
|
44
46
|
@auto_flushing = true
|
45
47
|
end
|
46
|
-
|
48
|
+
|
47
49
|
# Create the logger methods via meta programming, sweet.
|
48
50
|
%w{trace debug info warn error}.each do |severity|
|
49
51
|
class_eval <<-EOT, __FILE__, __LINE__ + 1
|
@@ -53,7 +55,7 @@ module Loggr
|
|
53
55
|
java_logger.#{severity}(marker, build_message(message, progname, &block)) # java_logger.debug(marker, build_message(message, progname, &block))
|
54
56
|
end # end
|
55
57
|
end # end
|
56
|
-
|
58
|
+
|
57
59
|
def #{severity}? # def debug?
|
58
60
|
!!java_logger.is_#{severity}_enabled(java_marker) # !!java_logger.is_debug_enabled(java_marker)
|
59
61
|
end # end
|
@@ -63,7 +65,28 @@ module Loggr
|
|
63
65
|
# Add support for fatal, just alias to error
|
64
66
|
alias_method :fatal, :error
|
65
67
|
alias_method :fatal?, :error?
|
66
|
-
|
68
|
+
|
69
|
+
# Uses the mapped diagnostic context to add tags, like
|
70
|
+
# ActiveSupport 3.2's TaggedLogger.
|
71
|
+
#
|
72
|
+
def tagged(*new_tags)
|
73
|
+
old_tags = java_mdc[:tags].to_s
|
74
|
+
java_mdc[:tags] = (old_tags.split(', ') + new_tags.flatten).join(', ')
|
75
|
+
yield
|
76
|
+
ensure
|
77
|
+
java_mdc[:tags] = old_tags.length == 0 ? nil : old_tags
|
78
|
+
end
|
79
|
+
|
80
|
+
# A more describtive alternative to tagged is mapped, which just makes
|
81
|
+
# use of the MDC directly, basically.
|
82
|
+
def mapped(hash = {})
|
83
|
+
old_keys = hash.keys.inject({}) { |hsh,k| hsh[k] = java_mdc[k]; hsh }
|
84
|
+
hash.each { |key, value| java_mdc[key] = value }
|
85
|
+
yield
|
86
|
+
ensure
|
87
|
+
old_keys.each { |key, value| java_mdc[key] = value }
|
88
|
+
end
|
89
|
+
|
67
90
|
# If a class, module or object is used converts `Foo::Bar::SomeThing` to
|
68
91
|
# java notation: `foo.bar.SomeThing`. Symbols and Strings are left as is!
|
69
92
|
#
|
@@ -74,15 +97,15 @@ module Loggr
|
|
74
97
|
last = parts.pop
|
75
98
|
parts.map { |p| p.downcase }.push(last).join('.')
|
76
99
|
end
|
77
|
-
|
100
|
+
|
78
101
|
protected
|
79
|
-
|
102
|
+
|
80
103
|
# Construct the message, note that progname will be ignored, maybe set as
|
81
104
|
# MDC?
|
82
105
|
def build_message(message = nil, progname = nil, &block)
|
83
106
|
message = yield if message.nil? && block_given?
|
84
107
|
message.to_s.gsub(/$\s*^/, '')
|
85
|
-
end
|
108
|
+
end
|
86
109
|
end
|
87
110
|
end
|
88
111
|
end
|
data/lib/loggr/slf4j/mdc.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
module Loggr
|
2
2
|
module SLF4J
|
3
|
-
|
3
|
+
|
4
4
|
# Wrapper around the SLF4J MDC.
|
5
5
|
#
|
6
6
|
class MDCWrapper
|
7
|
-
|
7
|
+
|
8
8
|
# Access the original SLF4J MDC
|
9
9
|
attr_accessor :java_mdc
|
10
|
-
|
10
|
+
|
11
11
|
# Create a new SLF4J MDC with the supplied implementation.
|
12
12
|
def initialize(impl = Java::OrgSlf4j::MDC)
|
13
13
|
@java_mdc = impl
|
@@ -15,20 +15,20 @@ module Loggr
|
|
15
15
|
|
16
16
|
# Read a key from the MDC.
|
17
17
|
def [](key); java_mdc.get(key.to_s) end
|
18
|
-
|
18
|
+
|
19
19
|
# Write a value to the MDC.
|
20
|
-
def []=(key, value); java_mdc.put(key.to_s, value.to_s) end
|
21
|
-
|
20
|
+
def []=(key, value); value.nil? ? java_mdc.remove(key.to_s) : java_mdc.put(key.to_s, value.to_s) end
|
21
|
+
|
22
22
|
# Remove a key from the MDC.
|
23
23
|
def delete(key); java_mdc.remove(key.to_s) end
|
24
|
-
|
24
|
+
|
25
25
|
# Clear all keys from the MDC.
|
26
26
|
def clear; java_mdc.clear() end
|
27
|
-
|
27
|
+
|
28
28
|
# Convert MDC to a real hash.
|
29
29
|
def to_hash; java_mdc.getCopyOfContextMap().freeze end
|
30
30
|
end
|
31
|
-
|
31
|
+
|
32
32
|
# An instance is available as MDC :)
|
33
33
|
MDC = MDCWrapper.new
|
34
34
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Loggr
|
2
|
+
|
3
|
+
module Support
|
4
|
+
|
5
|
+
#
|
6
|
+
#
|
7
|
+
module Annotations
|
8
|
+
|
9
|
+
# A doing nothing implementation of tagged & mapped,
|
10
|
+
# just to ensure the methods exist.
|
11
|
+
module NOPSupport
|
12
|
+
def tagged(*args); yield if block_given? end
|
13
|
+
alias_method :mapped, :tagged
|
14
|
+
end
|
15
|
+
|
16
|
+
# Enhances supplied logger with the required features
|
17
|
+
# to handle both `tagged` and `mapped` on the logger itself.
|
18
|
+
#
|
19
|
+
def self.enhance(logger)
|
20
|
+
return ::ActiveSupport::TaggedLogging.new(logger) if defined?(::ActiveSupport::TaggedLogging)
|
21
|
+
logger.send(:extend, NOPSupport)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Try to load AS::TaggedLogging
|
28
|
+
begin
|
29
|
+
require 'active_support/tagged_logging'
|
30
|
+
|
31
|
+
# Enable support for `mapped(:user => "demo")` which falls
|
32
|
+
# back to make use of its `tagged` method.
|
33
|
+
class ::ActiveSupport::TaggedLogging
|
34
|
+
|
35
|
+
# Uses `tagged` to tag items with the hash of infos.
|
36
|
+
def mapped(hash = {}, &block)
|
37
|
+
tagged(hash.map { |h,k| "#{h}=#{k}" }, &block)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
rescue LoadError; end # uhm, ignore we have other ideas ;)
|
data/lib/loggr/version.rb
CHANGED
data/loggr.gemspec
CHANGED
@@ -4,7 +4,7 @@ require "loggr/version"
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |s|
|
6
6
|
s.name = "loggr"
|
7
|
-
s.version = Loggr::
|
7
|
+
s.version = Loggr::GEM_VERSION
|
8
8
|
s.platform = Gem::Platform::RUBY
|
9
9
|
s.summary = 'Logger factory framework (including an SLF4J wrapper)'
|
10
10
|
s.description = 'Adapters for different ruby logging backends. Create loggers using different adapters, like Logger (Stdlib), Rails or SLF4J (in JRuby only).'
|
@@ -20,7 +20,9 @@ Gem::Specification.new do |s|
|
|
20
20
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
21
21
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
22
22
|
s.require_path = 'lib'
|
23
|
-
|
23
|
+
|
24
|
+
s.add_development_dependency "rake", ">= 0.8.7"
|
24
25
|
s.add_development_dependency "minitest", ">= 2.3.0"
|
25
26
|
s.add_development_dependency "activesupport", ">= 3.0.0"
|
27
|
+
s.add_development_dependency "appraisal", ">= 0.3.8"
|
26
28
|
end
|
data/test/test_helper.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'minitest/autorun'
|
3
3
|
require 'tempfile'
|
4
|
+
require 'active_support/version'
|
4
5
|
|
5
6
|
# Just to provide some shim ;)
|
6
7
|
module Loggr
|
@@ -11,26 +12,31 @@ module Loggr
|
|
11
12
|
end
|
12
13
|
|
13
14
|
class MiniTest::Unit::TestCase
|
14
|
-
|
15
|
+
|
15
16
|
# Path to root
|
16
17
|
ROOT = File.dirname(File.dirname(__FILE__))
|
17
|
-
|
18
|
-
# Returns `true` if running in java/jruby
|
18
|
+
|
19
|
+
# Returns `true` if running in java/jruby
|
19
20
|
def self.jruby?; !!(RUBY_PLATFORM =~ /java/) end
|
20
|
-
|
21
|
+
|
21
22
|
# Same at instance level
|
22
23
|
def jruby?; self.class.jruby? end
|
23
|
-
|
24
|
+
|
24
25
|
# Yield block if java
|
25
26
|
def if_jruby(&block)
|
26
27
|
yield if block_given? && jruby?
|
27
|
-
end
|
28
|
-
|
28
|
+
end
|
29
|
+
|
29
30
|
# Skip tests, unless using jruby
|
30
31
|
def skip_unless_jruby
|
31
32
|
skip("requires JRuby") unless jruby?
|
32
33
|
end
|
33
|
-
|
34
|
+
|
35
|
+
# Returns `true` if >= ActiveSupport 3.2 is used
|
36
|
+
def as_3_2?
|
37
|
+
ActiveSupport::VERSION::MAJOR >= 3 && ActiveSupport::VERSION::MINOR >= 2
|
38
|
+
end
|
39
|
+
|
34
40
|
# Yields path to tempfile into block, ensures is cleaned up
|
35
41
|
# afterwards
|
36
42
|
def with_tempfile(name = 'file', &block)
|
@@ -40,11 +46,11 @@ class MiniTest::Unit::TestCase
|
|
40
46
|
ensure
|
41
47
|
tempfile.unlink
|
42
48
|
end
|
43
|
-
|
49
|
+
|
44
50
|
# Ensure all log files are unlinked after block
|
45
51
|
def unlink_log_files(&block)
|
46
52
|
yield if block_given?
|
47
53
|
ensure
|
48
54
|
Dir[File.join(File.dirname(File.dirname(__FILE__))), '*.log'].each { |f| File.unlink(f) if f =~ /\.log$/ }
|
49
|
-
end
|
55
|
+
end
|
50
56
|
end
|