diff --git a/Makefile b/Makefile index fa1d935d7..11ec33f6c 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ update-version: codegen-format: bundle install --quiet - bundle exec rubocop -o /dev/null --auto-correct + bundle exec rubocop -o /dev/null --autocorrect ci-test: bundle install && bundle exec rake test diff --git a/README.md b/README.md index d0a12ed5a..206d349ff 100644 --- a/README.md +++ b/README.md @@ -291,10 +291,11 @@ Stripe.set_app_info('MyAwesomePlugin', version: '1.2.34', url: 'https://myawesom This information is passed along when the library makes calls to the Stripe API. -### Request latency telemetry +### Telemetry -By default, the library sends request latency telemetry to Stripe. These -numbers help Stripe improve the overall latency of its API for all users. +By default, the library sends telemetry to Stripe regarding request latency and feature usage. These +numbers help Stripe improve the overall latency of its API for all users, and +improve popular features. You can disable this behavior if you prefer: diff --git a/lib/stripe/api_operations/request.rb b/lib/stripe/api_operations/request.rb index 6e559de2e..f3b897070 100644 --- a/lib/stripe/api_operations/request.rb +++ b/lib/stripe/api_operations/request.rb @@ -5,14 +5,14 @@ module APIOperations module Request module ClassMethods def execute_resource_request(method, url, - params = {}, opts = {}) + params = {}, opts = {}, usage = []) execute_resource_request_internal( - :execute_request, method, url, params, opts + :execute_request, method, url, params, opts, usage ) end def execute_resource_request_stream(method, url, - params = {}, opts = {}, + params = {}, opts = {}, usage = [], &read_body_chunk_block) execute_resource_request_internal( :execute_request_stream, @@ -20,18 +20,19 @@ def execute_resource_request_stream(method, url, url, params, opts, + usage, &read_body_chunk_block ) end - private def request_stripe_object(method:, path:, params:, opts: {}) - resp, opts = execute_resource_request(method, path, params, opts) + private def request_stripe_object(method:, path:, params:, opts: {}, usage: []) + resp, opts = execute_resource_request(method, path, params, opts, usage) Util.convert_to_stripe_object_with_params(resp.data, params, opts) end private def execute_resource_request_internal(client_request_method_sym, method, url, - params, opts, + params, opts, usage, &read_body_chunk_block) params ||= {} @@ -54,8 +55,7 @@ def execute_resource_request_stream(method, url, client_request_method_sym, method, url, api_base: api_base, api_key: api_key, - headers: headers, params: params, - api_mode: api_mode, + headers: headers, params: params, usage: usage, api_mode: api_mode, &read_body_chunk_block ) @@ -68,6 +68,7 @@ def execute_resource_request_stream(method, url, [resp, opts_to_persist] end + # TODO: (major) # This method used to be called `request`, but it's such a short name # that it eventually conflicted with the name of a field on an API # resource (specifically, `Event#request`), so it was renamed to @@ -113,9 +114,9 @@ def self.included(base) end protected def execute_resource_request(method, url, - params = {}, opts = {}) + params = {}, opts = {}, usage = []) opts = @opts.merge(Util.normalize_opts(opts)) - self.class.execute_resource_request(method, url, params, opts) + self.class.execute_resource_request(method, url, params, opts, usage) end protected def execute_resource_request_stream(method, url, @@ -127,8 +128,8 @@ def self.included(base) ) end - private def request_stripe_object(method:, path:, params:, opts: {}) - resp, opts = execute_resource_request(method, path, params, opts) + private def request_stripe_object(method:, path:, params:, opts: {}, usage: []) + resp, opts = execute_resource_request(method, path, params, opts, usage) Util.convert_to_stripe_object_with_params(resp.data, params, opts) end diff --git a/lib/stripe/api_operations/save.rb b/lib/stripe/api_operations/save.rb index af7d3ada9..8c8efadcf 100644 --- a/lib/stripe/api_operations/save.rb +++ b/lib/stripe/api_operations/save.rb @@ -66,7 +66,7 @@ def save(params = {}, opts = {}) # generated a uri for this object with an identifier baked in values.delete(:id) - resp, opts = execute_resource_request(:post, save_url, values, opts) + resp, opts = execute_resource_request(:post, save_url, values, opts, ["save"]) initialize_from(resp.data, opts) end extend Gem::Deprecate diff --git a/lib/stripe/stripe_client.rb b/lib/stripe/stripe_client.rb index ca7c2f007..b17638b39 100644 --- a/lib/stripe/stripe_client.rb +++ b/lib/stripe/stripe_client.rb @@ -210,9 +210,9 @@ def request def execute_request(method, path, api_base: nil, api_key: nil, - headers: {}, params: {}, api_mode: nil) + headers: {}, params: {}, api_mode: nil, usage: []) http_resp, api_key = execute_request_internal( - method, path, api_base, api_key, headers, params, api_mode + method, path, api_base, api_key, headers, params, api_mode, usage ) begin @@ -241,7 +241,7 @@ def execute_request(method, path, # passed, then a StripeStreamResponse is returned containing an IO stream # with the response body. def execute_request_stream(method, path, - api_base: nil, api_key: nil, + api_base: nil, api_key: nil, usage: [], headers: {}, params: {}, api_mode: nil, &read_body_chunk_block) @@ -252,7 +252,7 @@ def execute_request_stream(method, path, http_resp, api_key = execute_request_internal( method, path, api_base, api_key, - headers, params, api_mode, &read_body_chunk_block + headers, params, api_mode, usage, &read_body_chunk_block ) # When the read_body_chunk_block is given, we no longer have access to the @@ -432,7 +432,7 @@ def self.maybe_gc_connection_managers private def execute_request_internal(method, path, api_base, api_key, headers, params, - api_mode, &read_body_chunk_block) + api_mode, usage, &read_body_chunk_block) raise ArgumentError, "method should be a symbol" \ unless method.is_a?(Symbol) raise ArgumentError, "path should be a string" \ @@ -498,7 +498,7 @@ def self.maybe_gc_connection_managers end http_resp = - execute_request_with_rescues(method, api_base, headers, context) do + execute_request_with_rescues(method, api_base, headers, usage, context) do self.class .default_connection_manager(config) .execute_request(method, url, @@ -583,7 +583,7 @@ def self.maybe_gc_connection_managers http_status >= 400 end - private def execute_request_with_rescues(method, api_base, headers, context) + private def execute_request_with_rescues(method, api_base, headers, usage, context) num_retries = 0 begin @@ -609,7 +609,7 @@ def self.maybe_gc_connection_managers if config.enable_telemetry? && context.request_id request_duration_ms = (request_duration * 1000).to_i @last_request_metrics = - StripeRequestMetrics.new(context.request_id, request_duration_ms) + StripeRequestMetrics.new(context.request_id, request_duration_ms, usage: usage) end # We rescue all exceptions from a request so that we have an easy spot to @@ -1072,13 +1072,19 @@ class StripeRequestMetrics # Request duration in milliseconds attr_accessor :request_duration_ms - def initialize(request_id, request_duration_ms) + # list of names of tracked behaviors associated with this request + attr_accessor :usage + + def initialize(request_id, request_duration_ms, usage: []) self.request_id = request_id self.request_duration_ms = request_duration_ms + self.usage = usage end def payload - { request_id: request_id, request_duration_ms: request_duration_ms } + ret = { request_id: request_id, request_duration_ms: request_duration_ms } + ret[:usage] = usage if !usage.nil? && !usage.empty? + ret end end end diff --git a/test/stripe/stripe_client_test.rb b/test/stripe/stripe_client_test.rb index cb4004269..18f63f530 100644 --- a/test/stripe/stripe_client_test.rb +++ b/test/stripe/stripe_client_test.rb @@ -1457,14 +1457,24 @@ class StripeClientTest < Test::Unit::TestCase false end.to_return(body: JSON.generate(object: "charge")) - Stripe::Charge.list + cus = Stripe::Customer.new("cus_xyz") + cus.description = "hello" + cus.save Stripe::Charge.list assert(!trace_metrics_header.nil?) + trace_payload = JSON.parse(trace_metrics_header) + + assert(trace_payload["last_request_metrics"]["request_id"] == "req_123") + assert(!trace_payload["last_request_metrics"]["request_duration_ms"].nil?) + assert(trace_payload["last_request_metrics"]["usage"] == ["save"]) + + Stripe::Charge.list trace_payload = JSON.parse(trace_metrics_header) assert(trace_payload["last_request_metrics"]["request_id"] == "req_123") assert(!trace_payload["last_request_metrics"]["request_duration_ms"].nil?) + assert(trace_payload["last_request_metrics"]["usage"].nil?) end end