-
Notifications
You must be signed in to change notification settings - Fork 5.5k
http: rc details for main Envoy workflow #6560
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
Changes from 3 commits
78e41f2
f576258
84414ff
eee0b1b
effdd68
204db09
5b50401
47b7db6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -76,8 +76,44 @@ enum ResponseFlag { | |
| struct ResponseCodeDetailValues { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Those look great, thanks, but you're effectively rewriting even the existing
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think when we implement proxy-status these could be extended. I could do a one off with today's proxy-status codes but I really don't want to sign up for keeping it up to date and I'd prefer to not add code which is going to bitrot as the IETF makes forward progress. I don't think creating this without the tuple creates more work for when we implement proxy-status, and it might reduce it (by filling in the details field) |
||
| // Response code was set by the upstream. | ||
| const std::string ViaUpstream = "via_upstream"; | ||
|
|
||
| // TODO(#6542): add values for sendLocalReply use-cases | ||
| // configured limits. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like this comment is cut off. |
||
| const std::string REQUEST_PAYLOAD_TOO_LARGE = "request_payload_too_large"; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: I think the preference is to use PascalCase for these constants.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. PascalCase for enums for sure. For consts "In the Envoy codebase we use ConstantVar or CONSTANT_VAR." That said I thought ALL_CAPS was strictly prefered and I prefer PascalCase so I'll switch nonetheless :-P
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I had argued for a slight preference for PascalCase for constants to avoid collisions with macros in files we don't control. That's codified mildly in https://github.com/envoyproxy/envoy/blob/master/STYLE.md
|
||
| // Envoy is doing non-streaming proxying, and the response payload exceeded | ||
| // configured limits. | ||
| const std::string RESPONSE_PAYLOAD_TOO_LARGE = "response_payload_too_large"; | ||
| // The per-stream keepalive timeout was exceeded. | ||
| const std::string STREAM_IDLE_TIMEOUT = "stream_idle_timeout"; | ||
| // The per-stream total request timeout was exceeded | ||
| const std::string REQUEST_OVERALL_TIMEOUT = "request_overall_timeout"; | ||
| // The request was rejected due to the Overload Manager reaching configured resource limits. | ||
| const std::string OVERLOAD = "overload"; | ||
| // The HTTP/1.0 or HTTP/0.9 request was rejected due to HTTP/1.0 support not being configured. | ||
| const std::string LOW_VERSION = "low_version"; | ||
| // The request was rejected due to the Host: or :authority field missing | ||
| const std::string MISSING_HOST = "missing_host_header"; | ||
| // The request was rejected due to the Host: or :authority field missing | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. copy paste mistake for this comment |
||
| const std::string REQUEST_HEADERS_TOO_LARGE = "request_headers_too_large"; | ||
| // The request was rejected because path normalization was configured on and failed, probably due | ||
| // to an invalid path. | ||
| const std::string PATH_NORMALIZATION_FAILED = "path_normalization_failed"; | ||
| // The request was rejected because it attempted an unsupported upgrade. | ||
|
|
||
| // TODO(reviewers) do we want a standard of filter etc. prefix or unique IDs enough? | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we simply use filter's well know name? Unique ID might make debugging harder. |
||
| // Alternately maybe this should be a proto. Ugh. | ||
| const std::string UPGRADE_FAILED = "upgrade_failed"; | ||
| // The request was rejected by the router filter because there was no route found. | ||
| const std::string ROUTE_NOT_FOUND = "route_not_found"; | ||
| // A direct response was generated by the router filter. | ||
| const std::string DIRECT_RESPONSE = "direct_response"; | ||
| // The request was rejected by the router filter because there was no route found. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe "because the cluster in the selected route does not exist"? |
||
| const std::string CLUSTER_NOT_FOUND = "cluster_not_found"; | ||
| // The request was rejected by the router filter because the cluster was in maintenance mode. | ||
| const std::string MAINTENANCE_MODE = "maintenance_mode"; | ||
| // The request was rejected by the router filter because there was no healthy upstream found. | ||
| const std::string NO_HEALTHY_UPSTREAM = "no_healthy_upstream"; | ||
| // The upstream stream was reset | ||
| const std::string Upstream = "upstream_reset{%s}"; | ||
| // TODO(#6542): continue addding values for sendLocalReply use-cases | ||
| }; | ||
|
|
||
| typedef ConstSingleton<ResponseCodeDetailValues> ResponseCodeDetails; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -291,7 +291,8 @@ Http::FilterHeadersStatus Filter::decodeHeaders(Http::HeaderMap& headers, bool e | |
| headers.Path()->value().getStringView()); | ||
|
|
||
| callbacks_->streamInfo().setResponseFlag(StreamInfo::ResponseFlag::NoRouteFound); | ||
| callbacks_->sendLocalReply(Http::Code::NotFound, "", nullptr, absl::nullopt); | ||
| callbacks_->sendLocalReply(Http::Code::NotFound, "", nullptr, absl::nullopt, | ||
| StreamInfo::ResponseCodeDetails::get().ROUTE_NOT_FOUND); | ||
| return Http::FilterHeadersStatus::StopIteration; | ||
| } | ||
|
|
||
|
|
@@ -310,7 +311,7 @@ Http::FilterHeadersStatus Filter::decodeHeaders(Http::HeaderMap& headers, bool e | |
| } | ||
| direct_response->finalizeResponseHeaders(response_headers, callbacks_->streamInfo()); | ||
| }, | ||
| absl::nullopt); | ||
| absl::nullopt, StreamInfo::ResponseCodeDetails::get().DIRECT_RESPONSE); | ||
| return Http::FilterHeadersStatus::StopIteration; | ||
| } | ||
|
|
||
|
|
@@ -323,7 +324,8 @@ Http::FilterHeadersStatus Filter::decodeHeaders(Http::HeaderMap& headers, bool e | |
|
|
||
| callbacks_->streamInfo().setResponseFlag(StreamInfo::ResponseFlag::NoRouteFound); | ||
| callbacks_->sendLocalReply(route_entry_->clusterNotFoundResponseCode(), "", nullptr, | ||
| absl::nullopt); | ||
| absl::nullopt, | ||
| StreamInfo::ResponseCodeDetails::get().CLUSTER_NOT_FOUND); | ||
| return Http::FilterHeadersStatus::StopIteration; | ||
| } | ||
| cluster_ = cluster->info(); | ||
|
|
@@ -350,7 +352,7 @@ Http::FilterHeadersStatus Filter::decodeHeaders(Http::HeaderMap& headers, bool e | |
| headers.insertEnvoyOverloaded().value(Http::Headers::get().EnvoyOverloadedValues.True); | ||
| } | ||
| }, | ||
| absl::nullopt); | ||
| absl::nullopt, StreamInfo::ResponseCodeDetails::get().MAINTENANCE_MODE); | ||
| cluster_->stats().upstream_rq_maintenance_mode_.inc(); | ||
| return Http::FilterHeadersStatus::StopIteration; | ||
| } | ||
|
|
@@ -424,7 +426,8 @@ void Filter::sendNoHealthyUpstreamResponse() { | |
| callbacks_->streamInfo().setResponseFlag(StreamInfo::ResponseFlag::NoHealthyUpstream); | ||
| chargeUpstreamCode(Http::Code::ServiceUnavailable, nullptr, false); | ||
| callbacks_->sendLocalReply(Http::Code::ServiceUnavailable, "no healthy upstream", nullptr, | ||
| absl::nullopt); | ||
| absl::nullopt, | ||
| StreamInfo::ResponseCodeDetails::get().NO_HEALTHY_UPSTREAM); | ||
| } | ||
|
|
||
| Http::FilterDataStatus Filter::decodeData(Buffer::Instance& data, bool end_stream) { | ||
|
|
@@ -581,14 +584,15 @@ void Filter::updateOutlierDetection(Http::Code code, UpstreamRequest& upstream_r | |
| } | ||
| } | ||
|
|
||
| // TODO(alyssawilk) details | ||
| void Filter::onUpstreamTimeoutAbort(StreamInfo::ResponseFlag response_flags) { | ||
| const absl::string_view body = | ||
| timeout_response_code_ == Http::Code::GatewayTimeout ? "upstream request timeout" : ""; | ||
| onUpstreamAbort(timeout_response_code_, response_flags, body, false); | ||
| onUpstreamAbort(timeout_response_code_, response_flags, body, false, ""); | ||
| } | ||
|
|
||
| void Filter::onUpstreamAbort(Http::Code code, StreamInfo::ResponseFlag response_flags, | ||
| absl::string_view body, bool dropped) { | ||
| absl::string_view body, bool dropped, absl::string_view details) { | ||
| ASSERT(upstream_requests_.size() <= 1); | ||
| // If we have not yet sent anything downstream, send a response with an appropriate status code. | ||
| // Otherwise just reset the ongoing response. | ||
|
|
@@ -626,7 +630,7 @@ void Filter::onUpstreamAbort(Http::Code code, StreamInfo::ResponseFlag response_ | |
| headers.insertEnvoyOverloaded().value(Http::Headers::get().EnvoyOverloadedValues.True); | ||
| } | ||
| }, | ||
| absl::nullopt); | ||
| absl::nullopt, details); | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -680,7 +684,15 @@ void Filter::onUpstreamReset(Http::StreamResetReason reset_reason, | |
|
|
||
| const bool dropped = reset_reason == Http::StreamResetReason::Overflow; | ||
| callbacks_->streamInfo().setUpstreamTransportFailureReason(transport_failure_reason); | ||
| onUpstreamAbort(Http::Code::ServiceUnavailable, response_flags, body, dropped); | ||
| // TODO(reviewer) do we want structure here rather than string? | ||
| // I think in practice if there's a transport failure it takes precedence, | ||
| // otherwise there was an application error. So maybe just converting both | ||
| // transport_failure_reasons and reset_reasons to the snake_case is | ||
| // sufficient? But maybe there's cases where we want multiple levels to add | ||
| // their information. | ||
| std::string details = | ||
| absl::StrCat("upstream_reset{", reset_reason, ",", transport_failure_reason, "}"); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Both the reset reason and the transport failure reason are already available in the StreamInfo so why include them also in the rc details string? Seems simpler to just have the rc details by a fixed string like "upstream reset" which can be easily checked for and then access logs can look at the other fields if they want more specifics.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's totally doable. What I don't like about that is I feel like it encourages a paradigm of "look elsewhere for the underlying failure cause" So today we have have "rc details" which might point us to "upstream failure" which would require us to know which of transport failure and/or reset reason to debug. But then we could have a generic "cache failure" which could tell you to look at the cache details (was the entry not present? expired? etc) and "WASM failure" with a bunch of reasons the code failed to execute. I want all of the information to be communicated in access logs and headers and I'd mildly prefer to combine the data in the string as it's created rather than to encourage each complicated filter to split out layers of reasons.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That makes sense. It does make it a bit difficult to programmatically check if the response code details from a StreamInfo matches this "constant" but perhaps that is not a big deal - we could add some kind of regex matching if we really want that. |
||
| onUpstreamAbort(Http::Code::ServiceUnavailable, response_flags, body, dropped, details); | ||
| } | ||
|
|
||
| StreamInfo::ResponseFlag | ||
|
|
||
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.
default arguments is only allowed for non-virtual methods
https://google.github.io/styleguide/cppguide.html#Default_Arguments