-
Notifications
You must be signed in to change notification settings - Fork 460
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
Introduce GetBackendWithConfig
and make logging configurable per backend
#611
Conversation
@@ -15,7 +15,7 @@ import ( | |||
) | |||
|
|||
func TestBearerAuth(t *testing.T) { | |||
c := &stripe.BackendConfiguration{URL: stripe.APIURL} | |||
c := stripe.GetBackend(stripe.APIBackend).(*stripe.BackendConfiguration) |
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.
Dang it. I kind of punted on finding the right way to solve this for now.
It's an improvement that we now use GetBackend
to get a default backend with good values set, but it's still bad that we then need to cast it back to BackendConfiguration
. The problem is that each of these tests uses BackendConfiguration.NewRequest
, and that is a function that's not part of the Backend
interface.
We should either add it to the interface, or find a better way to write these tests, with a preference for the latter.
c81a193
to
24e7655
Compare
}) | ||
orderClient := Client{B: backend, Key: stripe.Key} |
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.
Instantiating a new client turned out to be a far cleaner way to implement this test anyway (the defer
to reset the default backend at the top is no longer needed).
stripe.go
Outdated
// BackendConfiguration is the internal implementation for making HTTP calls to Stripe. | ||
// BackendConfig is used to configure a new Stripe backend. | ||
type BackendConfig struct { | ||
// HTTPClient is an HTTP client instance to use when maxing requests. |
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.
s/maxing/making/
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.
Thanks! Fixed.
// | ||
// Defaults to 0 (no logging), so please make sure to set this if you want | ||
// to see logging output in your custom configuration. | ||
LogLevel int |
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 don't think this is ever used; should it have a value in BackendConfiguration
and be used there too? Given that it will default to zero it may not be possible to determine if we should use this or the global LogLevel, I'm not sure how to do that in a backwards compatible way.
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 don't think this is ever used; should it have a value in BackendConfiguration and be used there too?
Haha, that's what I get for trying to push through a change like this near the end of the day!
Yep, that's a major omission. I just added LogLevel
to BackendConfiguration
and changed all existing checks on LogLevel
to use it.
// problem. | ||
// | ||
// Defaults to 0. | ||
MaxNetworkRetries int |
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.
Same as LogLevel
.
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.
Thanks! Fixed that as well. (Its value was already on BackendConfiguration
, but it was being carried over from the config struct.)
Wow, that was fast; thanks for implementing this! |
4f9ffc7
to
bfb2d9b
Compare
Yeah, the inability to check on I believe I've implemented this to be backwards compatible though — when getting a default backend (i.e., not through There are still problems in other areas though. For example, if we want to give either One possibility is to set these to |
(Oh, and thanks for the review @SamWhited!) |
@@ -233,8 +278,8 @@ func (s *BackendConfiguration) NewRequest(method, path, key, contentType string, | |||
// the backend's HTTP client to execute the request and unmarshals the response | |||
// into v. It also handles unmarshaling errors returned by the API. | |||
func (s *BackendConfiguration) Do(req *http.Request, v interface{}) error { | |||
if LogLevel > 1 { | |||
Logger.Printf("Requesting %v %v%v\n", req.Method, req.URL.Host, req.URL.Path) | |||
if s.LogLevel > 1 { |
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 should also make helpers for logInfo
, logError
, logDebug
so we don't have these ugly checks on LogLevel everywhere, but I'll tackle that in another PR.
Depending on how closely you want this to match what's already being done globally, one option might be to get rid of |
Ah, true. I'd be a little hesitant to introduce a new paradigm here though — leveled logging where the wanted level is set just once is a pretty widespread paradigm (even in Go). I just looked at Zap and Logrus, two popular libraries, and they both basically use an identical convention here: log.SetLevel(log.WarnLevel) (Which is probably roughly what we should be doing as well, even if it looks like just setting The one major departure compared to what we have is that normally the level is set on the logging object itself instead of as a separate field on the construct that holds the logger. I kind of want to change type Printfer interface {
Errorf(format string, v ...interface{})
Infof(format string, v ...interface{})
SetLogLevel(...)
Warnf(format string, v ...interface{})
} This would make using Zap and Logrus easy, but then of course Go's built in logging module would no longer comply to the interface. Sigh. I think the right thing to do for now is to leave it more or less as I have here, and we can decide on a larger breaking change later if it comes up again. |
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.
some minor comments but otherwise this looks good to me.
To be honest I don't 100% follow the logic/usage of the code though but I think I understood the changes
backend = GetBackendWithConfig( | ||
backendType, | ||
&BackendConfig{ | ||
HTTPClient: httpClient, |
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.
why pass all this since the method seems to set the default for us?
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.
Good eye. Yeah, I went back in forth on this — I settled for what you see because I felt that the explicitness is somewhat advantageous compared to setting a bunch of 0
/nil
and then having to follow the code down to GetBackendWithConfig
to see what's going to end up in there.
I don't feel too strongly about it though, and am happy to go with the other way too. What do you think?
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 don't feel strongly either so I'm fine leaving as is
stripe.go
Outdated
// to fulfill the principle of least astonishment. | ||
config.URL += "/v1" | ||
|
||
return &BackendConfiguration{ |
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 like the code is identical between both switch except for the url, could we generalize that?
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 point. I just updated the code and it looks way cleaner now.
bfb2d9b
to
80b6840
Compare
Yeah sorry, but unfortunately the relations of I think I can clean this up a lot in the future and make this way easier to wrap your head around, but I wanted to target a non-breaking change for this PR and see if we can improve things a bit later. ptal @remi-stripe Updated the patch, please take one more look. |
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.
LGTM
…ckend Introduces a new system for getting backends with a set of custom configuration that's a little cleaner than adding a new setter for every option that we add in the future. `BackendConfig` is introduced a user configurable struct which is then passed to `GetBackendWithConfig`, which returns a backend configured to spec. `GetBackend` remains, is backward compatible, and continues to set a default backend for either type. A new option on `BackendConfig` is being able to set a per-backend `Logger` and `LogLevel`. This is the impetus that sparked this change as documented in #608. So the unfortunate part is that `BackendConfig` is confusingly named similarly to the very poorly named `BackendConfiguration`, which is the final implementation of a backend. I wanted to keep this patch backward compatible, but I want to make a breaking change in the future to rename this to `backendImplementation` and make it unexported at the same time because it shouldn't be needed outside of the core package. We should also unexport `NewBackends` at the same time. It was introduced to allow some configuration for backends, but it was a pretty bad idea. Fixes #608.
80b6840
to
647da42
Compare
Thanks Remi! |
Released as 35.9.0. |
Fantastic, thanks again for your quick response! This will let me clean up a lot of hacky race-condition-prone stuff on my end where I had to make some logging global to pass it between modules and apply it to Stripe. Looking forward to cleaning that up! |
No worries! I hope it works out. |
* Adding workplan * Extracting out price comparison helper * PUlling transform_salesforce_billing_type_to_usage_type to functional helpers * Extract out tiered params sanitization * Eliminate sf_cpq_term_interval helper * Extract out custom price detection logic * Test for price helpers * Fixing mapper tests Tests removed are already covered in another test * Bump sfdx version to maybe fix ci issue * Fix typing error
Introduces a new system for getting backends with a set of custom
configuration that's a little cleaner than adding a new setter for every
option that we add in the future.
BackendConfig
is introduced a user configurable struct which is thenpassed to
GetBackendWithConfig
, which returns a backend configured tospec.
GetBackend
remains, is backward compatible, and continues to seta default backend for either type.
A new option on
BackendConfig
is being able to set a per-backendLogger
andLogLevel
. This is the impetus that sparked this change asdocumented in #608.
So the unfortunate part is that
BackendConfig
is confusingly namedsimilarly to the very poorly named
BackendConfiguration
, which is thefinal implementation of a backend. I wanted to keep this patch backward
compatible, but I want to make a breaking change in the future to rename
this to
backendImplementation
and make it unexported at the same timebecause it shouldn't be needed outside of the core package.
We should also unexport
NewBackends
at the same time. It wasintroduced to allow some configuration for backends, but it was a pretty
bad idea.
Fixes #608.
r? @remi-stripe