Amazon CodeGuru Profiler for monitoring cloud applications
Tags: aws, java, docker, serverless
Published: 2020-07-10 01:41:27

One of the challenges with building cloud applications is finding the correct way to optimize it. To do so you need to have an insight into how your application performs in production and what are current bottlenecks and latencies which exist in your code. The usual cycle is that you monitor your application, you find existing bottlenecks, next you prioritize based on the latency or CPU/RAM impact and then you optimize your code. Finally, you need to monitor the app after the change to make sure that your fix actually helped.

There are a lot of APM (Application Performance Monitoring) tools out there that could be used to monitor your application in production and they have different ways of gathering and visualizing data about your application. Amazon Codeguru takes a step further in the direction of handling bottlenecks and provides several great additions to the way how the optimization cycle works:
1. It provides automatic insights into what are possible ways to optimize your app. Service provides insights based on the combination of knowledge base and ML algorithms.
2. It puts a dollar value on each bottleneck based on the instance which you are using. This feature enables you to prioritize optimization between multiple apps while also providing a way to calculate ROI for decreasing technical debt. Also, it provides a way to find methods that contribute the most to the latency of the app and estimate what are the possibilities for decreasing your app’s latency.
3. It monitors data continuously and can notify you in case there are any anomalies in your app related. The service also generates cloudwatch metrics meaning you can add them in your main dashboard for low-level app monitoring and easier debugging.

In this post, I’ll cover a demo on how to use Amazon Codeguru with a Java application running on AWS Batch. I will use AWS Step Functions to handle AWS Batch invocations and will build the Java application using Maven.

We will cover the following:
- Building up and testing a Java application with Amazon CodeGuru Profiler
- Deploying Java application with AWS Batch and providing necessary permissions
- Monitoring application using Amazon CodeGuru dashboard

Prerequisites:
- Installed AWS CLI
- Installed Java 8 and Maven (optional)
- Installed docker
- Installed serverless frameworks with plugins

Code decomposition:
- Java project files (demoApplication.java, pom.xml)
- Dockerfile for the image which we will run
- Serverless config file which contains infrastructure which we will deploy

## Build and test Java application with Amazon CodeGuru profiler

We will use maven to build our Java project. If you have Java 8 and maven installed, you can run the following commands to build the project and run it locally. You will also need to have your AWS credentials set up locally (https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/credentials.html). Keep in mind that we will deploy necessary infrastructure in the next step so you would be able to run code successfully only once necessary AWS Lambda is deployed. Alternatively, you can deploy AWS Lambda manually and update demoApplication.java with its name. Also, you will need to set up profiling group “demoApplication” in CodeGuru dashboard (https://console.aws.amazon.com/codeguru/profiler/search):

```bash
git clone https://github.com/ryfeus/stepfunctions2processing.git
cd aws-batch-with-profiler/docker
mvn clean compile assembly:single
```

You can run your Java code locally with CodeGuru Profiler and it will report profiling data to AWS. It can be used for both testing your code locally and for profiling your code without deploying it to the cloud.

```bash
java -jar target/demo-1.0.0-jar-with-dependencies.jar
```

In this demo we are using CodeGuru Profiler library to run Profiler within application. Alternative way is to download Profiler jar directly (from https://d1osg35nybn3tt.cloudfront.net/) and the run it as an additional parameter for Java command. In this case you don’t need to update your code to include Profiler logic and you don’t need to include dependencies and repositories to your maven project.

Now let’s build docker image which we will run in AWS Batch by using docker.

```bash
docker build -t test-java-app-with-profiler .
```

## Deploying Java application to the cloud
Once image is built, let’s create repository in AWS ECR and push docker image there. We would need to login into ECR, create repository, tag built image and push it to ECR.

```bash
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin <accountId>.dkr.ecr.us-east-1.amazonaws.com
aws ecr create-repository --repository-name test-java-app-with-profiler
docker tag test-java-app-with-profiler:latest <accountId>.dkr.ecr.us-east-1.amazonaws.com/test-java-app-with-profiler:latest
docker push <accountId>.dkr.ecr.us-east-1.amazonaws.com/test-java-app-with-profiler:latest
```

Once the container image is pushed, we can install dependencies for the serverless framework and deploy services by using the following command:

```bash
cd aws-batch-with-profiler/aws-batch
npm install
serverless deploy
```

Here is how the output will look like:
```
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Creating Stack...
Serverless: Checking Stack create progress...
.....
Serverless: Stack create finished...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service StepFuncBatchWithProfiler.zip file to S3 (32.94 KB)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
..........................................................................................
Serverless: Stack update finished...
Service Information
service: StepFuncBatchWithProfiler
stage: dev
region: us-east-1
stack: StepFuncBatchWithProfiler-dev
resources: 30
api keys:
  None
endpoints:
functions:
  async: StepFuncBatchWithProfiler-dev-async
layers:
  None
Serverless StepFunctions OutPuts
endpoints:
  GET - https://<urlPrefix>.execute-api.us-east-1.amazonaws.com/dev/startFunction
```

We can use the url in the output to call deployed AWS Step Functions and AWS Batch. It could be done, for example, by using curl:
```
curl https://<urlPrefix>.execute-api.us-east-1.amazonaws.com/dev/startFunction
```

After that we can take a look at Step Functions execution graph at AWS Step Functions dashboard (https://console.aws.amazon.com/states/home):

![Step Function Console](https://dev-to-uploads.s3.amazonaws.com/i/vnqnggrq2lpeqq88tk15.png)

We can check logs produced by the application in Cloudwatch group “aws/batch/job” (https://console.aws.amazon.com/cloudwatch/home?region=us-east-1#logsV2:log-groups/log-group/$252Faws$252Fbatch$252Fjob). It should look in the following way:

![Cloudwatch Console](https://dev-to-uploads.s3.amazonaws.com/i/t6pb9qppsh84hpm7j9jh.png)

## Monitoring application using Amazon CodeGuru

Once everything is set up and you’ve run multiple jobs with CodeGuru Profiler running, you can start monitoring the results. CodeGuru Profiler provides data in a flame graph format. You can see the stack of your code’ and libraries’ methods and for each method you can see the CPU or amount of time which was spent within the method. This allows you to see which methods give the most latency and what are the places for possible optimizations. One of the main advantages is that you also will be able to see cost per each method which provides a way to estimate savings of potential optimizations.

![CodeGuru Profiler](https://dev-to-uploads.s3.amazonaws.com/i/ye14xsngjoaa5x4yl2h7.png)

## Conclusion
We deployed a demo Java application with Amazon CodeGuru Profiler on AWS Batch, wrapped by AWS Step Functions. You can use the same project settings to deploy your application and test it to see how it performs in the cloud and get recommendations. Amazon CodeGuru has a 90 day trial so you can do so completely free.