access log: add the detected protocol set#10524
access log: add the detected protocol set#10524kyessenov wants to merge 3 commits intoenvoyproxy:masterfrom
Conversation
Signed-off-by: Kuat Yessenov <kuat@google.com>
Signed-off-by: Kuat Yessenov <kuat@google.com>
mattklein123
left a comment
There was a problem hiding this comment.
Thanks for working on this. I flushed out some comments from a first pass. My gut reaction is that I think the strong only approach feels a little fragile. WDYT about retaining the HTTP protocol support as it exists today and adding additional string protocol support alongside? It's not optimal but it feels safer and less fragile to me. cc @zuercher for some additional thoughts on this PR.
/wait
| * filters (append only). Both object types can be consumed by multiple filters. | ||
| * @return the filter state associated with this request. | ||
| */ | ||
| virtual FilterStateSharedPtr& mutableFilterState() PURE; |
There was a problem hiding this comment.
It doesn't thrill me to expose a reference to the shared_ptr on the interface? Can you explain why this is needed?
There was a problem hiding this comment.
HTTP request stream info takes TCP stream info filter state by a mutable shared_ptr. I think an additional filter state was created before that was used for HTTP parent filter state, which does not feel right to me. I'm not sure why HTTP stream info is allowed to modify TCP stream info filter state.
| if (protocol) { | ||
| const std::string AccessLogFormatUtils::protocolToString(absl::Span<const std::string> protocols) { | ||
| auto protocol = Http::Utility::getProtocol(protocols); | ||
| if (protocol.has_value()) { |
There was a problem hiding this comment.
Why do we need to do the string to enum to string dance here? Can't we just return the protocol string directly? Or this is for HTTP back compat? If for back compat can you add comments and also maybe skip the final getProtocolString call by returning the string reference directly from getProtocol?
There was a problem hiding this comment.
Mostly for backwards compatibility. I can change the interface to return both the enum and the string.
There was a problem hiding this comment.
I think trying to mix strings and the protocol enum is going to be confusing and it already involves a lot of converting back and forth between the string and enum representation.
Perhaps a better approach would be to rename the existing StreamInfo::protocol() and StreamInfo::protocol(Http::Protocol) to http_protocol and provide a new StreamInfo::protocols() and StreamInfo::addProtocol that deal with strings. The implementation of http_protocol(Http::Protocol) would invoke addProtocol with the appropriate protocol name and also store the protocol in an absl::optional (returned by http_protocol()). That will make the changes in HCM simpler to review and allows access to the full stack of protocols in other situations.
Otherwise I think we'd need to work out a proper registry. I think that's feasible as long as we the identifiers are not exposed outside a given Envoy process (e.g. the X extension's ID may change from build-to-build but as long as the id is kept internal it shouldn't matter). We might even be able to arrange registrations of core protocols in a stable order so their ids wouldn't change from build-to-build.
There was a problem hiding this comment.
Got it. I'll preserve protocol() for HTTP as-is and add two more stubs to deal with the layered protocols. Thank you! I can also do the rename separately (maybe there's some clang tool to automate that) to make reviews easier.
There was a problem hiding this comment.
+1 this sounds like a good plan. Thank you!
| // The protocol may have shifted in the HTTP/1.0 case so reset it. | ||
| stream_info_.protocol(protocol); | ||
| if (Http::Utility::getProtocol(stream_info_.protocols()) != protocol) { | ||
| stream_info_.addProtocol(Http::Utility::getProtocolString(protocol)); |
There was a problem hiding this comment.
This is going to change the behavior, right? Meaning we will now have multiple HTTP protocol strings?
There was a problem hiding this comment.
It is always appended and getProtocol looks from the back, so there is no change in the behavior. But we will have multiple strings in the protocol list as decisions are made about the protocol.
| } | ||
|
|
||
| absl::optional<const Protocol> Utility::getProtocol(absl::Span<const std::string> protocols) { | ||
| for (auto it = protocols.rbegin(); it != protocols.rend(); it++) { |
There was a problem hiding this comment.
I assume you are going in reverse for a reason? Comment?
There was a problem hiding this comment.
Sure, sorry if it was not clear but it's basically append-only history of discovered protocols, so looking from the back is right.
| absl::optional<MonotonicTime> final_time_; | ||
|
|
||
| absl::optional<Http::Protocol> protocol_; | ||
| std::vector<std::string> protocols_; |
There was a problem hiding this comment.
I would recommend an InlinedVector here with a small number of protocols.
There was a problem hiding this comment.
Thanks. I am relying on inlined strings to save some space.
| const Server::OverloadActionState& overload_stop_accepting_requests_ref_; | ||
| const Server::OverloadActionState& overload_disable_keepalive_ref_; | ||
| TimeSource& time_source_; | ||
| std::shared_ptr<StreamInfo::FilterState> filter_state_; |
There was a problem hiding this comment.
This is the filter state that was (lazily) created by a network filter. I changed it to use the filter state from the connection stream info. Otherwise, it's invisible to access loggers at the connection level.
|
I'm fine preserving the existing protocol() as-is and adding another interface method to carry a list. I believe what we have here achieves it, but we have to be careful not to break HTTP code. |
|
Gentle ping @zuercher for your comments before I can proceed. |
|
Closing since I have split out smaller changes. |
Signed-off-by: Kuat Yessenov kuat@google.com
Description: Change
StreamInfoto carry a list of the detected protocols instead of just HTTP versions. For example, the common case should have TCP, HTTP, HTTP/2 as the value.Risk Level: low, I tried to keep the usage in HTTP context identical
Testing: updated all tests
Docs Changes: none
Release Notes: none
Fixes #10487