Skip to content
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

[1/3 header changes][metrics + grpc] Emit metrics for new headers handling behaviour. Hide actual changes under feature flag. #2268

Open
wants to merge 4 commits into
base: dev
Choose a base branch
from

Conversation

biosvs
Copy link
Collaborator

@biosvs biosvs commented Apr 25, 2024

Currently underlying implementation of headers handling wary significantly from one transport to another (docs/docs/headers-handling.md in this PR). Eventually, in one of the following releases, we want to make behaviour consistent and protective: filter inbound 'rpc-' headers, return error for attempting of 'rpc-' header setting.

Proposed changes are backward incompatible, so to identify the edges that are affected by the future changes, at first stage let's emit metrics.

Metrics: reserved_headers_stripped and reserved_headers_error metrics with "component": "yarpc-header-migration" constant tag and with source and dest variable tags

Part of #2265

@biosvs biosvs changed the title [1/3] Emit metrics for new headers handling behaviour. Hide actual changes under feature flag. [1/3 metrics + grpc] Emit metrics for new headers handling behaviour. Hide actual changes under feature flag. Apr 25, 2024
@biosvs biosvs force-pushed the emit-metrics-for-new-behavior-step-1 branch from 2da1be9 to 61a74eb Compare April 25, 2024 15:42
Copy link

codecov bot commented Apr 25, 2024

Codecov Report

Attention: Patch coverage is 92.21557% with 13 lines in your changes missing coverage. Please review.

Project coverage is 85.29%. Comparing base (23c069f) to head (d8e451e).
Report is 5 commits behind head on dev.

Files Patch % Lines
transport/tchannel/response_writer.go 78.68% 7 Missing and 6 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##              dev    #2268      +/-   ##
==========================================
+ Coverage   85.23%   85.29%   +0.06%     
==========================================
  Files         270      272       +2     
  Lines       15555    15630      +75     
==========================================
+ Hits        13258    13332      +74     
+ Misses       1876     1875       -1     
- Partials      421      423       +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@@ -0,0 +1,86 @@
# Headers handling

Yarpc has unified API for getting and setting headers. Although implementations may wary
Copy link
Collaborator

Choose a reason for hiding this comment

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

fixing some typo and grammar: YARPC has a single unified API for getting and setting headers across 3 L7 protocols, although implementations may vary by a lot.

Also it is worth calling out HTTP and gRPC (a HTTP2 protocol) allows multiple key for the same key, which is why [go http|https://pkg.go.dev/net/http#Header] defines the type as map[string][]string. This is very different from TChannel.

One more thing you can call out is, HTTP/gRPC header is case insensitive, but TChannel header is case sensitive. This is why we have an OriginalHeaders on the yarpc.CallFromContext(ctx).OriginalHeaders method.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

HTTP and gRPC support multiple values, but yarpc introduces undefined behaviour and uses only one value (https://github.com/yarpc/yarpc-go/blob/dev/transport/grpc/headers.go#L156, https://github.com/yarpc/yarpc-go/blob/dev/transport/http/header.go#L66).

Added these notes to doc.


### Inbound - Request (Parsing)

Predefined list of headers (one header, actually) is read and stripped from the inbound request.
Copy link
Collaborator

Choose a reason for hiding this comment

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

If it is just one, just phrase as: A single header (list the key) is read and stripped from the inbound request

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done


Predefined list of headers (one header, actually) is read and stripped from the inbound request.

All other headers are forwarded as is to an application code.
Copy link
Collaborator

Choose a reason for hiding this comment

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

All other headers are forwarded as is to the application handler.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Fixed.


### Inbound - Response (Writing)

Attempting to add a header with a name listed as reserved leads to an error "cannot use reserved header key".
Copy link
Collaborator

Choose a reason for hiding this comment

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

ambiguity: reserved by tchannel or yarpc? Can you call out and add a link if possible

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Added clarification and link


### Outbound - Response (Parsing)

Headers with the names listed as reserved are deleted. All other headers are forwarded to an application code as is.
Copy link
Collaborator

Choose a reason for hiding this comment

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

All other headers are forwarded to the outbound as is.

Comment on lines 49 to 61
// IncStripped increments the stripped metric.
func (m *ReservedHeaderMetrics) IncStripped(source, dest string) {
incHeaderMetric(m.strippedVec, source, dest)
}

// IncError increments the error metric.
func (m *ReservedHeaderMetrics) IncError(source, dest string) {
incHeaderMetric(m.errorVec, source, dest)
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

do we need those? If it is only used in IncStripped, you can just inline there?

func (r *ReservedHeaderReporter) IncStripped() {
        incHeaderMetric(r.m.strippedVec, source, dest)
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I checked, these calls are inlined by compiler, so we're fine in this regard. And as we're good from performance perspective, I would say, it's nice to have some ownership separation - edge doesn't know about internal structure of ReservedHeaderMetrics. Plus it may be useful one day anyway.

return v
}

func incHeaderMetric(vector *metrics.CounterVector, source, dest string) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

incHeaderVecMetric?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Fixed

@@ -153,9 +168,21 @@ func metadataToTransportRequest(md metadata.MD) (*transport.Request, error) {
request.Encoding = transport.Encoding(getContentSubtype(value))
}
default:
if isReservedHeaderPrefixV2(header) {
reportStrippedHeader = true
Copy link
Collaborator

Choose a reason for hiding this comment

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

instead of a true/false value, do you want to use a counter here? Right now, no matter how many violations we have, we already inc by 1.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It won't change anything, +1 or +10 - it's basically gives no new information.

}

func assertTuples(t *testing.T, snapshots []metrics.Snapshot, expected []tuple) {
var actual []tuple
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: actual := make([]tuple, len(snapshots)*2)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Fixed

m := NewReserveHeaderMetrics(nil, "test")

m.IncStripped("", "")
m.IncError("", "")
Copy link
Collaborator

Choose a reason for hiding this comment

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

should you assert something here? If you are testing no panic, you should do assert.NoPanic

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Added

@biosvs biosvs force-pushed the emit-metrics-for-new-behavior-step-1 branch from 61a74eb to 93a82ba Compare April 30, 2024 13:13
@biosvs biosvs force-pushed the emit-metrics-for-new-behavior-step-1 branch from 93a82ba to f7b3c8e Compare May 3, 2024 15:52
@biosvs biosvs changed the title [1/3 metrics + grpc] Emit metrics for new headers handling behaviour. Hide actual changes under feature flag. [1/4 metrics + grpc] Emit metrics for new headers handling behaviour. Hide actual changes under feature flag. May 3, 2024
@biosvs biosvs changed the title [1/4 metrics + grpc] Emit metrics for new headers handling behaviour. Hide actual changes under feature flag. [1/3 header changes][metrics + grpc] Emit metrics for new headers handling behaviour. Hide actual changes under feature flag. May 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

2 participants