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

fix: updated CDK examples to remove old references & improve comments #439

Merged
merged 6 commits into from
Jan 17, 2022
Merged
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.raiseOnEmptyMetrics();
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);
dreamorosi marked this conversation as resolved.
Show resolved Hide resolved
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();
};
50 changes: 29 additions & 21 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,
raiseOnEmptyMetrics: 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) {
Comment on lines 54 to 56
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above. Why try/catch without throw?

Copy link
Contributor Author

@dreamorosi dreamorosi Jan 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one has the throw at L57.

// 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)
ijemmy marked this conversation as resolved.
Show resolved Hide resolved
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));