libhoney 1.17.0 → 1.21.0

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.
@@ -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