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
Refactor tracing interceptor #450
Refactor tracing interceptor #450
Conversation
Codecov Report
@@ Coverage Diff @@
## v2 #450 +/- ##
===========================================
- Coverage 84.01% 58.59% -25.43%
===========================================
Files 30 31 +1
Lines 932 1577 +645
===========================================
+ Hits 783 924 +141
- Misses 110 590 +480
- Partials 39 63 +24
Continue to review full report at Codecov.
|
03ffb9e
to
8368b65
Compare
Since #394 has been merged, there have been some changes in the structuring of Please rebase the changes. |
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.
Looks good to me, I will have another round of review, particularly the kv package, seems like a lot of chunk for tracing is present there :)
8368b65
to
4a45a5b
Compare
4a45a5b
to
d0650ba
Compare
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.
Nice work! Did very quick pass with initial questions. Generally looks amazing! 💪🏽
interceptors/tracing/kv/value.go
Outdated
// instead of calling kv.Key(name).Bool(value) consider using a | ||
// convenience function provided by the api/key package - | ||
// key.Bool(name, value). | ||
func (k Key) Bool(v bool) KeyValue { |
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 a fan of this package. Looks very low value to maintain another type system. Can we avoid it?
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.
OTel uses a type-safe way to describe the type of attributes, I am afraid we will lose type information if we don't implement a type system.
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.
Everything looks good to me! Regarding the kv
package, I don't have any solid suggestions, but do you think we can define the interface for the kv
helper methods, and let the providers implement the kv
implementation?
SpanKindClient SpanKind = "client" | ||
) | ||
|
||
func reportable(tracer Tracer) interceptors.CommonReportableFunc { |
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 looks neat!
Co-authored-by: Yash Sharma <yashrsharma44@gmail.com>
Sounds good. @bwplotka WDYT? |
Just doing pass on this, sorry for lag. Feel free to ping me on Go/CNCF slack next time. Do you wish to move forward with this @XSAM ? We need that (: |
yeah, i can still work on this. |
Sweet, let me review this unless you want to change 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.
Nice, some comment first.
Good work 💪🏽
s.statusMessage = message | ||
} | ||
|
||
func (s *mockSpan) AddEvent(name string, attrs ...kv.KeyValue) { |
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.
func (s *mockSpan) AddEvent(name string, attrs ...kv.KeyValue) { | |
func (s *mockSpan) AddEvent(name string, attrs ...any) { |
How bad would be to operate on interfaces (any) and expect implementation to deal with types?
NOTE: I know we could use generics, but in practice they have still some overhead, plus not everyone moved to Go 1.18, so we can add generic type of implementation later on (maybe even in non braking compatibility manner)
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.
If we would move to interfaces, we won't be needing kv
package - Otel implementation can then use "go.opentelemetry.io/otel/attribute"
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 looks amzing, LGTM. Just one comment. Do you have the OTLP side handy somewhere?
// The default span status is OK, so it is not necessary to | ||
// explicitly set an OK status on successful Spans unless it | ||
// is to add an OK message or to override a previous status on the Span. | ||
SetStatus(code codes.Code, msg string) |
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.
Amazing idea to use gRPC codes here, love it!
s.statusMessage = message | ||
} | ||
|
||
func (s *mockSpan) AddEvent(name string, attrs ...tracing.KeyValue) { |
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.
Idea: Remove kv and use keyvals ...any
as in go-kit logger https://github.com/go-kit/kit/tree/master/log ? (:
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.
well ..interface{}
, since we can't just support Go 1.18 yet
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.
Then we can use something like
// borrowed from https://github.com/go-logfmt/logfmt/blob/main/encode.go#L75
func kvToAttr(keyvals ...interface{}) []attribute.KeyValue {
if len(keyvals) == 0 {
return nil
}
if len(keyvals)%2 == 1 {
keyvals = append(keyvals, nil)
}
j := 0
ret := make([]attribute.KeyValue, len(keyvals)/2)
for i := 0; i < len(keyvals); i += 2 {
k, ok := anyToString(keyvals[i])
if !ok {
k = "<unsupported key type>"
}
v, ok := anyToString(keyvals[i+1])
if !ok {
v = "<unsupported value type>"
}
ret[j] = attribute.String(k, v)
j++
}
return ret
}
func anyToString(value interface{}) (string, bool) {
switch v := value.(type) {
case nil:
return "nil", true
case string:
return v, true
case []byte:
return string(v), true
case error:
return v.Error(), true
case fmt.Stringer:
return v.String(), true
default:
rvalue := reflect.ValueOf(value)
switch rvalue.Kind() {
case reflect.Array, reflect.Chan, reflect.Func, reflect.Map, reflect.Slice, reflect.Struct:
return "", false
case reflect.Ptr:
if rvalue.IsNil() {
return "nil", true
}
return anyToString(rvalue.Elem().Interface())
}
return fmt.Sprint(v), true
}
}
Ping (: |
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.
Amazing, work thanks! Let's go!
Split from #312. I will create the remaining parts of #312 once this PR gets merged.
@bwplotka @yashrsharma44 PTAL