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

Propagate opentelemetry tracing headers in requests to limitador #49

Merged
merged 4 commits into from
Mar 25, 2024

Conversation

adam-cattermole
Copy link
Member

@adam-cattermole adam-cattermole commented Mar 19, 2024

Propagates the following three headers to limitador:

Example curl:

curl -H 'Authorization: APIKEY IAMALICE' -H 'Host: api.toystore.com' -H 'Traceparent: 00-80e1afed08e019fc1110464cfa66635c-7a085853722dc6d2-01' -H 'Tracestate: rojo=00f067aa0ba902b7' -H 'Baggage: key1=value1;property1;property2, key2 = value2, key3=value3; propertyKey=propertyValue' http://$GATEWAY_URL/cars

Limitador:

2024-03-19T16:32:39.529787Z DEBUG should_rate_limit: limitador_server::envoy_rls::server: Request received: Request { metadata: MetadataMap { headers: {"te": "trailers", "grpc-timeout": "5000m", "content-type": "application/grpc", "traceparent": "00-80e1afed08e019fc1110464cfa66635c-7a085853722dc6d2-01", "tracestate": "rojo=00f067aa0ba902b7", "baggage": "key1=value1;property1;property2, key2 = value2, key3=value3; propertyKey=propertyValue", "x-envoy-internal": "true", "x-envoy-expected-rq-timeout-ms": "5000"} }, message: RateLimitRequest { domain: "default/toystore", descriptors: [RateLimitDescriptor { entries: [Entry { key: "limit.alice_limit__f994feea", value: "1" }], limit: None }], hits_addend: 1 }, extensions: Extensions 

Resolves #48

let req_headers = self.get_http_request_headers();
for (header, value) in req_headers.iter() {
match header.as_str() {
"traceparent" | "tracestate" | "baggage" => {
Copy link
Contributor

Choose a reason for hiding this comment

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

self.get_http_request_headers returns lowercase header names? in other words, if the header is TraceParent, is the value captured? According to https://w3c.github.io/trace-context/#traceparent-header

The header name is [ASCII case-insensitive](https://infra.spec.whatwg.org/#ascii-case-insensitive). That is, TRACEPARENT, TraceParent, and traceparent are considered the same header. The header name is a single word; it does not contain any delimiters such as a hyphen.

Copy link
Member Author

@adam-cattermole adam-cattermole Mar 21, 2024

Choose a reason for hiding this comment

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

Yep from what I could tell no matter the provided format the headers were retrieved in lowercase - perhaps due to this https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_conn_man/header_casing

I could add a .to_lowercase() before the match for safety in case though (perhaps this preserve case formatter causes the headers to no longer be lowercase when received by wasm shim). Also considering moving the three header strings out to constants

Copy link
Contributor

Choose a reason for hiding this comment

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

if it's only used there, no need for a constant.

@adam-cattermole adam-cattermole marked this pull request as ready for review March 21, 2024 12:05
@adam-cattermole adam-cattermole self-assigned this Mar 21, 2024
@eguzki
Copy link
Contributor

eguzki commented Mar 21, 2024

verification steps

  • Run devel env
make development

This is currently failing but easily fixed with

diff --git a/Makefile b/Makefile
index 7808041..5362a26 100644
--- a/Makefile
+++ b/Makefile
@@ -61,10 +61,10 @@ $(WASM_RELEASE_PATH): $(RUST_SOURCES)
        make -C $(PROJECT_PATH) -f $(MKFILE_PATH) build
 
 development: $(WASM_RELEASE_PATH)
-       docker-compose up
+       docker compose up
 
 stop-development:
-       docker-compose down
+       docker compose down
 
 # get-protoc will download zip from $2 and install it to $1.
 define get-protoc
  • Send a request that will hit limitador with a Traceparent header (upper case T used on purpose)
curl -H "Host: test.c.com" -H "x-forwarded-for: 127.0.0.1" -H "My-Custom-Header-01: my-custom-header-value-01" -H 'Traceparent: 00-80e1afed08e019fc1110464cfa66635c-7a085853722dc6d2-01' -H "x-dyn-user-id: bob" http://127.0.0.1:18000/get

Expected to see in limitador's logs the traceparent

limitador-1  | 2024-03-21T16:28:47.739377Z DEBUG should_rate_limit: limitador_server::envoy_rls::server: Request received: Request { metadata: MetadataMap { headers: {"te": "trailers", "grpc-timeout": "5000m", "content-type": "application/grpc", "traceparent": "00-80e1afed08e019fc1110464cfa66635c-7a085853722dc6d2-01", "x-envoy-internal": "true", "x-forwarded-for": "172.21.0.4", "x-envoy-expected-rq-timeout-ms": "5000"} }, message: RateLimitRequest { domain: "rlp-ns-C/rlp-name-C", descriptors: [RateLimitDescriptor { entries: [Entry { key: "limit_to_be_activated", value: "1" }], limit: None }, RateLimitDescriptor { entries: [Entry { key: "source.address", value: "127.0.0.1:0" }], limit: None }, RateLimitDescriptor { entries: [Entry { key: "request.headers.My-Custom-Header-01", value: "my-custom-header-value-01" }], limit: None }, RateLimitDescriptor { entries: [Entry { key: "user_id", value: "bob" }], limit: None }], hits_addend: 1 }, extensions: Extensions }

@eguzki
Copy link
Contributor

eguzki commented Mar 21, 2024

@adam-cattermole nitpick: does it makes sense to use some external library, as a new dep strum, for such a simple thing as to iterate few values?

@adam-cattermole
Copy link
Member Author

adam-cattermole commented Mar 21, 2024

@adam-cattermole nitpick: does it makes sense to use some external library, as a new dep strum, for such a simple thing as to iterate few values?

I had the same thought on this - I'm wondering if there's a nice alternative that would allow us to simply add/remove from the TracingHeader enum without changing anything else - it didn't seem very straightforward to write the iter() method myself.


const RATELIMIT_SERVICE_NAME: &str = "envoy.service.ratelimit.v3.RateLimitService";
const RATELIMIT_METHOD_NAME: &str = "ShouldRateLimit";

// tracing headers
#[derive(EnumIter)]
#[derive(Clone)]
Copy link
Member

Choose a reason for hiding this comment

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

Not hurtful, but I don't know we clone that anywhere...

Copy link
Member Author

Choose a reason for hiding this comment

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

Woops, remnant from an earlier change - removed it now.

@adam-cattermole adam-cattermole merged commit eee0fbf into main Mar 25, 2024
2 checks passed
@adam-cattermole adam-cattermole deleted the tracing-otel branch March 25, 2024 14:25
@eguzki eguzki mentioned this pull request May 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

Propagate parenttrace id manually
3 participants