timber 2.0.20 → 2.0.21
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 +4 -4
- data/.travis.yml +1 -1
- data/lib/timber/config.rb +15 -1
- data/lib/timber/frameworks.rb +2 -2
- data/lib/timber/frameworks/rails.rb +8 -42
- data/lib/timber/integrations/active_record/log_subscriber/timber_log_subscriber.rb +3 -3
- data/lib/timber/integrator.rb +11 -0
- data/lib/timber/log_devices/http.rb +84 -40
- data/lib/timber/log_entry.rb +24 -0
- data/lib/timber/logger.rb +3 -2
- data/lib/timber/version.rb +1 -1
- data/spec/support/rails.rb +6 -1
- data/spec/support/timber.rb +1 -2
- data/spec/timber/log_devices/http_spec.rb +42 -21
- metadata +3 -4
- data/lib/timber/logger/metadata_methods.rb +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f65e44d5582af9d177dabd02f2229adda5ea094b
|
4
|
+
data.tar.gz: a113bb27776a6403b3b237b49d33c7fbac962758
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 10b371f99e2c4f4203526917a770140095581e17a12b72fba44dfc8db8b2151a198b5e771527fb715f6c9c4fe9e0d1c56772ff6663fb31c07f76bd95210339d4
|
7
|
+
data.tar.gz: e0b9fd2b91d7de66b4bee5305337afeb5017ec42fff2c76e8374c957af5d88445701aa029fca846f2f7e7778e4ffa7231989ea6c05d3814f307e244e5b2607d0
|
data/.travis.yml
CHANGED
data/lib/timber/config.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require "logger"
|
1
2
|
require "singleton"
|
2
3
|
|
3
4
|
module Timber
|
@@ -13,6 +14,13 @@ module Timber
|
|
13
14
|
class Config
|
14
15
|
class NoLoggerError < StandardError; end
|
15
16
|
|
17
|
+
class SimpleFormatter < ::Logger::Formatter
|
18
|
+
# This method is invoked when a log event occurs
|
19
|
+
def call(severity, timestamp, progname, msg)
|
20
|
+
"[Timber] #{String === msg ? msg : msg.inspect}\n"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
16
24
|
PRODUCTION_NAME = "production".freeze
|
17
25
|
STAGING_NAME = "staging".freeze
|
18
26
|
|
@@ -54,6 +62,7 @@ module Timber
|
|
54
62
|
file.binmode
|
55
63
|
file.sync = config.autoflush_log
|
56
64
|
file_logger = ::Logger.new(file)
|
65
|
+
file_logger.formatter = SimpleFormatter.new
|
57
66
|
self.debug_logger = file_logger
|
58
67
|
end
|
59
68
|
|
@@ -65,6 +74,7 @@ module Timber
|
|
65
74
|
# Timber::Config.instance.debug_to_file("log/timber.log")
|
66
75
|
def debug_to_stdout
|
67
76
|
stdout_logger = ::Logger.new(STDOUT)
|
77
|
+
stdout_logger.formatter = SimpleFormatter.new
|
68
78
|
self.debug_logger = stdout_logger
|
69
79
|
end
|
70
80
|
|
@@ -133,7 +143,11 @@ module Timber
|
|
133
143
|
# @example Everything else
|
134
144
|
# Timber::Config.instance.logger = Timber::Logger.new(STDOUT)
|
135
145
|
def logger
|
136
|
-
@logger
|
146
|
+
if @logger.is_a?(Proc)
|
147
|
+
@logger.call()
|
148
|
+
else
|
149
|
+
@logger ||= Logger.new(STDOUT)
|
150
|
+
end
|
137
151
|
end
|
138
152
|
|
139
153
|
private
|
data/lib/timber/frameworks.rb
CHANGED
@@ -3,12 +3,12 @@ require "logger"
|
|
3
3
|
# Attempt to require Rails. We can not list it as a gem
|
4
4
|
# dependency because we want to support multiple frameworks.
|
5
5
|
begin
|
6
|
-
require
|
6
|
+
require "rails"
|
7
7
|
rescue LoadError
|
8
8
|
end
|
9
9
|
|
10
10
|
if defined?(::Rails) && defined?(::Rails::Railtie)
|
11
|
-
require
|
11
|
+
require "timber/frameworks/rails"
|
12
12
|
end
|
13
13
|
|
14
14
|
module Timber
|
@@ -48,14 +48,17 @@ module Timber
|
|
48
48
|
class Railtie < ::Rails::Railtie
|
49
49
|
config.timber = Config.instance
|
50
50
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
logger = Rails.ensure_timber_logger(::Rails.logger)
|
55
|
-
Rails.set_logger(logger)
|
51
|
+
config.before_initialize do
|
52
|
+
Timber::Config.instance.logger = Proc.new { ::Rails.logger }
|
53
|
+
end
|
56
54
|
|
55
|
+
# Must be loaded after initializers so that we respect any Timber configuration
|
56
|
+
# set
|
57
|
+
initializer(:timber, after: :load_config_initializers) do
|
57
58
|
Integrations.integrate!
|
58
59
|
|
60
|
+
# Install the Rack middlewares so that we capture structured data instead of
|
61
|
+
# raw text logs.
|
59
62
|
timber_operations = Integrations::Rack.middlewares.collect do |middleware_class|
|
60
63
|
[:use, [middleware_class], nil]
|
61
64
|
end
|
@@ -63,43 +66,6 @@ module Timber
|
|
63
66
|
config.app_middleware.timber_operations = timber_operations
|
64
67
|
end
|
65
68
|
end
|
66
|
-
|
67
|
-
# This builds a new Timber::Logger from an existing logger. This allows us to transparentl
|
68
|
-
# switch users onto the Timber::Logger since we support a more useful logging API.
|
69
|
-
def self.ensure_timber_logger(existing_logger)
|
70
|
-
if existing_logger.is_a?(Logger)
|
71
|
-
return existing_logger
|
72
|
-
end
|
73
|
-
|
74
|
-
log_device = existing_logger.instance_variable_get(:@logdev).try(:dev)
|
75
|
-
logger = Logger.new(log_device)
|
76
|
-
logger.level = existing_logger.try(:level) || Logger::DEBUG
|
77
|
-
if defined?(::ActiveSupport::TaggedLogging)
|
78
|
-
logger = ::ActiveSupport::TaggedLogging.new(logger)
|
79
|
-
end
|
80
|
-
logger
|
81
|
-
end
|
82
|
-
|
83
|
-
# Sets the Rails logger. Rails
|
84
|
-
def self.set_logger(logger)
|
85
|
-
if defined?(::ActiveSupport::TaggedLogging) && !logger.is_a?(::ActiveSupport::TaggedLogging)
|
86
|
-
logger = ::ActiveSupport::TaggedLogging.new(logger)
|
87
|
-
end
|
88
|
-
|
89
|
-
Config.instance.logger = logger
|
90
|
-
|
91
|
-
# Set the various Rails framework loggers. We *have* to do this because Rails
|
92
|
-
# internally sets these with an ActiveSupport.onload(:active_record) { } callback.
|
93
|
-
# We don't have an opportunity to intercept this since the :initialize_logger
|
94
|
-
# initializer loads these modules. Moreover, earlier version of rails don't do this
|
95
|
-
# at all, hence the defined? checks. Yay for being implicit.
|
96
|
-
::ActionCable::Server::Base.logger = logger if defined?(::ActionCable::Server::Base) && ::ActionCable::Server::Base.respond_to?(:logger=)
|
97
|
-
::ActionController::Base.logger = logger if defined?(::ActionController::Base) && ::ActionController::Base.respond_to?(:logger=)
|
98
|
-
::ActionMailer::Base.logger = logger if defined?(::ActionMailer::Base) && ::ActionMailer::Base.respond_to?(:logger=)
|
99
|
-
::ActionView::Base.logger = logger if defined?(::ActionView::Base) && ::ActionView::Base.respond_to?(:logger=)
|
100
|
-
::ActiveRecord::Base.logger = logger if defined?(::ActiveRecord::Base) && ::ActiveRecord::Base.respond_to?(:logger=)
|
101
|
-
::Rails.logger = logger
|
102
|
-
end
|
103
69
|
end
|
104
70
|
end
|
105
71
|
end
|
@@ -1,6 +1,6 @@
|
|
1
|
-
# We require all of ActiveRecord because #logger
|
2
|
-
# We can't require active_record/base directly because ActiveRecord
|
3
|
-
# files properly.
|
1
|
+
# We require all of ActiveRecord because the #logger method in ::ActiveRecord::LogSubscriber
|
2
|
+
# uses ActiveRecord::Base. We can't require active_record/base directly because ActiveRecord
|
3
|
+
# does not require files properly and we receive unintialized constant errors.
|
4
4
|
require "active_record"
|
5
5
|
require "active_record/log_subscriber"
|
6
6
|
|
data/lib/timber/integrator.rb
CHANGED
@@ -6,7 +6,18 @@ module Timber
|
|
6
6
|
class RequirementNotMetError < StandardError; end
|
7
7
|
|
8
8
|
class << self
|
9
|
+
attr_writer :enabled
|
10
|
+
|
11
|
+
def enabled?
|
12
|
+
@enabled != false
|
13
|
+
end
|
14
|
+
|
9
15
|
def integrate!(*args)
|
16
|
+
if !enabled?
|
17
|
+
Config.instance.debug_logger.debug("#{name} integration disabled, skipping") if Config.instance.debug_logger
|
18
|
+
return false
|
19
|
+
end
|
20
|
+
|
10
21
|
new(*args).integrate!
|
11
22
|
Config.instance.debug_logger.debug("Integrated #{name}") if Config.instance.debug_logger
|
12
23
|
true
|
@@ -5,7 +5,8 @@ module Timber
|
|
5
5
|
module LogDevices
|
6
6
|
# A highly efficient log device that buffers and delivers log messages over HTTPS to
|
7
7
|
# the Timber API. It uses batches, keep-alive connections, and msgpack to deliver logs with
|
8
|
-
# high-throughput and little overhead.
|
8
|
+
# high-throughput and little overhead. All log preparation and delivery is done asynchronously
|
9
|
+
# in a thread as not to block application execution.
|
9
10
|
#
|
10
11
|
# See {#initialize} for options and more details.
|
11
12
|
class HTTP
|
@@ -118,6 +119,7 @@ module Timber
|
|
118
119
|
@requests_per_conn = options[:requests_per_conn] || 2_500
|
119
120
|
@msg_queue = LogMsgQueue.new(@batch_size)
|
120
121
|
@request_queue = options[:request_queue] || SizedQueue.new(3)
|
122
|
+
@successive_error_count = 0
|
121
123
|
@requests_in_flight = 0
|
122
124
|
end
|
123
125
|
|
@@ -133,7 +135,7 @@ module Timber
|
|
133
135
|
ensure_flush_threads_are_started
|
134
136
|
|
135
137
|
if @msg_queue.full?
|
136
|
-
debug_logger.debug("Flushing
|
138
|
+
debug_logger.debug("Flushing HTTP buffer via write") if debug_logger
|
137
139
|
flush
|
138
140
|
end
|
139
141
|
true
|
@@ -154,9 +156,26 @@ module Timber
|
|
154
156
|
|
155
157
|
# Closes the log device, cleans up, and attempts one last delivery.
|
156
158
|
def close
|
159
|
+
# Kill the flush thread immediately since we are about to flush again.
|
157
160
|
@flush_thread.kill if @flush_thread
|
158
|
-
|
161
|
+
|
162
|
+
# Flush all remaining messages
|
159
163
|
flush
|
164
|
+
|
165
|
+
# Kill the request_outlet thread gracefully. We do not want to kill it while a
|
166
|
+
# request is inflight. Ideally we'd let it finish before we die.
|
167
|
+
if @request_outlet_thread
|
168
|
+
4.times do
|
169
|
+
if @requests_in_flight == 0 && @request_queue.size == 0
|
170
|
+
@request_outlet_thread.kill
|
171
|
+
break
|
172
|
+
else
|
173
|
+
debug_logger.error("Busy delivering the final log messages, " +
|
174
|
+
"connection will close when complete.")
|
175
|
+
sleep 1
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
160
179
|
end
|
161
180
|
|
162
181
|
private
|
@@ -170,8 +189,8 @@ module Timber
|
|
170
189
|
# threads are started after process forking.
|
171
190
|
def ensure_flush_threads_are_started
|
172
191
|
if @flush_continuously
|
173
|
-
if @
|
174
|
-
@
|
192
|
+
if @request_outlet_thread.nil? || !@request_outlet_thread.alive?
|
193
|
+
@request_outlet_thread = Thread.new { request_outlet }
|
175
194
|
end
|
176
195
|
|
177
196
|
if @flush_thread.nil? || !@flush_thread.alive?
|
@@ -183,15 +202,17 @@ module Timber
|
|
183
202
|
def intervaled_flush
|
184
203
|
# Wait specified time period before starting
|
185
204
|
sleep @flush_interval
|
205
|
+
|
186
206
|
loop do
|
187
207
|
begin
|
188
208
|
if intervaled_flush_ready?
|
189
|
-
debug_logger.debug("Flushing
|
209
|
+
debug_logger.debug("Flushing HTTP buffer via the interval") if debug_logger
|
190
210
|
flush
|
191
211
|
end
|
192
|
-
|
212
|
+
|
213
|
+
sleep(0.5)
|
193
214
|
rescue Exception => e
|
194
|
-
logger.error("
|
215
|
+
logger.error("Intervaled HTTP flush failed: #{e.inspect}\n\n#{e.backtrace}")
|
195
216
|
end
|
196
217
|
end
|
197
218
|
end
|
@@ -200,50 +221,73 @@ module Timber
|
|
200
221
|
@last_flush.nil? || (Time.now.to_f - @last_flush.to_f).abs >= @flush_interval
|
201
222
|
end
|
202
223
|
|
203
|
-
def
|
224
|
+
def build_http
|
225
|
+
http = Net::HTTP.new(@timber_url.host, @timber_url.port)
|
226
|
+
http.set_debug_output(debug_logger) if debug_logger
|
227
|
+
http.use_ssl = true if @timber_url.scheme == 'https'
|
228
|
+
http.read_timeout = 30
|
229
|
+
http.ssl_timeout = 10
|
230
|
+
http.open_timeout = 10
|
231
|
+
http
|
232
|
+
end
|
233
|
+
|
234
|
+
def request_outlet
|
204
235
|
loop do
|
205
|
-
http =
|
206
|
-
http.set_debug_output(debug_logger) if debug_logger
|
207
|
-
http.use_ssl = true if @timber_url.scheme == 'https'
|
208
|
-
http.read_timeout = 30
|
209
|
-
http.ssl_timeout = 10
|
210
|
-
http.open_timeout = 10
|
236
|
+
http = build_http
|
211
237
|
|
212
238
|
begin
|
213
|
-
debug_logger.info("Starting
|
239
|
+
debug_logger.info("Starting HTTP connection") if debug_logger
|
240
|
+
|
214
241
|
http.start do |conn|
|
215
|
-
|
216
|
-
while num_reqs < @requests_per_conn
|
217
|
-
if debug_logger
|
218
|
-
debug_logger.debug("Waiting on next Timber request")
|
219
|
-
debug_logger.debug("Number of threads waiting on Timber request queue: #{@request_queue.num_waiting}")
|
220
|
-
end
|
221
|
-
|
222
|
-
# Blocks waiting for a request.
|
223
|
-
req = @request_queue.deq
|
224
|
-
@requests_in_flight += 1
|
225
|
-
resp = nil
|
226
|
-
begin
|
227
|
-
resp = conn.request(req)
|
228
|
-
rescue => e
|
229
|
-
debug_logger.error("Timber request error: #{e.message}") if debug_logger
|
230
|
-
next
|
231
|
-
ensure
|
232
|
-
@requests_in_flight -= 1
|
233
|
-
end
|
234
|
-
num_reqs += 1
|
235
|
-
debug_logger.debug("Timber request successful: #{resp.code}") if debug_logger
|
236
|
-
end
|
242
|
+
deliver_requests(conn)
|
237
243
|
end
|
238
244
|
rescue => e
|
239
|
-
debug_logger.error("
|
245
|
+
debug_logger.error("#request_outlet error: #{e.message}") if debug_logger
|
240
246
|
ensure
|
241
|
-
debug_logger.
|
247
|
+
debug_logger.info("Finishing HTTP connection") if debug_logger
|
242
248
|
http.finish if http.started?
|
243
249
|
end
|
244
250
|
end
|
245
251
|
end
|
246
252
|
|
253
|
+
def deliver_requests(conn)
|
254
|
+
num_reqs = 0
|
255
|
+
|
256
|
+
while num_reqs < @requests_per_conn
|
257
|
+
debug_logger.info("Waiting on next request, threads waiting: #{@request_queue.num_waiting}") if debug_logger
|
258
|
+
|
259
|
+
# Blocks waiting for a request.
|
260
|
+
req = @request_queue.deq
|
261
|
+
@requests_in_flight += 1
|
262
|
+
|
263
|
+
begin
|
264
|
+
resp = conn.request(req)
|
265
|
+
rescue => e
|
266
|
+
debug_logger.error("#deliver_request error: #{e.message}") if debug_logger
|
267
|
+
|
268
|
+
@successive_error_count += 1
|
269
|
+
|
270
|
+
# Back off so that we don't hammer the Timber API.
|
271
|
+
calculated_backoff = @successive_error_count * 2
|
272
|
+
backoff = calculated_backoff > 30 ? 30 : calculated_backoff
|
273
|
+
|
274
|
+
debug_logger.error("Backing off #{backoff} seconds, error ##{@successive_error_count}") if debug_logger
|
275
|
+
|
276
|
+
sleep backoff
|
277
|
+
|
278
|
+
# Throw the request back on the queue for a retry
|
279
|
+
@request_queue.enq(req)
|
280
|
+
return false
|
281
|
+
ensure
|
282
|
+
@requests_in_flight -= 1
|
283
|
+
end
|
284
|
+
|
285
|
+
@successive_error_count = 0
|
286
|
+
num_reqs += 1
|
287
|
+
debug_logger.info("Request successful: #{resp.code}") if debug_logger
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
247
291
|
def authorization_payload
|
248
292
|
@authorization_payload ||= "Basic #{Base64.urlsafe_encode64(@api_key).chomp}"
|
249
293
|
end
|
data/lib/timber/log_entry.rb
CHANGED
@@ -71,6 +71,10 @@ module Timber
|
|
71
71
|
Util::Hash.deep_compact(hash)
|
72
72
|
end
|
73
73
|
|
74
|
+
def inspect
|
75
|
+
to_s
|
76
|
+
end
|
77
|
+
|
74
78
|
def to_json(options = {})
|
75
79
|
as_json(options).to_json
|
76
80
|
end
|
@@ -79,6 +83,26 @@ module Timber
|
|
79
83
|
as_json.to_msgpack(*args)
|
80
84
|
end
|
81
85
|
|
86
|
+
# This is used when LogEntry objects make it to a non-Timber logger.
|
87
|
+
def to_s
|
88
|
+
log_message = message
|
89
|
+
|
90
|
+
if !event.nil?
|
91
|
+
event_hash = event.as_json
|
92
|
+
event_type = event_hash.keys.first
|
93
|
+
|
94
|
+
event_type = if event.is_a?(Events::Custom)
|
95
|
+
"event:#{event_type}.#{event.type}"
|
96
|
+
else
|
97
|
+
"event:#{event_type}"
|
98
|
+
end
|
99
|
+
|
100
|
+
log_message = "#{message} [#{event_type}]"
|
101
|
+
end
|
102
|
+
|
103
|
+
log_message + "\n"
|
104
|
+
end
|
105
|
+
|
82
106
|
private
|
83
107
|
def formatted_dt
|
84
108
|
@formatted_dt ||= time.iso8601(DT_PRECISION)
|
data/lib/timber/logger.rb
CHANGED
@@ -115,7 +115,8 @@ module Timber
|
|
115
115
|
|
116
116
|
# This method is invoked when a log event occurs
|
117
117
|
def call(severity, timestamp, progname, msg)
|
118
|
-
|
118
|
+
log_entry = build_log_entry(severity, timestamp, progname, msg)
|
119
|
+
log_entry.to_s
|
119
120
|
end
|
120
121
|
end
|
121
122
|
|
@@ -197,7 +198,7 @@ module Timber
|
|
197
198
|
|
198
199
|
self.level = environment_level
|
199
200
|
|
200
|
-
after_initialize if respond_to?
|
201
|
+
after_initialize if respond_to?(:after_initialize)
|
201
202
|
|
202
203
|
@initialized = true
|
203
204
|
end
|
data/lib/timber/version.rb
CHANGED
data/spec/support/rails.rb
CHANGED
@@ -46,7 +46,12 @@ if defined?(::Rails)
|
|
46
46
|
#
|
47
47
|
# You can see here that they use simple class attribute, hence the reason we need
|
48
48
|
# to update all of them: https://github.com/rails/rails/blob/700ec897f97c60016ad748236bf3a49ef15a20de/actionview/lib/action_view/base.rb#L157
|
49
|
-
|
49
|
+
::ActionCable::Server::Base.logger = logger if defined?(::ActionCable::Server::Base) && ::ActionCable::Server::Base.respond_to?(:logger=)
|
50
|
+
::ActionController::Base.logger = logger if defined?(::ActionController::Base) && ::ActionController::Base.respond_to?(:logger=)
|
51
|
+
::ActionMailer::Base.logger = logger if defined?(::ActionMailer::Base) && ::ActionMailer::Base.respond_to?(:logger=)
|
52
|
+
::ActionView::Base.logger = logger if defined?(::ActionView::Base) && ::ActionView::Base.respond_to?(:logger=)
|
53
|
+
::ActiveRecord::Base.logger = logger if defined?(::ActiveRecord::Base) && ::ActiveRecord::Base.respond_to?(:logger=)
|
54
|
+
::Rails.logger = logger
|
50
55
|
|
51
56
|
yield
|
52
57
|
|
data/spec/support/timber.rb
CHANGED
@@ -11,7 +11,7 @@ describe Timber::LogDevices::HTTP do
|
|
11
11
|
# Ensure that threads have not started
|
12
12
|
thread = http.instance_variable_get(:@flush_thread)
|
13
13
|
expect(thread).to be_nil
|
14
|
-
thread = http.instance_variable_get(:@
|
14
|
+
thread = http.instance_variable_get(:@request_outlet_thread)
|
15
15
|
expect(thread).to be_nil
|
16
16
|
end
|
17
17
|
end
|
@@ -23,6 +23,7 @@ describe Timber::LogDevices::HTTP do
|
|
23
23
|
it "should buffer the messages" do
|
24
24
|
http.write("test log message")
|
25
25
|
expect(msg_queue.flush).to eq(["test log message"])
|
26
|
+
http.close
|
26
27
|
end
|
27
28
|
|
28
29
|
it "should start the flush threads" do
|
@@ -30,8 +31,10 @@ describe Timber::LogDevices::HTTP do
|
|
30
31
|
|
31
32
|
thread = http.instance_variable_get(:@flush_thread)
|
32
33
|
expect(thread).to be_alive
|
33
|
-
thread = http.instance_variable_get(:@
|
34
|
+
thread = http.instance_variable_get(:@request_outlet_thread)
|
34
35
|
expect(thread).to be_alive
|
36
|
+
expect(http).to receive(:flush).exactly(1).times
|
37
|
+
http.close
|
35
38
|
end
|
36
39
|
|
37
40
|
context "with a low batch size" do
|
@@ -41,6 +44,8 @@ describe Timber::LogDevices::HTTP do
|
|
41
44
|
http.write("test")
|
42
45
|
expect(http).to receive(:flush).exactly(1).times
|
43
46
|
http.write("my log message")
|
47
|
+
expect(http).to receive(:flush).exactly(1).times
|
48
|
+
http.close
|
44
49
|
end
|
45
50
|
end
|
46
51
|
end
|
@@ -54,7 +59,7 @@ describe Timber::LogDevices::HTTP do
|
|
54
59
|
thread = http.instance_variable_get(:@flush_thread)
|
55
60
|
sleep 0.1 # too fast!
|
56
61
|
expect(thread).to_not be_alive
|
57
|
-
thread = http.instance_variable_get(:@
|
62
|
+
thread = http.instance_variable_get(:@request_outlet_thread)
|
58
63
|
sleep 0.1 # too fast!
|
59
64
|
expect(thread).to_not be_alive
|
60
65
|
end
|
@@ -86,13 +91,6 @@ describe Timber::LogDevices::HTTP do
|
|
86
91
|
message_queue = http.instance_variable_get(:@msg_queue)
|
87
92
|
expect(message_queue.size).to eq(0)
|
88
93
|
end
|
89
|
-
|
90
|
-
it "should preserve formatting for mshpack payloads" do
|
91
|
-
http = described_class.new("MYKEY", flush_continuously: false)
|
92
|
-
http.write("This is a log message 1".to_msgpack)
|
93
|
-
http.write("This is a log message 2".to_msgpack)
|
94
|
-
http.send(:flush)
|
95
|
-
end
|
96
94
|
end
|
97
95
|
|
98
96
|
# Testing a private method because it helps break down our tests
|
@@ -100,18 +98,17 @@ describe Timber::LogDevices::HTTP do
|
|
100
98
|
it "should start a intervaled flush thread and flush on an interval" do
|
101
99
|
http = described_class.new("MYKEY", flush_interval: 0.1)
|
102
100
|
http.send(:ensure_flush_threads_are_started)
|
103
|
-
expect(http).to receive(:flush).exactly(
|
104
|
-
sleep 0.
|
105
|
-
|
106
|
-
sleep 0.12 # too fast!
|
101
|
+
expect(http).to receive(:flush).exactly(2).times
|
102
|
+
sleep 0.15 # too fast!
|
103
|
+
http.close
|
107
104
|
end
|
108
105
|
end
|
109
106
|
|
110
107
|
# Outlet
|
111
|
-
describe "#
|
108
|
+
describe "#request_outlet" do
|
112
109
|
let(:time) { Time.utc(2016, 9, 1, 12, 0, 0) }
|
113
110
|
|
114
|
-
it "should
|
111
|
+
it "should deliver requests on an interval" do
|
115
112
|
stub = stub_request(:post, "https://logs.timber.io/frames").
|
116
113
|
with(
|
117
114
|
:body => start_with("\x92\x85\xA5level\xA4INFO\xA2dt\xBB2016-09-01T12:00:00.000000Z\xA7message\xB2test log message 1\xA7context\x81\xA6system".force_encoding("ASCII-8BIT")),
|
@@ -124,13 +121,37 @@ describe Timber::LogDevices::HTTP do
|
|
124
121
|
to_return(:status => 200, :body => "", :headers => {})
|
125
122
|
|
126
123
|
http = described_class.new("MYKEY", flush_interval: 0.1)
|
127
|
-
|
128
|
-
http.write(
|
129
|
-
|
130
|
-
http.write(
|
131
|
-
sleep
|
124
|
+
log_entry1 = Timber::LogEntry.new("INFO", time, nil, "test log message 1", nil, nil)
|
125
|
+
http.write(log_entry1)
|
126
|
+
log_entry2 = Timber::LogEntry.new("INFO", time, nil, "test log message 2", nil, nil)
|
127
|
+
http.write(log_entry2)
|
128
|
+
sleep 1
|
132
129
|
|
133
130
|
expect(stub).to have_been_requested.times(1)
|
131
|
+
|
132
|
+
http.close
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
describe "#deliver_requests" do
|
137
|
+
it "should handle exceptions properly and return" do
|
138
|
+
allow_any_instance_of(Net::HTTP).to receive(:request).and_raise("boom")
|
139
|
+
|
140
|
+
http_device = described_class.new("MYKEY", flush_continuously: false)
|
141
|
+
req_queue = http_device.instance_variable_get(:@request_queue)
|
142
|
+
|
143
|
+
# Place a request on the queue
|
144
|
+
req = Net::HTTP::Post.new("/")
|
145
|
+
req_queue.enq(req)
|
146
|
+
|
147
|
+
# Start a HTTP connection to test the method directly
|
148
|
+
http = http_device.send(:build_http)
|
149
|
+
http.start do |conn|
|
150
|
+
result = http_device.send(:deliver_requests, conn)
|
151
|
+
expect(result).to eq(false)
|
152
|
+
end
|
153
|
+
|
154
|
+
expect(req_queue.size).to eq(1)
|
134
155
|
end
|
135
156
|
end
|
136
157
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: timber
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.21
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Timber Technologies, Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-05-
|
11
|
+
date: 2017-05-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: msgpack
|
@@ -199,7 +199,6 @@ files:
|
|
199
199
|
- lib/timber/log_devices/http.rb
|
200
200
|
- lib/timber/log_entry.rb
|
201
201
|
- lib/timber/logger.rb
|
202
|
-
- lib/timber/logger/metadata_methods.rb
|
203
202
|
- lib/timber/overrides.rb
|
204
203
|
- lib/timber/overrides/lograge.rb
|
205
204
|
- lib/timber/overrides/rails_stdout_logging.rb
|
@@ -264,7 +263,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
264
263
|
version: '0'
|
265
264
|
requirements: []
|
266
265
|
rubyforge_project:
|
267
|
-
rubygems_version: 2.5.2
|
266
|
+
rubygems_version: 2.4.5.2
|
268
267
|
signing_key:
|
269
268
|
specification_version: 4
|
270
269
|
summary: Log Better. Solve Problems Faster. https://timber.io
|
@@ -1 +0,0 @@
|
|
1
|
-
metadata_methods.rb
|