Skip to content

Bug: fetch requests don't forward X-Ray trace header #3467

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

Closed
dreamorosi opened this issue Jan 11, 2025 · 2 comments · Fixed by #3470
Closed

Bug: fetch requests don't forward X-Ray trace header #3467

dreamorosi opened this issue Jan 11, 2025 · 2 comments · Fixed by #3470
Assignees
Labels
bug Something isn't working completed This item is complete and has been merged/shipped tracer This item relates to the Tracer Utility

Comments

@dreamorosi
Copy link
Contributor

Expected Behavior

When I make requests using the Fetch API and using Tracer, the X-Amzn-Trace-Id header should be constructed and forwarded along with the request so that I can get a full trace for a request.

For example, if I have an API Gateway A -> Lambda A -> API Gateway B -> Lambda B, and the first function in the chain is instrumented with Tracer, we should be able to see a trace like this:

Image

This is already supported when using the global http and https modules and their derivatives (i.e. axios) but doesn't work in our implementation when using Tracer with fetch.

Current Behavior

Currently the setup described above generates two disconnected traces, one for each API Gateway -> Lambda pair.

Code snippet

import { Logger } from "@aws-lambda-powertools/logger";
import { Tracer } from "@aws-lambda-powertools/tracer";

const logger = new Logger();
const tracer = new Tracer();

export const handler = async (event: { userId: number }) => {
	const parent = tracer.getSegment();
	const segment = parent?.addNewSubsegment("### functionA handler");
	segment && tracer.setSegment(segment);

	await fetch(`${process.env.API_URL}/functionB`, {
		method: "POST",
		body: JSON.stringify({ userId: event.userId }),
	});

	segment?.close();
	parent && tracer.setSegment(parent);

	return {
		statusCode: 200,
	};
};

Steps to Reproduce

  1. Deploy the infrastructure below
/// <reference path="./.sst/platform/config.d.ts" />

export default $config({
	app(input) {
		return {
			name: "missing-trace",
			removal: input?.stage === "production" ? "retain" : "remove",
			home: "aws",
		};
	},
	async run() {
		$transform(sst.aws.Function, (args) => {
			args.permissions = [
				{
					actions: [
						"xray:PutTraceSegments",
						"xray:PutTelemetryRecords",
						"xray:GetSamplingRules",
						"xray:GetSamplingTargets",
						"xray:GetSamplingStatisticSummaries",
					],
					resources: ["*"],
				},
			];
			args.transform = {
				function(args, opts, name) {
					args.tracingConfig = {
						mode: "Active",
					};
				},
			};
		});

		const apiB = new sst.aws.ApiGatewayV1("ApiB", {
			transform: {
				stage(args, opts, name) {
					args.xrayTracingEnabled = true;
				},
			},
		});

		apiB.route("POST /functionB", {
			handler: "src/functionB.handler",
			runtime: "nodejs22.x",
			timeout: "30 seconds",
			memory: "256 MB",
			logging: {
				retention: "1 day",
			},
		});

		apiB.deploy();

		const apiA = new sst.aws.ApiGatewayV1("ApiA", {
			transform: {
				stage(args, opts, name) {
					args.xrayTracingEnabled = true;
				},
			},
		});

		apiA.route("POST /functionA", {
			handler: "src/functionA.handler",
			runtime: "nodejs22.x",
			timeout: "30 seconds",
			memory: "256 MB",
			logging: {
				retention: "1 day",
			},
			environment: {
				API_URL: apiB.url,
			},
		});

		apiA.deploy();
	},
});
  1. Make a request to the first API Gateway endpoint (i.e. http POST https://api-id.execute-api.eu-west-1.amazonaws.com/stage/functionA userId=1
  2. Observe the traces

Possible Solution

Our implementation of the fetch module diverges significantly from the one in aws-xray-sdk-node-fetch. Their implementation relies on monkey patching, which as far as I can tell would only work with CJS.

On our side we decided (#1619) to instead use the node:diagnostics_channel which is the recommended way to instrument requests made with fetch.

During the implementation, we followed the types present in @types/node which suggest it's not possible to modify the Request object when instrumenting.

In reality however request object in the message has a addHeader() method that can be used to forward the X-Amzn-Trace-Id.

To make this work, we should construct the header to include the Root, Parent, and Sampled fields and add it to the request. I made a PoC of this and I already got it working. The screenshot at the top of the issue comes from a request instrumented with Tracer using Fetch.

Powertools for AWS Lambda (TypeScript) version

latest

AWS Lambda function runtime

22.x

Packaging format used

npm

Execution logs

@dreamorosi dreamorosi added bug Something isn't working confirmed The scope is clear, ready for implementation tracer This item relates to the Tracer Utility labels Jan 11, 2025
@dreamorosi dreamorosi self-assigned this Jan 11, 2025
@dreamorosi dreamorosi moved this from Triage to Working on it in Powertools for AWS Lambda (TypeScript) Jan 11, 2025
@github-project-automation github-project-automation bot moved this from Working on it to Coming soon in Powertools for AWS Lambda (TypeScript) Jan 14, 2025
Copy link
Contributor

⚠️ COMMENT VISIBILITY WARNING ⚠️

This issue is now closed. Please be mindful that future comments are hard for our team to see.

If you need more assistance, please either tag a team member or open a new issue that references this one.

If you wish to keep having a conversation with other community members under this issue feel free to do so.

@github-actions github-actions bot added pending-release This item has been merged and will be released soon and removed confirmed The scope is clear, ready for implementation labels Jan 14, 2025
Copy link
Contributor

This is now released under v2.13.0 version!

@github-actions github-actions bot added completed This item is complete and has been merged/shipped and removed pending-release This item has been merged and will be released soon labels Jan 14, 2025
@dreamorosi dreamorosi moved this from Coming soon to Shipped in Powertools for AWS Lambda (TypeScript) Jan 14, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working completed This item is complete and has been merged/shipped tracer This item relates to the Tracer Utility
Projects
1 participant