Thundra

Thundra: Serverless Observability for AWS Lambda

The black box nature of AWS Lambda and other serverless environments means that identifying and fixing performance issues is difficult and time-consuming. Built for straightforward debugging, monitoring, and observability, Thundra provides deep insight into your entire serverless environment. Thundra collects and correlates all your metrics, logs, and traces, allowing you to quickly identify problematic invocations and also analyzes external services associated with that function. With Thundra’s zero overhead and automated instrumentation capabilities, your developers are free to write code without worrying about bulking up their Lambdas or wasting time on chasing black box problems.

Get Started    Discussions

How to Instrument Node.js Functions

Instrumentation allows you to measure the behavior of your lambda functions in the form of spans. This provides detailed insights into the behavior of your functions, including information such as which function calls upon another function, the function arguments, return values, and possible errors. Moreover, it also provides information to external calls such as your Redis caches, AWS services, HTTP endpoints and much more.

Tracing capabilities are configured via instrumentation of your function, and can be done in two ways including manual and automated instrumentation. Depending on your choice of configuration, you can also use the OpenTracing API since Thundra's node agent is integrated with it.

Manual Instrumentation with Open Tracing

With manual instrumentation, you can add custom spans to your code to measure the execution time of your functions or any third party library or external services such as API or database calls and visualize them on the Thundra console with a simple programmatic API.

Thundra Agent is OpenTracing compliant, and thus you may use the OpenTracing API and the Thundra Tracer to measure execution times for specific pieces of code. This is done by initializing OpenTracing’s Global Tracer with the Thundra Tracer. In the following example, a Thundra Tracer is initialized and used as a global tracer.

After creating the global tracer, you may continue to monitor your Lambda functions using global tracer, or you may also use some Thundra specific methods, as defined in detail under Trace Support.

const thundra = require('@thundra/core');
const tracer = thundra.tracer();

const opentracing = require('opentracing'); // Require Opentrating node module
opentracing.initGlobalTracer(tracer);

//Get global tracer
const globalTracer = opentracing.globalTracer();

Remember to Initialize Thundra

When requiring thundra.tracer(), you would not require ('@thundra/core')() which would have initialized Thundra instantly. Instead, you must now initialize your Thundra when you are wrapping your function as exports.handler = thundra()((event, context, callback) =>

Automated Instrumentation

Thundra’s Node.js agent trace plug-in can allow you to perform automated instrumentation of your Lambda code with a simple configuration.

Each instrumentation feature can be configured via declaratively, programmatically or via environment variables. Declarative and programmatic configuration approach does not have any advantages over each other other than your code style preferences. However, with environment variable approach you can change configuration without redeploying your AWS Lambda functions.

Declarative Configuration

Configuring your Lambda function using automated instrumentation via a declarative approach involves the defining a traceConfig object in JSON notation. Within your TraceConfig object, you can define your configurations using the Thundra specific tracing variables, a list of which can be found here.

The code snippet below illustrates how the traceConfig object can be configured declaratively.

const config = {
	apiKey:<Your API Key>,
	traceConfig : {
		traceableConfigs: [{
			pattern : 'business.*.set*', //Defines what functions to monitor
		}],
	},
};

const thundra = require("@thundra/core");

exports.handler = thundra(config)((event, context, callback) => {
    callback(null, {msg : 'hello world'});    
});

As can be seen from the code snippet above, one of the traceConfig variables is traceDefs which further allows you to define a pattern, which allows you to state which function to monitor through Thundra trace. The format of the pattern property is <file-def>.<function-def> format where the property definitions are optional. Asterisk character () in the <file-def>``<function-def> is supported, and means all. Hence `business..set*` means that Thundra trace shall monitor all the functions that start with set in all the files under the business folder.

Programmatic Configuration

To configure Thundra’s Node.js agent trace plug-in using a programmatic approach, just create a TraceConfig object and configure the desired variables. Thundra specific tracing variables, a list of which can be found here.

The example below shows you how to configure a trace definition such that all functions which start with set under business folder will be traced. The format of the pattern property is <file-def>.<function-def> format where the property definitions are optional. Asterisk character () in the<file-def>``<function-def> is supported, and means all. Hence `business..set*means that Thundra Trace shall monitor all the functions that start with set in all the files under thebusiness` folder.

const thundra = require('@thundra/core');
const ThundraConfig = thundra.config.ThundraConfig;
const TraceConfig = thundra.config.TraceConfig;
const TraceableConfig = thundra.config.TraceableConfig;

const config = new ThundraConfig();
const traceConfig = new TraceConfig();
const traceableConfig = new TraceableConfig('business.*.set*');
traceConfig.traceConfigs.push(traceableConfig);

config.traceConfig = traceConfig;

exports.handler = thundra(config)((event, context, callback) => {
    callback(null, {msg : 'hello world'});    
});

Configuration via Environment Variables

To use environment variables, you must define your Environment Variable Prefixes, and pair these keys with respective values, and this will be done following a specific format as defined below:

Environment Variable Prefix: The name of the environment variable must start as below:

thundra_agent_lambda_trace_instrument_traceableConfig*

For example, thundra_agent_lambda_trace_instrument_traceableConfig, thundra_agent_lambda_trace_instrument_traceableConfig1, thundra_agent_lambda_trace_instrument_traceableConfigx, etc. There is no limit to the number of environment variables you declare, however, the AWS console does not allow the set size of environment variables to exceed 4 KB.

The environment variable value: The value of your environment variables must follow the format below.

<file-def>.<function-def>[propName1=propValue1,propName2=propValue2,...] 

The format where the property definitions are optional. Asterisk character (*) in the <file-def> and <function-def> are supported.

There are three property values that can be configured and these are:

  • traceArgs
  • traceReturn
  • traceError

For example, the value of environment values could be:

  • All functions in js files under ./user/service folder: user.service.*[]
  • All functions which start with get methods in the js files ./user/service folder:user.service.*.get

Additionally, by thundra_agent_lambda_trace_instrument_file_prefix environment variable, you can narrow down the scope of classes to be checked for reducing instrumentation overhead (reduces cold-start overhead as well). This configuration is strongly recommended for starting up Lambda applications faster. For example, you can set thundra_agent_lambda_trace_instrument_file_prefix environment variable to user.service for checking only js files from ./user/service folder.