-
Notifications
You must be signed in to change notification settings - Fork 1.8k
[RFC] Functional Interface pattern for Collector extension APIs #13902
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
base: main
Are you sure you want to change the base?
Conversation
…tor into jmacd/functionalcomp
…tor into jmacd/functionalcomp
|
I've referred to my former attempt at this many times in the months since I first opened it, so here it is again. Following feedback from @evan-bradley I changed the name to "Functional Interface" pattern. Any name will do, really. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #13902 +/- ##
==========================================
- Coverage 92.22% 92.21% -0.02%
==========================================
Files 658 658
Lines 41168 41168
==========================================
- Hits 37968 37963 -5
- Misses 2190 2193 +3
- Partials 1010 1012 +2 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
This PR was marked stale due to lack of activity. It will be closed in 14 days. |
|
open-telemetry/opentelemetry-collector-contrib#42573 is an example of an ad-hoc extension mechanism in collector-contrib: it might be valuable to apply these patterns in that repository. |
|
This PR was marked stale due to lack of activity. It will be closed in 14 days. |
|
This is a bit difficult to review comprehensively, but here is some initial feedback from reading it:
|
|
Thank you @jade-guiton-dd. Having received some feedback, I will return this to draft and work on improving it. I do want to address the central questions, and why I think this is important.
This is not about all interfaces, this is about extension interfaces, which includes some of the core interfaces but not all of them. For example, I come to this because I worked to add middleware and ratelimiter extension support, and in the code reviews there were many undocumented requirements stated, in particular by @bogdandrutu. I had to rewrite these components several times because at first, the requirements were not clear, and they are still not clear hence this RFC.
I am sure the existing codebase does not fulfil these requirements. It is self-inconsistent and I want to fix that situation; the existing self-inconsistency is part of the undocumented requirement problem--requirements are being asked that the codebase does not meet itself. The existing self-inconsistency is the reason why extension interfaces are hard to add.
No, nothing prevents a component from implementing multiple extension interfaces, except the presence of method-name re-use. We avoided extensionauth.Client.RoundTripper being the same as extensionmiddleware.Client.GetRoundTripper for this reason, even though they are the same method. Again, when I put rate-limiter changes up for review, these requirements felt very difficult to meet, being unstated.
Again, this requirement was given as I worked on middleware extensions. I would say that extensions are currently impossible to contribute to the code base, because of undocumented requirements. I will try to improve the document in the ways you suggested. |
I see, that makes sense to me. You may want to update the document to make that clearer, as right now it sounds like this would apply to all "major interfaces". I wasn't aware of these being existing (but unwritten) requirements for extension interfaces, and would not have known to enforce them. Sounds like it's a great idea to write them down and make sure all maintainers agree on them to avoid arbitrary enforcement and inconsistencies, so thank you for taking it on.
Hmm, would it be something like this? type myExtension struct {
CoolInterface1
CoolInterface1
}
func createExtension(ctx context.Context, set extension.Settings, cfg component.Config) (extension.Extension, error) {
ext := &myExtension{}
ext.CoolInterface1 = NewCoolInterface1(Method1Func(ext.myMethod1))
ext.CoolInterface2 = NewCoolInterface2(Method2Func(ext.myMethod2))
return ext
}
func NewFactory() extension.Factory {
return extension.NewFactory(metadata.Type, createDefaultConfig, createExtension, metadata.ExtensionStability)
}I don't think the current version has an example of how to implement the interface externally, I think that could be a useful addition (although not as useful for developers of new interfaces, which seems like the primary audience). |
Description
Replaces #13263
Documents the interface pattern used in core interfaces (e.g., component, consumer, extensions), which enables safe interface evolution as described in this RFC. This documents an existing pattern so that it can be applied more consistently across our code base.
Testing Documentation
This interface pattern has been checked and documented using examples from PR #13241.