Skip to content

Commit 4fef215

Browse files
feat: create init/overhead duration spans (#29)
1 parent 5ce0a1f commit 4fef215

22 files changed

Lines changed: 958 additions & 402 deletions

integration-tests/tests/src/test-dockerized-lambda.test.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ const verifyDockerizedInvocation = async (functionName: string, runtime: string)
4646
span = spanPayload.resourceSpans[0].scopeSpans[0].spans[0];
4747
const spanAttributes = getAttributesMap(span.attributes);
4848
expect(spanAttributes['faas.invocation_id'].stringValue).toEqual(invocationId);
49-
expect(spanAttributes['faas.init_duration'].doubleValue).toBeGreaterThan(0);
5049

5150
const resourceAttributes = getAttributesMap(spanPayload?.resourceSpans[0].resource.attributes);
5251
expect(resourceAttributes['service.name'].stringValue).toEqual(functionName);

integration-tests/tests/src/test-java-exception.test.ts

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,26 @@ const verifySuccessInvocation = async (functionName: string, invocationEnd: bool
2929
});
3030

3131
const spanPayload = await spanResponse.json() as any;
32-
expect(spanPayload?.resourceSpans.length).toEqual(1);
33-
expect(spanPayload?.resourceSpans[0].scopeSpans.length).toEqual(1);
3432
const expectedScopeName = traced ? "io.opentelemetry.aws-lambda-events-2.2" : "opentelemetry.instrumentation.aws_lambda";
35-
expect(spanPayload?.resourceSpans[0].scopeSpans[0].scope.name).toEqual(expectedScopeName);
36-
expect(spanPayload?.resourceSpans[0].scopeSpans[0].spans.length).toEqual(1);
37-
const resourceAttributes = getAttributesMap(spanPayload?.resourceSpans[0].resource.attributes);
38-
expect(resourceAttributes['service.name'].stringValue).toEqual(functionName);
33+
34+
// Find the Lambda instrumentation scope (supplementary spans may also be present)
35+
let lambdaScopeSpan = null;
36+
let lambdaResource = null;
37+
for (const rs of (spanPayload?.resourceSpans ?? [])) {
38+
for (const ss of (rs.scopeSpans ?? [])) {
39+
if (ss.scope?.name === expectedScopeName) {
40+
lambdaScopeSpan = ss;
41+
lambdaResource = rs.resource;
42+
}
43+
}
44+
}
45+
expect(lambdaScopeSpan).toBeDefined();
46+
expect(lambdaScopeSpan!.spans.length).toEqual(1);
3947
// check span attributes
40-
span = spanPayload.resourceSpans[0].scopeSpans[0].spans[0];
48+
span = lambdaScopeSpan!.spans[0];
49+
50+
const resourceAttributes = getAttributesMap(lambdaResource.attributes);
51+
expect(resourceAttributes['service.name'].stringValue).toEqual(functionName);
4152
const spanAttributes = getAttributesMap(span.attributes);
4253
expect(spanAttributes['faas.invocation_id'].stringValue).toEqual(invocationId);
4354

@@ -80,17 +91,14 @@ const verifySuccessInvocation = async (functionName: string, invocationEnd: bool
8091
if (!invocationEnd) {
8192
logsToBeChecked.push({ message: 'REPORT RequestId: ' });
8293
}
83-
const reportLog = await checkLogs({
94+
await checkLogs({
8495
invocationId: invocationId!,
8596
functionName,
8697
traceId: traceId!,
8798
parentSpanId: parentSpanId!,
8899
success: true,
89100
logsToBeChecked
90101
});
91-
if (!invocationEnd) {
92-
checkSpanAttributesFromReport(reportLog, span);
93-
}
94102
}
95103

96104
describe.concurrent('Lambda invocation', () => {

integration-tests/tests/src/test-java-success.test.ts

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@ import { setTimeout as delay } from 'node:timers/promises';
33
import { describe, expect, it } from 'vitest';
44
import { DASH0_ENDPOINT, DASH0_TOKEN, MAX_ATTEMPTS, RETRY_DELAY_MS } from "./config";
55
import {
6-
checkHttpSpan,
76
checkLogs,
87
checkResourceAttributes,
9-
checkSpanAttributesFromReport,
8+
checkSupplementarySpans,
109
getAttributesMap, LogToCheck,
1110
getRequestPayload,
1211
invokeFunction, runAllTests
@@ -18,6 +17,7 @@ const verifySuccessInvocation = async (functionName: string, invocationEnd: bool
1817

1918
let traceId: string | undefined = undefined;
2019
let parentSpanId: string | undefined = undefined;
20+
let rootSpanId: string | undefined = undefined;
2121
let span = undefined
2222
for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
2323
await delay(RETRY_DELAY_MS);
@@ -34,21 +34,30 @@ const verifySuccessInvocation = async (functionName: string, invocationEnd: bool
3434
});
3535

3636
const spanPayload = await spanResponse.json() as any;
37-
expect(spanPayload?.resourceSpans.length).toEqual(1);
38-
expect(spanPayload?.resourceSpans[0].scopeSpans.length).toEqual(1);
37+
// Find the Lambda instrumentation scope (supplementary spans may also be present)
3938
const expectedScopeName = traced ? "io.opentelemetry.aws-lambda-events-2.2" : "opentelemetry.instrumentation.aws_lambda";
40-
expect(spanPayload?.resourceSpans[0].scopeSpans[0].scope.name).toEqual(expectedScopeName);
41-
expect(spanPayload?.resourceSpans[0].scopeSpans[0].spans.length).toEqual(1);
42-
const resourceAttributes = getAttributesMap(spanPayload?.resourceSpans[0].resource.attributes);
39+
let lambdaScopeSpan = null;
40+
let lambdaResource = null;
41+
for (const rs of (spanPayload?.resourceSpans ?? [])) {
42+
for (const ss of (rs.scopeSpans ?? [])) {
43+
if (ss.scope?.name === expectedScopeName) {
44+
lambdaScopeSpan = ss;
45+
lambdaResource = rs.resource;
46+
}
47+
}
48+
}
49+
expect(lambdaScopeSpan).toBeDefined();
50+
expect(lambdaScopeSpan!.spans.length).toEqual(1);
51+
const resourceAttributes = getAttributesMap(lambdaResource!.attributes);
4352
expect(resourceAttributes['service.name'].stringValue).toEqual(functionName);
44-
checkResourceAttributes(spanPayload.resourceSpans[0].resource.attributes, functionName);
53+
checkResourceAttributes(lambdaResource!.attributes, functionName);
4554
// check span attributes
46-
span = spanPayload.resourceSpans[0].scopeSpans[0].spans[0];
55+
span = lambdaScopeSpan!.spans[0];
4756
const spanAttributes = getAttributesMap(span.attributes);
4857
expect(spanAttributes['faas.invocation_id'].stringValue).toEqual(invocationId);
49-
expect(spanAttributes['faas.init_duration'].doubleValue).toBeGreaterThan(0);
5058
traceId = span.traceId;
5159
parentSpanId = span.spanId;
60+
rootSpanId = span.parentSpanId;
5261
break;
5362
} catch (error) {
5463
console.error(`Error fetching spans on attempt ${attempt}:`, error);
@@ -66,17 +75,25 @@ const verifySuccessInvocation = async (functionName: string, invocationEnd: bool
6675
if (!invocationEnd) {
6776
logsToBeChecked.push({ message: 'REPORT RequestId: ' });
6877
}
69-
const reportLog = await checkLogs({
78+
await checkLogs({
7079
invocationId: invocationId!,
7180
functionName,
7281
traceId: traceId!,
7382
parentSpanId: parentSpanId!,
7483
success: true,
7584
logsToBeChecked
7685
});
77-
if (!invocationEnd) {
78-
checkSpanAttributesFromReport(reportLog, span);
86+
87+
// Supplementary spans are sent on the next invocation; trigger one if needed
88+
if (invocationEnd) {
89+
await invokeFunction(functionName, true, false);
7990
}
91+
await checkSupplementarySpans({
92+
invocationId: invocationId!,
93+
functionName,
94+
traceId: traceId!,
95+
rootSpanId: rootSpanId!,
96+
});
8097
}
8198

8299
describe.concurrent('Lambdainvocation', () => {

integration-tests/tests/src/test-java-timeout.test.ts

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@ import { describe, expect, it } from 'vitest';
44
import { DASH0_ENDPOINT, DASH0_TOKEN, MAX_ATTEMPTS, RETRY_DELAY_MS } from "./config";
55
import {
66
checkException,
7-
checkHttpSpan,
87
checkLogs,
98
checkResourceAttributes,
10-
checkSpanAttributesFromReport, LogToCheck,
9+
checkSupplementarySpans, LogToCheck,
1110
getAttributesMap,
1211
getRequestPayload,
1312
invokeFunction, runAllTests
@@ -19,6 +18,7 @@ const verifySuccessInvocation = async (functionName: string, invocationEnd: bool
1918

2019
let traceId: string | undefined = undefined;
2120
let parentSpanId: string | undefined = undefined;
21+
let rootSpanId: string | undefined = undefined;
2222
let span = undefined
2323
for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
2424
await delay(RETRY_DELAY_MS);
@@ -35,20 +35,29 @@ const verifySuccessInvocation = async (functionName: string, invocationEnd: bool
3535
});
3636

3737
const spanPayload = await spanResponse.json() as any;
38-
expect(spanPayload?.resourceSpans.length).toEqual(1);
39-
expect(spanPayload?.resourceSpans[0].scopeSpans.length).toEqual(1);
40-
expect(spanPayload?.resourceSpans[0].scopeSpans[0].scope.name).toEqual("opentelemetry.instrumentation.aws_lambda");
41-
expect(spanPayload?.resourceSpans[0].scopeSpans[0].spans.length).toEqual(1);
42-
const resourceAttributes = getAttributesMap(spanPayload?.resourceSpans[0].resource.attributes);
38+
// Find the Lambda instrumentation scope (supplementary spans may also be present)
39+
let lambdaScopeSpan = null;
40+
let lambdaResource = null;
41+
for (const rs of (spanPayload?.resourceSpans ?? [])) {
42+
for (const ss of (rs.scopeSpans ?? [])) {
43+
if (ss.scope?.name === 'opentelemetry.instrumentation.aws_lambda') {
44+
lambdaScopeSpan = ss;
45+
lambdaResource = rs.resource;
46+
}
47+
}
48+
}
49+
expect(lambdaScopeSpan).toBeDefined();
50+
expect(lambdaScopeSpan!.spans.length).toEqual(1);
51+
const resourceAttributes = getAttributesMap(lambdaResource!.attributes);
4352
expect(resourceAttributes['service.name'].stringValue).toEqual(functionName);
44-
checkResourceAttributes(spanPayload.resourceSpans[0].resource.attributes, functionName);
53+
checkResourceAttributes(lambdaResource!.attributes, functionName);
4554
// check span attributes
46-
span = spanPayload.resourceSpans[0].scopeSpans[0].spans[0];
55+
span = lambdaScopeSpan!.spans[0];
4756
const spanAttributes = getAttributesMap(span.attributes);
4857
expect(spanAttributes['faas.invocation_id'].stringValue).toEqual(invocationId);
49-
expect(spanAttributes['faas.init_duration'].doubleValue).toBeGreaterThan(0);
5058
traceId = span.traceId;
5159
parentSpanId = span.spanId;
60+
rootSpanId = span.parentSpanId;
5261
checkException(span, 'timeout');
5362
break;
5463
} catch (error) {
@@ -66,14 +75,26 @@ const verifySuccessInvocation = async (functionName: string, invocationEnd: bool
6675
if (!invocationEnd) {
6776
logsToBeChecked.push({ message: "Status: timeout" });
6877
}
69-
const reportLog = await checkLogs({
78+
await checkLogs({
7079
invocationId: invocationId!,
7180
functionName,
7281
traceId: traceId!,
7382
parentSpanId: parentSpanId!,
7483
success: false,
7584
logsToBeChecked
7685
});
86+
87+
// Supplementary spans are sent on the next invocation; trigger one if needed
88+
if (invocationEnd) {
89+
await invokeFunction(functionName, true, true);
90+
}
91+
await checkSupplementarySpans({
92+
invocationId: invocationId!,
93+
functionName,
94+
traceId: traceId!,
95+
rootSpanId: rootSpanId!,
96+
runtimeError: true,
97+
});
7798
}
7899

79100
describe.concurrent('Lambdainvocation java timeout', () => {

integration-tests/tests/src/test-node-exception.test.ts

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,21 @@ const verifySuccessInvocation = async (functionName: string, invocationEnd: bool
2929
});
3030

3131
const spanPayload = await spanResponse.json() as any;
32-
expect(spanPayload?.resourceSpans.length).toEqual(1);
33-
expect(spanPayload?.resourceSpans[0].scopeSpans.length).toEqual(1);
3432
const expectedScopeName = traced ? "@opentelemetry/instrumentation-aws-lambda" : "opentelemetry.instrumentation.aws_lambda";
35-
expect(spanPayload?.resourceSpans[0].scopeSpans[0].scope.name).toEqual(expectedScopeName);
36-
expect(spanPayload?.resourceSpans[0].scopeSpans[0].spans.length).toEqual(1);
33+
// Find the Lambda instrumentation scope (supplementary spans may also be present)
34+
let lambdaScopeSpan = null;
35+
for (const rs of (spanPayload?.resourceSpans ?? [])) {
36+
for (const ss of (rs.scopeSpans ?? [])) {
37+
if (ss.scope?.name === expectedScopeName) {
38+
lambdaScopeSpan = ss;
39+
}
40+
}
41+
}
42+
expect(lambdaScopeSpan).toBeDefined();
43+
expect(lambdaScopeSpan!.spans.length).toEqual(1);
3744
// check span attributes
38-
span = spanPayload.resourceSpans[0].scopeSpans[0].spans[0];
45+
span = lambdaScopeSpan!.spans[0];
46+
3947
const spanAttributes = getAttributesMap(span.attributes);
4048
expect(spanAttributes['faas.invocation_id'].stringValue).toEqual(invocationId);
4149

@@ -74,17 +82,14 @@ const verifySuccessInvocation = async (functionName: string, invocationEnd: bool
7482
if (!invocationEnd) {
7583
logsToBeChecked.push({ message: 'REPORT RequestId: ' });
7684
}
77-
const reportLog = await checkLogs({
85+
await checkLogs({
7886
invocationId: invocationId!,
7987
functionName,
8088
traceId: traceId!,
8189
parentSpanId: parentSpanId!,
8290
success: true,
8391
logsToBeChecked
8492
});
85-
if (!invocationEnd) {
86-
checkSpanAttributesFromReport(reportLog, span);
87-
}
8893
}
8994

9095
describe.concurrent('Lambda invocation', () => {

integration-tests/tests/src/test-node-success.test.ts

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
checkHttpSpan,
77
checkLogs,
88
checkResourceAttributes,
9-
checkSpanAttributesFromReport,
9+
checkSupplementarySpans,
1010
getAttributesMap,
1111
getRequestPayload,
1212
invokeFunction, LogToCheck, runAllTests
@@ -19,6 +19,7 @@ const verifySuccessInvocation = async (functionName: string, invocationEnd: bool
1919

2020
let traceId: string | undefined = undefined;
2121
let parentSpanId: string | undefined = undefined;
22+
let rootSpanId: string | undefined = undefined;
2223
let span = undefined
2324
for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
2425
await delay(RETRY_DELAY_MS);
@@ -35,22 +36,32 @@ const verifySuccessInvocation = async (functionName: string, invocationEnd: bool
3536
});
3637

3738
const spanPayload = await spanResponse.json() as any;
38-
expect(spanPayload?.resourceSpans.length).toEqual(1);
39-
expect(spanPayload?.resourceSpans[0].scopeSpans.length).toEqual(1);
39+
// Find the Lambda instrumentation scope (supplementary spans may also be present)
4040
const expectedScopeName = traced ? "@opentelemetry/instrumentation-aws-lambda" : "opentelemetry.instrumentation.aws_lambda";
41-
expect(spanPayload?.resourceSpans[0].scopeSpans[0].scope.name).toEqual(expectedScopeName);
42-
expect(spanPayload?.resourceSpans[0].scopeSpans[0].spans.length).toEqual(1);
41+
let lambdaScopeSpan = null;
42+
let lambdaResource = null;
43+
for (const rs of (spanPayload?.resourceSpans ?? [])) {
44+
for (const ss of (rs.scopeSpans ?? [])) {
45+
if (ss.scope?.name === expectedScopeName) {
46+
lambdaScopeSpan = ss;
47+
lambdaResource = rs.resource;
48+
}
49+
}
50+
}
51+
expect(lambdaScopeSpan).toBeDefined();
52+
expect(lambdaScopeSpan!.spans.length).toEqual(1);
4353
// check span attributes
44-
span = spanPayload.resourceSpans[0].scopeSpans[0].spans[0];
54+
span = lambdaScopeSpan!.spans[0];
4555
const spanAttributes = getAttributesMap(span.attributes);
4656
expect(spanAttributes['faas.invocation_id'].stringValue).toEqual(invocationId);
4757

48-
const resourceAttributes = getAttributesMap(spanPayload.resourceSpans[0].resource.attributes);
58+
const resourceAttributes = getAttributesMap(lambdaResource!.attributes);
4959
expect(JSON.parse(resourceAttributes['process.environ'].stringValue)['MASKED_FIELD']).toEqual('****');
50-
checkResourceAttributes(spanPayload.resourceSpans[0].resource.attributes, functionName);
60+
checkResourceAttributes(lambdaResource!.attributes, functionName);
5161

5262
traceId = span.traceId;
5363
parentSpanId = span.spanId;
64+
rootSpanId = span.parentSpanId;
5465
break;
5566
} catch (error) {
5667
console.error(`Error fetching spans on attempt ${attempt}:`, error);
@@ -85,17 +96,25 @@ const verifySuccessInvocation = async (functionName: string, invocationEnd: bool
8596
if (!invocationEnd) {
8697
logsToBeChecked.push({ message: 'REPORT RequestId: ' });
8798
}
88-
const reportLog = await checkLogs({
99+
await checkLogs({
89100
invocationId: invocationId!,
90101
functionName,
91102
traceId: traceId!,
92103
parentSpanId: parentSpanId!,
93104
success: true,
94105
logsToBeChecked
95106
});
96-
if (!invocationEnd) {
97-
checkSpanAttributesFromReport(reportLog, span);
107+
108+
// Supplementary spans are sent on the next invocation; trigger one if needed
109+
if (invocationEnd) {
110+
await invokeFunction(functionName, true, false);
98111
}
112+
await checkSupplementarySpans({
113+
invocationId: invocationId!,
114+
functionName,
115+
traceId: traceId!,
116+
rootSpanId: rootSpanId!,
117+
});
99118
}
100119

101120
describe.concurrent('Lambda invocation', () => {

0 commit comments

Comments
 (0)