-
Notifications
You must be signed in to change notification settings - Fork 436
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
contrib/k8s.io/client-go: add kubernetes integration, round-tripper #298
Conversation
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. Left an initial round of comments
) | ||
|
||
const ( | ||
apiPrefix = "/api/v1/" |
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 we do the same here as we did in the other PRs?
const (
prefixApi
prefixWatch
prefixNamespaces
)
Let me know if you have differing thoughts about this approach.
if !strings.HasPrefix(path, apiPrefix) { | ||
return resourceName | ||
} | ||
path = path[len(apiPrefix):] |
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.
Let's use path = strings.TrimPrefix(path, prefixAPI)
. Do you see any problems with that? It's clearer and has the same effect.
|
||
// strip out /watch | ||
if strings.HasPrefix(path, watchPrefix) { | ||
path = path[len(watchPrefix):] |
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 we use path = strings.TrimPrefix(path, prefixWatch)
here too?
contrib/net/http/roundtripper.go
Outdated
err = errors.New(res.Status) | ||
} | ||
} | ||
if rt.cfg.after != nil { |
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.
How would you feel about the following change?
- We put this in a
defer
clause right after the before counter-part is called (is this a performance concern?) - We name the error return value of
RoundTrip
, capture it in thedefer
and pass it to the after func - The default after func sets the error on the span (we don't set it in Finish).
If people want to skip errors or selectively decide which ones to take into account, they can always make their own "after func"
On the other hand, if this is a performance concern, let's leave it like this (but do set the error by default). If the need arises to work with errors we can just provide a new option to hook into them.
contrib/net/http/roundtripper.go
Outdated
if rt.cfg.after != nil { | ||
rt.cfg.after(res, span) | ||
} | ||
span.Finish(tracer.WithError(err)) |
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 we defer
this too at the top? After the span starts (or in the same defer
as the "after func" in you do that).
contrib/net/http/option.go
Outdated
cfg.before = f | ||
} | ||
} | ||
|
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.
Do we need WithServiceName
? I realize people can just make a short "before" or "after" func for it but maybe it would be nice to simplify this and also keep it matching our other contribs.
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.
WithServiceName
already exists for the MuxOption
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 can't easily figure out how MuxOption
connects to WrapRoundTripper
, which uses RoundTripperOption
. There is no service set in RoundTrip
currently, it will simply use whatever was set on the tracer. If nothing is set, the span will be refused by the agent. Am I missing something?
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 can't create a WithServiceName
function for RoundTripperOption
because it's already used by the MuxOption
which is in the same package. Should I create a WithRoundTripperServiceName
function?
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'm not sure. Would UseServiceName
be bad?
assert.Len(t, spans, 2) | ||
assert.Equal(t, spans[0].TraceID(), spans[1].TraceID()) | ||
|
||
{ |
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 saw we've started using this pattern. I see it a bit as a "lazy mode to create a closure". Maybe I'm not looking at it the right way? I'm wondering if we can't just use a for
loop and sub-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.
Not sure I follow about the for
loop... the things being tested for aren't the same for each span.
I used a block to re-use the s variable. I can change it to s1, s2.
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'd prefer it without the closure if possible. But I am open to considering it. I've been generally avoiding using it.
contrib/net/http/roundtripper.go
Outdated
|
||
func (rt *roundTripper) RoundTrip(req *http.Request) (*http.Response, error) { | ||
span, _ := tracer.StartSpanFromContext(req.Context(), "http.request", | ||
tracer.ResourceName(defaultResourceName), |
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're going to need to set the right type for the rest of our pipeline, this is an important part:
tracer.SpanType(ext.SpanTypeHTTP)
When the span type is set on a root span, it classifies the service in the application and enables making use of other systems such as obfuscation, quantization, etc.
// {type}/{name} | ||
lastType := "" | ||
for i := 0; ; i++ { | ||
idx := strings.IndexByte(path, '/') |
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 solution is very low level. Can we make use of the strings
package more? For example:
parts := strings.Split(path, "/") // n := len(parts)
for i, p := range parts {
} | ||
|
||
func requestToResource(method, path string) string { | ||
resourceName := 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.
Instead of repeatedly concatenating string constants, can we use strings.Builder
here?
if !strings.HasPrefix(path, prefixApi) {
return method
}
var out strings.Builder
out.WriteString(method)
out.WriteByte(' ')
// ...
return out.String()
Fixes #172, right? |
This is basically 2 PRs, do you think we could split it? The reason is that it turns out to be very helpful to do that when putting together a release change log. Each commit message is a clear one line description of the affected package and the change, as well as a link to a PR. This makes it really easy to cover everything when releasing. It also makes it easier to not miss anything when navigating commit history. I'd also be fine with two commits, except that would create an extra merge commit, but I'd be happy with that compromise if you prefer this alternative. |
…atch upstream changes, use a string builder for resource naming, refactor loop to use Split instead of IndexByte
426a579
to
922d575
Compare
@gbbr The http changes were split out and merged to v1. I think this PR should be ready to merge. Let me know if you see any additional problems. Thanks. |
|
||
path = strings.TrimPrefix(path, prefixAPI) | ||
|
||
// strip out /watch |
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 we put this comment inside the if
statement? That's what I've been doing all around. It makes sense (to me) because that's where the action happens (inside the if statement).
} | ||
|
||
// {type}/{name} | ||
lastType := "" |
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.
For "zero values" can we use?
var lastType string
Fixes #297
I thought that perhaps the easiest way to instrument Kubernetes would be to provide an
http.RoundTripper
with a couple extra integration points via Options:This would supersede: #172