-
Notifications
You must be signed in to change notification settings - Fork 599
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Stripe instrumentation #2180
Stripe instrumentation #2180
Conversation
Dependency detection, subscriber, config
def add_custom_attributes(segment, event) | ||
return if NewRelic::Agent.config[:'stripe.user_data.include'].empty? | ||
|
||
event.user_data.delete(:newrelic_segment) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be better to move these 2 lines from 2 separate methods that need not know about each other out into their own method that deletes and returns the segment:
event.user_data.delete(:newrelic_segment)
segment = event.user_data[:newrelic_segment]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Made some changes. Let me know if this works c59f04c
end | ||
|
||
def metric_name(event) | ||
"Stripe#{event.path} #{event.method}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should the metric name elements be slash delimited?
"Stripe#{event.path} #{event.method}" | |
"Stripe#{event.path}/#{event.method}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've updated this. c59f04c
end | ||
|
||
def finish_segment(event) | ||
begin |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seeing as the begin
wraps the entire method body, there's no need for it, and you can simply remove the begin
and end
and outdent the ensure
one level (to be on a peer level with def
and rescue
).
add_stripe_attributes(segment, event) | ||
add_custom_attributes(segment, event) | ||
ensure | ||
segment.finish |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is possible to reach the ensure
block with a nil
segment, and calling #finish
on nil
will raise another error which won't be handled. We can use the safe navigation operator to proactively anticipate and defend against this possibility.
segment.finish | |
segment&.finish |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great call c59f04c
object: 'list', | ||
data: [{'id': '12134'}], | ||
has_more: false, | ||
url: '/v1/charges' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't really matter given that the tests don't operate on the url contained in the response, but from a "the specs should tell the story" perspective, perhaps you should store 'v1/customers'
as a constant and use it both here and in the #detect
calls that the tests perform.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated 63014dd
end | ||
|
||
def test_newrelic_segment | ||
Stripe::StripeClient.stub(:default_connection_manager, @connection) do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seeing as you use this wrapper multiple times, it'd be a good candidate for a test helper.
def with_stubbed_connection_manager(&block)
Stripe::StripeClient.stub(:default_connection_manager, @connection) do
@connection.stub(:execute_request, @response) do
block.call
end
end
end
then for each test you could use it:
with_stubbed_connection_manager do
in_transaction do |txn|
Stripe::Customer.list({limit: 3})
stripe_segment = txn.segments.detect { |s| s.name == 'Stripe/v1/customers get' }
assert(stripe_segment)
end
end
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pattern into a method.. love and done! 63014dd
@connection.stub(:execute_request, @response) do | ||
in_transaction do |txn| | ||
Stripe::Customer.list({limit: 3}) | ||
stripe_segment = txn.segments.detect { |s| s.name == 'Stripe/v1/customers get' } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could see you doing something like:
stripe_segment = stripe_segment_from_txn(txn)
for this repeated pattern.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Love this. Kayla had a similar suggestion to put repeated patterns into methods. I've updated 63014dd
Stripe::Customer.list({limit: 3}) | ||
stripe_segment = txn.segments.detect { |s| s.name == 'Stripe/v1/customers get' } | ||
|
||
assert_empty txn.segments |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's always a single "dummy" segment when you use in_transaction
. You should be able to do:
refute stripe_segment
but you don't want the transaction's segment array itself to be empty, as it'll always have at least 1 entry.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That makes sense. I've updated what we're looking for 63014dd
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is so cool, Hannah! Awesome work. I found a few small things for you to consider before approval.
end | ||
|
||
def metric_name(event) | ||
"Stripe#{event.path} #{event.method}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can metric names have spaces in them? (I have no idea, but it struck me as odd)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both you and James called this out. I've removed the space c59f04c
license_key: bootstrap_newrelic_admin_license_key_000 | ||
ca_bundle_path: ../../../config/test.cert.crt | ||
instrumentation: | ||
sinatra: <%= $instrumentation_method %> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you want this to be stripe?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because pub/sub, I've removed this!
end | ||
|
||
def test_version_supported | ||
assert(Stripe::VERSION >= '5.38.0') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this need Gem::Version.new
to compare the values?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We were running fine without it, but I've definitely run into issues with this in the past. To be safe and match instrumentation, I've updated c997c51
Stripe::StripeClient.stub(:default_connection_manager, @connection) do | ||
@connection.stub(:execute_request, @response) do | ||
in_transaction do |txn| | ||
Stripe::Customer.list({limit: 3}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add the start a Stripe event
comment here too? I loved seeing it on the later tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alternatively, you could name a method start_stripe_event
and have it call Stripe::Customer.list({limit: 3})
, if the event is started the same way in all the tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great suggestion! 63014dd
While the Stripe include list is only concerned with user data hash keys, the exclude list looks at both the keys and their corresponding values in case there's anything sensitive or otherwise unwanted in the value. - Added a new test to demonstrate hash value filtration - Updated existing exclusion test which was yielding a false positive by not setting an include list (excludes won't work without an include list) - Updated the exclude list config option description
Stripe: exclude list works on user data values
Co-authored-by: Kayla Reopelle (she/her) <87386821+kaylareopelle@users.noreply.github.com>
c817989
SimpleCov Report
|
Adds instrumentation for Stripe 5.38.0+. Makes use of Stripe's pub/sub instrumentation pattern.
Stripe users can attach custom attributes to Stripe events via the
user_data
hash created on a Stripe request event initialization. No attributes are collected by default. Two new config options allow customers to fine-tune reported attributes:stripe.user_data.include
andstripe.user_data.exclude
closes #2057