Beyond Logs and Metrics: Crafting a Visionary Observability Strategy on AWS Serverless using Lambda Powertools
Published: 2023-09-28 14:19:24

In today's fast-paced and dynamic software landscape, microservices architecture has gained immense popularity for its ability to enable agility and scalability. However, managing microservices at scale brings its own set of challenges. One critical aspect of ensuring the reliability and performance of microservices is observability.

In this blog post, we will delve into the world of observability in microservices, focusing on AWS landscape. We'll explore the key concepts, tools, and best practices to effectively monitor and debug microservices in AWS.

####The Significance of Serverless Observability
Since microservices architectures are inherently made up of many distributed components, observability across all those components becomes critical. Amazon CloudWatch enables this, collecting and tracking metrics, monitoring log files, and reacting to changes in your AWS environment. It can monitor AWS resources and custom metrics generated by your applications and services.
Observability in microservices refers to the ability to gain insights into the internal workings of a distributed system. It encompasses logging, metrics, and tracing to provide a comprehensive view of how services interact and perform.
####Navigating the Serverless Landscape
Serverless architectures introduce a paradigm shift in application development, abstracting away infrastructure management. While this leads to increased agility and cost efficiency, it also poses challenges in terms of debugging, tracing, and monitoring. Serverless observability provides the necessary insights to understand, troubleshoot, and optimize the performance of our serverless applications.

####Real-time Insights for Business Continuity
In today's fast-paced digital landscape, downtime and performance bottlenecks can have significant repercussions. Observability equips us with real-time insights into the health and behavior of our serverless functions. This enables us to proactively address issues before they impact end-users, ensuring business continuity.


###Lets dive into Lambda Powertools
Lambda Powertools is a suite of utilities and libraries that will help in adopting best practices for tracing, structured logging, and so on in Lambda functions that are built around the AWS SDKs. Lambda Powertools will help in implementing observability best practices by keeping the Lambda functions lean and allowing you to focus on the business logic without writing complex code for logging and tracing requirements. Lambda Powertools currently supports Lambda functions written in Python, Java, Node.js, and .NET Lambda runtimes. There are three main core utilities, namely Logger, Metrics, and Tracer to support the three pillars of observability:

* The **Logger** utility offers a simple and standardized way to format your logs as a structured JSON. It allows you to pass in the string or more complex objects and will take care of serializing the output as a structured JSON. Common use cases include logging the Lambda event payload and capturing Lambda cold starts. The Logger also supports the use of your own custom log formatted by “bring your own formatter” to meet your organization’s specific standards.
* The **Tracer** utility of Lambda Powertools helps you effortlessly monitor serverless functions by sending traces to AWS X-Ray. This tool provides a clear view into function calls, interactions with other AWS services, or even external HTTP requests, allowing you to identify and resolve performance bottlenecks. The Tracer utility is a streamlined and user-friendly interface to the AWS X-Ray SDK, making it easier to implement observability best practices in your serverless architecture. With the ability to add annotations to traces, you can better categorize and analyze your traces, such as grouping by Lambda cold start information or transactions such as buying, selling, putting, or getting. The Tracer utility is also smart enough to automatically disable tracing when it is not running in the Lambda environment.
* The **Metrics** utility in Lambda Powertools makes it effortless to collect custom metrics from your application by utilizing Embedded Metric Format (EMF). EMF is a feature in CloudWatch that allows you to submit custom metrics to custom namespaces in AWS asynchronously. CloudWatch EMF provides a scalable and reliable solution for collecting custom metrics. Lambda Powertools for the Metrics utility leverages this EMF functionality, making it easy to store important business and application metrics in a CloudWatch custom namespace.

Lambda Powertools offers three different ways to instrument your code, offering flexibility and convenience to suit your specific needs:
* Middy: This is a middleware engine specifically designed for AWS Lambda functions that offers a quick and straightforward way to incorporate Lambda Powertools into your code with the fewest lines of code.
* Method Decorator: This method decorator approach is the best method for Lambda functions written in Typescript as classes and has only limited JavaScript support.
* Manual: The manual approach provides more control and is more verbose, but it also offers the greatest level of control over how Lambda Powertools is integrated into your Lambda function.

#### **Structured Enhanced Logging**
Let's import the logger from Lambda Powertools and use it to log information about the user data processing. The logger.info() function allows us to add structured data to our logs, which can be invaluable for analysis and troubleshooting.
 1. The code first imports the Logger and injectLambdaContext modules from the @aws-lambda-powertools/logger library: ```//Logging using Lambda powertools with Lambda context support.
//Inclusion of Logger PowerLambda Tools
const { Logger, injectLambdaContext } = require('@aws-lambda-powertools/logger');```

 2. A new Logger instance is created where the serviceName property is set to get-all-items. This is used to identify the source of the logs in the Amazon CloudWatch logs:```//Servicename of the lambda function shown in the CloudWatch Logs
const logger = new Logger({serviceName: 'get-all-items'});```

 3. The injectLambdaContext function is then used to log the Lambda context, which contains information about the function’s execution environment and its interaction with the AWS infrastructure.``` //Logging Lambda Context and the output of items as a JSON using logger standard format
        logger.addContext(context);
//Logging Items retrieved as a JSON in CloudWatch Logs.
        logger.info('Items in list:', { items }); ```
 4. Lets check the lambda cloudwatch logs:![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1do0tnrr20pms8pgknff.png)


#### **Custom Metrics**
 1. The code first imports the Metrics, MetricUnits, and logMetrics modules from the @aws-lambda-powertools/metrics library:```//Inclusion of Metrics from Lambda PowerTools
const { Metrics, MetricUnits, logMetrics } = require('@aws-lambda-powertools/metrics');```
 2. A new Metrics instance is created, where the namespace property is set to getitems and the serviceName property is set to get-all-items.```//Custom Metric namespace and service name in CloudWatch Custom Metrics
const metrics = new Metrics({ namespace: 'getitems', serviceName: 'get-all-items' });```
 3. The code then adds a custom metric called 'itemcount' to the Metrics instance, using the metrics.addMetric method. The metric is set to the count of items in the items array and has a unit of MetricUnits.Count.```// Adding the total retrieved items as a metric in the Custom namespace called "getitems"
        metrics.addMetric('itemcount', MetricUnits.Count, items.Count);
        metrics.publishStoredMetrics();```
 4. Verify from the CloudWatch logs ![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u7x2ziphvuzz3l5xfmtb.png)
 5. The getitems namespace is published with the details of the count of items retrieved from DynamoDB from the structure JSON output from the Lambda log: ![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w8zl6kfa5cd6jf7xw144.jpg) ![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i12r68j3pydytdrvxmp5.jpg)


#### **Enhanced Tracing**
 1. The code first imports the Tracer and captureLambdaHandler modules from the  @aws-lambda-powertools/tracer library:```//Inclusion of tracer from Lambda Powertools
const { Tracer, captureLambdaHandler } = require('@aws-lambda-powertools/tracer');```
 2. A new Tracer instance is created, where the serviceName property is set to get-all-items. This is used to identify the source of the traces in the AWS X-Ray service:```//X-Ray traces will be added with the servicename "get-all-items"
const tracer = new Tracer({ serviceName: 'get-all-items' });```
 3. The tracer.captureAWSClient method is used to capture and trace all calls to the DynamoDB service through DocumentClient:![xray](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tmxnorfw4ztzcdgts20l.jpg)
 4. Lets add annotations to the Lambda function about the cold start with the service name.```tracer.putAnnotation('awsRequestId', context.awsRequestId);
tracer.putMetadata('eventPayload', event);```![xray-tracing](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d30wcxmpc5xvuujeptj0.jpg)
 5. Close handler``` finally {
     // Close subsegment (the AWS Lambda one is closed automatically)
      handlerSegment.close();
      // Set back the facade segment as active again
      tracer.setSegment(segment);
  }```

Lambda Powertools provides a rich set of utilities and best practices to enhance the observability of your AWS Lambda functions. By incorporating structured logging, error handling, custom metrics, and distributed tracing, you can gain invaluable insights into the behavior and performance of your serverless applications.