Skip to content

Commit

Permalink
feat: report url for lambda invoked via api gateway (#2404)
Browse files Browse the repository at this point in the history
Co-authored-by: Marc Pichler <[email protected]>
  • Loading branch information
johnbley and pichlermarc authored Dec 10, 2024
1 parent ba615db commit 91c9089
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,10 @@ import {
TextMapGetter,
TracerProvider,
ROOT_CONTEXT,
Attributes,
} from '@opentelemetry/api';
import {
ATTR_URL_FULL,
SEMATTRS_FAAS_EXECUTION,
SEMRESATTRS_CLOUD_ACCOUNT_ID,
SEMRESATTRS_FAAS_ID,
Expand Down Expand Up @@ -244,6 +246,7 @@ export class AwsLambdaInstrumentation extends InstrumentationBase<AwsLambdaInstr
context.invokedFunctionArn
),
[ATTR_FAAS_COLDSTART]: requestIsColdStart,
...AwsLambdaInstrumentation._extractOtherEventFields(event),
},
},
parent
Expand Down Expand Up @@ -426,6 +429,52 @@ export class AwsLambdaInstrumentation extends InstrumentationBase<AwsLambdaInstr
return propagation.extract(otelContext.active(), httpHeaders, headerGetter);
}

private static _extractOtherEventFields(event: any): Attributes {
const answer: Attributes = {};
const fullUrl = this._extractFullUrl(event);
if (fullUrl) {
answer[ATTR_URL_FULL] = fullUrl;
}
return answer;
}

private static _extractFullUrl(event: any): string | undefined {
// API gateway encodes a lot of url information in various places to recompute this
if (!event.headers) {
return undefined;
}
// Helper function to deal with case variations (instead of making a tolower() copy of the headers)
function findAny(
event: any,
key1: string,
key2: string
): string | undefined {
return event.headers[key1] ?? event.headers[key2];
}
const host = findAny(event, 'host', 'Host');
const proto = findAny(event, 'x-forwarded-proto', 'X-Forwarded-Proto');
const port = findAny(event, 'x-forwarded-port', 'X-Forwarded-Port');
if (!(proto && host && (event.path || event.rawPath))) {
return undefined;
}
let answer = proto + '://' + host;
if (port) {
answer += ':' + port;
}
answer += event.path ?? event.rawPath;
if (event.queryStringParameters) {
let first = true;
for (const key in event.queryStringParameters) {
answer += first ? '?' : '&';
answer += encodeURIComponent(key);
answer += '=';
answer += encodeURIComponent(event.queryStringParameters[key]);
first = false;
}
}
return answer;
}

private static _determineParent(
event: any,
context: Context,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
import { Context } from 'aws-lambda';
import * as assert from 'assert';
import {
ATTR_URL_FULL,
SEMATTRS_EXCEPTION_MESSAGE,
SEMATTRS_FAAS_COLDSTART,
SEMATTRS_FAAS_EXECUTION,
Expand Down Expand Up @@ -768,4 +769,52 @@ describe('lambda handler', () => {
assert.strictEqual(span.parentSpanId, undefined);
});
});

describe('url parsing', () => {
it('pulls url from api gateway rest events', async () => {
initializeHandler('lambda-test/sync.handler');
const event = {
path: '/lambda/test/path',
headers: {
Host: 'www.example.com',
'X-Forwarded-Proto': 'http',
'X-Forwarded-Port': 1234,
},
queryStringParameters: {
key: 'value',
key2: 'value2',
},
};

await lambdaRequire('lambda-test/sync').handler(event, ctx, () => {});
const [span] = memoryExporter.getFinishedSpans();
assert.ok(
span.attributes[ATTR_URL_FULL] ===
'http://www.example.com:1234/lambda/test/path?key=value&key2=value2' ||
span.attributes[ATTR_URL_FULL] ===
'http://www.example.com:1234/lambda/test/path?key2=value2&key=value'
);
});
it('pulls url from api gateway http events', async () => {
initializeHandler('lambda-test/sync.handler');
const event = {
rawPath: '/lambda/test/path',
headers: {
host: 'www.example.com',
'x-forwarded-proto': 'http',
'x-forwarded-port': 1234,
},
queryStringParameters: {
key: 'value',
},
};

await lambdaRequire('lambda-test/sync').handler(event, ctx, () => {});
const [span] = memoryExporter.getFinishedSpans();
assert.strictEqual(
span.attributes[ATTR_URL_FULL],
'http://www.example.com:1234/lambda/test/path?key=value'
);
});
});
});

0 comments on commit 91c9089

Please sign in to comment.