libhoney 1.17.0 → 1.21.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,176 @@
1
+ ##
2
+ # SizedQueueWithTimeout is copyright and licensed per the LICENSE.txt in
3
+ # its containing subdirectory of this codebase.
4
+ #
5
+ module Libhoney
6
+ module Queueing
7
+ ##
8
+ # A queue implementation with optional size limit and optional timeouts on pop and push
9
+ # operations. Heavily influenced / liberally mimicking Avdi Grimm's
10
+ # {Tapas::Queue}[https://github.com/avdi/tapas-queue].
11
+ #
12
+ class SizedQueueWithTimeout
13
+ class PushTimedOut < ThreadError; end
14
+ class PopTimedOut < ThreadError; end
15
+
16
+ ##
17
+ # @param max_size [Integer, Float::INFINITY] the size limit for this queue
18
+ # @param options [Hash] optional dependencies to inject, primarily for testing
19
+ # @option options [QLock, Mutex] :lock the lock for synchronizing queue state change
20
+ # @option options [QCondition] :space_available_condition the condition variable
21
+ # to wait/signal on for space being available in the queue; when provided, must
22
+ # be accompanied by an +:item_available_condition+ and the shared +:lock+
23
+ # @option options [QCondition] :item_available_condition the condition variable
24
+ # to wait/signal on for an item being added to the queue; when provided, must
25
+ # be accompanied by an +:space_available_condition+ and the shared +:lock+
26
+ def initialize(max_size = Float::INFINITY, options = {})
27
+ @items = []
28
+ @max_size = max_size
29
+ @lock = options.fetch(:lock) { QLock.new }
30
+ @space_available = options.fetch(:space_available_condition) { QCondition.new(@lock) }
31
+ @item_available = options.fetch(:item_available_condition) { QCondition.new(@lock) }
32
+ end
33
+
34
+ ##
35
+ # Push something onto the queue.
36
+ #
37
+ # @param obj [Object] the thing to add to the queue
38
+ # @param timeout [Numeric, :never] how long in seconds to wait for the queue to have space available or
39
+ # +:never+ to wait "forever"
40
+ # @param timeout_policy [#call] defaults to +-> { raise PushTimedOut }+ - a lambda/Proc/callable, what to do
41
+ # when the timeout expires
42
+ #
43
+ # @raise {PushTimedOut}
44
+ def push(obj, timeout = :never, &timeout_policy)
45
+ timeout_policy ||= -> { raise PushTimedOut }
46
+
47
+ wait_for_condition(@space_available, -> { !full? }, timeout, timeout_policy) do
48
+ @items.push(obj)
49
+ @item_available.signal
50
+ end
51
+ end
52
+ alias enq push
53
+ alias << push
54
+
55
+ ##
56
+ # Pop something off the queue.
57
+ #
58
+ # @param timeout [Numeric, :never] how long in seconds to wait for the queue to have an item available or
59
+ # +:never+ to wait "forever"
60
+ # @param timeout_policy [#call] defaults to +-> { raise PopTimedOut }+ - a lambda/Proc/callable, what to do
61
+ # when the timeout expires
62
+ #
63
+ # @return [Object]
64
+ # @raise {PopTimedOut}
65
+ def pop(timeout = :never, &timeout_policy)
66
+ timeout_policy ||= -> { raise PopTimedOut }
67
+
68
+ wait_for_condition(@item_available, -> { !empty? }, timeout, timeout_policy) do
69
+ item = @items.shift
70
+ @space_available.signal unless full?
71
+ item
72
+ end
73
+ end
74
+ alias deq pop
75
+ alias shift pop
76
+
77
+ ##
78
+ # Removes all objects from the queue. They are cast into the abyss never to be seen again.
79
+ #
80
+ def clear
81
+ @lock.synchronize do
82
+ @items = []
83
+ @space_available.signal unless full?
84
+ end
85
+ end
86
+
87
+ private
88
+
89
+ ##
90
+ # Whether the queue is at capacity. Must be called with the queue's lock
91
+ # or the answer won't matter if you try to change state based on it.
92
+ #
93
+ # @return [true/false]
94
+ # @api private
95
+ def full?
96
+ @max_size <= @items.size
97
+ end
98
+
99
+ ##
100
+ # Whether the queue is empty. Must be called with the queue's lock or the
101
+ # answer won't matter if you try to change state based on it.
102
+ #
103
+ # @return [true/false]
104
+ # @api private
105
+ def empty?
106
+ @items.empty?
107
+ end
108
+
109
+ # a generic conditional variable wait with a timeout loop
110
+ #
111
+ # @param condition [#wait] a condition variable to wait upon.
112
+ # @param condition_predicate [#call] a callable (i.e. lambda or proc) that returns true/false to act
113
+ # as a state tester (i.e. "is the queue currently empty?") to check on whether to keep waiting;
114
+ # used to handle spurious wake ups occurring before the timeout has elapsed
115
+ # @param timeout [:never, Numeric] the amount of time in (seconds?) to wait, or :never to wait forever
116
+ # @param timeout_policy [#call] a callable, what to do when a timeout occurs? Return a default? Raise an
117
+ # exception? You decide.
118
+ def wait_for_condition(condition, condition_predicate, timeout = :never, timeout_policy = -> { nil })
119
+ deadline = timeout == :never ? :never : trustworthy_current_time + timeout
120
+ @lock.synchronize do
121
+ loop do
122
+ time_remaining = timeout == :never ? nil : deadline - trustworthy_current_time
123
+
124
+ if !condition_predicate.call && time_remaining.to_f >= 0 # rubocop:disable Style/IfUnlessModifier
125
+ condition.wait(time_remaining)
126
+ end
127
+
128
+ if condition_predicate.call # rubocop:disable Style/GuardClause
129
+ return yield
130
+ elsif deadline == :never || deadline > trustworthy_current_time
131
+ next
132
+ else
133
+ return timeout_policy.call
134
+ end
135
+ end
136
+ end
137
+ end
138
+
139
+ # Within the context of the current process, return time from a
140
+ # monotonically increasing clock because for timeouts we care about
141
+ # elapsed time within the process, not human time.
142
+ #
143
+ # @return [Numeric]
144
+ def trustworthy_current_time
145
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
146
+ end
147
+ end
148
+
149
+ class QCondition
150
+ def initialize(lock)
151
+ @lock = lock
152
+ @cv = ConditionVariable.new
153
+ end
154
+
155
+ def wait(timeout = nil)
156
+ @cv.wait(@lock.mutex, timeout)
157
+ end
158
+
159
+ def signal
160
+ @cv.signal
161
+ end
162
+ end
163
+
164
+ class QLock
165
+ attr_reader :mutex
166
+
167
+ def initialize
168
+ @mutex = Mutex.new
169
+ end
170
+
171
+ def synchronize(&block)
172
+ @mutex.synchronize(&block)
173
+ end
174
+ end
175
+ end
176
+ end
@@ -0,0 +1 @@
1
+ require 'libhoney/queueing/sized_queue_with_timeout'
@@ -1,7 +1,15 @@
1
- require 'http'
1
+ require 'http/response/status'
2
2
 
3
3
  module Libhoney
4
4
  class Response
5
+ # The response status from HTTP calls to a Honeycomb API endpoint.
6
+ #
7
+ # For most of the life of this client, this response object has been
8
+ # a pass-through to the underlying HTTP library's response object.
9
+ # This class in the Libhoney namespace now owns the interface for
10
+ # API responses.
11
+ class Status < HTTP::Response::Status; end
12
+
5
13
  attr_accessor :duration, :status_code, :metadata, :error
6
14
 
7
15
  def initialize(duration: 0,
@@ -9,7 +17,7 @@ module Libhoney
9
17
  metadata: nil,
10
18
  error: nil)
11
19
  @duration = duration
12
- @status_code = HTTP::Response::Status.new(status_code)
20
+ @status_code = Status.new(status_code)
13
21
  @metadata = metadata
14
22
  @error = error
15
23
  end
@@ -1,3 +1,5 @@
1
+ require 'addressable/uri'
2
+ require 'excon'
1
3
  require 'json'
2
4
  require 'timeout'
3
5
  require 'libhoney/response'
@@ -34,9 +36,9 @@ module Libhoney
34
36
  @send_queue = Queue.new
35
37
  @threads = []
36
38
  @lock = Mutex.new
37
- # use a SizedQueue so the producer will block on adding to the batch_queue when @block_on_send is true
38
- @batch_queue = SizedQueue.new(@pending_work_capacity)
39
39
  @batch_thread = nil
40
+
41
+ setup_batch_queue
40
42
  end
41
43
 
42
44
  def add(event)
@@ -51,26 +53,6 @@ module Libhoney
51
53
  ensure_threads_running
52
54
  end
53
55
 
54
- def event_valid(event)
55
- invalid = []
56
- invalid.push('api host') if event.api_host.nil? || event.api_host.empty?
57
- invalid.push('write key') if event.writekey.nil? || event.writekey.empty?
58
- invalid.push('dataset') if event.dataset.nil? || event.dataset.empty?
59
-
60
- unless invalid.empty?
61
- e = StandardError.new("#{self.class.name}: nil or empty required fields (#{invalid.join(', ')})"\
62
- '. Will not attempt to send.')
63
- Response.new(error: e).tap do |error_response|
64
- error_response.metadata = event.metadata
65
- enqueue_response(error_response)
66
- end
67
-
68
- return false
69
- end
70
-
71
- true
72
- end
73
-
74
56
  def send_loop
75
57
  http_clients = build_http_clients
76
58
 
@@ -93,7 +75,7 @@ module Libhoney
93
75
  }
94
76
 
95
77
  response = http.post(
96
- "/1/batch/#{Addressable::URI.escape(dataset)}",
78
+ path: "/1/batch/#{Addressable::URI.escape(dataset)}",
97
79
  body: body,
98
80
  headers: headers
99
81
  )
@@ -103,6 +85,8 @@ module Libhoney
103
85
  # because this is effectively the top-level exception handler for the
104
86
  # sender threads, and we don't want those threads to die (leaving
105
87
  # nothing consuming the queue).
88
+ warn "#{self.class.name}: 💥 " + e.message if %w[debug trace].include?(ENV['LOG_LEVEL'])
89
+ warn e.backtrace.join("\n").to_s if ['trace'].include?(ENV['LOG_LEVEL'])
106
90
  begin
107
91
  batch.each do |event|
108
92
  # nil events in the batch should already have had an error
@@ -129,23 +113,31 @@ module Libhoney
129
113
  end
130
114
 
131
115
  def close(drain)
132
- # if drain is false, clear the remaining unprocessed events from the queue
133
- unless drain
134
- @batch_queue.clear
135
- @send_queue.clear
136
- end
116
+ @lock.synchronize do
117
+ # if drain is false, clear the remaining unprocessed events from the queue
118
+ if drain
119
+ warn "#{self.class.name} - close: draining events" if %w[debug trace].include?(ENV['LOG_LEVEL'])
120
+ else
121
+ warn "#{self.class.name} - close: deleting unsent events" if %w[debug trace].include?(ENV['LOG_LEVEL'])
122
+ @batch_queue.clear
123
+ @send_queue.clear
124
+ end
137
125
 
138
- @batch_queue.enq(nil)
139
- @batch_thread.join unless @batch_thread.nil?
126
+ @batch_queue.enq(nil)
127
+ if @batch_thread.nil?
128
+ else
129
+ @batch_thread.join(1.0) # limit the amount of time we'll wait for the thread to end
130
+ end
140
131
 
141
- # send @threads.length number of nils so each thread will fall out of send_loop
142
- @threads.length.times { @send_queue << nil }
132
+ # send @threads.length number of nils so each thread will fall out of send_loop
133
+ @threads.length.times { @send_queue << nil }
143
134
 
144
- @threads.each(&:join)
145
- @threads = []
135
+ @threads.each(&:join)
136
+ @threads = []
137
+ end
146
138
 
147
139
  enqueue_response(nil)
148
-
140
+ warn "#{self.class.name} - close: close complete" if %w[debug trace].include?(ENV['LOG_LEVEL'])
149
141
  0
150
142
  end
151
143
 
@@ -157,25 +149,79 @@ module Libhoney
157
149
 
158
150
  loop do
159
151
  begin
152
+ # a timeout expiration waiting for an event
153
+ # 1. interrupts only when thread is in a blocking state (waiting for pop)
154
+ # 2. exception skips the break and is rescued
155
+ # 3. triggers the ensure to flush the current batch
156
+ # 3. begins the loop again with an updated next_send_time
160
157
  Thread.handle_interrupt(Timeout::Error => :on_blocking) do
158
+ # an event on the batch_queue
159
+ # 1. pops out and is truthy
160
+ # 2. gets included in the current batch
161
+ # 3. while waits for another event
161
162
  while (event = Timeout.timeout(@send_frequency) { @batch_queue.pop })
162
163
  key = [event.api_host, event.writekey, event.dataset]
163
164
  batched_events[key] << event
164
165
  end
165
166
  end
166
167
 
168
+ # a nil on the batch_queue
169
+ # 1. pops out and is falsy
170
+ # 2. ends the event-popping while do..end
171
+ # 3. breaks the loop
172
+ # 4. flushes the current batch
173
+ # 5. ends the batch_loop
167
174
  break
168
- rescue Exception
175
+ rescue Timeout::Error
176
+ # Timeout::Error happens when there is nothing to pop from the batch_queue.
177
+ # We rescue it here to avoid spamming the logs with "execution expired" errors.
178
+ rescue Exception => e
179
+ warn "#{self.class.name}: 💥 " + e.message if %w[debug trace].include?(ENV['LOG_LEVEL'])
180
+ warn e.backtrace.join("\n").to_s if ['trace'].include?(ENV['LOG_LEVEL'])
181
+
182
+ # regardless of the exception, figure out whether enough time has passed to
183
+ # send the current batched events, if so, send them and figure out the next send time
184
+ # before going back to the top of the loop
169
185
  ensure
170
186
  next_send_time = flush_batched_events(batched_events) if Time.now > next_send_time
171
187
  end
172
188
  end
173
189
 
190
+ # don't need to capture the next_send_time here because the batch_loop is exiting
191
+ # for some reason (probably transmission.close)
174
192
  flush_batched_events(batched_events)
175
193
  end
176
194
 
177
195
  private
178
196
 
197
+ def setup_batch_queue
198
+ # use a SizedQueue so the producer will block on adding to the batch_queue when @block_on_send is true
199
+ @batch_queue = SizedQueue.new(@pending_work_capacity)
200
+ end
201
+
202
+ REQUIRED_EVENT_FIELDS = %i[api_host writekey dataset].freeze
203
+
204
+ def event_valid(event)
205
+ missing_required_fields = REQUIRED_EVENT_FIELDS.select do |required_field|
206
+ event.public_send(required_field).nil? || event.public_send(required_field).empty?
207
+ end
208
+
209
+ if missing_required_fields.empty?
210
+ true
211
+ else
212
+ enqueue_response(
213
+ Response.new(
214
+ metadata: event.metadata,
215
+ error: StandardError.new(
216
+ "#{self.class.name}: nil or empty required fields (#{missing_required_fields.join(', ')})"\
217
+ '. Will not attempt to send.'
218
+ )
219
+ )
220
+ )
221
+ false
222
+ end
223
+ end
224
+
179
225
  ##
180
226
  # Enqueues a response to the responses queue suppressing ThreadError when
181
227
  # there is no space left on the queue and we are not blocking on response
@@ -186,15 +232,36 @@ module Libhoney
186
232
  end
187
233
 
188
234
  def process_response(http_response, before, batch)
189
- index = 0
190
- http_response.parse.each do |event|
191
- index += 1 while batch[index].nil? && index < batch.size
192
- break unless (batched_event = batch[index])
193
-
194
- Response.new(status_code: event['status']).tap do |response|
195
- response.duration = Time.now - before
196
- response.metadata = batched_event.metadata
197
- enqueue_response(response)
235
+ if http_response.status == 200
236
+ index = 0
237
+ JSON.parse(http_response.body).each do |event|
238
+ index += 1 while batch[index].nil? && index < batch.size
239
+ break unless (batched_event = batch[index])
240
+
241
+ enqueue_response(
242
+ Response.new(
243
+ status_code: event['status'],
244
+ duration: (Time.now - before),
245
+ metadata: batched_event.metadata
246
+ )
247
+ )
248
+ end
249
+ else
250
+ error = JSON.parse(http_response.body)['error']
251
+ if %w[debug trace].include?(ENV['LOG_LEVEL'])
252
+ warn "#{self.class.name}: error sending data to Honeycomb - #{http_response.status} #{error}"
253
+ end
254
+ batch.each do |batched_event|
255
+ next unless batched_event # skip nils enqueued from serialization errors
256
+
257
+ enqueue_response(
258
+ Response.new(
259
+ status_code: http_response.status, # single error from API applied to all events sent in batch
260
+ duration: (Time.now - before),
261
+ metadata: batched_event.metadata,
262
+ error: RuntimeError.new(error)
263
+ )
264
+ )
198
265
  end
199
266
  end
200
267
  end
@@ -230,9 +297,10 @@ module Libhoney
230
297
  end
231
298
 
232
299
  def build_user_agent(user_agent_addition)
233
- ua = "libhoney-rb/#{VERSION}"
234
- ua << " #{user_agent_addition}" if user_agent_addition
235
- ua
300
+ "libhoney-rb/#{VERSION}"
301
+ .concat(" #{user_agent_addition}")
302
+ .strip # remove trailing spaces if addition was empty
303
+ .concat(" Ruby/#{RUBY_VERSION} (#{RUBY_PLATFORM})")
236
304
  end
237
305
 
238
306
  def ensure_threads_running
@@ -256,14 +324,19 @@ module Libhoney
256
324
 
257
325
  def build_http_clients
258
326
  Hash.new do |h, api_host|
259
- client = HTTP.timeout(connect: @send_timeout, write: @send_timeout, read: @send_timeout)
260
- .persistent(api_host)
261
- .headers(
262
- 'User-Agent' => @user_agent,
263
- 'Content-Type' => 'application/json'
264
- )
265
-
266
- client = client.via(*@proxy_config) unless @proxy_config.nil?
327
+ client = ::Excon.new(
328
+ api_host,
329
+ persistent: true,
330
+ read_timeout: @send_timeout,
331
+ write_timeout: @send_timeout,
332
+ connect_timeout: @send_timeout,
333
+ proxy: @proxy_config,
334
+ headers: {
335
+ 'User-Agent' => @user_agent,
336
+ 'Content-Type' => 'application/json'
337
+ }
338
+ )
339
+
267
340
  h[api_host] = client
268
341
  end
269
342
  end
@@ -1,3 +1,3 @@
1
1
  module Libhoney
2
- VERSION = '1.17.0'.freeze
2
+ VERSION = '1.21.0'.freeze
3
3
  end
data/libhoney.gemspec CHANGED
@@ -24,15 +24,18 @@ Gem::Specification.new do |spec|
24
24
 
25
25
  spec.add_development_dependency 'bump', '~> 0.5'
26
26
  spec.add_development_dependency 'bundler'
27
+ spec.add_development_dependency 'lockstep'
27
28
  spec.add_development_dependency 'minitest', '~> 5.0'
28
- spec.add_development_dependency 'rake', '~> 12.3'
29
+ spec.add_development_dependency 'minitest-reporters'
30
+ spec.add_development_dependency 'rake', '~> 13.0'
29
31
  spec.add_development_dependency 'rubocop', '< 0.69'
30
32
  spec.add_development_dependency 'sinatra'
31
33
  spec.add_development_dependency 'sinatra-contrib'
32
- spec.add_development_dependency 'spy', '1.0.0'
34
+ spec.add_development_dependency 'spy', '~> 1.0'
33
35
  spec.add_development_dependency 'webmock', '~> 3.4'
34
36
  spec.add_development_dependency 'yard'
35
37
  spec.add_development_dependency 'yardstick', '~> 0.9'
36
38
  spec.add_dependency 'addressable', '~> 2.0'
37
- spec.add_dependency 'http', '>= 2.0', '< 5.0'
39
+ spec.add_dependency 'excon'
40
+ spec.add_dependency 'http', '>= 2.0', '< 6.0'
38
41
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: libhoney
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.17.0
4
+ version: 1.21.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - The Honeycomb.io Team
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-01-04 00:00:00.000000000 Z
11
+ date: 2021-09-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bump
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: lockstep
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: minitest
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -52,20 +66,34 @@ dependencies:
52
66
  - - "~>"
53
67
  - !ruby/object:Gem::Version
54
68
  version: '5.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: minitest-reporters
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
55
83
  - !ruby/object:Gem::Dependency
56
84
  name: rake
57
85
  requirement: !ruby/object:Gem::Requirement
58
86
  requirements:
59
87
  - - "~>"
60
88
  - !ruby/object:Gem::Version
61
- version: '12.3'
89
+ version: '13.0'
62
90
  type: :development
63
91
  prerelease: false
64
92
  version_requirements: !ruby/object:Gem::Requirement
65
93
  requirements:
66
94
  - - "~>"
67
95
  - !ruby/object:Gem::Version
68
- version: '12.3'
96
+ version: '13.0'
69
97
  - !ruby/object:Gem::Dependency
70
98
  name: rubocop
71
99
  requirement: !ruby/object:Gem::Requirement
@@ -112,16 +140,16 @@ dependencies:
112
140
  name: spy
113
141
  requirement: !ruby/object:Gem::Requirement
114
142
  requirements:
115
- - - '='
143
+ - - "~>"
116
144
  - !ruby/object:Gem::Version
117
- version: 1.0.0
145
+ version: '1.0'
118
146
  type: :development
119
147
  prerelease: false
120
148
  version_requirements: !ruby/object:Gem::Requirement
121
149
  requirements:
122
- - - '='
150
+ - - "~>"
123
151
  - !ruby/object:Gem::Version
124
- version: 1.0.0
152
+ version: '1.0'
125
153
  - !ruby/object:Gem::Dependency
126
154
  name: webmock
127
155
  requirement: !ruby/object:Gem::Requirement
@@ -178,6 +206,20 @@ dependencies:
178
206
  - - "~>"
179
207
  - !ruby/object:Gem::Version
180
208
  version: '2.0'
209
+ - !ruby/object:Gem::Dependency
210
+ name: excon
211
+ requirement: !ruby/object:Gem::Requirement
212
+ requirements:
213
+ - - ">="
214
+ - !ruby/object:Gem::Version
215
+ version: '0'
216
+ type: :runtime
217
+ prerelease: false
218
+ version_requirements: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - ">="
221
+ - !ruby/object:Gem::Version
222
+ version: '0'
181
223
  - !ruby/object:Gem::Dependency
182
224
  name: http
183
225
  requirement: !ruby/object:Gem::Requirement
@@ -187,7 +229,7 @@ dependencies:
187
229
  version: '2.0'
188
230
  - - "<"
189
231
  - !ruby/object:Gem::Version
190
- version: '5.0'
232
+ version: '6.0'
191
233
  type: :runtime
192
234
  prerelease: false
193
235
  version_requirements: !ruby/object:Gem::Requirement
@@ -197,7 +239,7 @@ dependencies:
197
239
  version: '2.0'
198
240
  - - "<"
199
241
  - !ruby/object:Gem::Version
200
- version: '5.0'
242
+ version: '6.0'
201
243
  description: Ruby gem for sending data to Honeycomb
202
244
  email: support@honeycomb.io
203
245
  executables: []
@@ -208,27 +250,45 @@ files:
208
250
  - ".circleci/setup-rubygems.sh"
209
251
  - ".editorconfig"
210
252
  - ".github/CODEOWNERS"
253
+ - ".github/ISSUE_TEMPLATE/bug_report.md"
254
+ - ".github/ISSUE_TEMPLATE/feature_request.md"
255
+ - ".github/ISSUE_TEMPLATE/question-discussion.md"
256
+ - ".github/ISSUE_TEMPLATE/security-vulnerability-report.md"
257
+ - ".github/PULL_REQUEST_TEMPLATE.md"
258
+ - ".github/dependabot.yml"
259
+ - ".github/workflows/add-to-project.yml"
260
+ - ".github/workflows/apply-labels.yml"
211
261
  - ".gitignore"
212
262
  - ".rubocop.yml"
213
263
  - ".rubocop_todo.yml"
214
264
  - CHANGELOG.md
265
+ - CODE_OF_CONDUCT.md
266
+ - CONTRIBUTING.md
215
267
  - CONTRIBUTORS
216
268
  - Gemfile
217
269
  - LICENSE
218
270
  - NOTICE
271
+ - OSSMETADATA
219
272
  - README.md
273
+ - RELEASING.md
220
274
  - Rakefile
275
+ - SECURITY.md
276
+ - SUPPORT.md
221
277
  - example/factorial.rb
222
278
  - lib/libhoney.rb
223
279
  - lib/libhoney/builder.rb
224
280
  - lib/libhoney/cleaner.rb
225
281
  - lib/libhoney/client.rb
226
282
  - lib/libhoney/event.rb
283
+ - lib/libhoney/experimental_transmission.rb
227
284
  - lib/libhoney/log_client.rb
228
285
  - lib/libhoney/log_transmission.rb
229
286
  - lib/libhoney/mock_transmission.rb
230
287
  - lib/libhoney/null_client.rb
231
288
  - lib/libhoney/null_transmission.rb
289
+ - lib/libhoney/queueing.rb
290
+ - lib/libhoney/queueing/LICENSE.txt
291
+ - lib/libhoney/queueing/sized_queue_with_timeout.rb
232
292
  - lib/libhoney/response.rb
233
293
  - lib/libhoney/test_client.rb
234
294
  - lib/libhoney/transmission.rb
@@ -253,7 +313,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
253
313
  - !ruby/object:Gem::Version
254
314
  version: '0'
255
315
  requirements: []
256
- rubygems_version: 3.1.4
316
+ rubygems_version: 3.1.6
257
317
  signing_key:
258
318
  specification_version: 4
259
319
  summary: send data to Honeycomb