loggability 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/ChangeLog CHANGED
@@ -1,8 +1,68 @@
1
+ 2012-05-10 Michael Granger <ged@FaerieMUD.org>
2
+
3
+ * .rvm.gems, README.rdoc, Rakefile, lib/loggability.rb,
4
+ spec/lib/helpers.rb, spec/loggability/logger_spec.rb,
5
+ spec/loggability_spec.rb:
6
+ Add Configurability support.
7
+ [555511f82876] [tip]
8
+
9
+ * lib/loggability/logger.rb:
10
+ Make Logger#inspect output a bit more terse
11
+ [fbddf3595a38]
12
+
13
+ 2012-05-08 Michael Granger <ged@FaerieMUD.org>
14
+
15
+ * .hgtags:
16
+ Added tag v0.1.0 for changeset 929216c0ffee
17
+ [65953fe69af2]
18
+
19
+ * .hgsigs:
20
+ Added signature for changeset ea1633c450be
21
+ [929216c0ffee] [v0.1.0]
22
+
23
+ * History.rdoc, lib/loggability.rb:
24
+ Bump minor version, update history.
25
+ [ea1633c450be]
26
+
27
+ * .hgignore, Rakefile, lib/loggability.rb,
28
+ lib/loggability/constants.rb, lib/loggability/formatter/color.rb,
29
+ lib/loggability/logger.rb, spec/loggability/formatter/html_spec.rb,
30
+ spec/loggability/formatter_spec.rb, spec/loggability/logger_spec.rb:
31
+ Remove all 1.9isms so it works under 1.8.x.
32
+
33
+ I've been trying to do everything in 1.9 first, but it turns out
34
+ there's still some 1.8 stuff that I need to support that I'd like to
35
+ use this with.
36
+ [e702bbec7c9d]
37
+
38
+ * lib/loggability/formatter/color.rb:
39
+ Fix the docs for the color formatter
40
+ [4191fb2e0d14]
41
+
42
+ 2012-05-07 Michael Granger <ged@FaerieMUD.org>
43
+
44
+ * .hgtags:
45
+ Added tag v0.0.2 for changeset 9a502152869e
46
+ [984798ba8ace]
47
+
48
+ * .hgsigs:
49
+ Added signature for changeset 1099204b229f
50
+ [9a502152869e] [v0.0.2]
51
+
52
+ * History.rdoc, lib/loggability.rb:
53
+ Bumped the patch version, updated History.
54
+ [1099204b229f]
55
+
56
+ * lib/loggability/formatter/html.rb, spec/lib/helpers.rb,
57
+ spec/loggability/formatter/html_spec.rb:
58
+ Fix escaping of the 'progname' in the HTML log formatter.
59
+ [748e600c8037]
60
+
1
61
  2012-05-06 Michael Granger <ged@FaerieMUD.org>
2
62
 
3
63
  * README.rdoc:
4
64
  Add some stuff to the README.
5
- [711c4dff84cf] [tip]
65
+ [711c4dff84cf] [github/master]
6
66
 
7
67
  * .hgtags:
8
68
  Added tag v0.0.1 for changeset 6dc36a56ff79
data/History.rdoc CHANGED
@@ -1,3 +1,8 @@
1
+ == v0.2.0 [2012-05-10] Michael Granger <ged@FaerieMUD.org>
2
+
3
+ Add Configurability support.
4
+
5
+
1
6
  == v0.1.0 [2012-05-08] Michael Granger <ged@FaerieMUD.org>
2
7
 
3
8
  - Add Ruby 1.8.7 support.
data/README.rdoc CHANGED
@@ -45,6 +45,43 @@ An example:
45
45
  Loggability.level = :info
46
46
 
47
47
 
48
+ === Configurability
49
+
50
+ Loggability has support for the Configurability[https://rubygems.org/gems/configurability]
51
+ library, which does the same thing for configuration that Loggability does for
52
+ logging.
53
+
54
+ You can configure all registered loggers from the 'logging' section of the config:
55
+
56
+ logging:
57
+ __default__: warn STDERR
58
+ mongrel2: info STDOUT (html)
59
+ strelka: debug (html)
60
+ inversion: error /var/log/templating.log (default)
61
+
62
+ The format of the value of each logger is:
63
+
64
+ SEVERITY [TARGET] [(FORMAT)]
65
+
66
+ where:
67
+
68
+ [+SEVERITY+]
69
+ The log level; one of: +debug+, +info+, +warn+, +error+, or +fatal+
70
+ [+TARGET+]
71
+ The destination for log messages. This can be the path to a log file, or
72
+ one of <tt>'STDOUT'</tt> or <tt>'STDERR'</tt>, which get mapped to the
73
+ equivalent filehandle. Optional.
74
+ [+FORMAT+]
75
+ The name of one of the formatters. Loggability comes with +default+ (plaintext),
76
+ +color+ (ANSI colored text), and +html+ formatters.
77
+
78
+ If the special key <tt>__default__</tt> is included, its config will be used to set
79
+ global defaults before the individual configs are applied.
80
+
81
+ If either of the optional values is unspecified, it is left unchanged from what it
82
+ was before configuration.
83
+
84
+
48
85
  == Prerequisites
49
86
 
50
87
  * Ruby 1.9.3 or better, Rubinius 2.0 or better
data/Rakefile CHANGED
@@ -21,10 +21,11 @@ hoespec = Hoe.spec 'loggability' do
21
21
 
22
22
  self.developer 'Michael Granger', 'ged@FaerieMUD.org'
23
23
 
24
- self.dependency 'pluginfactory', '~> 1.0'
24
+ self.dependency 'pluginfactory', '~> 1.0'
25
25
 
26
- self.dependency 'hoe-deveiate', '~> 0.1', :developer
27
- self.dependency 'simplecov', '~> 0.6', :developer
26
+ self.dependency 'hoe-deveiate', '~> 0.1', :developer
27
+ self.dependency 'simplecov', '~> 0.6', :developer
28
+ self.dependency 'configurability', '~> 1.2', :developer
28
29
 
29
30
  self.spec_extras[:licenses] = ["Ruby"]
30
31
  self.spec_extras[:rdoc_options] = ['-f', 'fivefish', '-t', 'Loggability Toolkit']
@@ -33,6 +33,15 @@ class Loggability::Logger < ::Logger
33
33
  @target = target
34
34
  end
35
35
 
36
+
37
+ ######
38
+ public
39
+ ######
40
+
41
+ # The target of the log device
42
+ attr_reader :target
43
+
44
+
36
45
  ### Append the specified +message+ to the target.
37
46
  def write( message )
38
47
  @target << message
@@ -128,6 +137,24 @@ class Loggability::Logger < ::Logger
128
137
  public
129
138
  ######
130
139
 
140
+ ### Return a human-readable representation of the object suitable for debugging.
141
+ def inspect
142
+ dev = if self.logdev.respond_to?( :dev )
143
+ self.logdev.dev.class
144
+ else
145
+ self.logdev.target.class
146
+ end
147
+
148
+ return "#<%p:%#x severity: %s, formatter: %s, outputting to: %p>" % [
149
+ self.class,
150
+ self.object_id * 2,
151
+ self.level,
152
+ self.formatter.class.name.sub( /.*::/, '' ).downcase,
153
+ dev,
154
+ ]
155
+ end
156
+
157
+
131
158
  #
132
159
  # :section: Severity Level
133
160
  #
data/lib/loggability.rb CHANGED
@@ -5,15 +5,14 @@
5
5
  require 'logger'
6
6
  require 'date'
7
7
 
8
-
9
8
  # A mixin that provides a top-level logging subsystem based on Logger.
10
9
  module Loggability
11
10
 
12
11
  # Package version constant
13
- VERSION = '0.1.0'
12
+ VERSION = '0.2.0'
14
13
 
15
14
  # VCS revision
16
- REVISION = %q$Revision: ea1633c450be $
15
+ REVISION = %q$Revision: 4c9840dcb9fd $
17
16
 
18
17
  # The key for the global logger (Loggability's own logger)
19
18
  GLOBAL_KEY = :__global__
@@ -21,6 +20,30 @@ module Loggability
21
20
  # The methods that are delegated across all loggers
22
21
  AGGREGATE_METHODS = [ :level=, :output_to, :write_to, :format_with, :format_as, :formatter= ]
23
22
 
23
+ # Configuration defaults
24
+ CONFIG_DEFAULTS = {
25
+ :defaults => {
26
+ :severity => 'warn',
27
+ :formatter => 'default',
28
+ :output => 'STDERR',
29
+ },
30
+ }
31
+
32
+ # Regexp for parsing logspec lines in the config
33
+ LOGSPEC_PATTERN = %r{
34
+ ^
35
+ \s*
36
+ ((?i:debug|info|warn|error|fatal)) # severity
37
+ (?:
38
+ \s+
39
+ ((?:[\w\-/:\.]|\\[ ])+)
40
+ )?
41
+ (?: \s+\(
42
+ (\w+)
43
+ \) )?
44
+ \s*
45
+ $
46
+ }x
24
47
 
25
48
  require 'loggability/constants'
26
49
  include Loggability::Constants
@@ -56,9 +79,26 @@ module Loggability
56
79
  end
57
80
 
58
81
 
82
+ ### Return the log host key for +object+, using its #log_host_key method
83
+ ### if it has one, or returning it as a Symbol if it responds to #to_sym. Returns
84
+ ### +nil+ if no key could be derived.
85
+ def self::log_host_key_for( object )
86
+ return object.log_host_key if object.respond_to?( :log_host_key )
87
+ return object.to_sym if object.respond_to?( :to_sym )
88
+ return nil
89
+ end
90
+
91
+
92
+ ### Returns +true+ if there is a log host associated with the given +object+.
93
+ def self::log_host?( object )
94
+ key = self.log_host_key_for( object ) or return false
95
+ return self.log_hosts.key?( key )
96
+ end
97
+
98
+
59
99
  ### Return the Loggability::Logger for the loghost associated with +logclient+.
60
100
  def self::[]( logclient )
61
- key = logclient.log_host_key if logclient.respond_to?( :log_host_key )
101
+ key = self.log_host_key_for( logclient )
62
102
  key ||= GLOBAL_KEY
63
103
 
64
104
  return self.log_hosts[ key ].logger
@@ -79,7 +119,10 @@ module Loggability
79
119
  ### Call the method with the given +methodname+ across the loggers of all loghosts with
80
120
  ### the given +arg+ and/or +block+.
81
121
  def self::aggregate( methodname, arg, &block )
122
+ # self.log.debug "Aggregating a call to %p with %p to %d log hosts" %
123
+ # [ methodname, arg, Loggability.log_hosts.length ]
82
124
  Loggability.log_hosts.values.each do |loghost|
125
+ # self.log.debug " %p.logger.%s( %p )" % [ loghost, methodname, arg ]
83
126
  loghost.logger.send( methodname, arg, &block )
84
127
  end
85
128
  end
@@ -221,17 +264,80 @@ module Loggability
221
264
  ### either the +key+ the host registered with, or the log host object itself. Log messages
222
265
  ### can be written to the loghost via the LogClient API, which is automatically included.
223
266
  def log_to( loghost )
224
- self.extend( Loggability::LogClient )
225
- self.log_host_key = if loghost.respond_to?( :log_host_key )
226
- loghost.log_host_key
267
+ extend( Loggability::LogClient )
268
+ include( Loggability::LogClient::InstanceMethods ) if self.is_a?( Class )
269
+
270
+ self.log_host_key = Loggability.log_host_key_for( loghost )
271
+ end
272
+
273
+
274
+ #
275
+ # :section: Configurability Support
276
+ #
277
+
278
+ # Load the Configurability library if it's installed
279
+ begin
280
+ require 'configurability'
281
+ rescue LoadError
282
+ end
283
+
284
+
285
+ # Configurability support -- load Loggability configuration from the 'logging' section
286
+ # of the config.
287
+ if defined?( Configurability )
288
+ extend Configurability
289
+ config_key :logging if respond_to?( :config_key )
290
+ end
291
+
292
+ ### Configurability API -- configure logging.
293
+ def self::configure( config=nil )
294
+ if config
295
+ self.log.debug "Configuring Loggability with custom config."
296
+
297
+ # Set up all loggers with defaults first
298
+ if defaultspec = config.delete( :__default__ ) || config.delete( '__default__' )
299
+ level, format, target = self.parse_config_spec( defaultspec )
300
+ Loggability.level = level if level
301
+ Loggability.format_as( format ) if format
302
+ Loggability.output_to( target ) if target
303
+ end
304
+
305
+ # Then let individual configs override.
306
+ config.each do |key, logspec|
307
+ unless Loggability.log_host?( key )
308
+ self.log.debug " no such log host %p; skipping" % [ key ]
309
+ next
310
+ end
311
+
312
+ self.log.debug " configuring logger for %p: %s" % [ key, logspec ]
313
+ level, format, target = self.parse_config_spec( logspec )
314
+ Loggability[ key ].level = level if level
315
+ Loggability[ key ].format_with( format ) if format
316
+ Loggability[ key ].output_to( target ) if target
317
+ end
318
+ else
319
+ self.log.debug "Configuring Loggability with defaults."
320
+ end
321
+ end
322
+
323
+
324
+ ### Parse the specified +spec+ into level,
325
+ def self::parse_config_spec( spec )
326
+ match = LOGSPEC_PATTERN.match( spec ) or
327
+ raise ArgumentError, "Couldn't parse logspec: %p" % [ spec ]
328
+ self.log.error " parsed config spec %p -> %p" % [ spec, match ]
329
+ severity, target, format = match.captures
330
+
331
+ target = case target
332
+ when 'STDOUT' then $stdout
333
+ when 'STDERR' then $stderr
227
334
  else
228
- loghost.to_sym
335
+ target
229
336
  end
230
337
 
231
- # For objects that also can be instantiated
232
- include( Loggability::LogClient::InstanceMethods ) if self.is_a?( Class )
338
+ return severity, format, target
233
339
  end
234
340
 
235
341
 
236
- end # module Strelka
342
+ end # module Loggability
237
343
 
data/spec/lib/helpers.rb CHANGED
@@ -28,9 +28,34 @@ require 'loggability' unless defined?( Loggability )
28
28
  #
29
29
  module Loggability::SpecHelpers
30
30
 
31
+ ### Reset the logging subsystem to its default state.
32
+ def reset_logging
33
+ Loggability.formatter = nil
34
+ Loggability.output_to( $stderr )
35
+ Loggability.level = :fatal
36
+ end
37
+
38
+
39
+ ### Alter the output of the default log formatter to be pretty in SpecMate output
40
+ def setup_logging( level=:fatal )
41
+
42
+ # Only do this when executing from a spec in TextMate
43
+ if ENV['HTML_LOGGING'] || (ENV['TM_FILENAME'] && ENV['TM_FILENAME'] =~ /_spec\.rb/)
44
+ logarray = []
45
+ Thread.current['logger-output'] = logarray
46
+ Loggability.output_to( logarray )
47
+ Loggability.format_as( :html )
48
+ Loggability.level = :debug
49
+ else
50
+ Loggability.level = level
51
+ end
52
+ end
53
+
54
+
31
55
  end # Loggability::SpecHelpers
32
56
 
33
57
 
58
+
34
59
  ### Mock with RSpec
35
60
  RSpec.configure do |c|
36
61
  c.mock_with( :rspec )
@@ -31,6 +31,10 @@ describe Loggability::Logger do
31
31
  end
32
32
 
33
33
 
34
+ it "has a less-verbose inspection format than that of its parent" do
35
+ @logger.inspect.should =~ /severity: \S+ formatter: \S+ outputting to: \S+/
36
+ end
37
+
34
38
  describe "severity level API" do
35
39
 
36
40
  it "defaults to :warn level" do
@@ -145,6 +149,12 @@ describe Loggability::Logger do
145
149
  messages.first.should =~ /DEBUG \{Object:0x[[:xdigit:]]+\} -- A debug message.\n/
146
150
  end
147
151
 
152
+ it "has a terse inspection format" do
153
+ object = Object.new
154
+ @logger.proxy_for( object ).inspect.
155
+ should =~ /ObjectNameProxy.* for Object/
156
+ end
157
+
148
158
  end
149
159
 
150
160
  end
@@ -13,12 +13,19 @@ require 'loggability/logger'
13
13
 
14
14
  describe Loggability do
15
15
 
16
+ before( :each ) do
17
+ setup_logging( :fatal )
18
+ end
19
+
20
+ after( :each ) do
21
+ reset_logging()
22
+ end
23
+
16
24
  it "is itself a log host for the global logger" do
17
25
  described_class.logger.should be_a( Loggability::Logger )
18
26
  described_class.log_hosts.should include( Loggability::GLOBAL_KEY => Loggability )
19
27
  end
20
28
 
21
-
22
29
  describe "version methods" do
23
30
  it "returns a version string if asked" do
24
31
  described_class.version_string.should =~ /\w+ [\d.]+/
@@ -46,6 +53,8 @@ describe Loggability do
46
53
  Loggability.log_hosts.should include( :testing => @class )
47
54
  @class.logger.should be_a( Loggability::Logger )
48
55
  @class.default_logger.should be( @class.logger )
56
+ Loggability[ @class ].should be( @class.logger )
57
+ Loggability[ :testing ].should be( @class.logger )
49
58
  end
50
59
 
51
60
  it "allows it to designate itself as a logging client" do
@@ -55,8 +64,12 @@ describe Loggability do
55
64
  end
56
65
  @class.log_to( :testing )
57
66
  @class.log.logger.should be( origin.logger )
67
+ Loggability[ @class ].should be( origin.logger )
58
68
 
59
- @class.new.log.logger.should be( origin.logger )
69
+ obj = @class.new
70
+
71
+ obj.log.logger.should be( origin.logger )
72
+ Loggability[ obj ].should be( origin.logger )
60
73
  end
61
74
 
62
75
  end
@@ -80,5 +93,87 @@ describe Loggability do
80
93
 
81
94
  end
82
95
 
96
+
97
+ describe "Configurability support" do
98
+
99
+ after( :each ) do
100
+ File.delete( 'spec-error.log' ) if File.exist?( 'spec-error.log' )
101
+ end
102
+
103
+ it "can parse a logging config spec with just a severity" do
104
+ Loggability.parse_config_spec( 'debug' ).should == [ 'debug', nil, nil ]
105
+ end
106
+
107
+ it "can parse a logging config spec with a severity and STDERR" do
108
+ Loggability.parse_config_spec( 'fatal STDERR' ).should == [ 'fatal', nil, $stderr ]
109
+ end
110
+
111
+ it "can parse a logging config spec with a severity and STDOUT" do
112
+ Loggability.parse_config_spec( 'error STDOUT' ).should == [ 'error', nil, $stdout ]
113
+ end
114
+
115
+ it "can parse a logging config spec with a severity and a path" do
116
+ Loggability.parse_config_spec( 'debug /var/log/debug.log' ).
117
+ should == [ 'debug', nil, '/var/log/debug.log' ]
118
+ end
119
+
120
+ it "can parse a logging config spec with a severity and a path with escaped spaces" do
121
+ Loggability.parse_config_spec( 'debug /store/media/Stormcrow\\ and\\ Raven/dl.log' ).
122
+ should == [ 'debug', nil, '/store/media/Stormcrow\\ and\\ Raven/dl.log' ]
123
+ end
124
+
125
+ it "can parse a logging config spec with a severity and a formatter" do
126
+ Loggability.parse_config_spec( 'warn (html)' ).
127
+ should == [ 'warn', 'html', nil ]
128
+ end
129
+
130
+ it "can parse a logging config spec with a severity, a path, and a formatter" do
131
+ Loggability.parse_config_spec( 'info /usr/local/www/htdocs/log.html (html)' ).
132
+ should == [ 'info', 'html', '/usr/local/www/htdocs/log.html' ]
133
+ end
134
+
135
+ it "can configure loghosts via its ::configure method" do
136
+ class1 = Class.new { extend Loggability; log_as :class1 }
137
+ class2 = Class.new { extend Loggability; log_as :class2 }
138
+
139
+ config = {'class1' => 'debug (html)', 'class2' => 'error spec-error.log'}
140
+ Loggability.configure( config )
141
+
142
+ Loggability[ class1 ].level.should == :debug
143
+ Loggability[ class1 ].formatter.should be_a( Loggability::Formatter::HTML )
144
+ Loggability[ class2 ].level.should == :error
145
+ Loggability[ class2 ].logdev.dev.should be_a( File )
146
+ Loggability[ class2 ].logdev.dev.path.should == 'spec-error.log'
147
+ end
148
+
149
+ it "can configure all loghosts with a config key of __default__" do
150
+ Loggability.configure( '__default__' => 'debug STDERR (html)' )
151
+
152
+ all_loggers = Loggability.log_hosts.values.map( &:logger )
153
+ all_loggers.all? {|lh| lh.level == :debug }.should be_true()
154
+ all_loggers.all? {|lh| lh.formatter.class == Loggability::Formatter::HTML }.should be_true()
155
+ all_loggers.all? {|lh| lh.logdev.dev.should == $stderr }.should be_true()
156
+ end
157
+
158
+ it "raises an error if configured with a logspec with an invalid severity" do
159
+ expect {
160
+ Loggability.configure( 'class1' => 'awesome /var/log/awesome.log' )
161
+ }.to raise_error( ArgumentError, /couldn't parse/i )
162
+ end
163
+
164
+ it "raises an error if configured with a logspec with an malformed filename" do
165
+ expect {
166
+ Loggability.configure( 'class1' => 'info Kitchen!!' )
167
+ }.to raise_error( ArgumentError, /couldn't parse/i )
168
+ end
169
+
170
+ it "raises an error if configured with a bogus formatter" do
171
+ expect {
172
+ Loggability.configure( 'class1' => 'debug (mindwaves)' )
173
+ }.to raise_error( FactoryError, /couldn't find a formatter/i )
174
+ end
175
+
176
+ end
177
+
83
178
  end
84
179
 
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: loggability
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:
@@ -36,7 +36,7 @@ cert_chain:
36
36
  YUhDS0xaZFNLai9SSHVUT3QrZ2JsUmV4OEZBaDhOZUEKY21saFhlNDZwWk5K
37
37
  Z1dLYnhaYWg4NWpJang5NWhSOHZPSStOQU01aUg5a09xSzEzRHJ4YWNUS1Bo
38
38
  cWo1UGp3RgotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
39
- date: 2012-05-08 00:00:00.000000000 Z
39
+ date: 2012-05-11 00:00:00.000000000 Z
40
40
  dependencies:
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: pluginfactory
@@ -134,6 +134,22 @@ dependencies:
134
134
  - - ~>
135
135
  - !ruby/object:Gem::Version
136
136
  version: '0.6'
137
+ - !ruby/object:Gem::Dependency
138
+ name: configurability
139
+ requirement: !ruby/object:Gem::Requirement
140
+ none: false
141
+ requirements:
142
+ - - ~>
143
+ - !ruby/object:Gem::Version
144
+ version: '1.2'
145
+ type: :development
146
+ prerelease: false
147
+ version_requirements: !ruby/object:Gem::Requirement
148
+ none: false
149
+ requirements:
150
+ - - ~>
151
+ - !ruby/object:Gem::Version
152
+ version: '1.2'
137
153
  - !ruby/object:Gem::Dependency
138
154
  name: hoe
139
155
  requirement: !ruby/object:Gem::Requirement
metadata.gz.sig CHANGED
@@ -1,3 +1 @@
1
- `�UJ�-�j|�`�(CG8p[��vj'���X5{6;o�Y���(ni3q
2
- �������ɏ<o�@
3
- e��<��]�B��� ���>
1
+ �� hZ���u�ҹ>|�"O'E���@�}I{��Yzw�諸g�<�H4� l���+����L�*�����o���NJ�Ɗ>��N>��_�!�a[