Skip to content
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

Add manual tracing to Identity #5283

Merged
merged 19 commits into from
Sep 30, 2019
Merged

Add manual tracing to Identity #5283

merged 19 commits into from
Sep 30, 2019

Conversation

xirzec
Copy link
Member

@xirzec xirzec commented Sep 27, 2019

This PR:

  • Adds tracing to the Identity client with manual Span propagation
  • Creates a new TestTracer for use in unit tests
  • Adds some unit tests to Identity that use TestTracer
  • Removes an unnecessary interface from core-tracing
  • Adds SpanOptions to RequestPrepareOptions in core-http

This PR cleans up a previous effort by Sarangan (pull #5019).

Love to get feedback on the feel of the tests, if there is anything folks would like to see done differently.

@xirzec xirzec added Client This issue points to a problem in the data-plane of the library. Azure.Identity labels Sep 27, 2019
@xirzec xirzec requested a review from sadasant as a code owner September 27, 2019 22:30
@xirzec xirzec self-assigned this Sep 27, 2019
@xirzec xirzec mentioned this pull request Sep 27, 2019
Copy link
Contributor

@chradek chradek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks good! "Hide whitespace changes" helped ;)

span.setStatus({
code: CanonicalCode.UNAUTHENTICATED,
message: err.message
})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: missing semi-colon.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good eyes! Definitely need to get lint working...

return tokenResponse;
return tokenResponse;
} catch (err) {
const code = err instanceof AuthenticationError ? CanonicalCode.UNAUTHENTICATED : CanonicalCode.UNKNOWN;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be safer to check the err.name for AuthenticationError?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So it's true that errors from another context (e.g. iframe) will fail instanceof checks, but the downside of using name is that if you want inheritance in your Error objects then you can't handle classes of errors together.

E.g. you can imagine doing something like

class ValidationError extends Error {}

class RangeError extends ValidationError {}

try { 
// something
} catch (e) {
  if (e instanceof ValidationError) {
    // this works for RangeError!
  }
}

I'm flexible on if we want to move to a name-based pattern (or some other approach), but since Identity was already relying on instanceof AuthenticationError in other code, I think keeping it consistent is fine for now.

/cc @bterlson if he has any design guidance for us.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I talked to Brian. This usage of instanceof probably is safe, but he was generally in favor of moving to checking name since we don't have plans for hierarchical errors anytime soon. I'll look at switching this over.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotcha. I think we had had some issue when using custom errors in core-amqp that made us switch to doing the name check but I’ll have to double-check to confirm. Didn’t realize it was already being done in the rest of the SDK and generally agree to favor consistency.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved this over to using name checks, please take another look

@xirzec xirzec requested a review from chradek September 30, 2019 19:25
(err.code === RestError.REQUEST_SEND_ERROR || err.code === RestError.REQUEST_ABORTED_ERROR)
) {
// Either request failed or IMDS endpoint isn't available
return false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the status of the span be a failure in this case? Unauthenticated?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think UNAVAILABLE makes more sense here, since we're checking the availability of the endpoint. Good spotting that catch wasn't rethrowing here.

@xirzec xirzec requested a review from chradek September 30, 2019 19:53
Copy link
Contributor

@daviwil daviwil left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great for the most part! The testing approach looks solid. A few other comments below

} catch (err) {
span.setStatus({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The purpose of this loop is to try each credential in the chain until one is able to authenticate successfully. If there are 3 credentials in the chain and the first two throw an exception but the last succeeds, shouldn't the span be considered successful? Maybe we should only trace in line 44/53 below where the AggregateAuthenticationError gets thrown and use the message from that exception instead.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The span is specific to the work it wraps. I think we do actually want to see that some spans failed, as it's the trace that will ultimately succeed (if there's a top-level span that wraps the chain, that could indicate success or failure as well).

For example, it can be useful for the customer to see that the 1st credential always fails, or only the 1st and 3rd pass. Then they could create their own chain if they wanted. Or maybe they think they are using one credential but it turns out that one is failing and they always fall back to another.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I see, the span is started outside the loop, not inside. (Missed that context when just reading the comment).

return (tokenResponse && tokenResponse.accessToken) || null;
} catch (err) {
span.setStatus({
code: CanonicalCode.UNKNOWN,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When should we use UNKNOWN versus UNAUTHENTICATED? Seems like a distinction might need to be made on the error type as done elsewhere in this PR.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UNKNOWN is the generic failure; I agree with adding the error type checking here.

return (tokenResponse && tokenResponse.accessToken) || null;
} catch (err) {
span.setStatus({
code: CanonicalCode.UNKNOWN,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe UNAUTHENTICATED?

return (tokenResponse && tokenResponse.accessToken) || null;
} catch (err) {
span.setStatus({
code: CanonicalCode.UNKNOWN,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe UNAUTHENTICATED?

return (tokenResponse && tokenResponse.accessToken) || null;
} catch (err) {
span.setStatus({
code: CanonicalCode.UNKNOWN,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe UNAUTHENTICATED?

@xirzec xirzec requested a review from daviwil September 30, 2019 21:01
Copy link
Contributor

@daviwil daviwil left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, thanks a lot!

@xirzec xirzec merged commit fc0887f into Azure:master Sep 30, 2019
@xirzec xirzec deleted the identityTracing branch September 30, 2019 21:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Azure.Identity Client This issue points to a problem in the data-plane of the library.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants