polylog 0.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.
@@ -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: []