Skip to content

Commit c8e3c15

Browse files
feat(all): moved EnvService to commons + exposed getXrayTraceId in tracer (#1123)
* feat: moved EnvService to commons + exposed getXrayTraceId in tracer * docs: added docs section for getRootXrayTraceId * Update docs/core/tracer.md Co-authored-by: Josh Kellendonk <[email protected]> * fix: remove reduntant methods * chore: updated unit test case Co-authored-by: Josh Kellendonk <[email protected]>
1 parent 6dc2bef commit c8e3c15

25 files changed

+332
-342
lines changed

Diff for: docs/core/tracer.md

+32
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,38 @@ Use **`POWERTOOLS_TRACER_CAPTURE_ERROR=false`** environment variable to instruct
484484

485485
1. You might **return sensitive** information from errors, stack traces you might not control
486486

487+
### Access AWS X-Ray Root Trace ID
488+
489+
Tracer exposes a `getRootXrayTraceId()` method that allows you to retrieve the [AWS X-Ray Root Trace ID](https://docs.aws.amazon.com/xray/latest/devguide/xray-concepts.html#xray-concepts-traces) corresponds to the current function execution.
490+
491+
!!! info "This is commonly useful in two scenarios"
492+
493+
1. By including the root trace id in your response, consumers can use it to correlate requests
494+
2. You might want to surface the root trace id to your end users so that they can reference it while contacting customer service
495+
496+
=== "index.ts"
497+
498+
```typescript hl_lines="9"
499+
import { Tracer } from '@aws-lambda-powertools/tracer';
500+
501+
const tracer = new Tracer({ serviceName: 'serverlessAirline' });
502+
503+
export const handler = async (event: unknown, context: Context): Promise<void> => {
504+
try {
505+
...
506+
} catch (err) {
507+
const rootTraceId = tracer.getRootXrayTraceId();
508+
509+
// Example of returning an error response
510+
return {
511+
statusCode: 500,
512+
body: `Internal Error - Please contact support and quote the following id: ${rootTraceId}`,
513+
headers: { "_X_AMZN_TRACE_ID": rootTraceId },
514+
};
515+
}
516+
};
517+
```
518+
487519
### Escape hatch mechanism
488520

489521
You can use `tracer.provider` attribute to access all methods provided by the [AWS X-Ray SDK](https://docs.aws.amazon.com/xray-sdk-for-nodejs/latest/reference/AWSXRay.html).

Diff for: layer-publisher/tests/unit/__snapshots__/layer-publisher.test.ts.snap

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ Object {
3232
"S3Bucket": Object {
3333
"Fn::Sub": "cdk-hnb659fds-assets-\${AWS::AccountId}-\${AWS::Region}",
3434
},
35-
"S3Key": "c2f621503b147cecccf2e6cc6df420a8f11ee29ae042d2c1f523cf5db3f47ca2.zip",
35+
"S3Key": "dbdb3f66eaeed03649521bf73dbcdd95a713086afccbac3f57fa407ffb76bdaa.zip",
3636
},
3737
"Description": "Lambda Powertools for TypeScript version 1.0.1",
3838
"LayerName": "AWSLambdaPowertoolsTypeScript",

Diff for: packages/commons/src/config/ConfigService.ts

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/**
2+
* Abstract class ConfigService
3+
*
4+
* This class defines common methods and variables that can be set by the developer
5+
* in the runtime.
6+
*
7+
* @class
8+
* @abstract
9+
*/
10+
abstract class ConfigService {
11+
12+
/**
13+
* It returns the value of an environment variable that has given name.
14+
*
15+
* @param {string} name
16+
* @returns {string}
17+
*/
18+
public abstract get(name: string): string;
19+
20+
/**
21+
* It returns the value of the POWERTOOLS_SERVICE_NAME environment variable.
22+
*
23+
* @returns {string}
24+
*/
25+
public abstract getServiceName(): string;
26+
27+
}
28+
29+
export {
30+
ConfigService,
31+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { ConfigService } from '.';
2+
3+
/**
4+
* Class EnvironmentVariablesService
5+
*
6+
* This class is used to return environment variables that are available in the runtime of
7+
* the current Lambda invocation.
8+
* These variables can be a mix of runtime environment variables set by AWS and
9+
* variables that can be set by the developer additionally.
10+
*
11+
* @class
12+
* @extends {ConfigService}
13+
* @see https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html#configuration-envvars-runtime
14+
* @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/#environment-variables
15+
*/
16+
class EnvironmentVariablesService extends ConfigService {
17+
18+
/**
19+
* @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/#environment-variables
20+
* @protected
21+
*/
22+
protected serviceNameVariable = 'POWERTOOLS_SERVICE_NAME';
23+
// Reserved environment variables
24+
private xRayTraceIdVariable = '_X_AMZN_TRACE_ID';
25+
26+
/**
27+
* It returns the value of an environment variable that has given name.
28+
*
29+
* @param {string} name
30+
* @returns {string}
31+
*/
32+
public get(name: string): string {
33+
return process.env[name]?.trim() || '';
34+
}
35+
36+
/**
37+
* It returns the value of the POWERTOOLS_SERVICE_NAME environment variable.
38+
*
39+
* @returns {string}
40+
*/
41+
public getServiceName(): string {
42+
return this.get(this.serviceNameVariable);
43+
}
44+
45+
/**
46+
* It returns the value of the _X_AMZN_TRACE_ID environment variable.
47+
*
48+
* The AWS X-Ray Trace data available in the environment variable has this format:
49+
* `Root=1-5759e988-bd862e3fe1be46a994272793;Parent=557abcec3ee5a047;Sampled=1`,
50+
*
51+
* The actual Trace ID is: `1-5759e988-bd862e3fe1be46a994272793`.
52+
*
53+
* @returns {string}
54+
*/
55+
public getXrayTraceId(): string | undefined {
56+
const xRayTraceId = this.get(this.xRayTraceIdVariable);
57+
58+
if (xRayTraceId === '') return undefined;
59+
60+
return xRayTraceId.split(';')[0].replace('Root=', '');
61+
}
62+
63+
}
64+
65+
export {
66+
EnvironmentVariablesService,
67+
};

Diff for: packages/commons/src/config/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './ConfigService';
2+
export * from './EnvironmentVariablesService';

Diff for: packages/commons/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export * from './utils/lambda';
22
export * from './Utility';
3+
export * from './config';
34
export * as ContextExamples from './samples/resources/contexts';
45
export * as Events from './samples/resources/events';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/**
2+
* Test EnvironmentVariablesService class
3+
*
4+
* @group unit/commons/all
5+
*/
6+
7+
import { EnvironmentVariablesService } from '../../../src/config';
8+
9+
describe('Class: EnvironmentVariablesService', () => {
10+
11+
const ENVIRONMENT_VARIABLES = process.env;
12+
13+
beforeEach(() => {
14+
jest.resetModules();
15+
process.env = { ...ENVIRONMENT_VARIABLES };
16+
});
17+
18+
afterAll(() => {
19+
process.env = ENVIRONMENT_VARIABLES;
20+
});
21+
22+
describe('Method: get', () => {
23+
24+
test('When the variable IS present, it returns the value of a runtime variable', () => {
25+
26+
// Prepare
27+
process.env.CUSTOM_VARIABLE = 'my custom value';
28+
const service = new EnvironmentVariablesService();
29+
30+
// Act
31+
const value = service.get('CUSTOM_VARIABLE');
32+
33+
// Assess
34+
expect(value).toEqual('my custom value');
35+
36+
});
37+
38+
test('When the variable IS NOT present, it returns an empty string', () => {
39+
40+
// Prepare
41+
delete process.env.CUSTOM_VARIABLE;
42+
const service = new EnvironmentVariablesService();
43+
44+
// Act
45+
const value = service.get('CUSTOM_VARIABLE');
46+
47+
// Assess
48+
expect(value).toEqual('');
49+
50+
});
51+
52+
});
53+
54+
describe('Method: getServiceName', () => {
55+
56+
test('It returns the value of the environment variable POWERTOOLS_SERVICE_NAME', () => {
57+
58+
// Prepare
59+
process.env.POWERTOOLS_SERVICE_NAME = 'shopping-cart-api';
60+
const service = new EnvironmentVariablesService();
61+
62+
// Act
63+
const value = service.getServiceName();
64+
65+
// Assess
66+
expect(value).toEqual('shopping-cart-api');
67+
});
68+
69+
});
70+
71+
describe('Method: getXrayTraceId', () => {
72+
73+
test('It returns the value of the environment variable _X_AMZN_TRACE_ID', () => {
74+
75+
// Prepare
76+
process.env._X_AMZN_TRACE_ID = 'abcd123456789';
77+
const service = new EnvironmentVariablesService();
78+
79+
// Act
80+
const value = service.getXrayTraceId();
81+
82+
// Assess
83+
expect(value).toEqual('abcd123456789');
84+
});
85+
test('It returns the value of the Root X-Ray segment ID properly formatted', () => {
86+
87+
// Prepare
88+
process.env._X_AMZN_TRACE_ID = 'Root=1-5759e988-bd862e3fe1be46a994272793;Parent=557abcec3ee5a047;Sampled=1';
89+
const service = new EnvironmentVariablesService();
90+
91+
// Act
92+
const value = service.getXrayTraceId();
93+
94+
// Assess
95+
expect(value).toEqual('1-5759e988-bd862e3fe1be46a994272793');
96+
});
97+
98+
test('It returns the value of the Root X-Ray segment ID properly formatted', () => {
99+
100+
// Prepare
101+
delete process.env._X_AMZN_TRACE_ID;
102+
const service = new EnvironmentVariablesService();
103+
104+
// Act
105+
const value = service.getXrayTraceId();
106+
107+
// Assess
108+
expect(value).toEqual(undefined);
109+
});
110+
111+
});
112+
113+
});

Diff for: packages/logger/src/Logger.ts

+3-19
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,8 @@ class Logger extends Utility implements ClassThatLogs {
117117

118118
private static readonly defaultServiceName: string = 'service_undefined';
119119

120-
private envVarsService?: EnvironmentVariablesService;
120+
// envVarsService is always initialized in the constructor in setOptions()
121+
private envVarsService!: EnvironmentVariablesService;
121122

122123
private logEvent: boolean = false;
123124

@@ -455,7 +456,7 @@ class Logger extends Utility implements ClassThatLogs {
455456
logLevel,
456457
timestamp: new Date(),
457458
message: typeof input === 'string' ? input : input.message,
458-
xRayTraceId: this.getXrayTraceId(),
459+
xRayTraceId: this.envVarsService.getXrayTraceId(),
459460
}, this.getPowertoolLogData());
460461

461462
const logItem = new LogItem({
@@ -545,23 +546,6 @@ class Logger extends Utility implements ClassThatLogs {
545546
return <number> this.powertoolLogData.sampleRateValue;
546547
}
547548

548-
/**
549-
* It returns the current X-Ray Trace ID parsing the content of the `_X_AMZN_TRACE_ID` env variable.
550-
*
551-
* The X-Ray Trace data available in the environment variable has this format:
552-
* `Root=1-5759e988-bd862e3fe1be46a994272793;Parent=557abcec3ee5a047;Sampled=1`,
553-
*
554-
* The actual Trace ID is: `1-5759e988-bd862e3fe1be46a994272793`.
555-
*
556-
* @private
557-
* @returns {string}
558-
*/
559-
private getXrayTraceId(): string {
560-
const xRayTraceId = this.getEnvVarsService().getXrayTraceId();
561-
562-
return xRayTraceId.length > 0 ? xRayTraceId.split(';')[0].replace('Root=', '') : xRayTraceId;
563-
}
564-
565549
/**
566550
* It returns true if the provided log level is valid.
567551
*

0 commit comments

Comments
 (0)