Skip to content

Commit ebc9ea8

Browse files
committed
In AWS Lambda instrumentation, extend invocation span start time back to Lambda environment startup time on coldstart
1 parent 5eb61d8 commit ebc9ea8

File tree

2 files changed

+37
-6
lines changed

2 files changed

+37
-6
lines changed

plugins/node/opentelemetry-instrumentation-aws-lambda/src/instrumentation.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,9 @@ export class AwsLambdaInstrumentation extends InstrumentationBase<AwsLambdaInstr
232232
const span = plugin.tracer.startSpan(
233233
name,
234234
{
235+
// For coldstarts,
236+
// use Lambda start time as invocation span start time to take initialization time into account.
237+
startTime: requestIsColdStart ? lambdaStartTime : Date.now(),
235238
kind: SpanKind.SERVER,
236239
attributes: {
237240
[SEMATTRS_FAAS_EXECUTION]: context.awsRequestId,

plugins/node/opentelemetry-instrumentation-aws-lambda/test/integrations/lambda-handler.test.ts

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ import {
5151
defaultTextMapGetter,
5252
} from '@opentelemetry/api';
5353
import { AWSXRayPropagator } from '@opentelemetry/propagator-aws-xray';
54-
import { W3CTraceContextPropagator } from '@opentelemetry/core';
54+
import { hrTimeToMilliseconds, W3CTraceContextPropagator } from '@opentelemetry/core';
5555
import { AWSXRayLambdaPropagator } from '@opentelemetry/propagator-aws-xray-lambda';
5656

5757
const memoryExporter = new InMemorySpanExporter();
@@ -266,10 +266,15 @@ describe('lambda handler', () => {
266266
});
267267

268268
it('should record coldstart', async () => {
269-
initializeHandler('lambda-test/sync.handler');
269+
const time0 = Date.now();
270+
initializeHandler('lambda-test/sync.handler', { lambdaStartTime: time0 });
271+
272+
// Simulate initialization time
273+
await new Promise(resolve => setTimeout(resolve, 10));
270274

271275
const handlerModule = lambdaRequire('lambda-test/sync');
272276

277+
const time1 = Date.now();
273278
const result1 = await new Promise((resolve, reject) => {
274279
handlerModule.handler('arg', ctx, (err: Error, res: any) => {
275280
if (err) {
@@ -280,6 +285,7 @@ describe('lambda handler', () => {
280285
});
281286
});
282287

288+
const time2 = Date.now();
283289
const result2 = await new Promise((resolve, reject) => {
284290
handlerModule.handler('arg', ctx, (err: Error, res: any) => {
285291
if (err) {
@@ -298,18 +304,28 @@ describe('lambda handler', () => {
298304
assertSpanSuccess(span1);
299305
assert.strictEqual(span1.parentSpanId, undefined);
300306
assert.strictEqual(span1.attributes[SEMATTRS_FAAS_COLDSTART], true);
307+
// Since it is coldstart, invocation span start time should be equal to lambda start time
308+
assert.strictEqual(hrTimeToMilliseconds(span1.startTime), time0);
309+
// Since it is coldstart, invocation span start time should be before actual handler call time
310+
assert.ok(hrTimeToMilliseconds(span1.startTime) < time1);
301311

302312
assert.strictEqual(result2, 'ok');
303313
assertSpanSuccess(span2);
304314
assert.strictEqual(span2.parentSpanId, undefined);
305315
assert.strictEqual(span2.attributes[SEMATTRS_FAAS_COLDSTART], false);
316+
// Since it is warm invocation, invocation span start time should be after than lambda start time
317+
assert.ok(hrTimeToMilliseconds(span2.startTime) > time0);
318+
// Since it is warm invocation, invocation span start time should be equal or after than handler call time
319+
assert.ok(hrTimeToMilliseconds(span2.startTime) >= time2);
306320
});
307321

308322
it('should record coldstart with provisioned concurrency', async () => {
309323
process.env.AWS_LAMBDA_INITIALIZATION_TYPE = 'provisioned-concurrency';
310324

311-
initializeHandler('lambda-test/sync.handler');
325+
const time0 = Date.now() - 1;
326+
initializeHandler('lambda-test/sync.handler', { lambdaStartTime: time0 });
312327

328+
const time1 = Date.now();
313329
const result = await new Promise((resolve, reject) => {
314330
lambdaRequire('lambda-test/sync').handler(
315331
'arg',
@@ -323,20 +339,26 @@ describe('lambda handler', () => {
323339
}
324340
);
325341
});
342+
326343
assert.strictEqual(result, 'ok');
327344
const spans = memoryExporter.getFinishedSpans();
328345
const [span] = spans;
346+
329347
assert.strictEqual(spans.length, 1);
330348
assertSpanSuccess(span);
331349
assert.strictEqual(span.parentSpanId, undefined);
332350
assert.strictEqual(span.attributes[SEMATTRS_FAAS_COLDSTART], false);
351+
// Since it is warm invocation, invocation span start time should be after than lambda start time
352+
assert.ok(hrTimeToMilliseconds(span.startTime) > time0);
353+
// Since it is warm invocation, invocation span start time should be equal or after than handler call time
354+
assert.ok(hrTimeToMilliseconds(span.startTime) >= time1);
333355
});
334356

335357
it('should record coldstart with proactive initialization', async () => {
336-
initializeHandler('lambda-test/sync.handler', {
337-
lambdaStartTime: Date.now() - 2 * lambdaMaxInitInMilliseconds,
338-
});
358+
const time0 = Date.now() - 2 * lambdaMaxInitInMilliseconds;
359+
initializeHandler('lambda-test/sync.handler', { lambdaStartTime: time0 });
339360

361+
const time1 = Date.now();
340362
const result = await new Promise((resolve, reject) => {
341363
lambdaRequire('lambda-test/sync').handler(
342364
'arg',
@@ -350,13 +372,19 @@ describe('lambda handler', () => {
350372
}
351373
);
352374
});
375+
353376
assert.strictEqual(result, 'ok');
354377
const spans = memoryExporter.getFinishedSpans();
355378
const [span] = spans;
379+
356380
assert.strictEqual(spans.length, 1);
357381
assertSpanSuccess(span);
358382
assert.strictEqual(span.parentSpanId, undefined);
359383
assert.strictEqual(span.attributes[SEMATTRS_FAAS_COLDSTART], false);
384+
// Since it is warm invocation, invocation span start time should be after than lambda start time
385+
assert.ok(hrTimeToMilliseconds(span.startTime) > time0);
386+
// Since it is warm invocation, invocation span start time should be equal or after than handler call time
387+
assert.ok(hrTimeToMilliseconds(span.startTime) >= time1);
360388
});
361389

362390
it('should record error', async () => {

0 commit comments

Comments
 (0)