loggability 0.14.0 → 0.15.0.pre20190714094638

Sign up to get free protection for your applications and to get access to all the features.
@@ -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