stripe 5.14.0 → 5.15.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +3 -0
- data/Gemfile +4 -1
- data/README.md +48 -29
- data/VERSION +1 -1
- data/lib/stripe/instrumentation.rb +44 -2
- data/lib/stripe/stripe_client.rb +43 -10
- data/lib/stripe/version.rb +1 -1
- data/test/stripe/instrumentation_test.rb +16 -3
- data/test/stripe/stripe_client_test.rb +51 -3
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1b0ca3c982da5bfe967d889047eeadbc2a2ba7ef6807dc860639a844f706cf15
|
4
|
+
data.tar.gz: 450bc197cbfd02398b3103aa89a5447f28bf2dd0f74608f3f54953e48e7ba4fd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 84c4915401aaf4a8e546763a17f44395df5ed284e36e721c6ba8d04612bbe4af9cc3d6bdeb235aba10abb82f5b001039f48ff0077e4d7477aed2f165a9f616a3
|
7
|
+
data.tar.gz: e4b3cacde2e92739ad543c2287cb06aa5041d2daa29780c83b3c670f97bdd395be7c537dc880cb452402575112b1498e10417244aada07653aec0fa52e551389
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 5.15.0 - 2020-02-10
|
4
|
+
* [#902](https://github.com/stripe/stripe-ruby/pull/902) Add `request_begin` instrumentation callback
|
5
|
+
|
3
6
|
## 5.14.0 - 2020-01-14
|
4
7
|
* [#896](https://github.com/stripe/stripe-ruby/pull/896) Add support for `CreditNoteLineItem`
|
5
8
|
* [#894](https://github.com/stripe/stripe-ruby/pull/894) Clean up test output by capturing `$stderr` when we expect warnings
|
data/Gemfile
CHANGED
@@ -11,7 +11,10 @@ group :development do
|
|
11
11
|
gem "rake"
|
12
12
|
gem "shoulda-context"
|
13
13
|
gem "test-unit"
|
14
|
-
|
14
|
+
|
15
|
+
# Version doesn't matter that much, but this one contains some fixes for Ruby
|
16
|
+
# 2.7 warnings that add noise to the test suite.
|
17
|
+
gem "webmock", ">= 3.8.0"
|
15
18
|
|
16
19
|
# Rubocop changes pretty quickly: new cops get added and old cops change
|
17
20
|
# names or go into new namespaces. This is a library and we don't have
|
data/README.md
CHANGED
@@ -14,8 +14,6 @@ The library also provides other features. For example:
|
|
14
14
|
|
15
15
|
- Easy configuration path for fast setup and use.
|
16
16
|
- Helpers for pagination.
|
17
|
-
- Tracking of "fresh" values in API resources so that partial updates can be
|
18
|
-
executed.
|
19
17
|
- Built-in mechanisms for the serialization of parameters according to the
|
20
18
|
expectations of Stripe's API.
|
21
19
|
|
@@ -65,13 +63,11 @@ value:
|
|
65
63
|
require "stripe"
|
66
64
|
Stripe.api_key = "sk_test_..."
|
67
65
|
|
68
|
-
# list
|
69
|
-
Stripe::
|
66
|
+
# list customers
|
67
|
+
Stripe::Customer.list()
|
70
68
|
|
71
|
-
# retrieve single
|
72
|
-
Stripe::
|
73
|
-
"ch_18atAXCdGbJFKhCuBAa4532Z",
|
74
|
-
)
|
69
|
+
# retrieve single customer
|
70
|
+
Stripe::Customer.retrieve("cus_123456789")
|
75
71
|
```
|
76
72
|
|
77
73
|
### Per-request Configuration
|
@@ -83,7 +79,7 @@ per-request key and/or account:
|
|
83
79
|
```ruby
|
84
80
|
require "stripe"
|
85
81
|
|
86
|
-
Stripe::
|
82
|
+
Stripe::Customer.list(
|
87
83
|
{},
|
88
84
|
{
|
89
85
|
api_key: "sk_test_...",
|
@@ -92,8 +88,8 @@ Stripe::Charge.list(
|
|
92
88
|
}
|
93
89
|
)
|
94
90
|
|
95
|
-
Stripe::
|
96
|
-
"
|
91
|
+
Stripe::Customer.retrieve(
|
92
|
+
"cus_123456789",
|
97
93
|
{
|
98
94
|
api_key: "sk_test_...",
|
99
95
|
stripe_account: "acct_...",
|
@@ -101,9 +97,9 @@ Stripe::Charge.retrieve(
|
|
101
97
|
}
|
102
98
|
)
|
103
99
|
|
104
|
-
Stripe::
|
100
|
+
Stripe::Customer.retrieve(
|
105
101
|
{
|
106
|
-
id: "
|
102
|
+
id: "cus_123456789",
|
107
103
|
expand: %w(balance_transaction)
|
108
104
|
},
|
109
105
|
{
|
@@ -112,8 +108,8 @@ Stripe::Charge.retrieve(
|
|
112
108
|
}
|
113
109
|
)
|
114
110
|
|
115
|
-
Stripe::
|
116
|
-
"
|
111
|
+
Stripe::Customer.capture(
|
112
|
+
"cus_123456789",
|
117
113
|
{},
|
118
114
|
{
|
119
115
|
stripe_version: "2018-02-28",
|
@@ -123,6 +119,7 @@ Stripe::Charge.capture(
|
|
123
119
|
```
|
124
120
|
|
125
121
|
Keep in mind that there are different method signatures depending on the action:
|
122
|
+
|
126
123
|
- When operating on a collection (e.g. `.list`, `.create`) the method signature is
|
127
124
|
`method(params, opts)`.
|
128
125
|
- When operating on resource (e.g. `.capture`, `.update`) the method signature is
|
@@ -138,10 +135,8 @@ method:
|
|
138
135
|
|
139
136
|
```ruby
|
140
137
|
client = Stripe::StripeClient.new
|
141
|
-
|
142
|
-
Stripe::
|
143
|
-
"ch_18atAXCdGbJFKhCuBAa4532Z",
|
144
|
-
)
|
138
|
+
customer, resp = client.request do
|
139
|
+
Stripe::Customer.retrieve("cus_123456789",)
|
145
140
|
end
|
146
141
|
puts resp.request_id
|
147
142
|
```
|
@@ -224,19 +219,43 @@ There are a few options for enabling it:
|
|
224
219
|
|
225
220
|
### Instrumentation
|
226
221
|
|
227
|
-
The library has
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
-
|
222
|
+
The library has various hooks that user code can tie into by passing a block to
|
223
|
+
`Stripe::Instrumentation.subscribe` to be notified about specific events.
|
224
|
+
|
225
|
+
#### `request_begin`
|
226
|
+
|
227
|
+
Invoked when an HTTP request starts. Receives `RequestBeginEvent` with the
|
228
|
+
following properties:
|
229
|
+
|
230
|
+
- `method`: HTTP method. (`Symbol`)
|
231
|
+
- `num_retries`: The number of retries. (`Integer`)
|
232
|
+
- `user_data`: A hash on which users can set arbitrary data, and which will be
|
233
|
+
passed through to `request_end` invocations. This could be used, for example,
|
234
|
+
to assign unique IDs to each request, and it'd work even if many requests are
|
235
|
+
running in parallel. All subscribers share the same object for any particular
|
236
|
+
request, so they must be careful to use unique keys that will not conflict
|
237
|
+
with other subscribers. (`Hash`)
|
238
|
+
|
239
|
+
#### `request_end`
|
240
|
+
|
241
|
+
Invoked when an HTTP request finishes, regardless of whether it terminated with
|
242
|
+
a success or error. Receives `RequestEndEvent` with the following properties:
|
243
|
+
|
244
|
+
- `duration`: Request duration in seconds. (`Float`)
|
245
|
+
- `http_status`: HTTP response code (`Integer`) if available, or `nil` in case
|
246
|
+
of a lower level network error.
|
247
|
+
- `method`: HTTP method. (`Symbol`)
|
248
|
+
- `num_retries`: The number of retries. (`Integer`)
|
249
|
+
- `path`: Request path. (`String`)
|
250
|
+
- `user_data`: A hash on which users may have set arbitrary data in
|
251
|
+
`request_begin`. See above for more information. (`Hash`)
|
252
|
+
|
253
|
+
#### Example
|
236
254
|
|
237
255
|
For example:
|
256
|
+
|
238
257
|
```ruby
|
239
|
-
Stripe::Instrumentation.subscribe(:
|
258
|
+
Stripe::Instrumentation.subscribe(:request_end) do |request_event|
|
240
259
|
tags = {
|
241
260
|
method: request_event.method,
|
242
261
|
resource: request_event.path.split("/")[2],
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
5.
|
1
|
+
5.15.0
|
@@ -2,23 +2,65 @@
|
|
2
2
|
|
3
3
|
module Stripe
|
4
4
|
class Instrumentation
|
5
|
-
|
5
|
+
# Event emitted on `request_begin` callback.
|
6
|
+
class RequestBeginEvent
|
7
|
+
attr_reader :method
|
8
|
+
attr_reader :path
|
9
|
+
|
10
|
+
# Arbitrary user-provided data in the form of a Ruby hash that's passed
|
11
|
+
# from subscribers on `request_begin` to subscribers on `request_end`.
|
12
|
+
# `request_begin` subscribers can set keys which will then be available
|
13
|
+
# in `request_end`.
|
14
|
+
#
|
15
|
+
# Note that all subscribers of `request_begin` share the same object, so
|
16
|
+
# they must be careful to set unique keys so as to not conflict with data
|
17
|
+
# set by other subscribers.
|
18
|
+
attr_reader :user_data
|
19
|
+
|
20
|
+
def initialize(method:, path:, user_data:)
|
21
|
+
@method = method
|
22
|
+
@path = path
|
23
|
+
@user_data = user_data
|
24
|
+
freeze
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Event emitted on `request_end` callback.
|
29
|
+
class RequestEndEvent
|
6
30
|
attr_reader :duration
|
7
31
|
attr_reader :http_status
|
8
32
|
attr_reader :method
|
9
33
|
attr_reader :num_retries
|
10
34
|
attr_reader :path
|
11
35
|
|
12
|
-
|
36
|
+
# Arbitrary user-provided data in the form of a Ruby hash that's passed
|
37
|
+
# from subscribers on `request_begin` to subscribers on `request_end`.
|
38
|
+
# `request_begin` subscribers can set keys which will then be available
|
39
|
+
# in `request_end`.
|
40
|
+
attr_reader :user_data
|
41
|
+
|
42
|
+
def initialize(duration:, http_status:, method:, num_retries:, path:,
|
43
|
+
user_data: nil)
|
13
44
|
@duration = duration
|
14
45
|
@http_status = http_status
|
15
46
|
@method = method
|
16
47
|
@num_retries = num_retries
|
17
48
|
@path = path
|
49
|
+
@user_data = user_data
|
18
50
|
freeze
|
19
51
|
end
|
20
52
|
end
|
21
53
|
|
54
|
+
# This class was renamed for consistency. This alias is here for backwards
|
55
|
+
# compatibility.
|
56
|
+
RequestEvent = RequestEndEvent
|
57
|
+
|
58
|
+
# Returns true if there are a non-zero number of subscribers on the given
|
59
|
+
# topic, and false otherwise.
|
60
|
+
def self.any_subscribers?(topic)
|
61
|
+
!subscribers[topic].empty?
|
62
|
+
end
|
63
|
+
|
22
64
|
def self.subscribe(topic, name = rand, &block)
|
23
65
|
subscribers[topic][name] = block
|
24
66
|
name
|
data/lib/stripe/stripe_client.rb
CHANGED
@@ -450,19 +450,26 @@ module Stripe
|
|
450
450
|
|
451
451
|
private def execute_request_with_rescues(method, api_base, context)
|
452
452
|
num_retries = 0
|
453
|
+
|
453
454
|
begin
|
454
|
-
request_start =
|
455
|
+
request_start = nil
|
456
|
+
user_data = nil
|
457
|
+
|
455
458
|
log_request(context, num_retries)
|
459
|
+
user_data = notify_request_begin(context)
|
460
|
+
|
461
|
+
request_start = Util.monotonic_time
|
456
462
|
resp = yield
|
457
463
|
request_duration = Util.monotonic_time - request_start
|
464
|
+
|
458
465
|
http_status = resp.code.to_i
|
459
466
|
context = context.dup_from_response_headers(resp)
|
460
467
|
|
461
468
|
handle_error_response(resp, context) if http_status >= 400
|
462
469
|
|
463
470
|
log_response(context, request_start, http_status, resp.body)
|
464
|
-
|
465
|
-
num_retries)
|
471
|
+
notify_request_end(context, request_duration, http_status,
|
472
|
+
num_retries, user_data)
|
466
473
|
|
467
474
|
if Stripe.enable_telemetry? && context.request_id
|
468
475
|
request_duration_ms = (request_duration * 1000).to_i
|
@@ -477,8 +484,8 @@ module Stripe
|
|
477
484
|
# If we modify context we copy it into a new variable so as not to
|
478
485
|
# taint the original on a retry.
|
479
486
|
error_context = context
|
480
|
-
request_duration = Util.monotonic_time - request_start
|
481
487
|
http_status = nil
|
488
|
+
request_duration = Util.monotonic_time - request_start if request_start
|
482
489
|
|
483
490
|
if e.is_a?(Stripe::StripeError)
|
484
491
|
error_context = context.dup_from_response_headers(e.http_headers)
|
@@ -488,7 +495,8 @@ module Stripe
|
|
488
495
|
else
|
489
496
|
log_response_error(error_context, request_start, e)
|
490
497
|
end
|
491
|
-
|
498
|
+
notify_request_end(context, request_duration, http_status, num_retries,
|
499
|
+
user_data)
|
492
500
|
|
493
501
|
if self.class.should_retry?(e, method: method, num_retries: num_retries)
|
494
502
|
num_retries += 1
|
@@ -512,15 +520,39 @@ module Stripe
|
|
512
520
|
resp
|
513
521
|
end
|
514
522
|
|
515
|
-
private def
|
516
|
-
|
523
|
+
private def notify_request_begin(context)
|
524
|
+
return unless Instrumentation.any_subscribers?(:request_begin)
|
525
|
+
|
526
|
+
event = Instrumentation::RequestBeginEvent.new(
|
527
|
+
method: context.method,
|
528
|
+
path: context.path,
|
529
|
+
user_data: {}
|
530
|
+
)
|
531
|
+
Stripe::Instrumentation.notify(:request_begin, event)
|
532
|
+
|
533
|
+
# This field may be set in the `request_begin` callback. If so, we'll
|
534
|
+
# forward it onto `request_end`.
|
535
|
+
event.user_data
|
536
|
+
end
|
537
|
+
|
538
|
+
private def notify_request_end(context, duration, http_status, num_retries,
|
539
|
+
user_data)
|
540
|
+
return if !Instrumentation.any_subscribers?(:request_end) &&
|
541
|
+
!Instrumentation.any_subscribers?(:request)
|
542
|
+
|
543
|
+
event = Instrumentation::RequestEndEvent.new(
|
517
544
|
duration: duration,
|
518
545
|
http_status: http_status,
|
519
546
|
method: context.method,
|
520
547
|
num_retries: num_retries,
|
521
|
-
path: context.path
|
548
|
+
path: context.path,
|
549
|
+
user_data: user_data || {}
|
522
550
|
)
|
523
|
-
Stripe::Instrumentation.notify(:
|
551
|
+
Stripe::Instrumentation.notify(:request_end, event)
|
552
|
+
|
553
|
+
# The name before `request_begin` was also added. Provided for backwards
|
554
|
+
# compatibility.
|
555
|
+
Stripe::Instrumentation.notify(:request, event)
|
524
556
|
end
|
525
557
|
|
526
558
|
private def general_api_error(status, body)
|
@@ -772,8 +804,9 @@ module Stripe
|
|
772
804
|
end
|
773
805
|
|
774
806
|
private def log_response_error(context, request_start, error)
|
807
|
+
elapsed = request_start ? Util.monotonic_time - request_start : nil
|
775
808
|
Util.log_error("Request error",
|
776
|
-
elapsed:
|
809
|
+
elapsed: elapsed,
|
777
810
|
error_message: error.message,
|
778
811
|
idempotency_key: context.idempotency_key,
|
779
812
|
method: context.method,
|
data/lib/stripe/version.rb
CHANGED
@@ -44,14 +44,27 @@ module Stripe
|
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
|
-
context "
|
47
|
+
context "RequestEventBegin" do
|
48
48
|
should "return a frozen object" do
|
49
|
-
event = Stripe::Instrumentation::
|
49
|
+
event = Stripe::Instrumentation::RequestBeginEvent.new(
|
50
|
+
method: :get,
|
51
|
+
path: "/v1/test",
|
52
|
+
user_data: nil
|
53
|
+
)
|
54
|
+
|
55
|
+
assert(event.frozen?)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context "RequestEventEnd" do
|
60
|
+
should "return a frozen object" do
|
61
|
+
event = Stripe::Instrumentation::RequestEndEvent.new(
|
50
62
|
duration: 0.1,
|
51
63
|
http_status: 200,
|
52
64
|
method: :get,
|
53
65
|
num_retries: 0,
|
54
|
-
path: "/v1/test"
|
66
|
+
path: "/v1/test",
|
67
|
+
user_data: nil
|
55
68
|
)
|
56
69
|
|
57
70
|
assert(event.frozen?)
|
@@ -1150,9 +1150,23 @@ module Stripe
|
|
1150
1150
|
Stripe::Instrumentation.unsubscribe(:request, :test)
|
1151
1151
|
end
|
1152
1152
|
|
1153
|
+
should "notify a subscribe on HTTP request start" do
|
1154
|
+
events = []
|
1155
|
+
Stripe::Instrumentation.subscribe(:request_end, :test) { |event| events << event }
|
1156
|
+
|
1157
|
+
stub_request(:get, "#{Stripe.api_base}/v1/charges")
|
1158
|
+
.to_return(body: JSON.generate(object: "charge"))
|
1159
|
+
Stripe::Charge.list
|
1160
|
+
|
1161
|
+
assert_equal(1, events.size)
|
1162
|
+
event = events.first
|
1163
|
+
assert_equal(:get, event.method)
|
1164
|
+
assert_equal("/v1/charges", event.path)
|
1165
|
+
end
|
1166
|
+
|
1153
1167
|
should "notify a subscriber of a successful HTTP request" do
|
1154
1168
|
events = []
|
1155
|
-
Stripe::Instrumentation.subscribe(:
|
1169
|
+
Stripe::Instrumentation.subscribe(:request_end, :test) { |event| events << event }
|
1156
1170
|
|
1157
1171
|
stub_request(:get, "#{Stripe.api_base}/v1/charges")
|
1158
1172
|
.to_return(body: JSON.generate(object: "charge"))
|
@@ -1169,7 +1183,7 @@ module Stripe
|
|
1169
1183
|
|
1170
1184
|
should "notify a subscriber of a StripeError" do
|
1171
1185
|
events = []
|
1172
|
-
Stripe::Instrumentation.subscribe(:
|
1186
|
+
Stripe::Instrumentation.subscribe(:request_end, :test) { |event| events << event }
|
1173
1187
|
|
1174
1188
|
error = {
|
1175
1189
|
code: "code",
|
@@ -1197,7 +1211,7 @@ module Stripe
|
|
1197
1211
|
|
1198
1212
|
should "notify a subscriber of a network error" do
|
1199
1213
|
events = []
|
1200
|
-
Stripe::Instrumentation.subscribe(:
|
1214
|
+
Stripe::Instrumentation.subscribe(:request_end, :test) { |event| events << event }
|
1201
1215
|
|
1202
1216
|
stub_request(:get, "#{Stripe.api_base}/v1/charges")
|
1203
1217
|
.to_raise(Net::OpenTimeout)
|
@@ -1213,6 +1227,40 @@ module Stripe
|
|
1213
1227
|
assert(event.duration.positive?)
|
1214
1228
|
assert_equal(0, event.num_retries)
|
1215
1229
|
end
|
1230
|
+
|
1231
|
+
should "pass `user_data` from `request_begin` to `request_end`" do
|
1232
|
+
actual_user_data = nil
|
1233
|
+
|
1234
|
+
Stripe::Instrumentation.subscribe(:request_begin) do |event|
|
1235
|
+
event.user_data[:foo] = :bar
|
1236
|
+
end
|
1237
|
+
Stripe::Instrumentation.subscribe(:request_end) do |event|
|
1238
|
+
actual_user_data = event.user_data
|
1239
|
+
end
|
1240
|
+
|
1241
|
+
stub_request(:get, "#{Stripe.api_base}/v1/charges")
|
1242
|
+
.to_return(body: JSON.generate(object: "charge"))
|
1243
|
+
Stripe::Charge.list
|
1244
|
+
|
1245
|
+
assert_equal({ foo: :bar }, actual_user_data)
|
1246
|
+
end
|
1247
|
+
|
1248
|
+
should "provide backward compatibility on `request` topic" do
|
1249
|
+
events = []
|
1250
|
+
Stripe::Instrumentation.subscribe(:request, :test) { |event| events << event }
|
1251
|
+
|
1252
|
+
stub_request(:get, "#{Stripe.api_base}/v1/charges")
|
1253
|
+
.to_return(body: JSON.generate(object: "charge"))
|
1254
|
+
Stripe::Charge.list
|
1255
|
+
|
1256
|
+
assert_equal(1, events.size)
|
1257
|
+
event = events.first
|
1258
|
+
assert_equal(:get, event.method)
|
1259
|
+
assert_equal("/v1/charges", event.path)
|
1260
|
+
assert_equal(200, event.http_status)
|
1261
|
+
assert(event.duration.positive?)
|
1262
|
+
assert_equal(0, event.num_retries)
|
1263
|
+
end
|
1216
1264
|
end
|
1217
1265
|
end
|
1218
1266
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stripe
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.15.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stripe
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-02-10 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Stripe is the easiest way to accept payments online. See https://stripe.com
|
14
14
|
for details.
|