Adding metadata header to client requests

This commit is contained in:
Anton Kropp 2018-10-26 11:14:40 -07:00
parent e2f4fa23d0
commit ab248ec691
No known key found for this signature in database
GPG Key ID: 845CE87B9069A920
5 changed files with 83 additions and 2 deletions

1
.gitignore vendored
View File

@ -5,3 +5,4 @@ Gemfile.lock
tags
/.bundle/
coverage/
.idea/

View File

@ -18,7 +18,7 @@ Metrics/BlockLength:
# Offense count: 8
# Configuration parameters: CountComments.
Metrics/ClassLength:
Max: 626
Max: 659
# Offense count: 11
Metrics/CyclomaticComplexity:

View File

@ -124,6 +124,8 @@ module Stripe
@open_timeout = 30
@read_timeout = 80
@enable_telemetry = false
class << self
attr_accessor :stripe_account, :api_key, :api_base, :verify_ssl_certs, :api_version, :client_id, :connect_base, :uploads_base,
:open_timeout, :read_timeout
@ -225,6 +227,14 @@ module Stripe
@max_network_retries = val.to_i
end
def self.enable_telemetry?
@enable_telemetry
end
def self.enable_telemetry=(val)
@enable_telemetry = val
end
# Sets some basic information about the running application that's sent along
# with API requests. Useful for plugin authors to identify their plugin when
# communicating with Stripe.

View File

@ -12,6 +12,7 @@ module Stripe
def initialize(conn = nil)
self.conn = conn || self.class.default_conn
@system_profiler = SystemProfiler.new
@last_request_metrics = nil
end
def self.active_client
@ -113,7 +114,6 @@ module Stripe
def execute_request(method, path,
api_base: nil, api_key: nil, headers: {}, params: {})
api_base ||= Stripe.api_base
api_key ||= Stripe.api_key
@ -218,6 +218,9 @@ module Stripe
resp = yield
context = context.dup_from_response(resp)
log_response(context, request_start, resp.status, resp.body)
if Stripe.enable_telemetry?
@last_request_metrics = StripeRequestMetrics.new(context.request_id, Time.now - request_start)
end
# We rescue all exceptions from a request so that we have an easy spot to
# implement our retry logic across the board. We'll re-raise if it's a type
@ -425,6 +428,10 @@ module Stripe
"Content-Type" => "application/x-www-form-urlencoded",
}
if Stripe.enable_telemetry? && !@last_request_metrics.nil?
headers["X-Stripe-Client-Telemetry"] = JSON.generate(last_request_metrics: @last_request_metrics.payload)
end
# It is only safe to retry network failures on post and delete
# requests if we add an Idempotency-Key header
if %i[post delete].include?(method) && Stripe.max_network_retries > 0
@ -594,5 +601,23 @@ module Stripe
}.delete_if { |_k, v| v.nil? }
end
end
# StripeRequestMetrics tracks metadata to be reported to stripe for metrics collection
class StripeRequestMetrics
# The Stripe request ID of the response.
attr_accessor :request_id
# Request duration
attr_accessor :request_duration
def initialize(request_id, request_duration)
self.request_id = request_id
self.request_duration = request_duration
end
def payload
{ request_id: request_id, request_duration: request_duration }
end
end
end
end

View File

@ -749,6 +749,51 @@ module Stripe
end
end
end
context "#telemetry" do
teardown do
# make sure to always set telemetry back to false
# to not mutate global state
Stripe.enable_telemetry = false
end
should "not send metrics if enable trace flag is not set" do
Stripe.enable_telemetry = false
trace_metrics_header = nil
stub_request(:get, "#{Stripe.api_base}/v1/charges")
.with do |req|
trace_metrics_header = req.headers["X-Stripe-Client-Telemetry"]
false
end.to_return(body: JSON.generate(object: "charge"))
Stripe::Charge.list
assert(trace_metrics_header.nil?)
Stripe::Charge.list
assert(trace_metrics_header.nil?)
end
should "send metrics if enabled telemetry is true" do
Stripe.enable_telemetry = true
trace_metrics_header = nil
stub_request(:get, "#{Stripe.api_base}/v1/charges")
.with do |req|
trace_metrics_header = req.headers["X-Stripe-Client-Telemetry"]
false
end.to_return(body: JSON.generate(object: "charge"))
Stripe::Charge.list
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"].nil?)
end
end
end
class SystemProfilerTest < Test::Unit::TestCase