5 minutes read

POSTED Mar, 2022 dot IN Serverless

Debugging Lambda Applications on LocalStack

Oguzhan Ozdemir

Written by Oguzhan Ozdemir


Solutions Engineer @Thundra

linkedin-share
 X

AWS Lambda applications are serverless applications that have gained popularity in the past few years, as they are very scalable (almost infinitely) and at the same time very cost-effective. LocalStack is a platform that allows developers to run Lambda applications locally on your machine.

In a CI environment, debugging and testing these applications is a major challenge, as it is both complex and time-consuming. In this article, we’ll see how Thundra Foresight can help you to optimize your CI pipeline performance.

Debugging and Monitoring Lambda Applications

Debugging and monitoring are an integral part of a project’s development and post-development process. They also make up the hardest and most time-consuming part of any development.

There are several challenges in debugging a Lambda application:

  • Finding the root cause of an error is complex and time-consuming.
  • Reviewing logs in Amazon CloudWatch can be challenging when you need to view the logs from multiple services and executions.
  • Builds often fail after hours of runtime due to a lack of visibility during CI processes, leading to an ever-increasing consumption of time and CI costs.
  • It is difficult to trace test failures with no known reason in a distributed system, which can cause significant delays in releasing features in production.

Explaining Thundra Foresight

Thundra Foresight is the first automated observability platform that provides deep analytics and debugging capabilities for continuous integration pipelines. It allows developers to easily and securely add traces to CI environments in real time, optimize build durations, and commit more frequent deployments. With Foresight's distributed tracing capabilities, developers and QA engineers gain 100% code-level observability and faster resolution to test failures, leading to increased productivity and lower CI costs.

Features of Foresight

Thundra Foresight offers:

  • Integration with CI pipelines: You can easily create a project on Foresight and integrate it with your CI pipeline by just adding a few lines of code into the configuration YAML file of your project.
  • Full visibility into test runs: Foresight captures every test failure to provide an aggregated view of a test run and its status summary at any commit.
  • Contextualized information for every test: You receive immediate context of the root cause of every test failure, along with contextualized information in the form of logs, metrics, traces, and performance charts.
  • Distributed tracing to debug tests: You can easily debug failed tests in real time by visualizing the traces in distributed trace charts.
  • Time travel debugging: Foresight captures a snapshot of your entire application across multiple external services to help you debug the previous states of your application.
  • Optimize CI performance: You can see the historic duration of your tests to help you detect performance bottlenecks and long-running outliers; this, in turn, lets you see trends over time to help you keep your builds green.

Integrating Lambda Application with Foresight

In this section, we’ll demonstrate the capabilities of Thundra Foresight. For this, we’ve created a demo serverless application in Java running on LocalStack. You can clone this application from this GitHub repo.

In the following steps, we will illustrate the integration of our demo Lambda application with the Foresight tool. First, if you don’t have one already, you’ll need to create a Thundra account. You can sign up for one or sign in here:

Figure 1: Create a Thundra account

Next, choose Foresight as the Thundra tool:

Figure 2: Thundra tools

Now, to create a project on Foresight, go to the Projects tab, click on the Create Project button, and then enter your project name:

Figure 3: Create Foresight project

After creating and configuring your project, copy the Project ID and API Key from the project settings:

Figure 4: Foresight project settings

Finally, update the Thundra API Key and Project ID in the Makefile of the demo application:

export THUNDRA_APIKEY = <YOUR-THUNDRA-API-KEY-HERE>
export THUNDRA_AGENT_TEST_PROJECT_ID = <YOUR-THUNDRA-API-KEY-HERE>

Your application is now integrated with Foresight, and any test runs from now on will be captured by Foresight for debugging and troubleshooting.

Debugging and Monitoring Using Foresight

After integrating your demo application with Foresight, you can run the application using the following command:

make start-embedded

If you just want to debug the tests, you don’t need to start the application; you can simply run:

make test

After running the tests, you can see a real-time status summary of all your test runs on Thundra Foresight, as shown below:

Figure 5: Application overview dashboard

By clicking on any of the test runs, you can also view detailed information such as execution time; git branch; a list of test suites; and the number of failed, passed, skipped, or aborted test suites:

Figure 6: Test Run overview dashboard

You can even click on any of the test suites to see all the tests defined under it, including some analytics showing you which tests failed the most or were the slowest:

Figure 7: Test Suite overview dashboard

By clicking on any of the test cases, you can also get an aggregated view of the test details:

Figure 8: Test Detail view

The Errors tab shows the stack trace of errors to help developers debug faster. For example, in the above screenshot, you can see the stack trace of AssertionFailedError occurred during the failure of the testGetRestaurantRequest test.

The Performance tab gives you a statistical chart comparing the duration of the test for each of its executions, while you can find all the logs of the test execution under the Logs tab.

Analyzing the Trace Map

Now, if you click on the Trace Map button on the top-right corner of the Test Detail page, you’ll be redirected to the trace map of invocations. Here, you get full observability of your test execution:

Figure 9: Trace map

This directed graph represents what happened with every invocation, what was being passed between the services, how long each service took to execute, and the number of times that service was invoked as a part of this specific trace.

For example, as you can see in the directed graph of the trace map shown above, our test uses an API gateway that invokes the Lambda, which then uses the DynamoDB. Now, if you click on any of the arrows, you’ll be able to see the details of the request or response that was sent to the service directed by the arrow; for example, you can view the details of the request that Lambda received from the API gateway and so on.

If any of these services is erroneous, the arrow of that service will be displayed in red to help you quickly identify the faulty service.

Figure 10: Trace chart of the request

Time Travel Debugging

Foresight additionally provides a very useful feature called Time Travel Debugging (TTD). This allows you to view the line-by-line execution of your code and the state of the variables at each line.

Time Travel debugging is disabled by default in Foresight, but you can enable it by simply setting up the traceLineByLine attribute of the THUNDRA_AGENT_TRACE_INSTRUMENT_TRACEABLECONFIG environment variable to true in your Makefile, like this:

THUNDRA_AGENT_TRACE_INSTRUMENT_TRACEABLECONFIG = org.com.demo.lambda.*.*[traceLineByLine=true]

This tells Foresight to enable TTD for all the methods of all the classes in the org.com.demo.lambda package.

The other option to enable TTD is to use Foresight’s annotation @Traced(traceLineByLine=true) on top of the class you want to enable for TTD. This will debug all the public methods of that class automatically. You can read up on all other options and customizations for TTD here.

Once you’ve enabled the TTD, you can debug your tests by going through the line-by-line execution of code, with the help of a trace chart and trace summary:

Figure 11: Trace chart and summary of the request

Here, you can click on any of the debug icons you see to open the code execution window showcasing the line of code executed and the value of the variables at that point in time. You can continue traversing through the code forward or backward, line by line, by clicking the arrows on the top of the trace summary as shown above. In this way, you can debug your application without having to put a breakpoint anywhere.

Conclusion

Foresight has successfully replaced the non-agile, iterative process required for debugging and troubleshooting failed builds in CI pipelines. In this article, we’ve explored how distributed tracing provided by Foresight helps in serverless observability and how it can reduce the impact and cost of potential failures in production.

Although observing and debugging CI tests can be challenging, Thundra Foresight helps you gain detailed and rapid insights into key metrics for your CI pipelines to keep them on track and optimized.

With Thundra Foresight in hand, you can spend more time writing tests, and less time debugging failed and long-running tests. Get started with Thundra Foresight now. Let’s catch up over Twitter and come and join our community Slack. We will be glad to answer your questions.