loggability 0.14.0 → 0.15.0.pre20190714094638

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.
@@ -10,6 +10,7 @@ lib/loggability/formatter.rb
10
10
  lib/loggability/formatter/color.rb
11
11
  lib/loggability/formatter/default.rb
12
12
  lib/loggability/formatter/html.rb
13
+ lib/loggability/formatter/structured.rb
13
14
  lib/loggability/logclient.rb
14
15
  lib/loggability/logger.rb
15
16
  lib/loggability/loghost.rb
@@ -17,7 +18,9 @@ lib/loggability/override.rb
17
18
  lib/loggability/spechelpers.rb
18
19
  spec/helpers.rb
19
20
  spec/loggability/formatter/color_spec.rb
21
+ spec/loggability/formatter/default_spec.rb
20
22
  spec/loggability/formatter/html_spec.rb
23
+ spec/loggability/formatter/structured_spec.rb
21
24
  spec/loggability/formatter_spec.rb
22
25
  spec/loggability/logger_spec.rb
23
26
  spec/loggability/loghost_spec.rb
data/Rakefile CHANGED
@@ -27,8 +27,9 @@ hoespec = Hoe.spec 'loggability' do
27
27
  self.dependency 'hoe-bundler', '~> 1.2', :developer
28
28
  self.dependency 'simplecov', '~> 0.7', :developer
29
29
  self.dependency 'configurability', '~> 3.1', :developer
30
+ self.dependency 'timecop', '~> 0.9', :developer
30
31
 
31
- self.license "Ruby"
32
+ self.license "BSD-3-Clause"
32
33
  self.require_ruby_version( '>=1.9.3' )
33
34
  self.hg_sign_tags = true if self.respond_to?( :hg_sign_tags= )
34
35
  self.check_history_on_release = true if self.respond_to?( :check_history_on_release= )
@@ -1,6 +1,6 @@
1
1
  # -*- ruby -*-
2
2
  # vim: set nosta noet ts=4 sw=4:
3
- # encoding: utf-8
3
+ # frozen_string_literal: true
4
4
 
5
5
  require 'logger'
6
6
  require 'date'
@@ -12,7 +12,7 @@ module Loggability
12
12
  VERSION = '0.14.0'
13
13
 
14
14
  # VCS revision
15
- REVISION = %q$Revision: 500260d36bfb $
15
+ REVISION = %q$Revision$
16
16
 
17
17
  # The key for the global logger (Loggability's own logger)
18
18
  GLOBAL_KEY = :__global__
@@ -1,6 +1,6 @@
1
- #!/usr/bin/env ruby
1
+ # -*- ruby -*-
2
2
  # vim: set nosta noet ts=4 sw=4:
3
- # encoding: utf-8
3
+ # frozen_string_literal: true
4
4
 
5
5
  require 'logger'
6
6
  require 'loggability' unless defined?( Loggability )
@@ -1,6 +1,6 @@
1
- #!/usr/bin/env ruby
1
+ # -*- ruby -*-
2
2
  # vim: set nosta noet ts=4 sw=4:
3
- # encoding: utf-8
3
+ # frozen_string_literal: true
4
4
 
5
5
  require 'loggability' unless defined?( Loggability )
6
6
 
@@ -8,21 +8,23 @@ require 'loggability' unless defined?( Loggability )
8
8
  ### An abstract base class for Loggability log formatters.
9
9
  class Loggability::Formatter
10
10
 
11
- # The default sprintf pattern
12
- DEFAULT_DATETIME_FORMAT = '%Y-%m-%d %H:%M:%S'
13
-
14
-
15
11
  ##
16
12
  # Derivative classes, keyed by name
17
- class << self; attr_reader :derivatives; end
13
+ singleton_class.attr_reader( :derivatives )
18
14
  @derivatives = {}
19
15
 
20
16
 
21
17
  ### Inherited hook -- add subclasses to the ::derivatives Array.
22
18
  def self::inherited( subclass )
23
19
  super
24
- classname = subclass.name.sub( /.*::/, '' ).downcase.to_sym
25
- Loggability::Formatter.derivatives[ classname ] = subclass
20
+
21
+ if ( name = subclass.name )
22
+ classname = name.sub( /.*::/, '' ).downcase
23
+ else
24
+ classname = "anonymous_%d" % [ subclass.object_id ]
25
+ end
26
+
27
+ Loggability::Formatter.derivatives[ classname.to_sym ] = subclass
26
28
  end
27
29
 
28
30
 
@@ -42,69 +44,13 @@ class Loggability::Formatter
42
44
  end
43
45
 
44
46
 
45
-
46
- ### Initialize a new Loggability::Formatter. The specified +logformat+ should
47
- ### be a sprintf pattern with positional placeholders:
48
- ###
49
- ### [<tt>%1$s</tt>] Time (pre-formatted using strftime with the +datetime_format+)
50
- ### [<tt>%2$d</tt>] Time microseconds
51
- ### [<tt>%3$d</tt>] PID
52
- ### [<tt>%4$s</tt>] Thread ID
53
- ### [<tt>%5$s</tt>] Severity
54
- ### [<tt>%6$s</tt>] Object/Program Name
55
- ### [<tt>%7$s</tt>] Message
56
- ###
57
- def initialize( logformat, datetime_format=DEFAULT_DATETIME_FORMAT )
58
- @format = logformat.dup
59
- @datetime_format = datetime_format.dup
60
- end
61
-
62
-
63
- ######
64
- public
65
- ######
66
-
67
- # Main log sprintf format
68
- attr_accessor :format
69
-
70
- # Strftime format for log messages
71
- attr_accessor :datetime_format
72
-
73
-
74
47
  ### Create a log message from the given +severity+, +time+, +progname+, and +message+
75
48
  ### and return it.
76
49
  def call( severity, time, progname, message )
77
- timeformat = self.datetime_format
78
- args = [
79
- time.strftime( timeformat ), # %1$s
80
- time.usec, # %2$d
81
- Process.pid, # %3$d
82
- Thread.current == Thread.main ? 'main' : Thread.current.object_id, # %4$s
83
- severity.downcase, # %5$s
84
- progname, # %6$s
85
- self.msg2str(message, severity) # %7$s
86
- ]
87
-
88
- return self.format % args
50
+ raise NotImplementedError, "%p doesn't implement required method %s" %
51
+ [ self.class, __method__ ]
89
52
  end
90
53
 
91
54
 
92
- #########
93
- protected
94
- #########
95
-
96
- ### Format the specified +msg+ for output to the log.
97
- def msg2str( msg, severity )
98
- case msg
99
- when String
100
- return msg
101
- when Exception
102
- bt = severity == 'DEBUG' ? msg.backtrace.join("\n") : msg.backtrace.first
103
- return "%p: %s from %s" % [ msg.class, msg.message, bt ]
104
- else
105
- return msg.inspect
106
- end
107
- end
108
-
109
55
  end # class Loggability::Formatter
110
56
 
@@ -1,6 +1,6 @@
1
- #!/usr/bin/env ruby
1
+ # -*- ruby -*-
2
2
  # vim: set nosta noet ts=4 sw=4:
3
- # encoding: utf-8
3
+ # frozen_string_literal: true
4
4
 
5
5
  require 'loggability' unless defined?( Loggability )
6
6
  require 'loggability/formatter' unless defined?( Loggability::Formatter )
@@ -1,20 +1,83 @@
1
- #!/usr/bin/env ruby
1
+ # -*- ruby -*-
2
2
  # vim: set nosta noet ts=4 sw=4:
3
- # encoding: utf-8
3
+ # frozen_string_literal: true
4
4
 
5
5
  require 'loggability' unless defined?( Loggability )
6
6
  require 'loggability/formatter' unless defined?( Loggability::Formatter )
7
7
 
8
8
 
9
- # The default log formatter class.
9
+ # The default sprintf-based log formatter class.
10
10
  class Loggability::Formatter::Default < Loggability::Formatter
11
11
 
12
+ # The default sprintf pattern
13
+ DEFAULT_DATETIME_FORMAT = '%Y-%m-%d %H:%M:%S'
14
+
12
15
  # The format to output unless debugging is turned on
13
16
  FORMAT = "[%1$s.%2$06d %3$d/%4$s] %5$5s {%6$s} -- %7$s\n"
14
17
 
15
- ### Specify the format for the default formatter.
16
- def initialize( format=FORMAT )
17
- super
18
+ ### Initialize a new Loggability::Formatter. The specified +logformat+ should
19
+ ### be a sprintf pattern with positional placeholders:
20
+ ###
21
+ ### [<tt>%1$s</tt>] Time (pre-formatted using strftime with the +datetime_format+)
22
+ ### [<tt>%2$d</tt>] Time microseconds
23
+ ### [<tt>%3$d</tt>] PID
24
+ ### [<tt>%4$s</tt>] Thread ID
25
+ ### [<tt>%5$s</tt>] Severity
26
+ ### [<tt>%6$s</tt>] Object/Program Name
27
+ ### [<tt>%7$s</tt>] Message
28
+ ###
29
+ def initialize( logformat=FORMAT, datetime_format=DEFAULT_DATETIME_FORMAT )
30
+ super()
31
+
32
+ @format = logformat.dup
33
+ @datetime_format = datetime_format.dup
34
+ end
35
+
36
+
37
+ ######
38
+ public
39
+ ######
40
+
41
+ # Main log sprintf format
42
+ attr_accessor :format
43
+
44
+ # Strftime format for log messages
45
+ attr_accessor :datetime_format
46
+
47
+
48
+ ### Create a log message from the given +severity+, +time+, +progname+, and +message+
49
+ ### and return it.
50
+ def call( severity, time, progname, message )
51
+ timeformat = self.datetime_format
52
+ args = [
53
+ time.strftime( timeformat ), # %1$s
54
+ time.usec, # %2$d
55
+ Process.pid, # %3$d
56
+ Thread.current == Thread.main ? 'main' : Thread.current.object_id, # %4$s
57
+ severity.downcase, # %5$s
58
+ progname, # %6$s
59
+ self.msg2str(message, severity) # %7$s
60
+ ]
61
+
62
+ return self.format % args
63
+ end
64
+
65
+
66
+ #########
67
+ protected
68
+ #########
69
+
70
+ ### Format the specified +msg+ for output to the log.
71
+ def msg2str( msg, severity )
72
+ case msg
73
+ when String
74
+ return msg
75
+ when Exception
76
+ bt = severity == 'DEBUG' ? msg.backtrace.join("\n") : msg.backtrace.first
77
+ return "%p: %s from %s" % [ msg.class, msg.message, bt ]
78
+ else
79
+ return msg.inspect
80
+ end
18
81
  end
19
82
 
20
83
  end # class Loggability::Formatter::Default
@@ -1,13 +1,13 @@
1
- #!/usr/bin/env ruby
1
+ # -*- ruby -*-
2
2
  # vim: set nosta noet ts=4 sw=4:
3
- # encoding: utf-8
3
+ # frozen_string_literal: true
4
4
 
5
- require 'loggability' unless defined?( Loggability )
6
5
  require 'loggability/formatter' unless defined?( Loggability::Formatter )
6
+ require 'loggability/formatter/default'
7
7
 
8
8
 
9
- # The default log formatter class.
10
- class Loggability::Formatter::HTML < Loggability::Formatter
9
+ # Output logs as HTML
10
+ class Loggability::Formatter::HTML < Loggability::Formatter::Default
11
11
 
12
12
  # The default HTML fragment that'll be used as the template for each log message.
13
13
  HTML_LOG_FORMAT = %q{
@@ -1,5 +1,6 @@
1
1
  # -*- ruby -*-
2
- #encoding: utf-8
2
+ # vim: set nosta noet ts=4 sw=4:
3
+ # frozen_string_literal: true
3
4
 
4
5
  require 'loggability' unless defined?( Loggability )
5
6
 
@@ -1,6 +1,6 @@
1
- #!/usr/bin/env ruby
1
+ # -*- ruby -*-
2
2
  # vim: set nosta noet ts=4 sw=4:
3
- # encoding: utf-8
3
+ # frozen_string_literal: true
4
4
 
5
5
  require 'logger'
6
6
  require 'loggability' unless defined?( Loggability )
@@ -278,7 +278,7 @@ class Loggability::Logger < ::Logger
278
278
 
279
279
  ### Format a log message using the current formatter and return it.
280
280
  def format_message( severity, datetime, progname, msg )
281
- self.formatter.call(severity, datetime, progname, msg)
281
+ self.formatter.call( severity, datetime, progname, msg )
282
282
  end
283
283
 
284
284
 
@@ -1,5 +1,6 @@
1
1
  # -*- ruby -*-
2
- #encoding: utf-8
2
+ # vim: set nosta noet ts=4 sw=4:
3
+ # frozen_string_literal: true
3
4
 
4
5
  require 'loggability' unless defined?( Loggability )
5
6
 
@@ -1,5 +1,6 @@
1
1
  # -*- ruby -*-
2
- #encoding: utf-8
2
+ # vim: set nosta noet ts=4 sw=4:
3
+ # frozen_string_literal: true
3
4
 
4
5
  require 'monitor'
5
6
  require 'loggability' unless defined?( Loggability )
@@ -1,6 +1,6 @@
1
1
  # -*- ruby -*-
2
2
  # vim: set nosta noet ts=4 sw=4:
3
- # encoding: utf-8
3
+ # frozen_string_literal: true
4
4
 
5
5
  require 'loggability' unless defined?( Loggability )
6
6
 
@@ -1,15 +1,6 @@
1
- #!/usr/bin/env ruby
1
+ # -*- ruby -*-
2
2
  # vim: set nosta noet ts=4 sw=4:
3
- # encoding: utf-8
4
-
5
- BEGIN {
6
- require 'pathname'
7
- basedir = Pathname.new( __FILE__ ).dirname.parent
8
-
9
- libdir = basedir + "lib"
10
-
11
- $LOAD_PATH.unshift( libdir.to_s ) unless $LOAD_PATH.include?( libdir.to_s )
12
- }
3
+ # frozen_string_literal: true
13
4
 
14
5
  # SimpleCov test coverage reporting; enable this using the :coverage rake task
15
6
  if ENV['COVERAGE']
@@ -25,6 +16,7 @@ begin
25
16
  rescue LoadError
26
17
  end
27
18
 
19
+ require 'timecop'
28
20
  require 'loggability'
29
21
  require 'loggability/spechelpers'
30
22
 
@@ -1,13 +1,9 @@
1
- # -*- rspec -*-
2
- #encoding: utf-8
1
+ # -*- ruby -*-
2
+ # vim: set nosta noet ts=4 sw=4:
3
+ # frozen_string_literal: true
3
4
 
4
5
  require_relative '../../helpers'
5
6
 
6
- require 'tempfile'
7
- require 'rspec'
8
-
9
- require 'loggability/logger'
10
- require 'loggability/formatter'
11
7
  require 'loggability/formatter/color'
12
8
 
13
9
 
@@ -1,13 +1,9 @@
1
- # -*- rspec -*-
2
- #encoding: utf-8
1
+ # -*- ruby -*-
2
+ # vim: set nosta noet ts=4 sw=4:
3
+ # frozen_string_literal: true
3
4
 
4
5
  require_relative '../../helpers'
5
6
 
6
- require 'tempfile'
7
- require 'rspec'
8
-
9
- require 'loggability/logger'
10
- require 'loggability/formatter'
11
7
  require 'loggability/formatter/html'
12
8
 
13
9
 
@@ -15,12 +11,14 @@ describe Loggability::Formatter::HTML do
15
11
 
16
12
  subject { described_class.new }
17
13
 
14
+
18
15
  it "formats messages as HTML" do
19
16
  expect(
20
17
  subject.call( 'INFO', Time.at(1336286481), nil, "Foom." )
21
18
  ).to match( %r{<span class="log-message-text">Foom.</span>}i )
22
19
  end
23
20
 
21
+
24
22
  it "formats exceptions into useful messages" do
25
23
  msg = nil
26
24
 
@@ -35,12 +33,14 @@ describe Loggability::Formatter::HTML do
35
33
  expect( msg ).to match( %r{ from <span class=\"log-exc-firstframe\">}i )
36
34
  end
37
35
 
36
+
38
37
  it "formats regular objects into useful messages" do
39
38
  expect(
40
39
  subject.call( 'INFO', Time.at(1336286481), nil, Object.new )
41
40
  ).to match( %r{<span class=\"log-message-text\">#&lt;Object:0x[[:xdigit:]]+&gt;</span>} )
42
41
  end
43
42
 
43
+
44
44
  it "escapes the 'progname' part of log messages" do
45
45
  progname = "#<Class:0x007f9efa153d08>:0x7f9efa153c18"
46
46
  expect(
@@ -1,52 +1,65 @@
1
- # -*- rspec -*-
1
+ # -*- ruby -*-
2
+ # vim: set nosta noet ts=4 sw=4:
3
+ # frozen_string_literal: true
2
4
 
3
5
  require_relative '../helpers'
4
6
 
5
- require 'tempfile'
6
- require 'rspec'
7
-
8
- require 'loggability/logger'
9
7
  require 'loggability/formatter'
10
- require 'loggability/formatter/default'
11
8
 
12
9
 
13
10
  describe Loggability::Formatter do
14
11
 
15
- it "formats messages with the pattern it's constructed with" do
16
- formatter = described_class.new( '[%5$s] %7$s' )
17
- result = formatter.call( 'INFO', Time.at(1336286481), nil, 'Foom.' )
18
- expect( result ).to match(/\[INFO\] Foom./i)
12
+ before( :all ) do
13
+ @actual_derivatives = described_class.derivatives.dup
14
+ end
15
+
16
+ after( :all ) do
17
+ described_class.derivatives.replace( @actual_derivatives )
19
18
  end
20
19
 
21
20
 
22
- it "formats exceptions into useful messages" do
23
- formatter = described_class.new( '[%5$s] %7$s' )
24
- msg = nil
21
+ describe "concrete subclasses" do
25
22
 
26
- begin
27
- raise ArgumentError, "invalid argument"
28
- rescue => err
29
- msg = formatter.call( 'INFO', Time.at(1336286481), nil, err )
23
+ class Test < described_class
30
24
  end
31
25
 
32
- expect( msg ).to match(/\[INFO\] ArgumentError: invalid argument/i)
33
- end
34
26
 
27
+ it "must implement #call" do
28
+ expect {
29
+ Test.new.call( 'INFO', Time.now, nil, "A message." )
30
+ }.to raise_error( /doesn't implement required method/i )
31
+ end
35
32
 
36
- it "formats regular objects into useful messages" do
37
- formatter = described_class.new( '[%5$s] %7$s' )
38
- result = formatter.call( 'INFO', Time.at(1336286481), nil, Object.new )
39
33
 
40
- expect( result ).to match(/\[INFO\] #<Object:0x[[:xdigit:]]+>/i)
41
- end
34
+ it "is tracked by the base class" do
35
+ expect( described_class.derivatives ).to include( test: Test )
36
+ end
42
37
 
43
38
 
44
- it "includes the thread ID if logging from a thread other than the main thread" do
45
- formatter = described_class.new( '%4$d' )
46
- thr = Thread.new do
47
- formatter.call( 'INFO', Time.now, nil, 'Foom.' )
39
+ it "is tracked if its anonymous" do
40
+ subclass = Class.new( described_class )
41
+ expect( described_class.derivatives.values ).to include( subclass )
48
42
  end
49
- expect( thr.value ).to eq( thr.object_id.to_s )
43
+
44
+
45
+ it "can be loaded by name" do
46
+ expect( described_class ).to receive( :require ).
47
+ with( "loggability/formatter/test" )
48
+
49
+ expect( described_class.create(:test) ).to be_an_instance_of( Test )
50
+ end
51
+
52
+
53
+ it "raises a LoadError if loading doesn't work" do
54
+ expect( described_class ).to receive( :require ).
55
+ with( "loggability/formatter/circus" )
56
+
57
+ expect {
58
+ described_class.create( :circus )
59
+ }.to raise_error( LoadError, /didn't load a class/i )
60
+ end
61
+
62
+
50
63
  end
51
64
 
52
65
  end