-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
improve X-Amz-Trace-Id for APIGW NG #11327
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
Conversation
Thanks for implementing this so quickly! For my use case, it would be super helpful to pass the caller's X-Amzn-Trace-Id, if one is provided. This allows me to have part of my application running in LocalStack, while keeping the trace ID consistent with the rest of my application that has already generated the ID. |
LocalStack Community integration with Pro 2 files ± 0 2 suites ±0 24m 35s ⏱️ - 1h 10m 42s Results for commit 735d404. ± Comparison against base commit cc6b849. This pull request removes 2530 and adds 1 tests. Note that renamed tests count towards both.
This pull request removes 342 skipped tests and adds 1 skipped test. Note that renamed tests count towards both.
♻️ This comment has been updated with latest results. |
@northvankiwiguy thanks a lot, I'll update the PR with a test and this functionality. Thanks for the quick feedback! |
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.
Thanks for tackling this!
Nice and clean implementation! Another proof of the strength of the NG provider!
I just left a question regarding the location of the helper methods!
def generate_trace_id(): | ||
"""https://docs.aws.amazon.com/xray/latest/devguide/xray-api-sendingdata.html#xray-api-traceids""" | ||
original_request_epoch = int(time.time()) | ||
timestamp_hex = hex(original_request_epoch)[2:] | ||
version_number = "1" | ||
unique_id = token_hex(12) | ||
return f"{version_number}-{timestamp_hex}-{unique_id}" | ||
|
||
|
||
def generate_trace_parent(): | ||
return token_hex(8) | ||
|
||
|
||
def parse_trace_id(trace_id: str) -> dict[str, str]: | ||
split_trace = trace_id.split(";") | ||
trace_values = {} | ||
for trace_part in split_trace: | ||
key_value = trace_part.split("=") | ||
if len(key_value) == 2: | ||
trace_values[key_value[0].capitalize()] = key_value[1] | ||
|
||
return trace_values |
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.
Question: Do you think we should put those method in a shared utils for more services to have access to? I feel like they will mostly be the same for everywhere?
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.
That's a good point! Not sure where it should live for now 🤔 we might keep it here for now, and if we hear about more x-ray traces, move it somewhere else?
I believe lambda might have a similar implementation..
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.
I think Lambda is only using long_uid()
, unless I missed it.
I was thinking that it could make sense in localstack-core/utils
maybe create a trace.py
but not super convinced either.
I think it is fine with it here for now, but we should stay alert to prevent this behavior to be implemented many times in the code base!
Thanks for the bug fix! I'm glad you handle both Active and Passive cases. However... right now I'm not able to see the HTTP header being passed to Lambda. I know that Lambda incorrectly overwrites the value, but I added There's a chance I'm looking in the wrong place, and I'll keep debugging it, but I thought I'd mention it in case you immediately knew the problem.
I have your latest commit in my workspace: |
Yes, it is currently not working for |
Thanks, I forgot I was using Proxy Integration. I double-checked and the header value is correctly being passed into the However, the Lambda functions Again... thanks for adding the API Gateway feature so quickly! |
It is somewhat similar, yes! There are 2 issues:
The point I was talking about above was the point 1, but we need to address point 2 first. It is still good to think about how to address passing the trace id along! |
Thank you, that makes sense. For Point 2 (Lambda overriding the passed-in trace ID), will I need to open a new issue to get that fixed? |
Yes, I think that would be good! |
incoming_parent = incoming_trace.get("Parent") | ||
parent = incoming_parent or generate_trace_parent() | ||
sampled = incoming_trace.get("Sampled", "1" if incoming_parent else "0") | ||
# TODO: lineage? not sure what it related to |
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.
Lineage is related to detecting recursive Lambda loops (July 2023): https://aws.amazon.com/blogs/compute/detecting-and-stopping-recursive-loops-in-aws-lambda-functions/
They extended support for S3, SQS, and SNS in Aug 2024: https://aws.amazon.com/blogs/compute/aws-lambda-introduces-recursive-loop-detection-apis/
Motivation
As talked about in #11253 (comment), we could use the same trace-id throughout the invocation, this was left as a TODO. I have a bit of time, so I implemented it quickly.
It seems the Lambda integration is overwriting the trace header for now, so it is hard to test. It might be done with a regular AWS integration, to SQS for example. We can work on this as a follow-up.
The implementation is pretty simple for now, I've written an AWS test to check how AWS populate the trace-id in a naive way.
Changes