Skip to content

Commit 0680037

Browse files
committed
Print warning instead of throw if fail to find role to set up x-ray
1 parent 62e2615 commit 0680037

File tree

2 files changed

+78
-59
lines changed

2 files changed

+78
-59
lines changed

serverless/src/tracing.ts

Lines changed: 62 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,10 @@ export enum TracingMode {
4848
NONE,
4949
}
5050

51-
function findIamRole(resources: Resources, lambda: LambdaFunction): IamRoleProperties | undefined {
51+
function findIamRoleFromCloudFormationTemplate(
52+
resources: Resources,
53+
lambda: LambdaFunction,
54+
): IamRoleProperties | undefined {
5255
const role = lambda.properties.Role;
5356
let roleKey;
5457
if (typeof role !== "string") {
@@ -79,58 +82,68 @@ export function getTracingMode(config: Configuration): TracingMode {
7982

8083
export function enableTracing(tracingMode: TracingMode, lambdas: LambdaFunction[], resources: Resources): void {
8184
if (tracingMode === TracingMode.XRAY || tracingMode === TracingMode.HYBRID) {
82-
log.debug("Enabling Xray tracing...");
83-
const xrayPolicies = {
84-
Effect: ALLOW,
85-
Action: [PUT_TRACE_SEGMENTS, PUT_TELEMETRY_RECORDS],
86-
Resource: ["*"],
87-
};
88-
log.debug(`Xray policies: ${xrayPolicies}`);
85+
enableXrayTracing(lambdas, resources);
86+
}
87+
if (tracingMode === TracingMode.HYBRID || tracingMode === TracingMode.DD_TRACE) {
88+
enableDatadogTracing(lambdas, tracingMode);
89+
}
90+
}
8991

90-
lambdas.forEach((lambda) => {
91-
const role = findIamRole(resources, lambda);
92+
function enableXrayTracing(lambdas: LambdaFunction[], resources: Resources): void {
93+
log.debug("Enabling Xray tracing...");
94+
const xrayPolicies = {
95+
Effect: ALLOW,
96+
Action: [PUT_TRACE_SEGMENTS, PUT_TELEMETRY_RECORDS],
97+
Resource: ["*"],
98+
};
99+
log.debug(`Xray policies: ${xrayPolicies}`);
92100

93-
if (role === undefined) {
94-
throw new MissingIamRoleError(
95-
`No AWS::IAM::Role resource was found for the function ${lambda.key} when adding xray tracing policies`,
96-
);
97-
}
101+
lambdas.forEach((lambda) => {
102+
const role = findIamRoleFromCloudFormationTemplate(resources, lambda);
103+
104+
if (role === undefined) {
105+
log.warn(
106+
`Failed to find the function ${lambda.key}'s role from the CloudFormation template when setting up xray tracing. \
107+
Please make sure the role already has the xray tracing policy. Follow the instructions to add the policy if you haven't done so. (TODO: add link)`,
108+
);
109+
return;
110+
}
111+
112+
log.debug(`Using IAM role: ${role}`);
98113

99-
log.debug(`Using IAM role: ${role}`);
100-
101-
if (role.Policies && role.Policies.length > 0) {
102-
const policy = role.Policies[0];
103-
const policyDocument = policy.PolicyDocument;
104-
if (policyDocument.Statement instanceof Array) {
105-
policyDocument.Statement.push(xrayPolicies);
106-
} else {
107-
const statement = policyDocument.Statement;
108-
policyDocument.Statement = [statement, xrayPolicies];
109-
}
114+
if (role.Policies && role.Policies.length > 0) {
115+
const policy = role.Policies[0];
116+
const policyDocument = policy.PolicyDocument;
117+
if (policyDocument.Statement instanceof Array) {
118+
policyDocument.Statement.push(xrayPolicies);
110119
} else {
111-
const policyName = { [FN_JOIN]: ["-", [lambda.key, POLICY]] };
112-
const policyDocument = {
113-
Version: POLICY_DOCUMENT_VERSION,
114-
Statement: xrayPolicies,
115-
};
116-
role.Policies = [{ PolicyName: policyName, PolicyDocument: policyDocument }];
120+
const statement = policyDocument.Statement;
121+
policyDocument.Statement = [statement, xrayPolicies];
117122
}
118-
lambda.properties.TracingConfig = { Mode: ACTIVE };
119-
});
120-
}
121-
if (tracingMode === TracingMode.HYBRID || tracingMode === TracingMode.DD_TRACE) {
122-
log.debug("Enabling ddtrace for all Lambda functions...");
123-
lambdas.forEach((lambda) => {
124-
const environment = lambda.properties.Environment ?? {};
125-
const envVariables = environment.Variables ?? {};
126-
if (!(DD_TRACE_ENABLED in envVariables)) {
127-
envVariables[DD_TRACE_ENABLED] = true;
128-
log.debug(`${lambda.properties.FunctionName} skipped as DD_TRACE_ENABLED was defined on a function level`);
129-
}
130-
envVariables[DD_MERGE_XRAY_TRACES] = tracingMode === TracingMode.HYBRID;
123+
} else {
124+
const policyName = { [FN_JOIN]: ["-", [lambda.key, POLICY]] };
125+
const policyDocument = {
126+
Version: POLICY_DOCUMENT_VERSION,
127+
Statement: xrayPolicies,
128+
};
129+
role.Policies = [{ PolicyName: policyName, PolicyDocument: policyDocument }];
130+
}
131+
lambda.properties.TracingConfig = { Mode: ACTIVE };
132+
});
133+
}
131134

132-
environment.Variables = envVariables;
133-
lambda.properties.Environment = environment;
134-
});
135-
}
135+
function enableDatadogTracing(lambdas: LambdaFunction[], tracingMode: TracingMode): void {
136+
log.debug("Enabling ddtrace for all Lambda functions...");
137+
lambdas.forEach((lambda) => {
138+
const environment = lambda.properties.Environment ?? {};
139+
const envVariables = environment.Variables ?? {};
140+
if (!(DD_TRACE_ENABLED in envVariables)) {
141+
envVariables[DD_TRACE_ENABLED] = true;
142+
log.debug(`${lambda.properties.FunctionName} skipped as DD_TRACE_ENABLED was defined on a function level`);
143+
}
144+
envVariables[DD_MERGE_XRAY_TRACES] = tracingMode === TracingMode.HYBRID;
145+
146+
environment.Variables = envVariables;
147+
lambda.properties.Environment = environment;
148+
});
136149
}

serverless/test/tracing.spec.ts

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { enableTracing, TracingMode, IamRoleProperties, MissingIamRoleError } from "../src/tracing";
22
import { ArchitectureType, LambdaFunction, RuntimeType } from "../src/layer";
3+
import log from "loglevel";
34

45
function mockLambdaFunction() {
56
return {
@@ -174,8 +175,9 @@ describe("enableTracing", () => {
174175
expect(resources.HelloWorldFunctionRole.Properties.Policies).toBeUndefined();
175176
});
176177

177-
it("throws MissingIamRoleError if IAM role is not found", () => {
178-
const tracingMode = TracingMode.XRAY;
178+
it("prints a warning if X-Ray tracing is enabled but IAM role is not found", () => {
179+
const warnSpy = jest.spyOn(log, "warn").mockImplementation(() => {});
180+
const tracingMode = TracingMode.HYBRID;
179181
const lambda: LambdaFunction = {
180182
properties: {
181183
Handler: "app.handler",
@@ -204,13 +206,17 @@ describe("enableTracing", () => {
204206
};
205207

206208
expect.assertions(2);
207-
try {
208-
enableTracing(tracingMode, [lambda], resources);
209-
} catch (err: any) {
210-
expect(err).toBeInstanceOf(MissingIamRoleError);
211-
expect(err.message).toEqual(
212-
`No AWS::IAM::Role resource was found for the function ${lambda.key} when adding xray tracing policies`,
213-
);
214-
}
209+
enableTracing(tracingMode, [lambda], resources);
210+
expect(warnSpy).toHaveBeenCalledWith(
211+
"Failed to find the function HelloWorldFunction's role from the CloudFormation template when setting up xray tracing. \
212+
Please make sure the role already has the xray tracing policy. Follow the instructions to add the policy if you haven't done so. (TODO: add link)",
213+
);
214+
expect(lambda.properties.Environment).toMatchObject({
215+
Variables: {
216+
DD_MERGE_XRAY_TRACES: true,
217+
},
218+
});
219+
220+
warnSpy.mockRestore();
215221
});
216222
});

0 commit comments

Comments
 (0)