slack_log_device 2.2.3 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dc81637219036304853c58b3abdff5b0461746b6
4
- data.tar.gz: cbd0673773540ba8b65ed7f7ed24a2a508a46df8
3
+ metadata.gz: 7da84e6d177382ef3698ba25b1cafddfd7e41e9d
4
+ data.tar.gz: 9643a365bff66ea7ea8219d38c73dcad7166185e
5
5
  SHA512:
6
- metadata.gz: 58320e47d7af2785ed9cf2c03a8770e5fa32ed4be7e3225491a9c36541693ba5be039a02aacb54e63d7761c9c4f7c9121b6a959eb24436722ec4882bebdbf9ef
7
- data.tar.gz: 9e3d6ac73a9b43877069efc40adb431629131d5a2c99a7b3f7bc759fb443c846f51f2d6eec5b650e48d0adbf3f517a3a1596fb5c2a5b51bb1c83010de91697a2
6
+ metadata.gz: a25cdda1fa68d846b11405ade1d656b0b0d349db2faa3c798290643ae58e78cd878e81eec53cfb204ceececdfc2a31a75b1561d8394d1450cf29f05e0e552f32
7
+ data.tar.gz: 44c2fda8c1c618aee82cd46fc6a6bf48445826290048fd269817da57daa34ddbc54a9e4a954e99069f35c794f628a111e86b26a0a120b2b6cadd4eaf4c751aaa
data/README.mdown CHANGED
@@ -46,7 +46,14 @@ starting with a `@`).
46
46
  It can be configured like this:
47
47
 
48
48
  ```ruby
49
- logger.formatter = SlackLogDevice::FORMATTER
49
+ logger.formatter = SlackLogDevice.formatter
50
+ ```
51
+
52
+ `SlackLogDevice.formatter` method also accepts block to transform logged
53
+ message, example:
54
+
55
+ ```ruby
56
+ logger.formatter = SlackLogDevice.formatter { |message| message.reverse }
50
57
  ```
51
58
 
52
59
  ## Rails configuration
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.2.3
1
+ 3.0.0
@@ -0,0 +1,94 @@
1
+ class SlackLogDevice
2
+
3
+ class Formatter
4
+
5
+ MAX_MESSAGE_LENGTH = 4000
6
+
7
+ attr_reader :extra_metadata
8
+
9
+ def initialize(options = {}, &block)
10
+ options.assert_valid_keys(:extra_metadata)
11
+ @extra_metadata = options.key?(:extra_metadata) ? options[:extra_metadata] : {}
12
+ @message_conveter = block_given? ? Proc.new(&block) : -> (message) { message }
13
+ end
14
+
15
+ def call(severity, datetime, progname, message)
16
+ text = "*`#{severity}`*"
17
+ text << " (*#{progname}*)" if progname.present?
18
+ text << ':'
19
+ if message.is_a?(Exception)
20
+ exception = message
21
+ text << " A `#{message.class}` occurred: #{convert_message(exception.message)}".rstrip
22
+ text = truncate(text)
23
+ text = append_metadata(text, exception)
24
+ text = append_backtrace(text, exception)
25
+ else
26
+ text << " #{convert_message(message)}".rstrip
27
+ text = append_metadata(text, message)
28
+ end
29
+ truncate(text)
30
+ end
31
+
32
+ private
33
+
34
+ def append_backtrace(text, exception)
35
+ backtrace = format_backtrace(exception, MAX_MESSAGE_LENGTH - text.size - 2)
36
+ text << "\n\n" << backtrace if backtrace.present?
37
+ text
38
+ end
39
+
40
+ def append_metadata(text, message)
41
+ metadata = format_metadata(message, MAX_MESSAGE_LENGTH - text.size - 2)
42
+ text << "\n\n" << metadata if metadata.present?
43
+ text
44
+ end
45
+
46
+ def convert_message(message)
47
+ @message_conveter.call(message.to_s.strip).to_s.strip
48
+ end
49
+
50
+ def default_metadata(request)
51
+ return {} if request.blank?
52
+ metadata = {
53
+ 'Method' => request.method,
54
+ 'URL' => request.url,
55
+ 'Remote address' => request.remote_addr,
56
+ 'User-Agent' => request.user_agent,
57
+ }
58
+ metadata.keys.each do |key|
59
+ value = metadata[key]
60
+ metadata[key] = "`#{value.strip}`" if value.present?
61
+ end
62
+ metadata
63
+ end
64
+
65
+ def format_backtrace(exception, size_available)
66
+ backtrace = exception.backtrace.try(:join, "\n")
67
+ return nil if backtrace.blank? || size_available < 7
68
+ "```#{truncate(backtrace, size_available - 6)}```"
69
+ end
70
+
71
+ def format_metadata(message, size_available)
72
+ return nil if size_available < 11
73
+ options = {}
74
+ options[:exception] = message if message.is_a?(Exception)
75
+ request = options[:exception].present? ? options[:exception].instance_variable_get(:@__slack_log_device_request) : nil
76
+ options[:request] = request if request.present?
77
+ text = default_metadata(request).merge(extra_metadata).map do |name, value|
78
+ value = value.call(options) if value.respond_to?(:call)
79
+ value.present? ? "• *#{name.strip}*: #{value.strip}" : nil
80
+ end.compact.join("\n")
81
+ return nil if text.blank?
82
+ truncate(text, size_available)
83
+ end
84
+
85
+ def truncate(message, max_length = MAX_MESSAGE_LENGTH)
86
+ message = message.strip
87
+ return message if message.size <= max_length
88
+ return message[0, max_length] if max_length < 3
89
+ "#{message[0, max_length - 3]}..."
90
+ end
91
+
92
+ end
93
+
94
+ end
@@ -0,0 +1,16 @@
1
+ class SlackLogDevice
2
+
3
+ module RailsExceptionsLogging
4
+
5
+ def log_error(request, wrapper)
6
+ logger = logger(request)
7
+ return unless logger
8
+ exception = wrapper.exception
9
+ return if defined?(ActionController::RoutingError) && exception.is_a?(ActionController::RoutingError)
10
+ exception.instance_variable_set(:@__slack_log_device_request, request)
11
+ logger.fatal(exception)
12
+ end
13
+
14
+ end
15
+
16
+ end
@@ -5,26 +5,15 @@ require 'logger'
5
5
 
6
6
  class SlackLogDevice
7
7
 
8
- FORMATTER = -> (severity, datetime, progname, message) do
9
- text = "*`#{severity}`*"
10
- text << " (*#{progname}*)" if progname.present?
11
- text << ': '
12
- if message.is_a?(Exception)
13
- text << "A `#{message.class}` occurred: #{message.message}\n\n```"
14
- backtrace = message.backtrace.join("\n")
15
- backtrace = backtrace[0, MAX_MESSAGE_LENGTH - 6 - text.size] << "..." if backtrace.size > MAX_MESSAGE_LENGTH - 3
16
- text << backtrace << '```'
17
- else
18
- text << message
19
- end
20
- end
21
- MAX_MESSAGE_LENGTH = 4000
22
-
23
8
  attr_reader :channel, :flush_delay, :max_buffer_size, :timeout, :username, :webhook_url
24
9
 
10
+ def self.formatter(options = {}, &block)
11
+ Formatter.new(options, &block)
12
+ end
13
+
25
14
  def initialize(options = {})
26
15
  options.assert_valid_keys(:auto_flush, :channel, :flush_delay, :max_buffer_size, :timeout, :username, :webhook_url)
27
- @buffer = []
16
+ @buffer = ''
28
17
  @mutex = Mutex.new
29
18
  @flush_thread
30
19
  self.auto_flush = options[:auto_flush]
@@ -58,8 +47,8 @@ class SlackLogDevice
58
47
  return if @buffer.empty?
59
48
  message = ''
60
49
  @mutex.synchronize do
61
- message = @buffer.join("\n")
62
- @buffer.clear
50
+ message = @buffer
51
+ @buffer = ''
63
52
  end
64
53
  data = { 'text' => message.to_s }
65
54
  data['channel'] = channel if channel.present?
@@ -73,7 +62,7 @@ class SlackLogDevice
73
62
  end
74
63
 
75
64
  def flush?
76
- auto_flush? || flush_delay.zero? || @buffer.join("\n").bytesize > max_buffer_size
65
+ auto_flush? || flush_delay.zero? || @buffer.bytesize > max_buffer_size || @buffer.include?('```')
77
66
  end
78
67
 
79
68
  def flush_delay=(value)
@@ -109,6 +98,7 @@ class SlackLogDevice
109
98
  message = message.to_s.try(:strip)
110
99
  return if message.blank?
111
100
  @mutex.synchronize do
101
+ @buffer << "\n" unless @buffer.empty?
112
102
  @buffer << message
113
103
  end
114
104
  @flush_thread.kill if @flush_thread
@@ -124,3 +114,10 @@ class SlackLogDevice
124
114
  end
125
115
 
126
116
  end
117
+
118
+ require 'slack_log_device/rails_exceptions_logging'
119
+ require 'slack_log_device/formatter'
120
+
121
+ if defined?(ActionDispatch::DebugExceptions)
122
+ ActionDispatch::DebugExceptions.prepend(SlackLogDevice::RailsExceptionsLogging)
123
+ end
@@ -0,0 +1,277 @@
1
+ require 'spec_helper'
2
+
3
+ describe SlackLogDevice::Formatter do
4
+
5
+ let(:max_message_length) { SlackLogDevice::Formatter::MAX_MESSAGE_LENGTH }
6
+
7
+ describe '::MAX_MESSAGE_LENGTH' do
8
+
9
+ it 'is 4000' do
10
+ expect(SlackLogDevice::Formatter::MAX_MESSAGE_LENGTH).to be(4000)
11
+ end
12
+
13
+ end
14
+
15
+ describe '#call' do
16
+
17
+ context "with no block or metadata" do
18
+
19
+ let(:formatter) { SlackLogDevice::Formatter.new }
20
+
21
+ it 'returns a formatted message' do
22
+ expect(formatter.call('DEBUG', Time.now, ' ', 'Hello World')).to eq('*`DEBUG`*: Hello World')
23
+ end
24
+
25
+ it 'message is stripped' do
26
+ expect(formatter.call('DEBUG', Time.now, ' ', " \nHello World ")).to eq('*`DEBUG`*: Hello World')
27
+ end
28
+
29
+ it 'message is converted to string' do
30
+ expect(formatter.call('DEBUG', Time.now, ' ', 42)).to eq('*`DEBUG`*: 42')
31
+ end
32
+
33
+ it 'includes progname if given' do
34
+ expect(formatter.call('DEBUG', Time.now, 'My App', 'Hello World')).to eq('*`DEBUG`* (*My App*): Hello World')
35
+ end
36
+
37
+ it 'formats exception' do
38
+ exception = RuntimeError.new('BAM!')
39
+ exception.set_backtrace(['foo', 'bar'])
40
+ expect(formatter.call('DEBUG', Time.now, nil, exception)).to eq("*`DEBUG`*: A `RuntimeError` occurred: BAM!\n\n```foo\nbar```")
41
+ end
42
+
43
+ it 'formats exception with no message' do
44
+ exception = RuntimeError.new(' ')
45
+ exception.set_backtrace(['foo', 'bar'])
46
+ expect(formatter.call('DEBUG', Time.now, nil, exception)).to eq("*`DEBUG`*: A `RuntimeError` occurred:\n\n```foo\nbar```")
47
+ end
48
+
49
+ it 'formats exception with no backtrace' do
50
+ exception = RuntimeError.new('BAM!')
51
+ expect(formatter.call('DEBUG', Time.now, nil, exception)).to eq("*`DEBUG`*: A `RuntimeError` occurred: BAM!")
52
+ end
53
+
54
+ it 'strips exception message' do
55
+ exception = RuntimeError.new(" BAM! \n")
56
+ expect(formatter.call('DEBUG', Time.now, nil, exception)).to eq("*`DEBUG`*: A `RuntimeError` occurred: BAM!")
57
+ end
58
+
59
+ it 'message never exceed 4000 chars (without exception)' do
60
+ message = formatter.call('DEBUG', Time.now, nil, 'Bam' * (max_message_length / 2))
61
+ expect(message.size).to eq(max_message_length)
62
+ expect(message).to end_with('BamBa...')
63
+ end
64
+
65
+ it 'message never exceed 4000 chars (with exception)' do
66
+ exception = RuntimeError.new('BAM!')
67
+ exception.set_backtrace(['a' * (max_message_length - 49)])
68
+ message = formatter.call('DEBUG', Time.now, nil, exception)
69
+ expect(message.size).to eq(max_message_length)
70
+ expect(message).to end_with("aaaaaa...```")
71
+ end
72
+
73
+ it 'can be exactly 4000 chars with trace (without three dots)' do
74
+ exception = RuntimeError.new('BAM!')
75
+ exception.set_backtrace(['a' * (max_message_length - 50)])
76
+ message = formatter.call('DEBUG', Time.now, nil, exception)
77
+ expect(message.size).to eq(max_message_length)
78
+ expect(message).to end_with('a```')
79
+ end
80
+
81
+ it 'does not add three dots if less than 4000' do
82
+ exception = RuntimeError.new('BAM!')
83
+ exception.set_backtrace(['a' * (max_message_length - 51)])
84
+ message = formatter.call('DEBUG', Time.now, nil, exception)
85
+ expect(message.size).to eq(max_message_length - 1)
86
+ expect(message).to end_with('a```')
87
+ end
88
+
89
+ it 'does not format backtrace if message is too long' do
90
+ exception = RuntimeError.new('BAM!' * max_message_length)
91
+ exception.set_backtrace(['hello world'])
92
+ message = formatter.call('DEBUG', Time.now, nil, exception)
93
+ expect(message.size).to eq(max_message_length)
94
+ expect(message).not_to include('hello')
95
+ expect(message).not_to include('```')
96
+ end
97
+
98
+ it 'message does not exceed 4000 if there is no backtrace' do
99
+ exception = RuntimeError.new('BAM!' * max_message_length)
100
+ message = formatter.call('DEBUG', Time.now, nil, exception)
101
+ expect(message.size).to eq(max_message_length)
102
+ end
103
+
104
+ it 'does not formats a blank backtrace (due to large message)' do
105
+ exception = RuntimeError.new('a' * (max_message_length - 46))
106
+ exception.set_backtrace(['hello world'])
107
+ message = formatter.call('DEBUG', Time.now, nil, exception)
108
+ expect(message.size).to eq(max_message_length - 8)
109
+ expect(message).not_to include('```')
110
+ expect(message).to end_with('a')
111
+ end
112
+
113
+ it 'can format a backtrace with just one char' do
114
+ exception = RuntimeError.new('a' * (max_message_length - 47))
115
+ exception.set_backtrace(['hello world'])
116
+ message = formatter.call('DEBUG', Time.now, nil, exception)
117
+ expect(message.size).to eq(max_message_length)
118
+ expect(message).to end_with("aaa\n\n```h```")
119
+ end
120
+
121
+ it 'can format a backtrace with just one char and three dots' do
122
+ exception = RuntimeError.new('a' * (max_message_length - 50))
123
+ exception.set_backtrace(['hello world'])
124
+ message = formatter.call('DEBUG', Time.now, nil, exception)
125
+ expect(message.size).to eq(max_message_length)
126
+ expect(message).to end_with("aaa\n\n```h...```")
127
+ end
128
+
129
+ end
130
+
131
+ context 'if a block is given' do
132
+
133
+ let(:formatter) { SlackLogDevice::Formatter.new { |message| "#{message.reverse} Hey hoy" } }
134
+
135
+ it 'returns formatter message with block invoked' do
136
+ expect(formatter.call('DEBUG', Time.now, ' ', 'Hello World')).to eq("*`DEBUG`*: dlroW olleH Hey hoy")
137
+ end
138
+
139
+ it 'invokes block with stripped message' do
140
+ expect(formatter.call('DEBUG', Time.now, ' ', " Hello World \t")).to eq("*`DEBUG`*: dlroW olleH Hey hoy")
141
+ end
142
+
143
+ it 'does not append block message if blank' do
144
+ formatter = SlackLogDevice.formatter { ' ' }
145
+ expect(formatter.call('DEBUG', Time.now, ' ', 'Hello World')).to eq('*`DEBUG`*:')
146
+ end
147
+
148
+ it 'converts block value to string' do
149
+ formatter = SlackLogDevice.formatter { 42 }
150
+ expect(formatter.call('DEBUG', Time.now, ' ', 'Hello World')).to eq('*`DEBUG`*: 42')
151
+ end
152
+
153
+ it 'is correct if block returns nil' do
154
+ formatter = SlackLogDevice.formatter { nil }
155
+ expect(formatter.call('DEBUG', Time.now, ' ', 'Hello World')).to eq('*`DEBUG`*:')
156
+ end
157
+
158
+ it 'strips block return value' do
159
+ formatter = SlackLogDevice.formatter { " hey \n" }
160
+ expect(formatter.call('DEBUG', Time.now, ' ', 'Hello World')).to eq('*`DEBUG`*: hey')
161
+ end
162
+
163
+ it 'includes progname if given' do
164
+ expect(formatter.call('DEBUG', Time.now, 'MyApp', 'Hello World')).to eq("*`DEBUG`* (*MyApp*): dlroW olleH Hey hoy")
165
+ end
166
+
167
+ it 'formats exception' do
168
+ exception = RuntimeError.new('BAM!')
169
+ exception.set_backtrace(['foo', 'bar'])
170
+ expect(formatter.call('DEBUG', Time.now, nil, exception)).to eq("*`DEBUG`*: A `RuntimeError` occurred: !MAB Hey hoy\n\n```foo\nbar```")
171
+ end
172
+
173
+ it 'is correct with exception if block returns a blank message' do
174
+ formatter = SlackLogDevice.formatter { ' ' }
175
+ exception = RuntimeError.new('BAM!')
176
+ exception.set_backtrace(['foo', 'bar'])
177
+ expect(formatter.call('DEBUG', Time.now, nil, exception)).to eq("*`DEBUG`*: A `RuntimeError` occurred:\n\n```foo\nbar```")
178
+ end
179
+
180
+ it 'message never exceed 4000 chars (without exception)' do
181
+ message = formatter.call('DEBUG', Time.now, ' ', 'Hello World' * (max_message_length / 3))
182
+ expect(message.size).to eq(max_message_length)
183
+ expect(message).to end_with('olleHdlro...')
184
+ end
185
+
186
+ it 'message never exceed 4000 chars (with exception)' do
187
+ exception = RuntimeError.new('BAM!')
188
+ exception.set_backtrace(['a' * max_message_length])
189
+ message = formatter.call('DEBUG', Time.now, 'My App', exception)
190
+ expect(message.size).to eq(max_message_length)
191
+ expect(message).to end_with("aaaaaa...```")
192
+ end
193
+
194
+ end
195
+
196
+ context 'with extra metadata' do
197
+
198
+ let(:extra_metadata) {{
199
+ 'User ' => " `#{user}` ",
200
+ ' Reversed user' => -> (options) { user.reverse },
201
+ }}
202
+ let(:formatter) { SlackLogDevice::Formatter.new(extra_metadata: extra_metadata) }
203
+ let(:user) { 'John' }
204
+
205
+ it 'returns a message formatted' do
206
+ expect(formatter.call('DEBUG', Time.now, ' ', 'Hello World')).to eq("*`DEBUG`*: Hello World\n\n• *User*: `John`\n• *Reversed user*: nhoJ")
207
+ end
208
+
209
+ it 'returns a message formatted (with exception)' do
210
+ exception = RuntimeError.new('BAM!')
211
+ exception.set_backtrace(['a', 'b'])
212
+ message = formatter.call('DEBUG', Time.now, 'My App', exception)
213
+ expect(message).to eq("*`DEBUG`* (*My App*): A `RuntimeError` occurred: BAM!\n\n• *User*: `John`\n• *Reversed user*: nhoJ\n\n```a\nb```")
214
+ end
215
+
216
+ it 'extra metadata are not added if message is too long' do
217
+ expect(formatter.call('DEBUG', Time.now, ' ', 'Hello World' * max_message_length)).not_to include('•')
218
+ end
219
+
220
+ it 'extra metadata are not added if message is too long (with exception)' do
221
+ exception = RuntimeError.new('BAM!' * max_message_length)
222
+ exception.set_backtrace(['a'])
223
+ message = formatter.call('DEBUG', Time.now, 'My App', exception)
224
+ expect(message).not_to include('•')
225
+ end
226
+
227
+ it 'blocks of extra metadata is invoked with options containing exception' do
228
+ extra_metadata['Exception class'] = -> (options) { options[:exception].class.name }
229
+ exception = RuntimeError.new('BAM!')
230
+ expect(formatter.call('DEBUG', Time.now, nil, exception)).to include('• *Exception class*: RuntimeError')
231
+ end
232
+
233
+ it 'blocks of extra metadata does not add exception option if not present' do
234
+ extra_metadata['Exception?'] = -> (options) { options.key?(:exception) ? 'Yes' : 'No' }
235
+ expect(formatter.call('DEBUG', Time.now, nil, 'Hello World')).to include("• *Exception?*: No")
236
+ end
237
+
238
+ end
239
+
240
+ context 'with an exception with @__slack_log_device_request set' do
241
+
242
+ let(:exception) { RuntimeError.new('BAM!').tap { |e| e.instance_variable_set(:@__slack_log_device_request, request) } }
243
+ let(:formatter) { SlackLogDevice::Formatter.new }
244
+ let(:request) { double(remote_addr: '127.0.0.1', user_agent: 'Mozilla', method: 'GET', url: 'http://google.com') }
245
+
246
+ it 'logs metadata' do
247
+ expect(formatter.call('DEBUG', Time.now, nil, exception)).to eq("*`DEBUG`*: A `RuntimeError` occurred: BAM!\n\n• *Method*: `GET`\n• *URL*: `http://google.com`\n• *Remote address*: `127.0.0.1`\n• *User-Agent*: `Mozilla`")
248
+ end
249
+
250
+ end
251
+
252
+ end
253
+
254
+ describe '#extra_metadata' do
255
+
256
+ it 'is an empty hash by default' do
257
+ expect(SlackLogDevice::Formatter.new.extra_metadata).to eq({})
258
+ end
259
+
260
+ it 'can be specified at constructor' do
261
+ formatter = SlackLogDevice::Formatter.new(extra_metadata: { 'Bar' => 'foo' })
262
+ expect(formatter.extra_metadata).to eq({ 'Bar' => 'foo' })
263
+ end
264
+
265
+ end
266
+
267
+ describe '#initialize' do
268
+
269
+ it 'raise an error if an invalid option is given' do
270
+ expect {
271
+ SlackLogDevice::Formatter.new(foo: 'bar')
272
+ }.to raise_error(ArgumentError, 'Unknown key: :foo. Valid keys are: :extra_metadata')
273
+ end
274
+
275
+ end
276
+
277
+ end
@@ -13,46 +13,20 @@ describe SlackLogDevice do
13
13
  expect(device).not_to be_a(Logger::LogDevice)
14
14
  end
15
15
 
16
- describe '::FORMATTER' do
16
+ describe '.formatter' do
17
17
 
18
- let(:formatter) { SlackLogDevice::FORMATTER }
19
-
20
- it 'returns a proc' do
21
- expect(formatter).to be_a(Proc)
18
+ it 'returns a SlackLogDevice::Formatter' do
19
+ expect(SlackLogDevice.formatter).to be_a(SlackLogDevice::Formatter)
22
20
  end
23
21
 
24
- describe '#call' do
25
-
26
- it 'returns a formatted message' do
27
- expect(formatter.call('DEBUG', Time.now, ' ', 'Hello World')).to eq('*`DEBUG`*: Hello World')
28
- end
29
-
30
- it 'includes progname if given' do
31
- expect(formatter.call('DEBUG', Time.now, 'My App', 'Hello World')).to eq('*`DEBUG`* (*My App*): Hello World')
32
- end
33
-
34
- it 'formats exception' do
35
- exception = RuntimeError.new('BAM!')
36
- exception.set_backtrace(['foo', 'bar'])
37
- expect(formatter.call('DEBUG', Time.now, nil, exception)).to eq("*`DEBUG`*: A `RuntimeError` occurred: BAM!\n\n```foo\nbar```")
38
- end
39
-
40
- it 'message with trace never exceed 4000 chars' do
41
- exception = RuntimeError.new('BAM!')
42
- exception.set_backtrace(['a' * 4500])
43
- message = formatter.call('DEBUG', Time.now, 'My App', exception)
44
- expect(message.size).to eq(4000)
45
- expect(message).to end_with("aaaaaa...```")
46
- end
47
-
48
- it 'can be exactly 4000 chars (without three dots)' do
49
- exception = RuntimeError.new('BAM!')
50
- exception.set_backtrace(['a' * 3950])
51
- message = formatter.call('DEBUG', Time.now, nil, exception)
52
- expect(message).to end_with('a```')
53
- expect(message.size).to eq(4000)
54
- end
22
+ it 'block is given to formatter constructor' do
23
+ formatter = SlackLogDevice.formatter { |message| message.reverse }
24
+ expect(formatter.call('DEBUG', Time.now, ' ', 'Hello World')).to eq("*`DEBUG`*: dlroW olleH")
25
+ end
55
26
 
27
+ it 'options are forwarded to formatter constructor' do
28
+ formatter = SlackLogDevice.formatter(extra_metadata: { 'bar' => 'foo' })
29
+ expect(formatter.extra_metadata).to eq({ 'bar' => 'foo' })
56
30
  end
57
31
 
58
32
  end
@@ -186,7 +160,7 @@ describe SlackLogDevice do
186
160
  device.write('BIM!')
187
161
  expect {
188
162
  device.flush
189
- }.to change { device.instance_variable_get(:@buffer) }.to([])
163
+ }.to change { device.instance_variable_get(:@buffer) }.to('')
190
164
  expect(HTTParty).not_to receive(:post)
191
165
  device.flush
192
166
  end
@@ -197,17 +171,17 @@ describe SlackLogDevice do
197
171
 
198
172
  it 'is true if max_buffer_size is reached' do
199
173
  options[:max_buffer_size] = 10
200
- device.write('012345678')
174
+ device.write('0123456789')
201
175
  expect {
202
- device.instance_variable_get(:@buffer).push('a')
176
+ device.instance_variable_get(:@buffer).send(:<<, 'a')
203
177
  }.to change { device.flush? }.from(false).to(true)
204
178
  end
205
179
 
206
180
  it 'use byte size to compare max_buffer_size' do
207
181
  options[:max_buffer_size] = 10
208
- device.write('0123456é')
182
+ device.write('01234567é')
209
183
  expect {
210
- device.instance_variable_get(:@buffer).push('a')
184
+ device.instance_variable_get(:@buffer).send(:<<, 'a')
211
185
  }.to change { device.flush? }.from(false).to(true)
212
186
  end
213
187
 
@@ -223,6 +197,12 @@ describe SlackLogDevice do
223
197
  }.to change { device.flush? }.from(false).to(true)
224
198
  end
225
199
 
200
+ it 'is true if it contains markdown code block' do
201
+ expect {
202
+ device.instance_variable_get(:@buffer).send(:<<, '```hello world```')
203
+ }.to change { device.flush? }.from(false).to(true)
204
+ end
205
+
226
206
  end
227
207
 
228
208
  describe '#flush_delay' do
@@ -486,12 +466,19 @@ describe SlackLogDevice do
486
466
 
487
467
  it 'strips message' do
488
468
  device.write(" BAM !\n")
489
- expect(device.instance_variable_get(:@buffer)).to eq(['BAM !'])
469
+ expect(device.instance_variable_get(:@buffer)).to eq('BAM !')
490
470
  end
491
471
 
492
472
  it 'converts message to string' do
493
473
  device.write(42)
494
- expect(device.instance_variable_get(:@buffer)).to eq(['42'])
474
+ expect(device.instance_variable_get(:@buffer)).to eq('42')
475
+ end
476
+
477
+ it 'adds given string to existing buffer with a \n' do
478
+ device.write('BAM!')
479
+ expect {
480
+ device.write('BIM!')
481
+ }.to change { device.instance_variable_get(:@buffer) }.from('BAM!').to("BAM!\nBIM!")
495
482
  end
496
483
 
497
484
  it 'does nothing if message is blank' do
@@ -504,7 +491,7 @@ describe SlackLogDevice do
504
491
  it 'does nothing if message is nil' do
505
492
  expect(HTTParty).not_to receive(:post)
506
493
  expect(device.write(nil)).to be_nil
507
- expect(device.instance_variable_get(:@buffer)).to eq([])
494
+ expect(device.instance_variable_get(:@buffer)).to eq('')
508
495
  end
509
496
 
510
497
  it 'does not post HTTP message if auto flush is false' do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: slack_log_device
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.3
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexis Toulotte
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-01-24 00:00:00.000000000 Z
11
+ date: 2017-01-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -124,7 +124,10 @@ files:
124
124
  - Rakefile
125
125
  - VERSION
126
126
  - lib/slack_log_device.rb
127
+ - lib/slack_log_device/formatter.rb
128
+ - lib/slack_log_device/rails_exceptions_logging.rb
127
129
  - slack_log_device.gemspec
130
+ - spec/slack_log_device/formatter_spec.rb
128
131
  - spec/slack_log_device_spec.rb
129
132
  - spec/spec_helper.rb
130
133
  homepage: https://github.com/alexistoulotte/slack_log_device
@@ -152,5 +155,6 @@ signing_key:
152
155
  specification_version: 4
153
156
  summary: LogDevice for Slack
154
157
  test_files:
158
+ - spec/slack_log_device/formatter_spec.rb
155
159
  - spec/slack_log_device_spec.rb
156
160
  - spec/spec_helper.rb