loggability 0.14.0 → 0.18.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.
- checksums.yaml +5 -5
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/History.rdoc +55 -0
- data/Manifest.txt +15 -4
- data/{README.rdoc → README.md} +78 -71
- data/Rakefile +5 -77
- data/lib/loggability.rb +19 -27
- data/lib/loggability/constants.rb +2 -2
- data/lib/loggability/formatter.rb +13 -67
- data/lib/loggability/formatter/color.rb +2 -2
- data/lib/loggability/formatter/default.rb +69 -6
- data/lib/loggability/formatter/html.rb +5 -5
- data/lib/loggability/formatter/structured.rb +35 -0
- data/lib/loggability/log_device.rb +86 -0
- data/lib/loggability/log_device/appending.rb +34 -0
- data/lib/loggability/log_device/datadog.rb +90 -0
- data/lib/loggability/log_device/file.rb +37 -0
- data/lib/loggability/log_device/http.rb +310 -0
- data/lib/loggability/logclient.rb +2 -1
- data/lib/loggability/logger.rb +45 -42
- data/lib/loggability/loghost.rb +2 -1
- data/lib/loggability/override.rb +2 -1
- data/lib/loggability/spechelpers.rb +1 -1
- data/spec/helpers.rb +6 -12
- data/spec/loggability/formatter/color_spec.rb +3 -7
- data/spec/loggability/formatter/default_spec.rb +50 -0
- data/spec/loggability/formatter/html_spec.rb +7 -7
- data/spec/loggability/formatter/structured_spec.rb +61 -0
- data/spec/loggability/formatter_spec.rb +42 -29
- data/spec/loggability/log_device/appending_spec.rb +27 -0
- data/spec/loggability/log_device/datadog_spec.rb +67 -0
- data/spec/loggability/log_device/file_spec.rb +27 -0
- data/spec/loggability/log_device/http_spec.rb +217 -0
- data/spec/loggability/logger_spec.rb +46 -5
- data/spec/loggability/loghost_spec.rb +3 -1
- data/spec/loggability/override_spec.rb +18 -5
- data/spec/loggability/spechelpers_spec.rb +3 -4
- data/spec/loggability_spec.rb +16 -13
- metadata +77 -105
- metadata.gz.sig +0 -0
- data/ChangeLog +0 -621
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- rspec -*-
|
2
|
+
#encoding: utf-8
|
3
|
+
|
4
|
+
require 'rspec'
|
5
|
+
|
6
|
+
require 'loggability/logger'
|
7
|
+
require 'loggability/log_device/appending'
|
8
|
+
|
9
|
+
|
10
|
+
describe Loggability::LogDevice::Appending do
|
11
|
+
|
12
|
+
let ( :logger ) { described_class.new( [] ) }
|
13
|
+
|
14
|
+
|
15
|
+
it "The target is an array" do
|
16
|
+
expect( logger.target ).to be_instance_of( Array )
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
it "can append to the array" do
|
21
|
+
logger.write("log message one")
|
22
|
+
logger.write("log message two")
|
23
|
+
expect( logger.target.size ).to eq( 2 )
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# -*- rspec -*-
|
2
|
+
#encoding: utf-8
|
3
|
+
|
4
|
+
require 'securerandom'
|
5
|
+
require 'rspec'
|
6
|
+
|
7
|
+
require 'loggability/logger'
|
8
|
+
require 'loggability/log_device/datadog'
|
9
|
+
|
10
|
+
|
11
|
+
describe Loggability::LogDevice::Datadog do
|
12
|
+
|
13
|
+
|
14
|
+
let( :api_key ) { SecureRandom.hex(24) }
|
15
|
+
let( :http_client ) { instance_double(Net::HTTP) }
|
16
|
+
|
17
|
+
|
18
|
+
it "includes the configured API key in request headers" do
|
19
|
+
device = described_class.new(
|
20
|
+
api_key,
|
21
|
+
max_batch_size: 3,
|
22
|
+
batch_interval: 0.1,
|
23
|
+
executor_class: Concurrent::ImmediateExecutor )
|
24
|
+
device.instance_variable_set( :@http_client, http_client )
|
25
|
+
|
26
|
+
expect( http_client ).to receive( :request ) do |request|
|
27
|
+
expect( request ).to be_a( Net::HTTP::Post )
|
28
|
+
expect( request['Content-type'] ).to match( %r|application/json|i )
|
29
|
+
expect( request['DD-API-KEY'] ).to eq( api_key )
|
30
|
+
end.at_least( :once )
|
31
|
+
|
32
|
+
device.write( "message data" * 10 ) # 120 bytes
|
33
|
+
device.write( "message data" * 100 ) # 1200 bytes
|
34
|
+
device.write( "message data" * 85 ) # 1020 bytes
|
35
|
+
device.write( "message data" * 86 ) # 1032 bytes
|
36
|
+
|
37
|
+
sleep( 0.1 ) until device.logs_queue.empty?
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
it "includes the hostname in individual log messages" do
|
42
|
+
device = described_class.new(
|
43
|
+
api_key,
|
44
|
+
max_batch_size: 3,
|
45
|
+
batch_interval: 0.1,
|
46
|
+
executor_class: Concurrent::ImmediateExecutor )
|
47
|
+
device.instance_variable_set( :@http_client, http_client )
|
48
|
+
|
49
|
+
expect( http_client ).to receive( :request ) do |request|
|
50
|
+
expect( request ).to be_a( Net::HTTP::Post )
|
51
|
+
|
52
|
+
data = JSON.parse( request.body )
|
53
|
+
|
54
|
+
expect( data ).to all( be_a Hash )
|
55
|
+
expect( data ).to all( include('hostname' => device.hostname) )
|
56
|
+
end.at_least( :once )
|
57
|
+
|
58
|
+
device.write( "message data" * 10 ) # 120 bytes
|
59
|
+
device.write( "message data" * 100 ) # 1200 bytes
|
60
|
+
device.write( "message data" * 85 ) # 1020 bytes
|
61
|
+
device.write( "message data" * 86 ) # 1032 bytes
|
62
|
+
|
63
|
+
sleep( 0.1 ) until device.logs_queue.empty?
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- rspec -*-
|
2
|
+
#encoding: utf-8
|
3
|
+
|
4
|
+
require 'tempfile'
|
5
|
+
require 'rspec'
|
6
|
+
|
7
|
+
require 'loggability/logger'
|
8
|
+
require 'loggability/log_device/file'
|
9
|
+
|
10
|
+
|
11
|
+
describe Loggability::LogDevice::File do
|
12
|
+
|
13
|
+
let( :logfile ) { Tempfile.new( 'test.log' ) }
|
14
|
+
let( :logger ) { described_class.new( logfile.path ) }
|
15
|
+
|
16
|
+
|
17
|
+
it "The logger is an instance of Loggability::LogDevice::File" do
|
18
|
+
expect( logger ).to be_instance_of( Loggability::LogDevice::File )
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
it "The log device is delegated to Ruby's built-in log device" do
|
23
|
+
expect( logger.target ).to be_instance_of( ::Logger::LogDevice )
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
@@ -0,0 +1,217 @@
|
|
1
|
+
# -*- rspec -*-
|
2
|
+
|
3
|
+
require_relative '../../helpers'
|
4
|
+
|
5
|
+
require 'tempfile'
|
6
|
+
require 'rspec'
|
7
|
+
|
8
|
+
require 'loggability/log_device/http'
|
9
|
+
|
10
|
+
|
11
|
+
describe Loggability::LogDevice::Http do
|
12
|
+
|
13
|
+
|
14
|
+
let( :http_client ) { instance_double(Net::HTTP) }
|
15
|
+
|
16
|
+
|
17
|
+
it "can be created with defaults" do
|
18
|
+
result = described_class.new
|
19
|
+
|
20
|
+
expect( result ).to be_an_instance_of( described_class )
|
21
|
+
expect( result.batch_interval ).to eq( described_class::DEFAULT_BATCH_INTERVAL )
|
22
|
+
expect( result.write_timeout ).to eq( described_class::DEFAULT_WRITE_TIMEOUT )
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
it "doesn't start when created" do
|
27
|
+
result = described_class.new
|
28
|
+
|
29
|
+
expect( result ).to_not be_running
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
it "sends logs when a full batch is ready" do
|
34
|
+
device = described_class.new( max_batch_size: 3, executor_class: Concurrent::ImmediateExecutor )
|
35
|
+
device.instance_variable_set( :@http_client, http_client )
|
36
|
+
|
37
|
+
expect( http_client ).to receive( :request ) do |request|
|
38
|
+
expect( request ).to be_a( Net::HTTP::Post )
|
39
|
+
expect( request['Content-type'] ).to match( %r|application/json|i )
|
40
|
+
expect( request.body ).to match( /message 1/i )
|
41
|
+
expect( request.body ).to match( /message 2/i )
|
42
|
+
expect( request.body ).to match( /message 3/i )
|
43
|
+
end
|
44
|
+
|
45
|
+
device.write( "Message 1" )
|
46
|
+
device.write( "Message 2" )
|
47
|
+
device.write( "Message 3" )
|
48
|
+
device.write( "Message 4" )
|
49
|
+
|
50
|
+
expect( device.logs_queue ).to have_attributes( length: 1 )
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
it "sends logs when enough time has elapsed since the last message" do
|
55
|
+
device = described_class.new(
|
56
|
+
max_batch_size: 3, batch_interval: 0.1, executor_class: Concurrent::ImmediateExecutor )
|
57
|
+
device.instance_variable_set( :@http_client, http_client )
|
58
|
+
device.start
|
59
|
+
device.timer_task.shutdown # Don't let the timer fire
|
60
|
+
|
61
|
+
expect( http_client ).to receive( :request ) do |request|
|
62
|
+
expect( request ).to be_a( Net::HTTP::Post )
|
63
|
+
expect( request['Content-type'] ).to match( %r|application/json|i )
|
64
|
+
expect( request.body ).to match( /message 1/i )
|
65
|
+
expect( request.body ).to match( /message 2/i )
|
66
|
+
end
|
67
|
+
|
68
|
+
device.write( "Message 1" )
|
69
|
+
|
70
|
+
# Now wait for the batch interval to pass and send another
|
71
|
+
sleep device.batch_interval
|
72
|
+
expect( device ).to have_batch_ready
|
73
|
+
device.write( "Message 2" )
|
74
|
+
|
75
|
+
expect( device.logs_queue ).to have_attributes( length: 0 )
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
it "sends logs on the batch interval even when messages aren't arriving" do
|
80
|
+
device = described_class.new(
|
81
|
+
max_batch_size: 3, batch_interval: 0.1, executor_class: Concurrent::ImmediateExecutor )
|
82
|
+
device.instance_variable_set( :@http_client, http_client )
|
83
|
+
|
84
|
+
expect( http_client ).to receive( :request ) do |request|
|
85
|
+
expect( request ).to be_a( Net::HTTP::Post )
|
86
|
+
expect( request['Content-type'] ).to match( %r|application/json|i )
|
87
|
+
expect( request.body ).to match( /message 1/i )
|
88
|
+
end
|
89
|
+
|
90
|
+
device.write( "Message 1" )
|
91
|
+
|
92
|
+
# Now wait for the batch interval to pass and send another
|
93
|
+
sleep device.batch_interval * 2
|
94
|
+
|
95
|
+
expect( device.logs_queue ).to have_attributes( length: 0 )
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
it "limits messages to the configured byte size constraints" do
|
100
|
+
device = described_class.new(
|
101
|
+
max_batch_size: 3,
|
102
|
+
max_message_bytesize: 1024,
|
103
|
+
batch_interval: 0.1,
|
104
|
+
executor_class: Concurrent::ImmediateExecutor )
|
105
|
+
device.instance_variable_set( :@http_client, http_client )
|
106
|
+
|
107
|
+
expect( http_client ).to receive( :request ) do |request|
|
108
|
+
expect( request ).to be_a( Net::HTTP::Post )
|
109
|
+
expect( request['Content-type'] ).to match( %r|application/json|i )
|
110
|
+
|
111
|
+
data = JSON.parse( request.body )
|
112
|
+
|
113
|
+
expect( data ).to all( have_attributes(bytesize: a_value <= 1024) )
|
114
|
+
end.at_least( :once )
|
115
|
+
|
116
|
+
device.write( "message data" * 10 ) # 120 bytes
|
117
|
+
device.write( "message data" * 100 ) # 1200 bytes
|
118
|
+
device.write( "message data" * 85 ) # 1020 bytes
|
119
|
+
device.write( "message data" * 86 ) # 1032 bytes
|
120
|
+
|
121
|
+
sleep( 0.1 ) until device.logs_queue.empty?
|
122
|
+
end
|
123
|
+
|
124
|
+
|
125
|
+
it "limits the batch to the configured byte size constraints" do
|
126
|
+
device = described_class.new(
|
127
|
+
max_batch_bytesize: 1024,
|
128
|
+
batch_interval: 0.1,
|
129
|
+
executor_class: Concurrent::ImmediateExecutor )
|
130
|
+
device.instance_variable_set( :@http_client, http_client )
|
131
|
+
|
132
|
+
expect( http_client ).to receive( :request ) do |request|
|
133
|
+
expect( request ).to be_a( Net::HTTP::Post )
|
134
|
+
expect( request['Content-type'] ).to match( %r|application/json|i )
|
135
|
+
|
136
|
+
expect( request.body.bytesize ).to be <= 1024
|
137
|
+
end.at_least( :once )
|
138
|
+
|
139
|
+
20.times { device.write( "message data" * 10 ) } # 120 bytes
|
140
|
+
20.times { device.write( "message data" * 100 ) } # 1200 bytes
|
141
|
+
20.times { device.write( "message data" * 85 ) } # 1020 bytes
|
142
|
+
20.times { device.write( "message data" * 86 ) } # 1032 bytes
|
143
|
+
|
144
|
+
sleep( 0.1 ) until device.logs_queue.empty?
|
145
|
+
end
|
146
|
+
|
147
|
+
|
148
|
+
it "uses an HTTP client for the appropriate host and port" do
|
149
|
+
device = described_class.new(
|
150
|
+
'http://logs.example.com:12881/v1/log_ingester',
|
151
|
+
executor_class: Concurrent::ImmediateExecutor )
|
152
|
+
http = device.http_client
|
153
|
+
|
154
|
+
expect( http.address ).to eq( 'logs.example.com' )
|
155
|
+
expect( http.port ).to eq( 12881 )
|
156
|
+
end
|
157
|
+
|
158
|
+
|
159
|
+
it "verifies the peer cert if sending to an HTTPS endpoint" do
|
160
|
+
device = described_class.new(
|
161
|
+
'https://logs.example.com:12881/v1/log_ingester',
|
162
|
+
executor_class: Concurrent::ImmediateExecutor )
|
163
|
+
http = device.http_client
|
164
|
+
|
165
|
+
expect( http.use_ssl? ).to be_truthy
|
166
|
+
expect( http.verify_mode ).to eq( OpenSSL::SSL::VERIFY_PEER )
|
167
|
+
end
|
168
|
+
|
169
|
+
|
170
|
+
it "stops queuing more messages if max queue size is reached" do
|
171
|
+
device = described_class.new(
|
172
|
+
max_batch_bytesize: 1024,
|
173
|
+
batch_interval: 100,
|
174
|
+
max_queue_bytesize: 100,
|
175
|
+
executor_class: Concurrent::ImmediateExecutor )
|
176
|
+
device.instance_variable_set( :@http_client, http_client )
|
177
|
+
|
178
|
+
expect( device ).to receive( :send_logs ).at_least( :once )
|
179
|
+
|
180
|
+
msg = "test message"
|
181
|
+
device.write(msg)
|
182
|
+
expect( device.logs_queue_bytesize == msg.bytesize )
|
183
|
+
|
184
|
+
hash_msg = { message: "This is a test log message", tags: ["tag1", "tag2"] }
|
185
|
+
device.write( hash_msg )
|
186
|
+
previous_bytesize = device.logs_queue_bytesize - hash_msg.to_json.bytesize
|
187
|
+
expect( device.logs_queue_bytesize ).to eq( hash_msg.to_json.bytesize + previous_bytesize )
|
188
|
+
|
189
|
+
queue_current_bytesize = device.logs_queue_bytesize
|
190
|
+
hash_msg = { message: "This is a test log message", tags: ["tag1", "tag2"] }
|
191
|
+
device.write( hash_msg )
|
192
|
+
expect( device.logs_queue_bytesize ).to eq( queue_current_bytesize )
|
193
|
+
end
|
194
|
+
|
195
|
+
|
196
|
+
it "reduces the queue bytesize once messages are sent" do
|
197
|
+
device = described_class.new(
|
198
|
+
max_batch_bytesize: 1024,
|
199
|
+
batch_interval: 100,
|
200
|
+
max_queue_bytesize: 100,
|
201
|
+
executor_class: Concurrent::ImmediateExecutor )
|
202
|
+
device.instance_variable_set( :@http_client, http_client )
|
203
|
+
|
204
|
+
expect( device ).to receive( :send_logs ).at_least( :once )
|
205
|
+
msg = "test message"
|
206
|
+
device.write(msg)
|
207
|
+
expect( device.logs_queue_bytesize == msg.bytesize )
|
208
|
+
|
209
|
+
msg = "this is just a test message"
|
210
|
+
device.write( msg )
|
211
|
+
previous_bytesize = device.logs_queue_bytesize - msg.bytesize
|
212
|
+
expect( device.logs_queue_bytesize ).to eq( msg.bytesize + previous_bytesize )
|
213
|
+
|
214
|
+
expect { device.get_next_log_payload }.to change { device.logs_queue_bytesize }.to( 0 )
|
215
|
+
end
|
216
|
+
|
217
|
+
end
|
@@ -1,12 +1,12 @@
|
|
1
|
-
# -*-
|
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
7
|
require 'tempfile'
|
6
|
-
require 'rspec'
|
7
8
|
|
8
9
|
require 'loggability/logger'
|
9
|
-
require 'loggability/formatter'
|
10
10
|
require 'loggability/formatter/default'
|
11
11
|
|
12
12
|
|
@@ -106,6 +106,7 @@ describe Loggability::Logger do
|
|
106
106
|
expect( logger.level ).to eq( :warn )
|
107
107
|
end
|
108
108
|
|
109
|
+
|
109
110
|
it "defaults to :debug level when $DEBUG is true" do
|
110
111
|
begin
|
111
112
|
$DEBUG = true
|
@@ -115,6 +116,7 @@ describe Loggability::Logger do
|
|
115
116
|
end
|
116
117
|
end
|
117
118
|
|
119
|
+
|
118
120
|
it "allows its levels to be set with integers like Logger" do
|
119
121
|
newlevel = Logger::DEBUG
|
120
122
|
$stderr.puts "Setting newlevel to %p" % [ newlevel ]
|
@@ -122,11 +124,13 @@ describe Loggability::Logger do
|
|
122
124
|
expect( logger.level ).to eq( :debug )
|
123
125
|
end
|
124
126
|
|
127
|
+
|
125
128
|
it "allows its levels to be set with Symbolic level names" do
|
126
129
|
logger.level = :info
|
127
130
|
expect( logger.level ).to eq( :info )
|
128
131
|
end
|
129
132
|
|
133
|
+
|
130
134
|
it "allows its levels to be set with Stringish level names" do
|
131
135
|
logger.level = 'fatal'
|
132
136
|
expect( logger.level ).to eq( :fatal )
|
@@ -141,12 +145,14 @@ describe Loggability::Logger do
|
|
141
145
|
expect( logger.logdev.dev ).to be( $stderr )
|
142
146
|
end
|
143
147
|
|
148
|
+
|
144
149
|
it "can be told to log to a file" do
|
145
150
|
tmpfile = Tempfile.new( 'loggability-device-spec' )
|
146
151
|
logger.output_to( tmpfile.path )
|
147
152
|
expect( logger.logdev.dev ).to be_a( File )
|
148
153
|
end
|
149
154
|
|
155
|
+
|
150
156
|
it "supports log-rotation arguments for logfiles" do
|
151
157
|
tmpfile = Tempfile.new( 'loggability-device-spec' )
|
152
158
|
logger.output_to( tmpfile.path, 5, 125000 )
|
@@ -156,16 +162,45 @@ describe Loggability::Logger do
|
|
156
162
|
expect( logger.logdev.instance_variable_get(:@shift_size) ).to eq( 125000 )
|
157
163
|
end
|
158
164
|
|
165
|
+
|
166
|
+
it "can be told to log to a file and delegate to ruby's built-in logger log device" do
|
167
|
+
logfile = double( "logfile.log" )
|
168
|
+
expect( Loggability::LogDevice ).to receive( :create ).
|
169
|
+
with( :file, 'log_file.log' ).
|
170
|
+
and_return( logfile )
|
171
|
+
|
172
|
+
logfile = Loggability::LogDevice.create( :file, 'log_file.log' )
|
173
|
+
expect( logger ).to receive( :output_to ).
|
174
|
+
with( logfile ).
|
175
|
+
and_return( nil )
|
176
|
+
|
177
|
+
logger.output_to( logfile )
|
178
|
+
|
179
|
+
expect( logger.logdev ).to be_a( Logger::LogDevice )
|
180
|
+
end
|
181
|
+
|
182
|
+
|
183
|
+
it "can be told to log to a custom log device type" do
|
184
|
+
logger.output_to( :http, 'https://logapi.example.com:41133/v1/logintake' )
|
185
|
+
|
186
|
+
device = logger.logdev
|
187
|
+
|
188
|
+
expect( device ).to be_a( Loggability::LogDevice::Http )
|
189
|
+
expect( device.endpoint.to_s ).to eq( 'https://logapi.example.com:41133/v1/logintake' )
|
190
|
+
end
|
191
|
+
|
192
|
+
|
159
193
|
it "can be told to log to an Array" do
|
160
194
|
logmessages = []
|
161
195
|
logger.output_to( logmessages )
|
162
|
-
expect( logger.logdev ).to be_a( Loggability::
|
196
|
+
expect( logger.logdev ).to be_a( Loggability::LogDevice::Appending )
|
163
197
|
logger.level = :debug
|
164
198
|
logger.info( "Something happened." )
|
165
199
|
expect( logmessages.size ).to eq( 1 )
|
166
200
|
expect( logmessages.first ).to match( /something happened/i )
|
167
201
|
end
|
168
202
|
|
203
|
+
|
169
204
|
it "doesn't re-wrap a Logger::LogDevice" do
|
170
205
|
tmpfile = Tempfile.new( 'loggability-device-spec' )
|
171
206
|
logger.output_to( tmpfile.path, 5, 125000 )
|
@@ -176,7 +211,8 @@ describe Loggability::Logger do
|
|
176
211
|
expect( logger.logdev ).to be( original_logdev )
|
177
212
|
end
|
178
213
|
|
179
|
-
|
214
|
+
|
215
|
+
it "doesn't re-wrap an Appending log device" do
|
180
216
|
log_array = []
|
181
217
|
logger.output_to( log_array )
|
182
218
|
logger.output_to( logger.logdev )
|
@@ -193,11 +229,13 @@ describe Loggability::Logger do
|
|
193
229
|
expect( logger.formatter ).to be_a( Loggability::Formatter::Default )
|
194
230
|
end
|
195
231
|
|
232
|
+
|
196
233
|
it "can be told to use the default formatter explicitly" do
|
197
234
|
logger.format_as( :default )
|
198
235
|
expect( logger.formatter ).to be_a( Loggability::Formatter::Default )
|
199
236
|
end
|
200
237
|
|
238
|
+
|
201
239
|
it "can be told to use a block as a formatter" do
|
202
240
|
logger.format_with do |severity, datetime, progname, msg|
|
203
241
|
original_formatter.call(severity, datetime, progname, msg.dump)
|
@@ -206,11 +244,13 @@ describe Loggability::Logger do
|
|
206
244
|
expect( logger.formatter ).to be_a( Proc )
|
207
245
|
end
|
208
246
|
|
247
|
+
|
209
248
|
it "can be told to use the HTML formatter" do
|
210
249
|
logger.format_as( :html )
|
211
250
|
expect( logger.formatter ).to be_a( Loggability::Formatter::HTML )
|
212
251
|
end
|
213
252
|
|
253
|
+
|
214
254
|
it "supports formatting with ::Logger::Formatter, too" do
|
215
255
|
output = []
|
216
256
|
logger.output_to( output )
|
@@ -244,6 +284,7 @@ describe Loggability::Logger do
|
|
244
284
|
expect( messages.first ).to match( expected_format )
|
245
285
|
end
|
246
286
|
|
287
|
+
|
247
288
|
it "has a terse inspection format" do
|
248
289
|
object = Object.new
|
249
290
|
expect(
|