madvertise-logging 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.8.7
4
+ - 1.9.2
5
+ - 1.9.3
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --no-private
data/Gemfile CHANGED
@@ -6,5 +6,9 @@ gemspec
6
6
  group :test do
7
7
  gem 'rspec'
8
8
  gem 'simplecov'
9
+ gem 'ruby2ruby', '=1.3.0' # 1.3.1 is broken :(
10
+ gem 'reek'
11
+ gem 'yard'
12
+ gem 'redcarpet'
9
13
  gem 'syslogger', :require => false
10
14
  end
data/README.md CHANGED
@@ -1,6 +1,10 @@
1
1
  # Madvertise::Logging
2
2
 
3
- TODO: Write a gem description
3
+ The madvertise-logging gem is a collection of classes for logging related
4
+ tasks. The main class (`ImprovedLogger`) is an improved version of DaemonKits
5
+ `AbstractLogger` class including token support, buffer backend and more.
6
+
7
+ [![Build Status](https://secure.travis-ci.org/madvertise/logging.png)](http://travis-ci.org/madvertise/logging)
4
8
 
5
9
  ## Installation
6
10
 
@@ -18,7 +22,7 @@ Or install it yourself as:
18
22
 
19
23
  ## Usage
20
24
 
21
- TODO: Write usage instructions here
25
+ Please refer to the [API documentation](http://rubydoc.info/gems/madvertise-logging/frames).
22
26
 
23
27
  ## Contributing
24
28
 
@@ -3,12 +3,22 @@ require 'stringio'
3
3
 
4
4
  module Madvertise
5
5
  module Logging
6
+
7
+ ##
8
+ # ImprovedLogger is an enhanced version of DaemonKits AbstractLogger class
9
+ # with token support, buffer backend and more.
10
+ #
6
11
  class ImprovedLogger
7
12
 
13
+ # Write a copy of all log messages to STDOUT.
8
14
  attr_accessor :copy_to_stdout
9
- attr_accessor :transaction_token
15
+
16
+ # Program name prefix. Used as ident for syslog backends.
10
17
  attr_accessor :progname
11
18
 
19
+ # Arbitrary token to prefix log messages with.
20
+ attr_accessor :token
21
+
12
22
  @severities = {
13
23
  :debug => Logger::DEBUG,
14
24
  :info => Logger::INFO,
@@ -21,217 +31,211 @@ module Madvertise
21
31
  @silencer = true
22
32
 
23
33
  class << self
34
+ # Hash of Symbol/Fixnum pairs to map Logger levels.
24
35
  attr_reader :severities
36
+
37
+ # Enable/disable the silencer on a global basis. Useful for debugging
38
+ # otherwise silenced code blocks.
25
39
  attr_accessor :silencer
26
40
  end
27
41
 
28
42
  def initialize(logfile = nil, progname = nil)
29
43
  @copy_to_stdout = false
30
44
  @progname = progname || File.basename($0)
31
- self.logger = logfile || STDERR
45
+ self.logger = logfile
32
46
  end
33
47
 
34
- # Silence the logger for the duration of the block.
35
- def silence(temporary_level = :error)
36
- if self.class.silencer
37
- begin
38
- old_level, self.level = self.level, temporary_level
39
- yield self
40
- ensure
41
- self.level = old_level
42
- end
43
- else
44
- yield self
45
- end
48
+ # Get the backend logger.
49
+ #
50
+ # @return [Logger] The currently active backend logger object.
51
+ def logger
52
+ @logger ||= create_backend
46
53
  end
47
54
 
48
- def debug(msg)
49
- add(:debug, msg)
55
+ # Set a different backend.
56
+ #
57
+ # @param [Symbol, String, Logger] value The new logger backend. Either a
58
+ # Logger object, a String containing the logfile path or a Symbol to
59
+ # create a default backend for :syslog or :buffer
60
+ # @return [Logger] The newly created backend logger object.
61
+ def logger=(value)
62
+ @logger.close rescue nil
63
+ @logfile = value.is_a?(String) ? value : nil
64
+ @backend = value.is_a?(Symbol) ? value : :logger
65
+ @logger = value.is_a?(Logger) ? value : create_backend
50
66
  end
51
67
 
52
- def debug?
53
- self.level == :debug
68
+ # Close any connections/descriptors that may have been opened by the
69
+ # current backend.
70
+ def close
71
+ logger.close rescue nil
72
+ @logger = nil
54
73
  end
55
74
 
56
- def info(msg)
57
- add(:info, msg)
75
+ # Retrieve the current buffer in case this instance is a buffered logger.
76
+ #
77
+ # @return [String] Contents of the buffer.
78
+ def buffer
79
+ @logfile.string if @backend == :buffer
80
+ end
81
+
82
+ # Get the current logging level.
83
+ #
84
+ # @return [Symbol] Current logging level.
85
+ def level
86
+ self.class.severities.invert[@logger.level]
58
87
  end
59
88
 
60
- def info?
61
- self.level == :info
89
+ # Set the logging level.
90
+ #
91
+ # @param [Symbol, Fixnum] level New level as Symbol or Fixnum from Logger class.
92
+ # @return [Fixnum] New level converted to Fixnum from Logger class.
93
+ def level=(level)
94
+ level = level.is_a?(Symbol) ? self.class.severities[level] : level
95
+ logger.level = level
62
96
  end
63
97
 
64
- def warn(msg)
65
- add(:warn, msg)
98
+ # Log a debug level message.
99
+ def debug(msg)
100
+ add(:debug, msg)
66
101
  end
67
102
 
68
- def warn?
69
- self.level == :warn
103
+ # Log an info level message.
104
+ def info(msg)
105
+ add(:info, msg)
70
106
  end
71
107
 
72
- def error(msg)
73
- add(:error, msg)
108
+ # Log a warning level message.
109
+ def warn(msg)
110
+ add(:warn, msg)
74
111
  end
75
112
 
76
- def error?
77
- self.level == :error
113
+ # Log an error level message.
114
+ def error(msg)
115
+ add(:error, msg)
78
116
  end
79
117
 
118
+ # Log a fatal level message.
80
119
  def fatal(msg)
81
120
  add(:fatal, msg)
82
121
  end
83
122
 
84
- def fatal?
85
- self.level == :fatal
86
- end
87
-
123
+ # Log a message with unknown level.
88
124
  def unknown(msg)
89
125
  add(:unknown, msg)
90
126
  end
91
127
 
92
- def unknown?
93
- self.level == :unknown
94
- end
95
-
96
- def exception(e)
97
- if e.is_a?(::Exception)
98
- message = "EXCEPTION: #{e.message}: #{clean_trace(e.backtrace)}"
128
+ # Log an exception with error level.
129
+ #
130
+ # @param [Exception, String] exc The exception to log. If exc is a
131
+ # String no backtrace will be generated.
132
+ def exception(exc)
133
+ if exc.is_a?(::Exception)
134
+ message = "EXCEPTION: #{exc.message}: #{clean_trace(exc.backtrace)}"
99
135
  else
100
- message = e
136
+ message = exc
101
137
  end
102
138
  add(:error, message, true)
103
139
  end
104
140
 
105
- def add(severity, message, skip_caller = false)
106
- message = "#{called(caller)}: #{message}" unless skip_caller
107
- message = "[#{@transaction_token}] #{message}" if @transaction_token
108
-
109
- self.logger.add(self.class.severities[severity]) { message }
110
-
111
- STDOUT.puts(message) if self.copy_to_stdout && self.class.severities[severity] >= self.logger.level
112
- end
113
-
114
- def level
115
- self.class.severities.invert[@logger.level]
116
- end
117
-
118
- def level=(level)
119
- level = (Symbol === level ? self.class.severities[level] : level)
120
- self.logger.level = level
121
- end
122
-
123
- def new_transaction(v)
124
- @transaction_token = v
125
- end
126
-
127
- def end_transaction
128
- @transaction_token = nil
129
- end
130
-
131
- def save_transaction(obj)
132
- if @transaction_token && obj
133
- @transactions ||= {}
134
- @transactions[obj.object_id] = @transaction_token
141
+ # Save the current token and associate it with obj#object_id.
142
+ def save_token(obj)
143
+ if @token
144
+ @tokens ||= {}
145
+ @tokens[obj.object_id] = @token
135
146
  end
136
147
  end
137
148
 
138
- def restore_transaction(obj)
139
- @transactions ||= {}
140
- @transaction_token = @transactions.delete(obj.object_id) if obj
141
- end
142
-
143
- def logger
144
- @logger ||= create_logger
149
+ # Restore the token that has been associated with obj#object_id.
150
+ def restore_token(obj)
151
+ @tokens ||= {}
152
+ @token = @tokens.delete(obj.object_id)
145
153
  end
146
154
 
147
- def logger=(value)
148
- @logger.close rescue nil
149
-
150
- if value.is_a?(Logger)
151
- @backend = :logger
152
- @logger = value
153
- elsif value.is_a?(Symbol)
154
- @backend = value
155
- @logger = create_logger
155
+ # Silence the logger for the duration of the block.
156
+ def silence(temporary_level = :error)
157
+ if self.class.silencer
158
+ begin
159
+ old_level, self.level = self.level, temporary_level
160
+ yield self
161
+ ensure
162
+ self.level = old_level
163
+ end
156
164
  else
157
- @backend = :logger
158
- @logfile = value
159
- @logger = create_logger
165
+ yield self
160
166
  end
161
167
  end
162
168
 
169
+ # Remove references to the madvertise-logging gem from exception
170
+ # backtraces.
171
+ #
172
+ # @private
163
173
  def clean_trace(trace)
164
- trace = trace.map { |l| l.gsub(ROOT, '') }
165
- trace = trace.reject { |l| l =~ /gems\/madvertise-logging/ }
166
- trace = trace.reject { |l| l =~ /vendor\/madvertise-logging/ }
167
- trace
168
- end
169
-
170
- def close
171
- case @backend
172
- when :logger
173
- self.logger.close
174
- @logger = nil
175
- end
176
- end
177
-
178
- def buffer
179
- if @backend == :buffer && @buffer
180
- @buffer.string
174
+ trace.map do |line|
175
+ line.gsub(ROOT, '')
176
+ end.reject do |line|
177
+ line =~ /(gems|vendor)\/madvertise-logging/
181
178
  end
182
179
  end
183
180
 
184
181
  private
185
182
 
186
- def called(trace)
187
- l = trace.detect('unknown:0') do |l|
188
- l.index(File.basename(__FILE__)).nil?
183
+ # Return the first callee outside the madvertise-logging gem. Used in add
184
+ # to figure out where in the source code a message has been produced.
185
+ def called_from
186
+ location = caller.detect('unknown:0') do |line|
187
+ line.match(/(improved_logger|multi_logger)\.rb/).nil?
189
188
  end
190
189
 
191
- file, num, _ = l.split(':')
190
+ file, num, discard = location.split(':')
192
191
  [ File.basename(file), num ].join(':')
193
192
  end
194
193
 
195
- def create_logger
194
+ def add(severity, message, skip_caller = false)
195
+ severity = self.class.severities[severity]
196
+ message = "#{called_from}: #{message}" unless skip_caller
197
+ message = "[#{@token}] #{message}" if @token
198
+
199
+ logger.add(severity) { message }
200
+
201
+ STDOUT.puts(message) if self.copy_to_stdout && severity >= @logger.level
202
+ end
203
+
204
+ def create_backend
196
205
  case @backend
197
206
  when :buffer
198
- create_buffering_logger
207
+ create_buffering_backend
199
208
  when :syslog
200
- create_syslog_logger
209
+ create_syslog_backend
201
210
  else
202
- create_standard_logger
211
+ create_standard_backend
203
212
  end
204
213
  end
205
214
 
206
- def create_buffering_logger
207
- @buffer = StringIO.new
208
- Logger.new(@buffer).tap do |l|
209
- l.formatter = Formatter.new
210
- l.progname = progname
211
- end
215
+ def create_buffering_backend
216
+ @logfile = StringIO.new
217
+ create_logger
212
218
  end
213
219
 
214
- def create_standard_logger
215
- @logfile ||= STDERR
216
-
217
- if @logfile.is_a?(String)
218
- logdir = File.dirname(@logfile)
219
-
220
- begin
221
- FileUtils.mkdir_p(logdir)
222
- rescue
223
- STDERR.puts "#{logdir} not writable, using STDERR for logging"
224
- @logfile = STDERR
225
- end
220
+ def create_standard_backend
221
+ begin
222
+ FileUtils.mkdir_p(File.dirname(@logfile))
223
+ rescue
224
+ STDERR.puts "#{@logfile} not writable, using STDERR for logging" if @logfile
225
+ @logfile = STDERR
226
226
  end
227
227
 
228
- Logger.new(@logfile).tap do |l|
229
- l.formatter = Formatter.new
230
- l.progname = progname
228
+ create_logger
229
+ end
230
+
231
+ def create_logger
232
+ Logger.new(@logfile).tap do |logger|
233
+ logger.formatter = Formatter.new
234
+ logger.progname = progname
231
235
  end
232
236
  end
233
237
 
234
- def create_syslog_logger
238
+ def create_syslog_backend
235
239
  begin
236
240
  require 'syslogger'
237
241
  Syslogger.new(progname, Syslog::LOG_PID, Syslog::LOG_LOCAL1)
@@ -241,23 +245,25 @@ module Madvertise
241
245
  end
242
246
  end
243
247
 
248
+ ##
249
+ # The Formatter class is responsible for formatting log messages. The
250
+ # default format is:
251
+ #
252
+ # YYYY:MM:DD HH:MM:SS.MS daemon_name(pid) level: message
253
+ #
244
254
  class Formatter
245
255
 
246
- # YYYY:MM:DD HH:MM:SS.MS daemon_name(pid) level: message
247
256
  @format = "%s %s(%d) [%s] %s\n"
248
257
 
249
258
  class << self
259
+ # Format string for log messages.
250
260
  attr_accessor :format
251
261
  end
252
262
 
263
+ # @private
253
264
  def call(severity, time, progname, msg)
254
- self.class.format % [format_time( time ), progname, $$, severity, msg.to_s]
255
- end
256
-
257
- private
258
-
259
- def format_time(time)
260
- time.strftime("%Y-%m-%d %H:%M:%S.") + time.usec.to_s
265
+ time = time.strftime("%Y-%m-%d %H:%M:%S.") + time.usec.to_s
266
+ self.class.format % [time, progname, $$, severity, msg.to_s]
261
267
  end
262
268
  end
263
269
  end
@@ -1,22 +1,32 @@
1
1
  module Madvertise
2
2
  module Logging
3
+
4
+ ##
5
+ # MultiLogger is a simple class for multiplexing ImprovedLogger objects. It
6
+ # support attach/detach to send messages to any number of loggers.
7
+
3
8
  class MultiLogger
4
9
  def initialize(*loggers)
5
10
  @loggers = loggers
6
11
  end
7
12
 
13
+ # Attach an ImprovedLogger object.
8
14
  def attach(logger)
9
- logger.new_transaction(@loggers.first.transaction_token)
15
+ logger.token = @loggers.first.token
10
16
  @loggers << logger
11
17
  end
12
18
 
19
+ # Detach an ImprovedLogger object.
13
20
  def detach(logger)
14
21
  @loggers.delete(logger)
15
22
  end
16
23
 
24
+ # Delegate all method calls to all attached loggers.
25
+ #
26
+ # @private
17
27
  def method_missing(name, *args)
18
- @loggers.each do |l|
19
- l.send(name, *args)
28
+ @loggers.each do |logger|
29
+ logger.send(name, *args)
20
30
  end
21
31
  end
22
32
  end
@@ -1,5 +1,6 @@
1
1
  module Madvertise
2
2
  module Logging
3
- VERSION = "0.1.0"
3
+ # @private
4
+ VERSION = "0.2.0"
4
5
  end
5
6
  end
@@ -39,62 +39,32 @@ describe ImprovedLogger do
39
39
  @logfile.should have_received_message(/\[DEBUG\].*Debug test/)
40
40
  end
41
41
 
42
- it "should return true if debug level is set" do
43
- @logger.level = :debug
44
- @logger.debug?.should be true
45
- end
46
-
47
42
  it "should log info level messages" do
48
43
  @logger.info("Info test")
49
44
  @logfile.should have_received_message(/\[INFO\].*Info test/)
50
45
  end
51
46
 
52
- it "should return true if info level is set" do
53
- @logger.level = :info
54
- @logger.info?.should be true
55
- end
56
-
57
47
  it "should log warn level messages" do
58
48
  @logger.warn("Warn test")
59
49
  @logfile.should have_received_message(/\[WARN\].*Warn test/)
60
50
  end
61
51
 
62
- it "should return true if warn level is set" do
63
- @logger.level = :warn
64
- @logger.warn?.should be true
65
- end
66
-
67
52
  it "should log error level messages" do
68
53
  @logger.error("Err test")
69
54
  @logfile.should have_received_message(/\[ERROR\].*Err test/)
70
55
  end
71
56
 
72
- it "should return true if error level is set" do
73
- @logger.level = :error
74
- @logger.error?.should be true
75
- end
76
-
77
57
  it "should log fatal level messages" do
78
58
  @logger.fatal("Fatal test")
79
59
 
80
60
  @logfile.should have_received_message(/\[FATAL\].*Fatal test/)
81
61
  end
82
62
 
83
- it "should return true if fatal level is set" do
84
- @logger.level = :fatal
85
- @logger.fatal?.should be true
86
- end
87
-
88
63
  it "should log unknown level messages" do
89
64
  @logger.unknown("Unknown test")
90
65
  @logfile.should have_received_message(/\[ANY\].*Unknown test/)
91
66
  end
92
67
 
93
- it "should return true if unknown level is set" do
94
- @logger.level = :unknown
95
- @logger.unknown?.should be true
96
- end
97
-
98
68
  it "should log the caller file and line number" do
99
69
  f = File.basename(__FILE__)
100
70
  l = __LINE__ + 2
@@ -164,40 +134,39 @@ describe ImprovedLogger do
164
134
  ImprovedLogger.silencer = true
165
135
  end
166
136
 
167
- it "should support a transaction token" do
137
+ it "should support a token" do
168
138
  token = "3d5e27f7-b97c-4adc-b1fd-adf1bd4314e0"
169
139
 
170
- @logger.new_transaction(token)
171
- @logger.info "This should include a transaction token"
140
+ @logger.token = token
141
+ @logger.info "This should include a token"
172
142
  @logfile.should have_received_message(token)
173
143
 
174
- @logger.end_transaction
175
- @logger.info "This should not include a transaction token"
144
+ @logger.token = nil
145
+ @logger.info "This should not include a token"
176
146
  @logfile.should_not have_received_message(token)
177
147
  end
178
148
 
179
- it "should support save/restore on transaction tokens" do
149
+ it "should support save/restore on tokens" do
180
150
  token1 = "3d5e27f7-b97c-4adc-b1fd-adf1bd4314e0"
181
151
  token2 = "1bdef605-34b9-4ec7-9a1c-cb58efc8a635"
182
152
 
183
- obj1 = Object.new
153
+ obj = Object.new
184
154
 
185
- @logger.new_transaction(token1)
186
- @logger.info "This should include transaction token1"
155
+ @logger.token = token1
156
+ @logger.info "This should include token1"
187
157
  @logfile.should have_received_message(token1)
188
158
 
189
- @logger.save_transaction(obj1)
190
- @logger.new_transaction(token2)
191
- @logger.info "This should include transaction token2"
159
+ @logger.save_token(obj)
160
+ @logger.token = token2
161
+ @logger.info "This should include token2"
192
162
  @logfile.should have_received_message(token2)
193
- @logger.end_transaction
194
163
 
195
- @logger.restore_transaction(obj1)
196
- @logger.info "This should include transaction token1"
164
+ @logger.restore_token(obj)
165
+ @logger.info "This should include token1"
197
166
  @logfile.should have_received_message(token1)
198
167
 
199
- @logger.end_transaction
200
- @logger.info "This should not include a transaction token"
168
+ @logger.token = nil
169
+ @logger.info "This should not include a token"
201
170
  @logfile.should_not have_received_message(token1)
202
171
  @logfile.should_not have_received_message(token2)
203
172
  end
@@ -224,6 +193,7 @@ describe ImprovedLogger do
224
193
  syslogger_paths = $:.select { |p| p.match(/gems\/.*syslogger-/) }
225
194
  $:.replace($: - syslogger_paths)
226
195
 
196
+ STDERR.should_receive(:puts).with(/using STDERR for logging/)
227
197
  STDERR.should_receive(:write).with(/reverting to standard logger/)
228
198
  @logger = ImprovedLogger.new(:syslog)
229
199
  @logger.logger.should be_instance_of(Logger)
data/tasks/reek.rake ADDED
@@ -0,0 +1,5 @@
1
+ require 'reek/rake/task'
2
+
3
+ Reek::Rake::Task.new do |t|
4
+ t.fail_on_error = false
5
+ end
data/tasks/rspec.rake CHANGED
@@ -1,20 +1,7 @@
1
- begin
2
- require 'rspec'
3
- rescue LoadError
4
- require 'rubygems'
5
- require 'rspec'
6
- end
7
-
8
- begin
9
- require 'rspec/core/rake_task'
1
+ require 'rspec'
2
+ require 'rspec/core/rake_task'
10
3
 
11
- desc "Run the specs"
12
- RSpec::Core::RakeTask.new do |t|
13
- t.rspec_opts = ['--options', "spec/spec.opts"]
14
- end
15
- rescue LoadError
16
- puts <<-EOS
17
- To use rspec for testing you must install rspec gem:
18
- gem install rspec
19
- EOS
4
+ desc "Run the specs"
5
+ RSpec::Core::RakeTask.new do |t|
6
+ t.rspec_opts = ['--options', "spec/spec.opts"]
20
7
  end
data/tasks/yard.rake ADDED
@@ -0,0 +1,5 @@
1
+ require 'yard'
2
+
3
+ YARD::Rake::YardocTask.new do |t|
4
+ t.files = ['lib/**/*.rb', 'README.rdoc']
5
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: madvertise-logging
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-01-19 00:00:00.000000000 Z
12
+ date: 2012-01-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
16
- requirement: &15364280 !ruby/object:Gem::Requirement
16
+ requirement: &14192340 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *15364280
24
+ version_requirements: *14192340
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rake
27
- requirement: &15363560 !ruby/object:Gem::Requirement
27
+ requirement: &14191540 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,7 +32,7 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *15363560
35
+ version_requirements: *14191540
36
36
  description: Advanced logging classes with buffer backend, transactions, multi logger,
37
37
  etc
38
38
  email:
@@ -43,6 +43,8 @@ extra_rdoc_files: []
43
43
  files:
44
44
  - .gitignore
45
45
  - .rvmrc
46
+ - .travis.yml
47
+ - .yardopts
46
48
  - Gemfile
47
49
  - LICENSE
48
50
  - README.md
@@ -56,7 +58,9 @@ files:
56
58
  - spec/multi_logger_spec.rb
57
59
  - spec/spec.opts
58
60
  - spec/spec_helper.rb
61
+ - tasks/reek.rake
59
62
  - tasks/rspec.rake
63
+ - tasks/yard.rake
60
64
  homepage: https://github.com/madvertise/logging
61
65
  licenses: []
62
66
  post_install_message:
@@ -71,7 +75,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
71
75
  version: '0'
72
76
  segments:
73
77
  - 0
74
- hash: 3354586897547183297
78
+ hash: 3732635707387209248
75
79
  required_rubygems_version: !ruby/object:Gem::Requirement
76
80
  none: false
77
81
  requirements:
@@ -80,7 +84,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
80
84
  version: '0'
81
85
  segments:
82
86
  - 0
83
- hash: 3354586897547183297
87
+ hash: 3732635707387209248
84
88
  requirements: []
85
89
  rubyforge_project:
86
90
  rubygems_version: 1.8.10
@@ -93,3 +97,4 @@ test_files:
93
97
  - spec/multi_logger_spec.rb
94
98
  - spec/spec.opts
95
99
  - spec/spec_helper.rb
100
+ has_rdoc: