Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs(tracer): Allow to reuse Tracer across your code #767

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions docs/core/tracer.md
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,85 @@ Use **`POWERTOOLS_TRACER_CAPTURE_ERROR=false`** environment variable to instruct

1. You might **return sensitive** information from exceptions, stack traces you might not control

### Reusing Tracer across your code

Tracer keeps a copy of its configuration after the first initialization. This is useful for scenarios where you want to use Tracer in more than one location across your code base.

=== "index.ts"

```typescript hl_lines="5"
import { Tracer } from '@aws-lambda-powertools/tracer';
import middy from '@middy/core';
import collectPayment from './payment';

const tracer = new Tracer(); // (1)

export const handler = middy(async (event: any, _context: any): Promise<void> => {
await collectPayment(event.chargeId);
}).use(captureLambdaHandler(tracer));
```

1. Because of the way ESM modules work, in order to set up Tracer, you'll need to pass the configurations as [environment variables](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/#environment-variables).
dreamorosi marked this conversation as resolved.
Show resolved Hide resolved
=== "payment.ts"

```typescript hl_lines="3"
import { Tracer } from '@aws-lambda-powertools/tracer';

const tracer = new Tracer(); // (1)

const collectPayment = async (chargeId: string) => {
const mainSegment = tracer.getSegment(); // (2)
const subsegment = mainSegment.addNewSubsegment('### collectPayment');
tracer.setSegment(subsegment);

// This annotation will be done on the `### collectPayment` segment
tracer.putAnnotation('chargeId', chargeId);

/* ... */

subsegment.close();
tracer.setSegment(mainSegment);
};

export default collectPayment;
```

1. You don't need to pass any parameters here, this instance will have the same configuration as the other Tracer instance
2. This is the main subsegment called `### index.handler` that was created by the `captureLambdaHandler` middleware
=== "Example Raw X-Ray Trace excerpt"

```json hl_lines="3 17 20 24"
{
"id": "22883fbc730e3a0b",
"name": "## index.handler",
"start_time": 1647956168.22749,
"end_time": 1647956169.0679862,
"annotations": {
"ColdStart": true
},
"metadata": {
"default": {
"index.handler response": {
"body": "{\"message\":\"Payment collected for chargeId: 1234\"}",
"statusCode": 200
}
}
},
"subsegments": [
{
"id": "24542b252e5c0756",
"name": "collectPayment",
"start_time": 1647956169.22749,
"end_time": 1647956169.32749,
"annotations": {
"chargeId": "1234"
}
}
]
}
```


### Escape hatch mechanism

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).
Expand Down
56 changes: 31 additions & 25 deletions packages/tracing/src/Tracer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,27 +113,33 @@ import { Segment, Subsegment } from 'aws-xray-sdk-core';
*/
class Tracer extends Utility implements TracerInterface {

public provider: ProviderServiceInterface;

public provider: ProviderServiceInterface = new ProviderService();

private static _instance?: Tracer;

private captureError: boolean = true;

private captureHTTPsRequests: boolean = true;

private captureResponse: boolean = true;

private customConfigService?: ConfigServiceInterface;

private envVarsService?: EnvironmentVariablesService;

private serviceName?: string;

private tracingEnabled: boolean = true;

public constructor(options: TracerOptions = {}) {
super();

if (Tracer._instance) {
return Tracer._instance;
}
Tracer._instance = this;

this.setOptions(options);
this.provider = new ProviderService();
if (this.isTracingEnabled() && this.captureHTTPsRequests) {
this.provider.captureHTTPsGlobal();
}
Expand Down Expand Up @@ -269,7 +275,7 @@ class Tracer extends Utility implements TracerInterface {
// instrumentation contract like most base clients.
// For detailed explanation see: https://github.com/awslabs/aws-lambda-powertools-typescript/issues/524#issuecomment-1024493662
this.provider.captureAWSClient((service as T & { service: T }).service);

return service;
} catch {
throw error;
Expand Down Expand Up @@ -361,7 +367,7 @@ class Tracer extends Utility implements TracerInterface {
subsegment?.close();
subsegment?.flush();
}

return result;
});
}) as Handler;
Expand Down Expand Up @@ -408,7 +414,7 @@ class Tracer extends Utility implements TracerInterface {
public captureMethod(): MethodDecorator {
return (target, _propertyKey, descriptor) => {
const originalMethod = descriptor.value;

descriptor.value = (...args: unknown[]) => {
if (!this.isTracingEnabled()) {
return originalMethod?.apply(target, [...args]);
Expand All @@ -426,15 +432,15 @@ class Tracer extends Utility implements TracerInterface {
} finally {
subsegment?.close();
}

return result;
});
};

return descriptor;
};
}

/**
* Get the active segment or subsegment in the current scope.
*
Expand All @@ -461,11 +467,11 @@ class Tracer extends Utility implements TracerInterface {
if (!this.isTracingEnabled()) {
return new Subsegment('## Dummy segment');
}
const segment = this.provider.getSegment();
const segment = this.provider.getSegment();
if (segment === undefined) {
throw new Error('Failed to get the current sub/segment from the context.');
}

return segment;
}

Expand Down Expand Up @@ -506,12 +512,12 @@ class Tracer extends Utility implements TracerInterface {
const document = this.getSegment();
if (document instanceof Segment) {
console.warn('You cannot annotate the main segment in a Lambda execution environment');

return;
}
document?.addAnnotation(key, value);
}

/**
* Adds metadata to existing segment or subsegment.
*
Expand Down Expand Up @@ -539,14 +545,14 @@ class Tracer extends Utility implements TracerInterface {
const document = this.getSegment();
if (document instanceof Segment) {
console.warn('You cannot add metadata to the main segment in a Lambda execution environment');

return;
}

namespace = namespace || this.serviceName;
document?.addMetadata(key, value, namespace);
}

/**
* Sets the passed subsegment as the current active subsegment.
*
Expand All @@ -571,7 +577,7 @@ class Tracer extends Utility implements TracerInterface {
*/
public setSegment(segment: Segment | Subsegment): void {
if (!this.isTracingEnabled()) return;

return this.provider.setSegment(segment);
}

Expand All @@ -590,15 +596,15 @@ class Tracer extends Utility implements TracerInterface {
private getEnvVarsService(): EnvironmentVariablesService {
return <EnvironmentVariablesService> this.envVarsService;
}

/**
* Determine if we are running in a Lambda execution environment.
* Used internally during initialization.
*/
private isLambdaExecutionEnv(): boolean {
return this.getEnvVarsService()?.getAwsExecutionEnv() !== '';
}

/**
* Determine if we are running inside a SAM CLI process.
* Used internally during initialization.
Expand Down Expand Up @@ -770,21 +776,21 @@ class Tracer extends Utility implements TracerInterface {
private setTracingEnabled(enabled?: boolean): void {
if (enabled !== undefined && !enabled) {
this.tracingEnabled = enabled;

return;
}

const customConfigValue = this.getCustomConfigService()?.getTracingEnabled();
if (customConfigValue !== undefined && customConfigValue.toLowerCase() === 'false') {
this.tracingEnabled = false;

return;
}

const envVarsValue = this.getEnvVarsService()?.getTracingEnabled();
if (envVarsValue.toLowerCase() === 'false') {
this.tracingEnabled = false;

return;
}

Expand Down
Loading