Skip to content

Commit

Permalink
fix: updated CDK examples to remove old references & improve comments (
Browse files Browse the repository at this point in the history
…#439)

* fix: updated CDK examples to correct errors & improved comments/structure

* fix: updated comment

* fix: Update examples/cdk/lib/example-function.Tracer.CaptureErrorDisabled.ts

Co-authored-by: ijemmy <ijemmy@users.noreply.github.com>

* fix: Update examples/cdk/lib/example-function.MyFunctionWithMiddy.ts

Co-authored-by: ijemmy <ijemmy@users.noreply.github.com>

* fix: added missing throw error statement

Co-authored-by: ijemmy <ijemmy@users.noreply.github.com>
  • Loading branch information
dreamorosi and ijemmy authored Jan 17, 2022
1 parent cf43568 commit 4cdaaea
Show file tree
Hide file tree
Showing 12 changed files with 189 additions and 110 deletions.
50 changes: 31 additions & 19 deletions examples/cdk/lib/example-function.MyFunction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,24 @@ import { Tracer } from '@aws-lambda-powertools/tracer';
const namespace = 'CDKExample';
const serviceName = 'MyFunctionWithStandardHandler';

const metrics = new Metrics({ namespace: namespace, service: serviceName });
const metrics = new Metrics({ namespace: namespace, serviceName: serviceName });
const logger = new Logger({ logLevel: 'INFO', serviceName: serviceName });
const tracer = new Tracer({ serviceName: serviceName });

export const handler = async (_event: unknown, context: Context): Promise<void> => {
export const handler = async (event: unknown, context: Context): Promise<void> => {
// Since we are in manual mode we need to create the handler segment (the 4 lines below would be done for you by decorator/middleware)
// we do it at the beginning because we want to trace the whole duration of the handler
const segment = tracer.getSegment(); // This is the facade segment (the one that is created by Lambda & that can't be manipulated)
const handlerSegment = segment.addNewSubsegment(`## ${context.functionName}`);
// TODO: expose tracer.annotateColdStart()
tracer.putAnnotation('ColdStart', Tracer.coldStart);
const segment = tracer.getSegment(); // This is the facade segment (the one that is created by AWS Lambda)
// Create subsegment for the function & set it as active
const handlerSegment = segment.addNewSubsegment(`## ${process.env._HANDLER}`);
tracer.setSegment(handlerSegment);

// ### Experiment logger
// Annotate the subsegment with the cold start & serviceName
tracer.annotateColdStart();
tracer.addServiceNameAnnotation();

// ### Experiment with Logger
logger.addContext(context);
logger.addPersistentLogAttributes({
testKey: 'testValue',
});
Expand All @@ -27,7 +32,7 @@ export const handler = async (_event: unknown, context: Context): Promise<void>
logger.warn('This is an WARN log');
logger.error('This is an ERROR log');

// ### Experiment metrics
// ### Experiment with Metrics
metrics.captureColdStartMetric();
metrics.throwOnEmptyMetrics();
metrics.setDefaultDimensions({ environment: 'example', type: 'standardFunction' });
Expand All @@ -38,24 +43,31 @@ export const handler = async (_event: unknown, context: Context): Promise<void>
metricWithItsOwnDimensions.addMetric('single-metric', MetricUnits.Percent, 50);

metrics.publishStoredMetrics();
metrics.raiseOnEmptyMetrics();

// ### Experiment tracer
metrics.throwOnEmptyMetrics();

tracer.putAnnotation('Myannotation', 'My annotation\'s value');
// ### Experiment with Tracer
// This annotation & metadata will be added to the handlerSegment subsegment (## index.handler)
tracer.putAnnotation('awsRequestId', context.awsRequestId);
tracer.putMetadata('eventPayload', event);

// Create subsegment & set it as active
const subsegment = handlerSegment.addNewSubsegment('MySubSegment');
// Create another subsegment & set it as active
const subsegment = handlerSegment.addNewSubsegment('### MySubSegment');
tracer.setSegment(subsegment);

let res;
try {
throw new Error('test');
// Add the response as metadata
res = { foo: 'bar' };
tracer.addResponseAsMetadata(res, process.env._HANDLER);
} catch (err) {
// Add the error as metadata
subsegment.addError(err as Error, false);
throw err;
} finally {
// Close subsegments (the AWS Lambda one is closed automatically)
subsegment.close(); // (### MySubSegment)
handlerSegment.close(); // (## index.handler)
// Set the facade segment as active again (the one created by AWS Lambda)
tracer.setSegment(segment);
}

// Close subsegment
subsegment.close();
handlerSegment.close();
};
48 changes: 28 additions & 20 deletions examples/cdk/lib/example-function.MyFunctionWithDecorator.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
import { Tracer } from '@aws-lambda-powertools/tracer';
import { Callback, Context } from 'aws-lambda';
import { Context } from 'aws-lambda';
import { Events, LambdaInterface } from '@aws-lambda-powertools/commons';
import { Metrics, MetricUnits } from '@aws-lambda-powertools/metrics';
import { Logger } from '@aws-lambda-powertools/logger';

const namespace = 'CDKExample';
const serviceName = 'MyFunctionWithDecorator';

const metrics = new Metrics({ namespace: namespace, service: serviceName });
const metrics = new Metrics({ namespace: namespace, serviceName: serviceName });
const logger = new Logger({ logLevel: 'INFO', serviceName: serviceName });
const tracer = new Tracer({ serviceName: serviceName });

export class MyFunctionWithDecorator {
@tracer.captureLambdaHanlder()
export class MyFunctionWithDecorator implements LambdaInterface {
// We decorate the handler with the various decorators
@tracer.captureLambdaHandler()
@logger.injectLambdaContext()
@metrics.logMetrics({
captureColdStartMetric: true,
throwOnEmptyMetrics: true,
defaultDimensions: { environment: 'example', type: 'withDecorator' },
})
public handler(_event: unknown, _context: Context, _callback: Callback<unknown>): void | Promise<unknown> {
public async handler(event: typeof Events.Custom.CustomEvent, context: Context): Promise<unknown> {
// ### Experiment logger
logger.addPersistentLogAttributes({
testKey: 'testValue',
Expand All @@ -36,28 +38,34 @@ export class MyFunctionWithDecorator {
metricWithItsOwnDimensions.addMetric('single-metric', MetricUnits.Percent, 50);

// ### Experiment tracer
tracer.putAnnotation('Myannotation', 'My annotation\'s value');

// Create subsegment & set it as active
const segment = tracer.getSegment(); // This is the facade segment (the one that is created by Lambda & that can't be manipulated)
const subsegment = segment.addNewSubsegment('MySubSegment');
// Service & Cold Start annotations will be added for you by the decorator/middleware

// These traces will be added to the main segment (## index.handler)
tracer.putAnnotation('awsRequestId', context.awsRequestId);
tracer.putMetadata('eventPayload', event);

// Create another subsegment & set it as active
const handlerSegment = tracer.getSegment(); // This is the custom segment created by Tracer for you (## index.handler)
const subsegment = handlerSegment.addNewSubsegment('### MySubSegment');
tracer.setSegment(subsegment);
// TODO: Add the ColdStart annotation !!! NOT POSSIBLE
// tracer.putAnnotation('ColdStart', tracer);

let res;
try {
throw new Error('test');
// Add the response as metadata
res = { foo: 'bar' };
} catch (err) {
// Add the error as metadata
subsegment.addError(err as Error, false);
throw err;
} finally {
// Close the subsegment you created (### MySubSegment)
subsegment.close();
// Set back the original segment as active (## index.handler)
tracer.setSegment(handlerSegment);
// The main segment (facade) will be closed for you at the end by the decorator/middleware
}

// Close subsegment
subsegment.close();

return res;
}
}

export const handlerClass = new MyFunctionWithDecorator();
export const handler = handlerClass.handler;
export const myFunction = new MyFunctionWithDecorator();
export const handler = myFunction.handler;
90 changes: 60 additions & 30 deletions examples/cdk/lib/example-function.MyFunctionWithMiddy.ts
Original file line number Diff line number Diff line change
@@ -1,43 +1,73 @@
import middy from '@middy/core';
import { Callback, Context } from 'aws-lambda';
import { Metrics, MetricUnits } from '@aws-lambda-powertools/metrics';
import { Context } from 'aws-lambda';
import { Events } from '@aws-lambda-powertools/commons';
import { Metrics, MetricUnits, logMetrics } from '@aws-lambda-powertools/metrics';
import { Tracer, captureLambdaHandler } from '@aws-lambda-powertools/tracer';
import { Logger, injectLambdaContext } from '@aws-lambda-powertools/logger';

const metrics = new Metrics({ namespace: 'CDKExample', service: 'withMiddy' }); // Sets metric namespace, and service as a metric dimension
const namespace = 'CDKExample';
const serviceName = 'MyFunctionWithMiddyMiddleware';

type CustomEvent = {
throw: boolean
};
const metrics = new Metrics({ namespace: namespace, serviceName: serviceName });
const logger = new Logger({ logLevel: 'INFO', serviceName: serviceName });
const tracer = new Tracer({ serviceName: serviceName });

class MyFunctionWithDecorator {
const lambdaHandler = async (event: typeof Events.Custom.CustomEvent, context: Context) => {
// ### Experiment with Logger
// AWS Lambda context is automatically injected by the middleware

@metrics.logMetrics({ captureColdStartMetric: true })
public handler(_event: CustomEvent, _context: Context, _callback: Callback<unknown>): void | Promise<unknown> {
metrics.addMetric('test-metric', MetricUnits.Count, 10);
if (_event.throw) {
throw new Error('Test error');
}
}
}
logger.addPersistentLogAttributes({
testKey: 'testValue',
});
logger.debug('This is an DEBUG log'); // Won't show because we pass logLevel: 'INFO' in the constructor.
logger.info('This is an INFO log');
logger.warn('This is an WARN log');
logger.error('This is an ERROR log');

const handler = middy(async (_event, _context) => {
// ### Experiment with Metrics
// Default metrics, cold start, and throwOnEmptyMetrics are enabled by the middleware

const handlerClass = new MyFunctionWithDecorator();
metrics.addMetric('test-metric', MetricUnits.Count, 10);

return handlerClass.handler(_event, _context, () => console.log('Lambda invoked!'));
});
const metricWithItsOwnDimensions = metrics.singleMetric();
metricWithItsOwnDimensions.addDimension('InnerDimension', 'true');
metricWithItsOwnDimensions.addMetric('single-metric', MetricUnits.Percent, 50);

// ### Experiment with Tracer

handler.before(async (_request) => {
metrics.addMetric('beforeHandlerCalled', MetricUnits.Count, 1);
});
// Service & Cold Start annotations will be added for you by the decorator/middleware

handler.after(async (_request) => {
// Won't be flushed since happens after
metrics.addMetric('afterHandlerCalled', MetricUnits.Count, 1);
// These traces will be added to the main segment (## index.handler)
tracer.putAnnotation('awsRequestId', context.awsRequestId);
tracer.putMetadata('eventPayload', event);

});
// Create another subsegment & set it as active
const handlerSegment = tracer.getSegment(); // This is the custom segment created by Tracer for you (## index.handler)
const subsegment = handlerSegment.addNewSubsegment('### MySubSegment');
tracer.setSegment(subsegment);

handler.onError(async (_request) => {
metrics.addMetric('onErrorHandlerCalled', MetricUnits.Count, 1);
});
let res;
try {
res = { foo: 'bar' };
} catch (err) {
throw err;
} finally {
// Close the subsegment you created (### MySubSegment)
subsegment.close();
// Set back the original segment as active (## index.handler)
tracer.setSegment(handlerSegment);
// The main segment (facade) will be closed for you at the end by the decorator/middleware
}

return res;
}

module.exports = { handler };
// We instrument the handler with the various Middy middlewares
export const handler = middy(lambdaHandler)
.use(captureLambdaHandler(tracer))
.use(logMetrics(metrics, {
captureColdStartMetric: true,
throwOnEmptyMetrics: true,
defaultDimensions: { environment: 'example', type: 'withDecorator' },
}))
.use(injectLambdaContext(logger));
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import { Context } from 'aws-lambda';
import { Events } from '@aws-lambda-powertools/commons';
import { captureLambdaHandler, Tracer } from '@aws-lambda-powertools/tracer';

// Set environment variable to disable capture response
// Set environment variable to disable capture response - https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html
process.env.POWERTOOLS_TRACER_ERROR_RESPONSE = 'false';
const tracer = new Tracer({ serviceName: 'tracerCaptureErrorDisabledFn' });

// In this example we are using the middleware pattern but you could use also the captureLambdaHandler decorator
// In this example we are using the Middy middleware pattern but you can instrument your functions also with the captureLambdaHandler decorator & manual instrumentation
export const handler = middy(async (event: typeof Events.Custom.CustomEvent, context: Context) => {
tracer.putAnnotation('awsRequestId', context.awsRequestId);
tracer.putMetadata('eventPayload', event);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Context } from 'aws-lambda';
import { Events } from '@aws-lambda-powertools/commons';
import { captureLambdaHandler, Tracer } from '@aws-lambda-powertools/tracer';

// Set environment variable to disable capture response
// Set environment variable to disable capture response - https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html
process.env.POWERTOOLS_TRACER_CAPTURE_RESPONSE = 'false';
const tracer = new Tracer({ serviceName: 'tracerCaptureResponseDisabledFn' });

Expand Down
3 changes: 2 additions & 1 deletion examples/cdk/lib/example-function.Tracer.Decorator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import { Callback, Context } from 'aws-lambda';
import { Events } from '@aws-lambda-powertools/commons';
import { Tracer } from '@aws-lambda-powertools/tracer';

// process.env.POWERTOOLS_SERVICE_NAME = 'tracerManualFn'; // Alternative to setting the service name in the constructor
const tracer = new Tracer({ serviceName: 'tracerDecoratorFn' });
// Alternatively, you can also set the service name using the POWERTOOLS_SERVICE_NAME environment variable
// Learn more at: https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html

export class MyFunctionWithDecorator {
// We instrument the handler with the decorator and the tracer will automatically create a subsegment and capture relevant annotations and metadata
Expand Down
12 changes: 7 additions & 5 deletions examples/cdk/lib/example-function.Tracer.Disabled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ import { Context } from 'aws-lambda';
import { Events } from '@aws-lambda-powertools/commons';
import { captureLambdaHandler, Tracer } from '@aws-lambda-powertools/tracer';

// process.env.POWERTOOLS_TRACE_ENABLED = 'false'; // Alternative to disabling tracing in the constructor
// Disable Tracer by setting POWERTOOLS_TRACE_ENABLED = 'false' in the function environment variables - https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html
const tracer = new Tracer({ serviceName: 'tracerDisabledFn', enabled: false });

// In this example we are using the middleware pattern but you could use also the captureLambdaHandler decorator or the manual mode
export const handler = middy(async (event: typeof Events.Custom.CustomEvent, context: Context) => {
// In this example we are using the middleware pattern but the same applies also the captureLambdaHandler decorator or to manual instrumentation
const lambdaHandler = async (event: typeof Events.Custom.CustomEvent, context: Context) => {
// No tracing will be done and the commands will be ignored, this is useful for testing
tracer.putAnnotation('awsRequestId', context.awsRequestId);
tracer.putMetadata('eventPayload', event);

let res;
try {
res = { foo: 'bar' };
Expand All @@ -20,4 +20,6 @@ export const handler = middy(async (event: typeof Events.Custom.CustomEvent, con
}

return res;
}).use(captureLambdaHandler(tracer));
}

export const handler = middy(lambdaHandler).use(captureLambdaHandler(tracer));
3 changes: 2 additions & 1 deletion examples/cdk/lib/example-function.Tracer.Manual.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import { Context } from 'aws-lambda';
import { Events } from '@aws-lambda-powertools/commons';
import { Tracer } from '@aws-lambda-powertools/tracer';

// process.env.POWERTOOLS_SERVICE_NAME = 'tracerManualFn'; // Alternative to setting the service name in the constructor
const tracer = new Tracer({ serviceName: 'tracerManualFn' });
// Alternatively, you can also set the service name using the POWERTOOLS_SERVICE_NAME environment variable
// Learn more at: https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html

export const handler = async (event: typeof Events.Custom.CustomEvent, context: Context): Promise<unknown> => {
const segment = tracer.getSegment(); // This is the facade segment (the one that is created by AWS Lambda)
Expand Down
17 changes: 12 additions & 5 deletions examples/cdk/lib/example-function.Tracer.Middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ import { Context } from 'aws-lambda';
import { Events } from '@aws-lambda-powertools/commons';
import { captureLambdaHandler, Tracer } from '@aws-lambda-powertools/tracer';

// process.env.POWERTOOLS_SERVICE_NAME = 'tracerManualFn'; // Alternative to setting the service name in the constructor
const tracer = new Tracer({ serviceName: 'tracerMiddlewareFn' });
// Alternatively, you can also set the service name using the POWERTOOLS_SERVICE_NAME environment variable
// Learn more at: https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html

// We instrument the handler with the middy middleware and the tracer will automatically create a subsegment and capture relevant annotations and metadata
export const handler = middy(async (event: typeof Events.Custom.CustomEvent, context: Context) => {
const lambdaHandler = async (event: typeof Events.Custom.CustomEvent, context: Context) => {
// Add custom annotation & metadata
tracer.putAnnotation('awsRequestId', context.awsRequestId);
tracer.putMetadata('eventPayload', event);

let res;
try {
res = { foo: 'bar' };
Expand All @@ -20,4 +20,11 @@ export const handler = middy(async (event: typeof Events.Custom.CustomEvent, con
}

return res;
}).use(captureLambdaHandler(tracer));
}

// We instrument the handler with the Middy middleware and the Tracer will automatically:
// * handle the lifecycle of the subsegment
// * create a ColdStart annotation to easily filter traces that have had an initialization overhead
// * create a Service annotation to easily filter traces that have a specific service name
// * captures any response, or full exceptions generated by the handler, and include them as tracing metadata
export const handler = middy(lambdaHandler).use(captureLambdaHandler(tracer));
Loading

0 comments on commit 4cdaaea

Please sign in to comment.