Skip to content

access log: add the detected protocol set#10524

Closed
kyessenov wants to merge 3 commits intoenvoyproxy:masterfrom
kyessenov:downstream_protocol
Closed

access log: add the detected protocol set#10524
kyessenov wants to merge 3 commits intoenvoyproxy:masterfrom
kyessenov:downstream_protocol

Conversation

@kyessenov
Copy link
Contributor

Signed-off-by: Kuat Yessenov kuat@google.com

Description: Change StreamInfo to 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

Signed-off-by: Kuat Yessenov <kuat@google.com>
Signed-off-by: Kuat Yessenov <kuat@google.com>
Signed-off-by: Kuat Yessenov <kuat@google.com>
@mattklein123 mattklein123 self-assigned this Mar 25, 2020
Copy link
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

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

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;
Copy link
Member

Choose a reason for hiding this comment

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

It doesn't thrill me to expose a reference to the shared_ptr on the interface? Can you explain why this is needed?

Copy link
Contributor Author

@kyessenov kyessenov Mar 26, 2020

Choose a reason for hiding this comment

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

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()) {
Copy link
Member

Choose a reason for hiding this comment

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

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Mostly for backwards compatibility. I can change the interface to return both the enum and the string.

Copy link
Member

@zuercher zuercher Apr 2, 2020

Choose a reason for hiding this comment

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

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.

Copy link
Contributor Author

@kyessenov kyessenov Apr 2, 2020

Choose a reason for hiding this comment

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

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.

Copy link
Member

Choose a reason for hiding this comment

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

+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));
Copy link
Member

Choose a reason for hiding this comment

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

This is going to change the behavior, right? Meaning we will now have multiple HTTP protocol strings?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

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++) {
Copy link
Member

Choose a reason for hiding this comment

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

I assume you are going in reverse for a reason? Comment?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

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_;
Copy link
Member

Choose a reason for hiding this comment

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

I would recommend an InlinedVector here with a small number of protocols.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

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_;
Copy link
Contributor Author

@kyessenov kyessenov Mar 26, 2020

Choose a reason for hiding this comment

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

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.

@kyessenov
Copy link
Contributor Author

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.

@kyessenov
Copy link
Contributor Author

Gentle ping @zuercher for your comments before I can proceed.

@kyessenov
Copy link
Contributor Author

Closing since I have split out smaller changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

stream info: expand protocol set

3 participants