polylog 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 30bf99c4368b2308581792e2f887e75e2533b1ef
4
+ data.tar.gz: 59f9b5c104970d4d73244db7381c9a197358271c
5
+ SHA512:
6
+ metadata.gz: 29508ecd47dd8b423e799f8a7c71b8dc7bb8a8ed8de2120b15563f06e44bd126421ef342cedf615fc8f02967a839d9a13321d4641311f59823ca874d8bfda15d
7
+ data.tar.gz: d00c98550192a44ce783f61bd61c5c087a9c669e643921dee8efbe4a39c1bb6ac24d446049d1c63b3f1ffcd1337565f59133614b6c75d10dc698751efd3a1bae
@@ -0,0 +1,19 @@
1
+ # The list of files that should be ignored by Mr Bones.
2
+ # Lines that start with '#' are comments.
3
+ #
4
+ # A .gitignore file can be used instead by setting it as the ignore
5
+ # file in your Rakefile:
6
+ #
7
+ # Bones {
8
+ # ignore_file '.gitignore'
9
+ # }
10
+ #
11
+ # For a project with a C extension, the following would be a good set of
12
+ # exclude patterns (uncomment them if you want to use them):
13
+ # *.[oa]
14
+ # *~
15
+ announcement.txt
16
+ coverage
17
+ doc
18
+ pkg
19
+ vendor
@@ -0,0 +1,4 @@
1
+ == 0.1.0 / 2013-10-14
2
+
3
+ * 1 major enhancement
4
+ * Birthday!
@@ -0,0 +1,22 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2012-2013 by Tim Pease
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ 'Software'), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,200 @@
1
+ ## polylog
2
+
3
+ Decoupling the logging layer since 2012
4
+
5
+ ### Description
6
+
7
+ Logging provides a simple mechanism for observing the state of a running
8
+ application, and most ruby gems and applications use some sort of logging.
9
+ This is great! Setting up a logging infrastructure across various gems and
10
+ applications is the not so great part.
11
+
12
+ In a Rails application it is assumed that all gems will use the `Rails.logger`
13
+ and that's the end of it. So as a gem developer you can just grab the Rails
14
+ logger and be done. The downside of that choice is your gem is now locked to
15
+ Rails and cannot be used elsewhere. Another option is to provide a
16
+ `setup( options = {} )` method (or something similar) and the application can
17
+ provide you with a logger. The downside of that choice is that applications
18
+ need to configure your gem and every other gem that adopts the same
19
+ convention.
20
+
21
+ A third option is to be clever and see if the Rails module exists when your
22
+ gem is loaded and then just grab the Rails logger. This makes testing
23
+ difficult and can lead to unintended side effects. Eschew clever code.
24
+
25
+ Polylog is an agreement between the gem developer and the application
26
+ developer on how logging is configured. For the gem developer, instead of
27
+ assuming the Rails environment or providing a `setup` method you ask Polylog
28
+ for a logger instance. For the application developer, instead of configuring
29
+ logging for multiple gems you configure Polylog with the logging
30
+ infrastructure you plan on using.
31
+
32
+ The gem developer no longer needs to worry what the application is going to
33
+ do. The logging for the gem does not need to be configured by the application.
34
+ Conversely, the application does not have to configure logging for every gem.
35
+ The application provides the logging infrastructure once to Polylog.
36
+
37
+ Let's see what this looks like in practice.
38
+
39
+ ### Usage
40
+
41
+ The two primary use cases for Polylog are:
42
+
43
+ * obtaining a logger
44
+ * configuring the logging provider
45
+
46
+ Obtaining a logger is the domain of the gem developer (or supporting
47
+ application code). Configuring the logging provider is the domain of the
48
+ application.
49
+
50
+ #### Obtaining a Logger
51
+
52
+ Obtaining a logger is simple:
53
+
54
+ ```ruby
55
+ Polylog.logger self
56
+ ```
57
+
58
+ Passing `self` is optional but recommended. It provides context to Polylog and
59
+ allows object specific loggers to be returned (actually, they are class
60
+ specific). The application can configure different logger instances to be
61
+ returned depending upon the requesting class. This is useful if you want to
62
+ enable debugging for just one portion of the application.
63
+
64
+ In practice, you can create a module and include it where you want a `logger`
65
+ method to be available:
66
+
67
+ ```ruby
68
+ module MyGem::Logger
69
+ def logger
70
+ Polylog.logger self
71
+ end
72
+ end
73
+
74
+ class MyGem::SomeClass
75
+ include MyGem::Logger
76
+ end
77
+ ```
78
+
79
+ In this example each class in `MyGem` can obtain its own unique logger if
80
+ Polylog is configured to do so. But you can also develop your gem to use a
81
+ single logger instance, too.
82
+
83
+ ```ruby
84
+ module MyGem::Logger
85
+ def logger
86
+ Polylog.logger 'MyGem'
87
+ end
88
+ end
89
+ ```
90
+
91
+ Instead of passing `self` the top level namespace of the gem is used. Anywhere
92
+ this logger module is included the returned logger will be the same.
93
+
94
+ #### Configuring the Logging Provider
95
+
96
+ Without any configuration Polylog with provide a null logger for all requests.
97
+ This logger implements all the methods of the Ruby `Logger` class, but all the
98
+ methods do nothing. Not very useful except for preventing exceptions.
99
+
100
+ So lets log everything to standard out (a useful start):
101
+
102
+ ```ruby
103
+ provider = Polylog::SoloProvider.new(Logger.new(STDOUT))
104
+ Polylog.register_provider 'stdout', provider
105
+
106
+ Polylog.use_provider 'stdout'
107
+ ```
108
+
109
+ Yikes! That looks pretty complicated. The three lines of code are the three
110
+ steps to configuring a logging provider.
111
+
112
+ The first line creates the provider we are going to use. The `SoloProvider`
113
+ provides exactly one logger. In the example it is providing a standard Ruby
114
+ `Logger` configured to log everything to `STDOUT`.
115
+
116
+ The second line registers the provider we created with Polylog. Multiple
117
+ providers can be registered but only one will be used. Each provider is
118
+ registered with a unique name. Logging frameworks like
119
+ [Log4r](https://github.com/colbygk/log4r), [Logging](https://github.com/twp/logging),
120
+ and [Scrolls](https://github.com/asenchi/scrolls) can register themselves with
121
+ Polylog. In this case, applications can skip the provider creation and just use
122
+ one that is already registered.
123
+
124
+ The third line tells Polylog to use the 'stdout' provider. All calls to
125
+ `Polylog.logger()` will lookup this provider and then call the `logger()`
126
+ method implemented by the provider. In this case, it is the solo-provider
127
+ which returns a STDOUT logger instance for all requests.
128
+
129
+ Lets register a few more providers:
130
+
131
+ ```ruby
132
+ Polylog.register_provider 'stdout', Polylog::SoloProvider.new(Logger.new(STDOUT))
133
+ Polylog.register_provider 'stderr', Polylog::SoloProvider.new(Logger.new(STDERR))
134
+ Polylog.register_provider 'file', Polylog::SoloProvider.new(Logger.new('app.log'))
135
+
136
+ Polylog.use_provider 'file'
137
+ ```
138
+
139
+ Even though we have providers for logging to `STDOUT` and `STDERR`, we have
140
+ chosen to send all our logs to a file instead. It is easy enough to swap
141
+ providers now. Because we are using the solo-provider all log messages will
142
+ end up going to the same destination.
143
+
144
+ We can send log messages to multiple destinations by using a multi-provider.
145
+
146
+ ```ruby
147
+ provider = Polylog::MultiProvider.new(Logger.new(STDOUT))
148
+ provider['MyClass'] = Logger.new('my_class.log')
149
+
150
+ Polylog.register_provider 'my_class', provider
151
+ Polylog.use_provider 'my_class'
152
+
153
+ Polylog.logger # STDOUT logger
154
+ Polylog.logger(MyClass) # 'my_class.log' logger
155
+ ```
156
+
157
+ The multi-provider can return more than one logger instance. It is configured
158
+ to return a default logger for all requests. However, a different logger can
159
+ be returned based on the Class of the object passed to the `Polylog.logger()`
160
+ method. In the example we are passing in `MyClass` to get the specific logger
161
+ for that class; instances of `MyClass` would also return the same logger.
162
+
163
+ If you want to get more creative with your logging configuration, I highly
164
+ recommend checking out the [Logging](https://github.com/twp/logging)
165
+ framework. It is designed to provide unique loggers and logging destinations.
166
+
167
+ #### Integrating With Rails
168
+
169
+ It would be wonderful if Polylog were integrated directly with Rails. This
170
+ would require Rails to adopt the `Polylog.logger()` style of acquiring a
171
+ logger instance. However, until that time happens, Polylog needs to be
172
+ configured with a provider that returns the `Rails.logger` instance.
173
+
174
+ ```ruby
175
+ Polylog.register_provider 'rails', Polylog::SoloProvider.new(Rails.logger)
176
+ Polylog.use_provider 'rails'
177
+ ```
178
+
179
+ And that's pretty much it.
180
+
181
+ ### Developing
182
+
183
+ Polylog makes use of Mr Bones to handle general project tasks such as running
184
+ tests, generating a gem file, interacting with GitHub, and publishing
185
+ to rubygems.org. A `script/bootstrap` script is provided to setup the
186
+ development environment:
187
+
188
+ ```shell
189
+ script/bootstrap
190
+ ```
191
+
192
+ After this is run, you can use `rake` normally to run tests. You can view all
193
+ the available rake tasks via `rake -T`.
194
+
195
+ ```shell
196
+ rake -T
197
+ rake spec
198
+ ```
199
+
200
+ Thank you for reading! Any contributions are greatly appreciated.
@@ -0,0 +1,26 @@
1
+
2
+ begin
3
+ require 'bones'
4
+ rescue LoadError
5
+ abort '### Please install the "bones" gem ###'
6
+ end
7
+
8
+ task :default => 'spec:run'
9
+ task 'gem:release' => 'spec:run'
10
+
11
+
12
+ Bones {
13
+ name 'polylog'
14
+ authors 'Tim Pease'
15
+ email 'tim.pease@gmail.com'
16
+ url 'http://rubygems.org/gems/polylog'
17
+
18
+ spec.opts << '--color' << '--format documentation'
19
+
20
+ use_gmail
21
+
22
+ depend_on 'bones-rspec', :development => true
23
+ depend_on 'bones-git', :development => true
24
+ depend_on 'rdoc', :development => true
25
+ }
26
+
@@ -0,0 +1,162 @@
1
+
2
+ module Polylog
3
+ extend self
4
+
5
+ # Request a logger instance for the given object from the configured
6
+ # provider.
7
+ #
8
+ # object - Any ruby object
9
+ #
10
+ # Returns a logger instance from the provider.
11
+ def logger( object = nil )
12
+ name = logger_name object
13
+ provider.logger name
14
+ end
15
+
16
+ # Return the currently selected provider. If a provider has not yet been
17
+ # specified, then the "null" provider will be used.
18
+ #
19
+ # Returns a logger provider.
20
+ def provider
21
+ use_provider('null') unless defined? @provider
22
+ @provider
23
+ end
24
+
25
+ # Returns the list of available providers as an Array of Strings. These
26
+ # names are used to select which provider to use.
27
+ def providers
28
+ @providers.keys
29
+ end
30
+
31
+ # Configure the logger provider that will be used by Polylog. The provider
32
+ # must already be registered using the same `name`.
33
+ #
34
+ # name - The provider name as a String.
35
+ #
36
+ # Returns the logger provider.
37
+ # Raises a Polylog::UnknownProvider exception.
38
+ def use_provider( name )
39
+ name = name.to_s
40
+ raise Polylog::UnknownProvider, "unknown provider: #{name.inspect}" unless @providers.key? name
41
+
42
+ @provider = @providers[name]
43
+ end
44
+
45
+ # Register a logger provider under the given name. The provider can be any
46
+ # Ruby object that responds to the `logger` method and returns valid logger
47
+ # instances. An exception is raised if the provider does not respond to the
48
+ # `logger` method or the `logger` method does not have an arity of 1.
49
+ #
50
+ # name - The provider name as a String.
51
+ # provider - The provider object that responds to the `logger` method.
52
+ #
53
+ # Returns the logger provider.
54
+ # Raises a Polylog::InvalidProvider exception.
55
+ def register_provider( name, provider )
56
+ @providers ||= Hash.new
57
+ name = name.to_s
58
+
59
+ unless provider.respond_to?(:logger)
60
+ raise Polylog::InvalidProvider, "`logger` method not found for provider #{name.inspect}"
61
+ end
62
+
63
+ arity = provider.method(:logger).arity
64
+ unless 1 == arity
65
+ raise Polylog::InvalidProvider, "`logger` method arity must be 1; arity is #{arity} for provider #{name.inspect}"
66
+ end
67
+
68
+ @providers[name] = provider
69
+ end
70
+
71
+ # Internal: Given any ruby object, try to construct a sensible logger name
72
+ # to use for looking up specific logger instances from a provider. For
73
+ # nearly every object passed in this will be the class name of the instance.
74
+ #
75
+ # If you pass in `nil` or a String then the original object is return.
76
+ # Symbols will be converted to Strings.
77
+ #
78
+ # The only objects we cannot generate a logger name for are anonymous
79
+ # modules. For these we just return `nil`.
80
+ #
81
+ # object - Any ruby object
82
+ #
83
+ # Returns the logger name String or nil.
84
+ def logger_name( object )
85
+ case object
86
+ when nil, String; object
87
+ when Symbol; object.to_s
88
+ when Module; logger_name_for_module(object)
89
+ when Object; logger_name_for_module(object.class)
90
+ end
91
+ end
92
+
93
+ # Internal: Generate logger names for classes, modules, singleton classes,
94
+ # and anonymous modules. For all of these we use the class name or the
95
+ # module name. For anonymous modules we return `nil`.
96
+ #
97
+ # mod - A Module or Class
98
+ #
99
+ # Returns the logger name String or nil.
100
+ def logger_name_for_module( mod )
101
+ return mod.name unless mod.name.nil? or mod.name.empty?
102
+
103
+ # check if we have a metaclass (or eigenclass)
104
+ if mod.ancestors.include? Class
105
+ mod.inspect =~ %r/#<Class:([^#>]+)>/
106
+ return $1
107
+ end
108
+
109
+ # see if we have a superclass
110
+ if mod.respond_to? :superclass
111
+ return logger_name_for_module(mod.superclass)
112
+ end
113
+
114
+ # we have an anonymous module
115
+ return nil
116
+ end
117
+
118
+ LIBPATH = ::File.expand_path('../', __FILE__)
119
+ PATH = ::File.dirname(LIBPATH)
120
+
121
+ # Returns the version String for the library.
122
+ def version
123
+ @version ||= File.read(path('version.txt')).strip
124
+ end
125
+
126
+ # Internal: Returns the library path for the module. If any arguments are
127
+ # given, they will be joined to the end of the library path using
128
+ # `File.join`.
129
+ def libpath( *args )
130
+ rv = args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
131
+ if block_given?
132
+ begin
133
+ $LOAD_PATH.unshift LIBPATH
134
+ rv = yield
135
+ ensure
136
+ $LOAD_PATH.shift
137
+ end
138
+ end
139
+ return rv
140
+ end
141
+
142
+ # Internal: Returns the path for the module. If any arguments are given,
143
+ # they will be joined to the end of the path using `File.join`.
144
+ def path( *args )
145
+ rv = args.empty? ? PATH : ::File.join(PATH, args.flatten)
146
+ if block_given?
147
+ begin
148
+ $LOAD_PATH.unshift PATH
149
+ rv = yield
150
+ ensure
151
+ $LOAD_PATH.shift
152
+ end
153
+ end
154
+ return rv
155
+ end
156
+
157
+ end
158
+
159
+ require Polylog.libpath('polylog/errors')
160
+ require Polylog.libpath('polylog/solo_provider')
161
+ require Polylog.libpath('polylog/multi_provider')
162
+ require Polylog.libpath('polylog/null_logger')
@@ -0,0 +1,15 @@
1
+
2
+ module Polylog
3
+
4
+ # Parent class for all Polylog errors.
5
+ Error = Class.new StandardError
6
+
7
+ # This is error is raised when an unknown provider is requested by the user.
8
+ UnknownProvider = Class.new Error
9
+
10
+ # This is error is raised when a provider is registered and it does not
11
+ # respond to the `logger` method or the `logger` method has an arity other
12
+ # than 1.
13
+ InvalidProvider = Class.new Error
14
+
15
+ end
@@ -0,0 +1,80 @@
1
+
2
+ module Polylog
3
+
4
+ # The purpose of a MultiProvider is to provide a default logger instance
5
+ # when requested. Other loggers can be provided by registering them with the
6
+ # provider under the appropriate logger name. So when this name is passed to
7
+ # the `logger` method the registered logger instance will be returned.
8
+ #
9
+ # The example below shows how to use the MultiProvider to send all log
10
+ # messages from all instances of a single class to a log file instead of
11
+ # STDOUT. You might want to do this when debugging the class; you can set
12
+ # the logger level to debug and capture lots of text to a single location.
13
+ #
14
+ # Examples
15
+ #
16
+ # provider = Polylog::MultiProvider.new(Logger.new(STDOUT))
17
+ # provider['MyClass'] = Logger.new('my_class.log')
18
+ #
19
+ # Polylog.register_provider 'example', provider
20
+ # Polylog.use_provider 'example'
21
+ #
22
+ # logger = Polylog.logger # STDOUT logger
23
+ # my_class_logger = Polylog.logger(MyClass) # 'my_class.log' logger
24
+ #
25
+ class MultiProvider
26
+
27
+ # Create a new MultiProvider configured with the given logger as the
28
+ # default logger. Other loggers can be added to the provider. These will
29
+ # be returned by the provider (instead of the default logger) when their
30
+ # name is passed to the `logger` method.
31
+ #
32
+ # logger - The default logger to return.
33
+ def initialize( logger )
34
+ @hash = Hash.new
35
+ @default_logger = logger
36
+ end
37
+
38
+ # Accessor for getting and setting the default logger.
39
+ attr_accessor :default_logger
40
+
41
+ # Returns the named logger if it is present in the provider. If the named
42
+ # logger is not present then the default logger is returned.
43
+ #
44
+ # name - The logger name as a String.
45
+ def logger( name )
46
+ return default_logger if name.nil?
47
+ @hash.fetch(name, default_logger)
48
+ end
49
+
50
+ # Returns the logger or `nil` if the logger is not present.
51
+ #
52
+ # name - The logger name as a String.
53
+ def []( name )
54
+ @hash[name]
55
+ end
56
+
57
+ # Add a logger provider under the given name.
58
+ #
59
+ # name - The logger name as a String.
60
+ # logger - The logger.
61
+ #
62
+ # Returns the logger.
63
+ def []=( name, logger )
64
+ @hash[name] = logger
65
+ end
66
+
67
+ # Returns an Array with the names of the loggers present in the provider.
68
+ def loggers
69
+ @hash.keys
70
+ end
71
+
72
+ # Returns `true` if the logger is present in the provider.
73
+ #
74
+ # name - The logger name as a String.
75
+ def logger?( name )
76
+ @hash.key? name
77
+ end
78
+
79
+ end
80
+ end
@@ -0,0 +1,28 @@
1
+
2
+ module Polylog
3
+
4
+ # This is a no-op logger that implements the principal methods from the
5
+ # standard Ruby logger. All methods do nothing and return either `false`
6
+ # or `nil`.
7
+ class NullLogger
8
+ def <<(msg) nil end
9
+ def close() nil end
10
+
11
+ def debug?() false end
12
+ alias :info? :debug?
13
+ alias :warn? :debug?
14
+ alias :error? :debug?
15
+ alias :fatal? :debug?
16
+
17
+ def add(*args) false end
18
+ alias :debug :add
19
+ alias :info :add
20
+ alias :warn :add
21
+ alias :error :add
22
+ alias :fatal :add
23
+ alias :unknown :add
24
+ alias :log :add
25
+ end
26
+
27
+ register_provider('null', SoloProvider.new(NullLogger.new))
28
+ end
@@ -0,0 +1,41 @@
1
+ module Polylog
2
+
3
+ # The purpose of the SoloProvider is to return a single instance for all
4
+ # logger requests. You would use this provider to supply all parts of the
5
+ # application with the exact same logger.
6
+ #
7
+ # The NullLogger uses the SoloProvider to register itself under the "null"
8
+ # provider name.
9
+ #
10
+ # Examples
11
+ #
12
+ # Polylog.register_provider 'stdout', Polylog::SoloProvider.new(Logger.new(STDOUT))
13
+ # Polylog.register_provider 'stderr', Polylog::SoloProvider.new(Logger.new(STDERR))
14
+ # Polylog.register_provider 'file', Polylog::SoloProvider.new(Logger.new('app.log'))
15
+ #
16
+ # Polylog.use_provider 'stderr'
17
+ # logger = Polylog.logger # returns a STDERR logger
18
+ #
19
+ # Polylog.use_provider 'file'
20
+ # logger = Polylog.logger # returns an 'app.log' file logger
21
+ #
22
+ class SoloProvider
23
+
24
+ # Constructs a new SoloProvider that will provide the same instance for
25
+ # each request for a logger.
26
+ #
27
+ # logger - The logger instance that will be provided.
28
+ def initialize( logger )
29
+ @logger = logger
30
+ end
31
+
32
+ # Returns the same logger instance for all requests. The `name` is not
33
+ # used by this this method.
34
+ #
35
+ # name - The logger name as a String
36
+ def logger( name )
37
+ @logger
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env sh
2
+
3
+ gem list -i bones >/dev/null 2>&1
4
+ rc=$?
5
+ if [[ $rc != 0 ]]; then
6
+ gem install bones
7
+ fi
8
+
9
+ rake gem:install_dependencies
@@ -0,0 +1,41 @@
1
+
2
+ require File.expand_path('../../spec_helper', __FILE__)
3
+
4
+ describe Polylog::SoloProvider do
5
+ attr_reader :provider
6
+
7
+ context 'with only a default logger' do
8
+ before(:all) { @provider = Polylog::MultiProvider.new 'Multipass' }
9
+
10
+ it 'provides the same default logger' do
11
+ default = provider.default_logger
12
+
13
+ expect(provider.logger 'foo').to equal default
14
+ expect(provider.logger 'bar').to equal default
15
+ end
16
+ end
17
+
18
+ context 'when configured with multiple loggers' do
19
+ before(:all) do
20
+ @provider = Polylog::MultiProvider.new 'Multipass'
21
+ @provider['foo'] = 'FooLogger'
22
+ @provider['bar'] = 'BarLogger'
23
+ end
24
+
25
+ it 'provides loggers based on name' do
26
+ expect(provider.logger 'foo').to equal provider['foo']
27
+ expect(provider.logger 'bar').to equal provider['bar']
28
+ expect(provider.logger 'baz').to equal provider.default_logger
29
+ end
30
+
31
+ it 'returns the list of available loggers' do
32
+ expect(provider.loggers).to match_array %w[foo bar]
33
+ end
34
+
35
+ it 'determines if a logger is present' do
36
+ expect(provider.logger? 'foo').to be_true
37
+ expect(provider.logger? 'bar').to be_true
38
+ expect(provider.logger? 'baz').to be_false
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,82 @@
1
+
2
+ require File.expand_path('../../spec_helper', __FILE__)
3
+
4
+ describe Polylog::NullLogger do
5
+ attr_reader :null_logger
6
+ before(:all) { @null_logger = Polylog::NullLogger.new }
7
+
8
+ it 'responds to `<<`' do
9
+ expect(null_logger).to respond_to :<<
10
+ expect(null_logger << 'foo').to be_nil
11
+ end
12
+
13
+ it 'responds to `close`' do
14
+ expect(null_logger).to respond_to :close
15
+ expect(null_logger.close).to be_nil
16
+ end
17
+
18
+ it 'responds to `debug?`' do
19
+ expect(null_logger).to respond_to :debug?
20
+ expect(null_logger.debug?).to be_false
21
+ end
22
+
23
+ it 'responds to `info?`' do
24
+ expect(null_logger).to respond_to :info?
25
+ expect(null_logger.info?).to be_false
26
+ end
27
+
28
+ it 'responds to `warn?`' do
29
+ expect(null_logger).to respond_to :warn?
30
+ expect(null_logger.warn?).to be_false
31
+ end
32
+
33
+ it 'responds to `error?`' do
34
+ expect(null_logger).to respond_to :error?
35
+ expect(null_logger.error?).to be_false
36
+ end
37
+
38
+ it 'responds to `fatal?`' do
39
+ expect(null_logger).to respond_to :fatal?
40
+ expect(null_logger.fatal?).to be_false
41
+ end
42
+
43
+ it 'responds to `add`' do
44
+ expect(null_logger).to respond_to :add
45
+ expect(null_logger.add 'foo').to be_false
46
+ end
47
+
48
+ it 'responds to `debug`' do
49
+ expect(null_logger).to respond_to :debug
50
+ expect(null_logger.debug 'foo').to be_false
51
+ end
52
+
53
+ it 'responds to `info`' do
54
+ expect(null_logger).to respond_to :info
55
+ expect(null_logger.info 'foo').to be_false
56
+ end
57
+
58
+ it 'responds to `warn`' do
59
+ expect(null_logger).to respond_to :warn
60
+ expect(null_logger.warn 'foo').to be_false
61
+ end
62
+
63
+ it 'responds to `error`' do
64
+ expect(null_logger).to respond_to :error
65
+ expect(null_logger.error 'foo').to be_false
66
+ end
67
+
68
+ it 'responds to `fatal`' do
69
+ expect(null_logger).to respond_to :fatal
70
+ expect(null_logger.fatal 'foo').to be_false
71
+ end
72
+
73
+ it 'responds to `unknown`' do
74
+ expect(null_logger).to respond_to :unknown
75
+ expect(null_logger.unknown 'foo').to be_false
76
+ end
77
+
78
+ it 'responds to `log`' do
79
+ expect(null_logger).to respond_to :log
80
+ expect(null_logger.log 'foo').to be_false
81
+ end
82
+ end
@@ -0,0 +1,14 @@
1
+
2
+ require File.expand_path('../../spec_helper', __FILE__)
3
+
4
+ describe Polylog::SoloProvider do
5
+ attr_reader :provider
6
+ before(:all) { @provider = Polylog::SoloProvider.new 'Han Solo' }
7
+
8
+ it 'always provides the same instance' do
9
+ str = provider.logger nil
10
+
11
+ expect(provider.logger 'foo').to equal str
12
+ expect(provider.logger 'bar').to equal str
13
+ end
14
+ end
@@ -0,0 +1,124 @@
1
+
2
+ require File.expand_path('../spec_helper', __FILE__)
3
+
4
+ describe Polylog do
5
+
6
+ it 'provides a canonical version string' do
7
+ expect(Polylog.version).to match %r/^\d+\.\d+\.\d+$/
8
+ end
9
+
10
+ context 'without any configuration' do
11
+ it 'provides a null logger' do
12
+ expect(Polylog.logger).to be_an_instance_of Polylog::NullLogger
13
+ end
14
+
15
+ it 'provides the smae null logger for all requests' do
16
+ null_logger = Polylog.logger
17
+
18
+ expect(Polylog.logger 'foo').to equal null_logger
19
+ expect(Polylog.logger 'bar').to equal null_logger
20
+ end
21
+
22
+ it 'only has the null provider registered' do
23
+ expect(Polylog.providers).to eq %w[null]
24
+ end
25
+ end
26
+
27
+ context 'when registering a provider' do
28
+ it 'raises an error for providers that have no `logger` method' do
29
+ expect {
30
+ Polylog.register_provider('nope', Object.new)
31
+ }.to raise_error(Polylog::InvalidProvider, /method not found for provider/)
32
+ end
33
+
34
+ it 'raises an error when the `logger` method has the wrong airty' do
35
+ provider = Object.new
36
+ class << provider
37
+ def logger() nil; end
38
+ end
39
+
40
+ expect {
41
+ Polylog.register_provider('nope', provider)
42
+ }.to raise_error(Polylog::InvalidProvider, /method arity must be 1/)
43
+ end
44
+
45
+ it 'adds the provider to the registry' do
46
+ expect(Polylog.providers).not_to include('test1')
47
+
48
+ provider = Polylog::SoloProvider.new(:test1)
49
+ Polylog.register_provider 'test1', provider
50
+
51
+ expect(Polylog.providers).to include('test1')
52
+ end
53
+
54
+ it 'overwrites existing providers' do
55
+ provider = Polylog::SoloProvider.new(:test2)
56
+ Polylog.register_provider 'test2', provider
57
+ expect(Polylog.providers).to include('test2')
58
+ Polylog.use_provider 'test2'
59
+
60
+ provider = Polylog::SoloProvider.new(:overwrite)
61
+ Polylog.register_provider 'test2', provider
62
+
63
+ expect(Polylog.logger).to equal :test2
64
+ Polylog.use_provider 'test2'
65
+ expect(Polylog.logger).to equal :overwrite
66
+ end
67
+ end
68
+
69
+ context 'when selecting a provider to use' do
70
+ it 'raises an error for unknown providers' do
71
+ expect {
72
+ Polylog.use_provider 'foo'
73
+ }.to raise_error(Polylog::UnknownProvider, 'unknown provider: "foo"')
74
+ end
75
+
76
+ it 'can use a registered provider' do
77
+ provider = Polylog::SoloProvider.new(:test3)
78
+ Polylog.register_provider 'test3', provider
79
+
80
+ expect(Polylog.providers).to include('test3')
81
+
82
+ Polylog.use_provider 'test3'
83
+ expect(Polylog.logger).to equal :test3
84
+ end
85
+ end
86
+
87
+ context 'when generating logger names' do
88
+ it 'uses nil as the default' do
89
+ expect(Polylog.logger_name nil).to be_nil
90
+ end
91
+
92
+ it 'uses String names as is' do
93
+ expect(Polylog.logger_name 'foo').to eql 'foo'
94
+ end
95
+
96
+ it 'converts Symbols to Strings' do
97
+ expect(Polylog.logger_name :foo).to eql 'foo'
98
+ end
99
+
100
+ it 'uses Module names' do
101
+ expect(Polylog.logger_name Enumerable).to eql 'Enumerable'
102
+ end
103
+
104
+ it 'uses Class names for instances' do
105
+ expect(Polylog.logger_name Object).to eql 'Object'
106
+ expect(Polylog.logger_name Object.new).to eql 'Object'
107
+ expect(Polylog.logger_name []).to eql 'Array'
108
+ end
109
+
110
+ it 'uses the orignal Class name for singletons (eigenclasses)' do
111
+ ary = []
112
+ eigen = class << ary; self; end
113
+
114
+ expect(Polylog.logger_name eigen).to eql 'Array'
115
+ end
116
+
117
+ it 'gives up when confronted with an anonymous module' do
118
+ m = Module.new { def foo() nil end }
119
+ expect(Polylog.logger_name m).to be_nil
120
+ end
121
+ end
122
+
123
+ end
124
+
@@ -0,0 +1,31 @@
1
+
2
+ require File.expand_path('../../lib/polylog', __FILE__)
3
+
4
+ RSpec.configure do |config|
5
+ config.before(:all) { Polylog.reset! }
6
+
7
+ # == Mock Framework
8
+ #
9
+ # RSpec uses it's own mocking framework by default. If you prefer to
10
+ # use mocha, flexmock or RR, uncomment the appropriate line:
11
+ #
12
+ # config.mock_with :mocha
13
+ # config.mock_with :flexmock
14
+ # config.mock_with :rr
15
+ end
16
+
17
+ module Polylog
18
+ # Only used for testing. This resets the Polylog providers configuration to
19
+ # its uninitialized state.
20
+ def reset!
21
+ remove_instance_variable :@provider if defined? @provider
22
+
23
+ @providers.keys.each do |key|
24
+ next if key == 'null'
25
+ @providers.delete key
26
+ end
27
+
28
+ self
29
+ end
30
+ end
31
+
@@ -0,0 +1 @@
1
+ 0.1.0
metadata ADDED
@@ -0,0 +1,118 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: polylog
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Tim Pease
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-10-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bones-rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: 2.0.1
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: 2.0.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: bones-git
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: 1.3.0
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: 1.3.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: rdoc
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: 3.12.2
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: 3.12.2
55
+ - !ruby/object:Gem::Dependency
56
+ name: bones
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: 3.8.1
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: 3.8.1
69
+ description: ''
70
+ email: tim.pease@gmail.com
71
+ executables: []
72
+ extensions: []
73
+ extra_rdoc_files:
74
+ - History.txt
75
+ files:
76
+ - .gitignore
77
+ - History.txt
78
+ - LICENSE.md
79
+ - README.md
80
+ - Rakefile
81
+ - lib/polylog.rb
82
+ - lib/polylog/errors.rb
83
+ - lib/polylog/multi_provider.rb
84
+ - lib/polylog/null_logger.rb
85
+ - lib/polylog/solo_provider.rb
86
+ - script/bootstrap
87
+ - spec/polylog/multi_provider_spec.rb
88
+ - spec/polylog/null_logger_spec.rb
89
+ - spec/polylog/solo_provider_spec.rb
90
+ - spec/polylog_spec.rb
91
+ - spec/spec_helper.rb
92
+ - version.txt
93
+ homepage: http://rubygems.org/gems/polylog
94
+ licenses: []
95
+ metadata: {}
96
+ post_install_message:
97
+ rdoc_options:
98
+ - --main
99
+ - README.md
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - '>='
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ required_rubygems_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - '>='
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ requirements: []
113
+ rubyforge_project: polylog
114
+ rubygems_version: 2.0.3
115
+ signing_key:
116
+ specification_version: 4
117
+ summary: ''
118
+ test_files: []