Skip to content

Commit 54c0841

Browse files
committed
feat: report url for lambda invoked via api gateway
1 parent d30c85c commit 54c0841

File tree

2 files changed

+63
-0
lines changed

2 files changed

+63
-0
lines changed

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

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,15 @@ import {
3838
TraceFlags,
3939
TracerProvider,
4040
ROOT_CONTEXT,
41+
Attributes,
4142
} from '@opentelemetry/api';
4243
import {
4344
AWSXRAY_TRACE_ID_HEADER,
4445
AWSXRayPropagator,
4546
} from '@opentelemetry/propagator-aws-xray';
4647
import {
4748
SEMATTRS_FAAS_EXECUTION,
49+
SEMATTRS_HTTP_URL,
4850
SEMRESATTRS_CLOUD_ACCOUNT_ID,
4951
SEMRESATTRS_FAAS_ID,
5052
} from '@opentelemetry/semantic-conventions';
@@ -203,6 +205,7 @@ export class AwsLambdaInstrumentation extends InstrumentationBase<AwsLambdaInstr
203205
AwsLambdaInstrumentation._extractAccountId(
204206
context.invokedFunctionArn
205207
),
208+
...AwsLambdaInstrumentation._extractOtherEventFields(event),
206209
},
207210
},
208211
parent
@@ -385,6 +388,41 @@ export class AwsLambdaInstrumentation extends InstrumentationBase<AwsLambdaInstr
385388
return propagation.extract(otelContext.active(), httpHeaders, headerGetter);
386389
}
387390

391+
private static _extractOtherEventFields(event: any): Attributes {
392+
const answer: Attributes = {};
393+
const fullUrl = this._extractFullUrl(event);
394+
if (fullUrl) {
395+
answer[SEMATTRS_HTTP_URL] = fullUrl;
396+
}
397+
return answer;
398+
}
399+
400+
private static _extractFullUrl(event: any): string | undefined {
401+
// API gateway encodes a lot of url information in various places to recompute this
402+
if (!event.headers || !event.path) {
403+
return undefined;
404+
}
405+
let answer = '';
406+
if (event.headers['x-forwarded-proto']) {
407+
answer += event.headers['x-forwarded-proto'] + '://';
408+
}
409+
if (event.headers['host']) {
410+
answer += event.headers['host'];
411+
}
412+
answer += event.path;
413+
if (event.queryStringParameters) {
414+
let first = true;
415+
for (const key in event.queryStringParameters) {
416+
answer += first ? '?' : '&';
417+
answer += encodeURIComponent(key);
418+
answer += '=';
419+
answer += encodeURIComponent(event.queryStringParameters[key]);
420+
first = false;
421+
}
422+
}
423+
return answer.length === 0 ? undefined : answer;
424+
}
425+
388426
private static _determineParent(
389427
event: any,
390428
context: Context,

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import * as assert from 'assert';
3535
import {
3636
SEMATTRS_EXCEPTION_MESSAGE,
3737
SEMATTRS_FAAS_EXECUTION,
38+
SEMATTRS_HTTP_URL,
3839
SEMRESATTRS_FAAS_NAME,
3940
} from '@opentelemetry/semantic-conventions';
4041
import {
@@ -983,4 +984,28 @@ describe('lambda handler', () => {
983984
assert.strictEqual(span.parentSpanId, undefined);
984985
});
985986
});
987+
988+
describe('url parsing', () => {
989+
it('pulls url from api gateway events', async () => {
990+
initializeHandler('lambda-test/sync.handler');
991+
const event = {
992+
path: '/lambda/test/path',
993+
headers: {
994+
host: 'www.example.com',
995+
'x-forwarded-proto': 'http',
996+
},
997+
queryStringParameters: {
998+
key: 'value',
999+
},
1000+
};
1001+
1002+
await lambdaRequire('lambda-test/sync').handler(event, ctx, () => {});
1003+
const [span] = memoryExporter.getFinishedSpans();
1004+
assert.strictEqual(
1005+
span.attributes[SEMATTRS_HTTP_URL],
1006+
'http://www.example.com/lambda/test/path?key=value'
1007+
);
1008+
console.log(span);
1009+
});
1010+
});
9861011
});

0 commit comments

Comments
 (0)