Skip to content

Commit 21d7db6

Browse files
committed
chore: add un-trace command
1 parent 551556e commit 21d7db6

File tree

5 files changed

+124
-11
lines changed

5 files changed

+124
-11
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"scripts": {
1212
"deploy": "yarn build && yarn turbo deploy --env-mode=loose --color",
1313
"auto-trace": "cd packages/api && yarn auto-trace",
14+
"un-trace": "cd packages/api && yarn un-trace",
1415
"build": "yarn turbo build --env-mode=loose --color",
1516
"test": "yarn turbo test --env-mode=loose --color",
1617
"start": "turbo dev --env-mode=loose --color",

packages/api/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"dev": "serverless offline start",
88
"deploy": "serverless deploy --verbose",
99
"auto-trace": "serverless invoke local -f main -d '{\"action\": \"auto-trace\"}'",
10+
"un-trace": "serverless invoke local -f main -d '{\"action\": \"un-trace\"}'",
1011
"test": "jest"
1112
},
1213
"dependencies": {
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import {
2+
GetFunctionCommand,
3+
LambdaClient,
4+
ListFunctionsCommand,
5+
UpdateFunctionConfigurationCommand,
6+
} from "@aws-sdk/client-lambda";
7+
import pLimit from "p-limit";
8+
9+
import Logger from "../lib/logger";
10+
11+
const lambdaExecWrapper = "/opt/nodejs/tracer_wrapper";
12+
const logger = new Logger("auto-trace");
13+
14+
const getAccountLambdas = async () => {
15+
const lambdaClient = new LambdaClient();
16+
17+
let nextToken = null;
18+
let lambdas = [];
19+
20+
do {
21+
const listFunctionsCommand = new ListFunctionsCommand({
22+
Marker: nextToken,
23+
MaxItems: 50,
24+
});
25+
const { Functions, NextMarker } =
26+
await lambdaClient.send(listFunctionsCommand);
27+
lambdas = lambdas.concat(Functions);
28+
nextToken = NextMarker;
29+
} while (nextToken);
30+
31+
return lambdas;
32+
};
33+
34+
const updateLambda = async (lambda, arnBase) => {
35+
const command = new UpdateFunctionConfigurationCommand({
36+
FunctionName: lambda.FunctionName,
37+
Layers: [
38+
...(lambda.Layers || [])
39+
.map((layer) => layer.Arn)
40+
.filter((arn) => !arn.startsWith(arnBase)),
41+
],
42+
Environment: {
43+
...(lambda.Environment || {}),
44+
Variables: {
45+
...(lambda.Environment?.Variables || {}),
46+
AUTO_TRACE_QUEUE_URL: undefined,
47+
AUTO_TRACE_QUEUE_REGION: undefined,
48+
AWS_LAMBDA_EXEC_WRAPPER: undefined,
49+
},
50+
},
51+
});
52+
53+
await new LambdaClient().send(command);
54+
};
55+
56+
const getLambdaTags = async (lambda) => {
57+
// try not to run into the 100 requests per second limit
58+
await new Promise((resolve) => setTimeout(resolve, 250));
59+
const lambdaClient = new LambdaClient();
60+
const { Tags } = await lambdaClient.send(
61+
new GetFunctionCommand({
62+
FunctionName: lambda.FunctionName,
63+
}),
64+
);
65+
66+
return Tags;
67+
};
68+
69+
export const unTrace = async () => {
70+
// Check if we know our Lambda Layer ARN
71+
const arn = process.env.LAMBDA_LAYER_ARN;
72+
const arnBase = arn?.substring(0, arn?.lastIndexOf(":") + 1);
73+
if (!arn || !arnBase) {
74+
throw new Error("LAMBDA_LAYER_ARN is not defined");
75+
}
76+
77+
// List all the lambda functions in the AWS account
78+
let lambdas = await getAccountLambdas();
79+
logger.info(`Found ${lambdas.length} lambdas in the account`);
80+
81+
// Update qualifying lambdas
82+
const limit = pLimit(4);
83+
await Promise.all(
84+
lambdas.map((lambda) =>
85+
limit(async () => {
86+
const layers = lambda.Layers || [];
87+
const envVars = lambda.Environment?.Variables || {};
88+
89+
const isTraceStack = envVars.LAMBDA_LAYER_ARN === arn;
90+
const isUpdating = lambda.LastUpdateStatus === "InProgress";
91+
const hasLayer = layers.find(({ Arn }) => Arn.startsWith(arnBase));
92+
const hasOtherWrapper =
93+
envVars.AWS_LAMBDA_EXEC_WRAPPER &&
94+
envVars.AWS_LAMBDA_EXEC_WRAPPER !== lambdaExecWrapper;
95+
96+
if (hasLayer && !isTraceStack && !isUpdating && !hasOtherWrapper) {
97+
try {
98+
await updateLambda(lambda, arnBase);
99+
logger.info(`✓ Removed layer from ${lambda.FunctionName}`);
100+
} catch (e) {
101+
logger.warn(`✗ Failed to update ${lambda.FunctionName}`, e);
102+
}
103+
}
104+
}),
105+
),
106+
);
107+
};

packages/api/src/index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import authRoute from "./routes/auth";
1010
import usersRoute from "./routes/users";
1111

1212
import { autoTrace } from "./events/auto-trace";
13+
import {unTrace} from "./events/un-trace";
1314
import { auth } from "./routes/auth/middleware";
1415

1516
const app = new Hono();
@@ -38,6 +39,9 @@ export const handler = (event, context) => {
3839
if (event.action === "auto-trace") {
3940
return autoTrace();
4041
}
42+
if (event.action === "un-trace") {
43+
return unTrace();
44+
}
4145

4246
return httpApp(event, context);
4347
};

packages/lambda-layer/lib/utils/httpSpansAgent.js

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
const { SQSClient, SendMessageCommand } = require("@aws-sdk/client-sqs");
2-
const { FetchHttpHandler } = require("@smithy/fetch-http-handler");
2+
// const { FetchHttpHandler } = require("@smithy/fetch-http-handler");
33

44
/*
55
* This module handles sending spans to an SQS queue.
@@ -16,7 +16,7 @@ exports.HttpSpansAgent = (() => {
1616
try {
1717
sqsClient = new SQSClient({
1818
region: process.env.AUTO_TRACE_QUEUE_REGION || "eu-west-1",
19-
requestHandler: new FetchHttpHandler({}),
19+
// requestHandler: new FetchHttpHandler({}),
2020
});
2121
} catch (error) {
2222
console.warn("Error initializing SQS client:", error);
@@ -46,15 +46,15 @@ exports.HttpSpansAgent = (() => {
4646

4747
// This is a workaround to avoid the fetch function being overridden
4848
// @ts-ignore
49-
if (fetch && fetch.__originalFetch) {
50-
const wrappedFetch = fetch;
51-
// @ts-ignore
52-
fetch = wrappedFetch.__originalFetch;
53-
setTimeout(() => {
54-
// @ts-ignore
55-
fetch = wrappedFetch;
56-
}, 1);
57-
}
49+
// if (fetch && fetch.__originalFetch) {
50+
// const wrappedFetch = fetch;
51+
// // @ts-ignore
52+
// fetch = wrappedFetch.__originalFetch;
53+
// setTimeout(() => {
54+
// // @ts-ignore
55+
// fetch = wrappedFetch;
56+
// }, 1);
57+
// }
5858

5959
await sqsClient.send(command);
6060
} catch (error) {

0 commit comments

Comments
 (0)