semantic_logger 4.3.1 → 4.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/semantic_logger.rb +7 -1
- data/lib/semantic_logger/appender.rb +3 -0
- data/lib/semantic_logger/appender/async.rb +29 -10
- data/lib/semantic_logger/appender/rabbitmq.rb +120 -0
- data/lib/semantic_logger/appenders.rb +89 -0
- data/lib/semantic_logger/base.rb +3 -3
- data/lib/semantic_logger/concerns/compatibility.rb +2 -2
- data/lib/semantic_logger/formatters.rb +1 -0
- data/lib/semantic_logger/formatters/base.rb +28 -6
- data/lib/semantic_logger/formatters/color.rb +4 -3
- data/lib/semantic_logger/formatters/fluentd.rb +37 -0
- data/lib/semantic_logger/formatters/json.rb +4 -2
- data/lib/semantic_logger/formatters/raw.rb +2 -2
- data/lib/semantic_logger/formatters/signalfx.rb +4 -3
- data/lib/semantic_logger/levels.rb +38 -0
- data/lib/semantic_logger/log.rb +11 -6
- data/lib/semantic_logger/loggable.rb +1 -1
- data/lib/semantic_logger/logger.rb +43 -1
- data/lib/semantic_logger/processor.rb +10 -130
- data/lib/semantic_logger/reporters/minitest.rb +49 -0
- data/lib/semantic_logger/semantic_logger.rb +40 -75
- data/lib/semantic_logger/version.rb +1 -1
- metadata +9 -81
- data/test/appender/async_batch_test.rb +0 -60
- data/test/appender/async_test.rb +0 -44
- data/test/appender/bugsnag_test.rb +0 -81
- data/test/appender/elasticsearch_http_test.rb +0 -74
- data/test/appender/elasticsearch_test.rb +0 -248
- data/test/appender/file_test.rb +0 -120
- data/test/appender/graylog_test.rb +0 -82
- data/test/appender/honeybadger_test.rb +0 -45
- data/test/appender/http_test.rb +0 -63
- data/test/appender/kafka_test.rb +0 -35
- data/test/appender/mongodb_test.rb +0 -104
- data/test/appender/new_relic_test.rb +0 -80
- data/test/appender/newrelic_rpm.rb +0 -14
- data/test/appender/sentry_test.rb +0 -47
- data/test/appender/splunk_http_test.rb +0 -79
- data/test/appender/splunk_test.rb +0 -83
- data/test/appender/syslog_test.rb +0 -61
- data/test/appender/tcp_test.rb +0 -66
- data/test/appender/udp_test.rb +0 -59
- data/test/appender/wrapper_test.rb +0 -95
- data/test/concerns/compatibility_test.rb +0 -117
- data/test/debug_as_trace_logger_test.rb +0 -81
- data/test/formatters/color_test.rb +0 -153
- data/test/formatters/default_test.rb +0 -175
- data/test/formatters/one_line_test.rb +0 -60
- data/test/formatters/signalfx_test.rb +0 -197
- data/test/formatters_test.rb +0 -36
- data/test/in_memory_appender.rb +0 -8
- data/test/in_memory_appender_helper.rb +0 -43
- data/test/in_memory_batch_appender.rb +0 -8
- data/test/in_memory_metrics_appender.rb +0 -13
- data/test/loggable_test.rb +0 -103
- data/test/logger_test.rb +0 -334
- data/test/measure_test.rb +0 -346
- data/test/metric/new_relic_test.rb +0 -35
- data/test/metric/signalfx_test.rb +0 -77
- data/test/semantic_logger_test.rb +0 -303
- data/test/test_helper.rb +0 -31
@@ -1,35 +0,0 @@
|
|
1
|
-
# So that the NewRelic appender will load the mock
|
2
|
-
$LOAD_PATH.unshift File.dirname(__FILE__)
|
3
|
-
require_relative '../test_helper'
|
4
|
-
|
5
|
-
# Unit Test for SemanticLogger::Appender::NewRelic
|
6
|
-
module Metric
|
7
|
-
class NewRelicTest < Minitest::Test
|
8
|
-
describe SemanticLogger::Appender::NewRelic do
|
9
|
-
before do
|
10
|
-
@appender = SemanticLogger::Metric::NewRelic.new
|
11
|
-
@message = 'AppenderNewRelicTest log message'
|
12
|
-
end
|
13
|
-
|
14
|
-
it 'logs counter metric' do
|
15
|
-
name = amount = nil
|
16
|
-
NewRelic::Agent.stub(:increment_metric, ->(name_, amount_) { name = name_, amount = amount_ }) do
|
17
|
-
@appender.info(message: @message, metric: 'User/authenticated')
|
18
|
-
end
|
19
|
-
assert_equal 'Custom/User/authenticated', name.first
|
20
|
-
assert_equal 1, amount
|
21
|
-
end
|
22
|
-
|
23
|
-
it 'logs duration metric' do
|
24
|
-
name = duration = nil
|
25
|
-
NewRelic::Agent.stub(:record_metric, ->(name_, duration_) { name = name_, duration = duration_ }) do
|
26
|
-
@appender.measure_info(message: @message, metric: 'User/authenticate') do
|
27
|
-
sleep 0.001
|
28
|
-
end
|
29
|
-
end
|
30
|
-
assert_equal 'Custom/User/authenticate', name.first
|
31
|
-
assert duration
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
@@ -1,77 +0,0 @@
|
|
1
|
-
require_relative '../test_helper'
|
2
|
-
|
3
|
-
module Appender
|
4
|
-
class SignalfxTest < Minitest::Test
|
5
|
-
describe SemanticLogger::Metric::Signalfx do
|
6
|
-
before do
|
7
|
-
@metric = '/user/login'
|
8
|
-
@log = SemanticLogger::Log.new('User', :debug)
|
9
|
-
@log.metric = @metric
|
10
|
-
end
|
11
|
-
|
12
|
-
let :appender do
|
13
|
-
if ENV['SIGNALFX_TOKEN']
|
14
|
-
SemanticLogger::Metric::Signalfx.new(token: ENV['SIGNALFX_TOKEN'])
|
15
|
-
else
|
16
|
-
Net::HTTP.stub_any_instance(:start, true) do
|
17
|
-
@appender = SemanticLogger::Metric::Signalfx.new(token: 'TEST')
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
describe 'log message' do
|
23
|
-
let :response do
|
24
|
-
# Do not stub if the token is available in the environment
|
25
|
-
if ENV['SIGNALFX_TOKEN']
|
26
|
-
appender.log(@log)
|
27
|
-
else
|
28
|
-
response_mock = Struct.new(:code, :body)
|
29
|
-
request = nil
|
30
|
-
appender.http.stub(:request, ->(r) { request = r; response_mock.new('200', 'ok') }) do
|
31
|
-
appender.log(@log)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
it 'send counter metric when there is no duration' do
|
37
|
-
assert response
|
38
|
-
end
|
39
|
-
|
40
|
-
it 'send custom counter metric when there is no duration' do
|
41
|
-
@log.metric = 'Filter/count'
|
42
|
-
@log.dimensions = {action: 'hit', user: 'jbloggs', state: 'FL'}
|
43
|
-
assert response
|
44
|
-
end
|
45
|
-
|
46
|
-
it 'send gauge metric when log includes duration' do
|
47
|
-
@log.duration = 1234
|
48
|
-
assert response
|
49
|
-
end
|
50
|
-
|
51
|
-
it 'whitelists dimensions' do
|
52
|
-
@log.named_tags = {user_id: 47, application: 'sample', tracking_number: 7474, session_id: 'hsdhngsd'}
|
53
|
-
appender.formatter.dimensions = %i[user_id application]
|
54
|
-
assert response
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
describe 'should_log?' do
|
59
|
-
it 'logs metric only metric' do
|
60
|
-
assert appender.should_log?(@log)
|
61
|
-
end
|
62
|
-
|
63
|
-
it 'not logs when no metric' do
|
64
|
-
@log.message = 'blah'
|
65
|
-
@log.metric = nil
|
66
|
-
refute appender.should_log?(@log)
|
67
|
-
end
|
68
|
-
|
69
|
-
it 'logs metric only metric with dimensions' do
|
70
|
-
@log.metric = 'Filter/count'
|
71
|
-
@log.dimensions = {action: 'hit', user: 'jbloggs', state: 'FL'}
|
72
|
-
assert appender.should_log?(@log)
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
@@ -1,303 +0,0 @@
|
|
1
|
-
require_relative 'test_helper'
|
2
|
-
|
3
|
-
class SemanticLoggerTest < Minitest::Test
|
4
|
-
describe SemanticLogger do
|
5
|
-
describe '.add_appender' do
|
6
|
-
before do
|
7
|
-
@appender = nil
|
8
|
-
end
|
9
|
-
|
10
|
-
after do
|
11
|
-
SemanticLogger.remove_appender(@appender)
|
12
|
-
File.delete('sample.log') if File.exist?('sample.log')
|
13
|
-
end
|
14
|
-
|
15
|
-
it 'adds file appender' do
|
16
|
-
@appender = SemanticLogger.add_appender(file_name: 'sample.log')
|
17
|
-
assert @appender.is_a?(SemanticLogger::Appender::File)
|
18
|
-
assert SemanticLogger.appenders.include?(@appender)
|
19
|
-
assert @appender.formatter.is_a?(SemanticLogger::Formatters::Default)
|
20
|
-
end
|
21
|
-
|
22
|
-
it 'adds file appender with json format' do
|
23
|
-
@appender = SemanticLogger.add_appender(file_name: 'sample.log', formatter: :json)
|
24
|
-
assert @appender.is_a?(SemanticLogger::Appender::File)
|
25
|
-
assert SemanticLogger.appenders.include?(@appender)
|
26
|
-
assert @appender.formatter.is_a?(SemanticLogger::Formatters::Json), @appender.formatter.inspect
|
27
|
-
end
|
28
|
-
|
29
|
-
it 'adds stream appender' do
|
30
|
-
@appender = SemanticLogger.add_appender(io: STDOUT)
|
31
|
-
assert @appender.is_a?(SemanticLogger::Appender::File)
|
32
|
-
assert SemanticLogger.appenders.include?(@appender)
|
33
|
-
end
|
34
|
-
|
35
|
-
it 'adds symbol appender' do
|
36
|
-
@appender = SemanticLogger.add_appender(appender: :wrapper, logger: Logger.new(STDOUT))
|
37
|
-
assert @appender.is_a?(SemanticLogger::Appender::Wrapper), -> { @appender.ai }
|
38
|
-
assert SemanticLogger.appenders.include?(@appender)
|
39
|
-
end
|
40
|
-
|
41
|
-
it 'adds symbol appender with underscores' do
|
42
|
-
@appender = SemanticLogger.add_appender(appender: :new_relic)
|
43
|
-
assert @appender.is_a?(SemanticLogger::Appender::NewRelic), -> { @appender.ai }
|
44
|
-
assert SemanticLogger.appenders.include?(@appender)
|
45
|
-
end
|
46
|
-
|
47
|
-
it 'adds logger wrapper appender' do
|
48
|
-
@appender = SemanticLogger.add_appender(logger: ::Logger.new(STDOUT))
|
49
|
-
assert @appender.is_a?(SemanticLogger::Appender::Wrapper)
|
50
|
-
assert @appender.logger.is_a?(::Logger)
|
51
|
-
assert SemanticLogger.appenders.include?(@appender)
|
52
|
-
assert @appender.formatter.is_a?(SemanticLogger::Formatters::Default)
|
53
|
-
end
|
54
|
-
|
55
|
-
it 'adds logger wrapper appender with color formatter' do
|
56
|
-
@appender = SemanticLogger.add_appender(logger: ::Logger.new(STDOUT), formatter: :color)
|
57
|
-
assert @appender.is_a?(SemanticLogger::Appender::Wrapper)
|
58
|
-
assert @appender.logger.is_a?(::Logger)
|
59
|
-
assert SemanticLogger.appenders.include?(@appender)
|
60
|
-
assert @appender.formatter.is_a?(SemanticLogger::Formatters::Color)
|
61
|
-
end
|
62
|
-
|
63
|
-
it 'adds appender' do
|
64
|
-
@appender = SemanticLogger.add_appender(appender: SemanticLogger::Appender::File.new(io: STDOUT))
|
65
|
-
assert @appender.is_a?(SemanticLogger::Appender::File), @appender.ai
|
66
|
-
assert SemanticLogger.appenders.include?(@appender)
|
67
|
-
end
|
68
|
-
|
69
|
-
it 'fails to add invalid logger appender' do
|
70
|
-
assert_raises do
|
71
|
-
SemanticLogger.add_appender(logger: 'blah')
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
describe '.add_appender DEPRECATED' do
|
77
|
-
before do
|
78
|
-
@appender = nil
|
79
|
-
end
|
80
|
-
|
81
|
-
after do
|
82
|
-
SemanticLogger.remove_appender(@appender) if @appender
|
83
|
-
File.delete('sample.log') if File.exist?('sample.log')
|
84
|
-
end
|
85
|
-
|
86
|
-
it 'adds file appender' do
|
87
|
-
@appender = SemanticLogger.add_appender('sample.log')
|
88
|
-
assert @appender.is_a?(SemanticLogger::Appender::File)
|
89
|
-
assert SemanticLogger.appenders.include?(@appender)
|
90
|
-
end
|
91
|
-
|
92
|
-
it 'adds stream appender' do
|
93
|
-
@appender = SemanticLogger.add_appender(STDOUT)
|
94
|
-
assert @appender.is_a?(SemanticLogger::Appender::File)
|
95
|
-
assert SemanticLogger.appenders.include?(@appender)
|
96
|
-
end
|
97
|
-
|
98
|
-
it 'adds appender' do
|
99
|
-
@appender = SemanticLogger.add_appender(SemanticLogger::Appender::File.new(io: STDOUT))
|
100
|
-
assert @appender.is_a?(SemanticLogger::Appender::File), @appender.ai
|
101
|
-
assert SemanticLogger.appenders.include?(@appender)
|
102
|
-
end
|
103
|
-
|
104
|
-
it 'adds logger wrapper appender' do
|
105
|
-
@appender = SemanticLogger.add_appender(::Logger.new(STDOUT))
|
106
|
-
assert @appender.is_a?(SemanticLogger::Appender::Wrapper)
|
107
|
-
assert @appender.logger.is_a?(::Logger)
|
108
|
-
assert SemanticLogger.appenders.include?(@appender)
|
109
|
-
end
|
110
|
-
|
111
|
-
it 'fails to add invalid logger appender' do
|
112
|
-
assert_raises do
|
113
|
-
SemanticLogger.add_appender(logger: 'blah')
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
describe 'mock_logger' do
|
119
|
-
include InMemoryAppenderHelper
|
120
|
-
|
121
|
-
describe '.tagged' do
|
122
|
-
it 'add tags to log entries' do
|
123
|
-
SemanticLogger.tagged('12345', 'DJHSFK') do
|
124
|
-
logger.info('Hello world')
|
125
|
-
|
126
|
-
assert log = log_message
|
127
|
-
assert_equal %w[12345 DJHSFK], log.tags
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
it 'add embedded tags to log entries' do
|
132
|
-
SemanticLogger.tagged('First Level', 'tags') do
|
133
|
-
SemanticLogger.tagged('Second Level') do
|
134
|
-
logger.info('Hello world')
|
135
|
-
|
136
|
-
assert log = log_message
|
137
|
-
assert_equal ['First Level', 'tags', 'Second Level'], log.tags
|
138
|
-
end
|
139
|
-
assert_equal 2, SemanticLogger.tags.count, SemanticLogger.tags
|
140
|
-
assert_equal 'First Level', SemanticLogger.tags.first
|
141
|
-
assert_equal 'tags', SemanticLogger.tags.last
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
it 'also supports named tagging' do
|
146
|
-
SemanticLogger.tagged(level1: 1) do
|
147
|
-
assert_equal({level1: 1}, SemanticLogger.named_tags)
|
148
|
-
SemanticLogger.tagged(level2: 2, more: 'data') do
|
149
|
-
assert_equal({level1: 1, level2: 2, more: 'data'}, SemanticLogger.named_tags)
|
150
|
-
SemanticLogger.tagged(level3: 3) do
|
151
|
-
assert_equal({level1: 1, level2: 2, more: 'data', level3: 3}, SemanticLogger.named_tags)
|
152
|
-
end
|
153
|
-
end
|
154
|
-
end
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
describe '.named_tags' do
|
159
|
-
it 'returns named tags in creation order' do
|
160
|
-
SemanticLogger.named_tagged(level1: 1) do
|
161
|
-
assert_equal({level1: 1}, SemanticLogger.named_tags)
|
162
|
-
SemanticLogger.named_tagged(level2: 2, more: 'data') do
|
163
|
-
assert_equal({level1: 1, level2: 2, more: 'data'}, SemanticLogger.named_tags)
|
164
|
-
SemanticLogger.named_tagged(level3: 3) do
|
165
|
-
assert_equal({level1: 1, level2: 2, more: 'data', level3: 3}, SemanticLogger.named_tags)
|
166
|
-
end
|
167
|
-
end
|
168
|
-
end
|
169
|
-
end
|
170
|
-
end
|
171
|
-
|
172
|
-
describe '.named_tagged' do
|
173
|
-
it 'logs named tags in creation order' do
|
174
|
-
SemanticLogger.named_tagged(level1: 1) do
|
175
|
-
SemanticLogger.named_tagged(level2: 2, more: 'data') do
|
176
|
-
SemanticLogger.named_tagged(level3: 3) do
|
177
|
-
logger.info('Hello world')
|
178
|
-
|
179
|
-
assert log = log_message
|
180
|
-
assert_equal({level1: 1, level2: 2, more: 'data', level3: 3}, log.named_tags)
|
181
|
-
end
|
182
|
-
end
|
183
|
-
end
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
describe '.fast_tag' do
|
188
|
-
it 'add string tag to log entries' do
|
189
|
-
logger.fast_tag('12345') do
|
190
|
-
logger.info('Hello world')
|
191
|
-
|
192
|
-
assert log = log_message
|
193
|
-
assert_equal %w[12345], log.tags
|
194
|
-
end
|
195
|
-
end
|
196
|
-
end
|
197
|
-
|
198
|
-
describe '.default_level' do
|
199
|
-
before do
|
200
|
-
SemanticLogger.default_level = :debug
|
201
|
-
end
|
202
|
-
|
203
|
-
it 'not log at a level below the global default' do
|
204
|
-
assert_equal :debug, SemanticLogger.default_level
|
205
|
-
assert_equal :debug, logger.level
|
206
|
-
logger.trace('hello world')
|
207
|
-
|
208
|
-
refute log_message
|
209
|
-
end
|
210
|
-
|
211
|
-
it 'log at the instance level' do
|
212
|
-
assert_equal :debug, SemanticLogger.default_level
|
213
|
-
logger.level = :trace
|
214
|
-
assert_equal :trace, logger.level
|
215
|
-
logger.trace('hello world')
|
216
|
-
|
217
|
-
assert log = log_message
|
218
|
-
assert_equal :trace, log.level
|
219
|
-
assert_equal 'hello world', log.message
|
220
|
-
end
|
221
|
-
|
222
|
-
it 'not log at a level below the instance level' do
|
223
|
-
assert_equal :debug, SemanticLogger.default_level
|
224
|
-
logger.level = :warn
|
225
|
-
assert_equal :warn, logger.level
|
226
|
-
logger.debug('hello world')
|
227
|
-
|
228
|
-
refute log_message
|
229
|
-
end
|
230
|
-
end
|
231
|
-
|
232
|
-
describe '.silence' do
|
233
|
-
before do
|
234
|
-
SemanticLogger.default_level = :info
|
235
|
-
end
|
236
|
-
|
237
|
-
it 'not log at a level below the silence level' do
|
238
|
-
assert_equal :info, SemanticLogger.default_level
|
239
|
-
assert_equal :info, logger.level
|
240
|
-
logger.silence do
|
241
|
-
logger.warn('hello world')
|
242
|
-
logger.info('hello world')
|
243
|
-
logger.debug('hello world')
|
244
|
-
logger.trace('hello world')
|
245
|
-
end
|
246
|
-
|
247
|
-
refute log_message
|
248
|
-
end
|
249
|
-
|
250
|
-
it 'log at the instance level even with the silencer at a higher level' do
|
251
|
-
logger.level = :trace
|
252
|
-
assert_equal :trace, logger.level
|
253
|
-
logger.silence do
|
254
|
-
logger.trace('hello world')
|
255
|
-
end
|
256
|
-
|
257
|
-
assert log = log_message
|
258
|
-
assert_equal :trace, log.level
|
259
|
-
assert_equal 'hello world', log.message
|
260
|
-
end
|
261
|
-
|
262
|
-
it 'log at a silence level below the default level' do
|
263
|
-
assert_equal :info, SemanticLogger.default_level
|
264
|
-
assert_equal :info, logger.level
|
265
|
-
logger.silence(:debug) do
|
266
|
-
logger.debug('hello world')
|
267
|
-
end
|
268
|
-
|
269
|
-
assert log = log_message
|
270
|
-
assert_equal :debug, log.level
|
271
|
-
assert_equal 'hello world', log.message
|
272
|
-
end
|
273
|
-
end
|
274
|
-
|
275
|
-
describe '.on_log' do
|
276
|
-
before do
|
277
|
-
SemanticLogger.default_level = :info
|
278
|
-
end
|
279
|
-
|
280
|
-
after do
|
281
|
-
SemanticLogger::Processor.instance.appender.log_subscribers = nil
|
282
|
-
end
|
283
|
-
|
284
|
-
it 'registers a log listener' do
|
285
|
-
SemanticLogger.on_log do |log|
|
286
|
-
log.set_context(:custom_info, 'test')
|
287
|
-
end
|
288
|
-
|
289
|
-
assert_equal :info, SemanticLogger.default_level
|
290
|
-
assert_equal :info, logger.level
|
291
|
-
logger.silence(:debug) do
|
292
|
-
logger.debug('hello world')
|
293
|
-
end
|
294
|
-
|
295
|
-
assert log = log_message
|
296
|
-
assert_equal :debug, log.level
|
297
|
-
assert_equal 'hello world', log.message
|
298
|
-
assert_equal 'test', log.context[:custom_info]
|
299
|
-
end
|
300
|
-
end
|
301
|
-
end
|
302
|
-
end
|
303
|
-
end
|
data/test/test_helper.rb
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
# Allow test to be run in-place without requiring a gem install
|
2
|
-
$LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
|
3
|
-
|
4
|
-
# Configure Rails Environment
|
5
|
-
ENV['RAILS_ENV'] = 'test'
|
6
|
-
|
7
|
-
require 'minitest/autorun'
|
8
|
-
require 'minitest/reporters'
|
9
|
-
require 'minitest/stub_any_instance'
|
10
|
-
require 'semantic_logger'
|
11
|
-
# require 'logger'
|
12
|
-
require_relative 'in_memory_appender'
|
13
|
-
require_relative 'in_memory_batch_appender'
|
14
|
-
require_relative 'in_memory_metrics_appender'
|
15
|
-
require_relative 'in_memory_appender_helper'
|
16
|
-
require 'awesome_print'
|
17
|
-
|
18
|
-
# Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new
|
19
|
-
class Minitest::Test
|
20
|
-
# Use AwesomePrint to display diffs
|
21
|
-
define_method :mu_pp, &:awesome_inspect
|
22
|
-
|
23
|
-
# Use AwesomePrint to display messages
|
24
|
-
def message(msg = nil, ending = nil)
|
25
|
-
proc {
|
26
|
-
msg = msg.call.chomp('.') if Proc === msg
|
27
|
-
custom_message = "#{msg.ai}.\n" unless msg.nil? || msg.to_s.empty?
|
28
|
-
"#{custom_message}#{yield}#{ending || '.'}"
|
29
|
-
}
|
30
|
-
end
|
31
|
-
end
|