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