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.
- checksums.yaml +4 -4
- data/.circleci/config.yml +2 -0
- data/.github/CODEOWNERS +1 -1
- data/.github/ISSUE_TEMPLATE/bug_report.md +27 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +25 -0
- data/.github/ISSUE_TEMPLATE/question-discussion.md +14 -0
- data/.github/ISSUE_TEMPLATE/security-vulnerability-report.md +22 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +20 -0
- data/.github/dependabot.yml +15 -0
- data/.github/workflows/add-to-project.yml +14 -0
- data/.github/workflows/apply-labels.yml +10 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +4 -2
- data/CHANGELOG.md +44 -1
- data/CODE_OF_CONDUCT.md +5 -0
- data/CONTRIBUTING.md +3 -0
- data/CONTRIBUTORS +1 -0
- data/OSSMETADATA +1 -0
- data/README.md +5 -1
- data/RELEASING.md +11 -0
- data/SECURITY.md +3 -0
- data/SUPPORT.md +3 -0
- data/lib/libhoney/client.rb +96 -31
- data/lib/libhoney/experimental_transmission.rb +107 -0
- data/lib/libhoney/mock_transmission.rb +1 -1
- data/lib/libhoney/null_transmission.rb +2 -0
- data/lib/libhoney/queueing/LICENSE.txt +23 -0
- data/lib/libhoney/queueing/sized_queue_with_timeout.rb +176 -0
- data/lib/libhoney/queueing.rb +1 -0
- data/lib/libhoney/response.rb +10 -2
- data/lib/libhoney/transmission.rb +129 -56
- data/lib/libhoney/version.rb +1 -1
- data/libhoney.gemspec +6 -3
- metadata +71 -11
@@ -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'
|
data/lib/libhoney/response.rb
CHANGED
@@ -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 =
|
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
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
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
|
-
|
139
|
-
|
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
|
-
|
142
|
-
|
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
|
-
|
145
|
-
|
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
|
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
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
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
|
-
|
234
|
-
|
235
|
-
|
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 =
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
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
|
data/lib/libhoney/version.rb
CHANGED
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 '
|
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
|
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 '
|
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.
|
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-
|
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: '
|
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: '
|
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
|
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
|
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: '
|
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: '
|
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.
|
316
|
+
rubygems_version: 3.1.6
|
257
317
|
signing_key:
|
258
318
|
specification_version: 4
|
259
319
|
summary: send data to Honeycomb
|