Skip to content

Commit f66b30d

Browse files
authored
Merge pull request #318 from gkono-splunk/lambda-tracing
Add Lambda Tracing Ninja Workshop
2 parents 38cb349 + 7766e59 commit f66b30d

21 files changed

+812
-0
lines changed
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
---
2+
title: Setup
3+
linkTitle: 1. Setup
4+
weight: 1
5+
---
6+
7+
![Lambda application, not yet instrumented](../images/01-Architecture.png)
8+
9+
## Prerequisites
10+
11+
### Observability Workshop Instance
12+
The Observability Workshop is most often completed on a Splunk-issued and preconfigured EC2 instance running Ubuntu.
13+
- Your workshop instructor will have provided you with your credentials to access your instance.
14+
- Alternatively, you can deploy a local observability workshop instance using Multipass.
15+
16+
### AWS Command Line Interface (awscli)
17+
The AWS Command Line Interface, or `awscli`, is an API used to interact with AWS resources. In this workshop, it is used by certain scripts to interact with the resource you'll deploy.
18+
19+
- Check if the **aws** command is installed on your instance with the following command:
20+
```bash
21+
which aws
22+
```
23+
- _The expected output would be **/usr/local/bin/aws**_
24+
25+
- If the **aws** command is not installed on your instance, run the following command:
26+
```bash
27+
sudo apt install awscli
28+
```
29+
30+
### Terraform
31+
Terraform is an Infrastructure as Code (IaC) platform, used to deploy, manage and destroy resource by defining them in configuration files. Terraform employs HCL to define those resources, and supports multiple providers for various platforms and technologies.
32+
33+
We will be using Terraform at the command line in this workshop to deploy the following resources:
34+
1. AWS API Gateway
35+
2. Lambda Functions
36+
3. Kinesis Stream
37+
4. CloudWatch Log Groups
38+
5. S3 Bucket
39+
- _and other supporting resources_
40+
41+
- Check if the **terraform** command is installed on your instance:
42+
```bash
43+
which terraform
44+
```
45+
- _The expected output would be **/usr/local/bin/terraform**_
46+
47+
- If the **terraform** command is not installed on your instance, follow Terraform's recommended installation commands listed below:
48+
```bash
49+
wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
50+
51+
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
52+
53+
sudo apt update && sudo apt install terraform
54+
```
55+
56+
### Workshop Directory (o11y-lambda-workshop)
57+
The Workshop Directory `o11y-lambda-workshop` is a repository that contains all the configuration files and scripts to complete both the auto-instrumentation and manual instrumentation of the example Lambda-based application we will be using today.
58+
59+
- Confirm you have the workshop directory in your home directory:
60+
```bash
61+
cd && ls
62+
```
63+
- _The expected output would include **o11y-lambda-workshop**_
64+
65+
- If the **o11y-lambda-workshop** directory is not in your home directory, clone it with the following command:
66+
```bash
67+
git clone https://github.com/gkono-splunk/o11y-lambda-workshop.git
68+
```
69+
70+
### AWS & Terraform Variables
71+
72+
#### AWS
73+
The AWS CLI requires that you have credentials to be able to access and manage resources deployed by their services. Both Terraform and the Python scripts in this workshop require these variables to perform their tasks.
74+
75+
- Ensure you have the following environment variables set for AWS access:
76+
```bash
77+
echo $AWS_ACCESS_KEY_ID
78+
echo $AWS_SECRET_ACCESS_KEY
79+
```
80+
- _These commands should output text results for your **access key ID** and **secret access key**_
81+
82+
- If the AWS environment variables aren't set, request those keys from your instructor.
83+
- Replace the **CHANGEME** values for the following variables, then copy and paste them into your command line.
84+
```bash
85+
export AWS_ACCESS_KEY_ID="CHANGEME"
86+
export AWS_SECRET_ACCESS_KEY="CHANGEME"
87+
```
88+
89+
#### Terraform
90+
Terraform supports the passing of variables to ensure sensitive or dynamic data is not hard-coded in your .tf configuration files.
91+
92+
Terraform variables are defined by setting TF_VAR_ environment variables and declaring those variables in our TF configuration files.
93+
94+
In our workshop, Terraform requires variables necessary for deploying the Lambda functions with the right environment variables for the OpenTelemetry Lambda layer, as well as the ingest values for Splunk Observability Cloud.
95+
96+
- Ensure you have the following environment variables set for AWS access:
97+
```bash
98+
echo $TF_VAR_o11y_access_token
99+
echo $TF_VAR_o11y_realm
100+
echo $TF_VAR_otel_lambda_layer
101+
echo $TF_VAR_prefix
102+
```
103+
- _These commands should output text for the **access token**, **realm**, and **otel lambda layer** for Splunk Observability Cloud, which your instructor has, or can, share with you._
104+
- _Also there should be an output for the **prefix** that will be used to name your resources. It will be a value that you provide._
105+
106+
- If the Terraform environment variables aren't set, request the **access token**, **realm**, and **otel lambda layer** from your instructor.
107+
- Replace the **CHANGEME** values for the following variables, then copy and paste them into your command line.
108+
```bash
109+
export TF_VAR_o11y_access_token="CHANGEME"
110+
export TF_VAR_o11y_realm="CHANGEME"
111+
export TF_VAR_otel_lambda_layer='["CHANGEME"]'
112+
export TF_VAR_prefix="CHANGEME"
113+
```
114+
115+
Now that we've squared off the prerequisites, we can get started with the workshop!
Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
---
2+
title: Auto-Instrumentation
3+
linkTitle: 2. Auto-Instrumentation
4+
weight: 2
5+
---
6+
7+
The first part of our workshop will demonstrate how auto-instrumentation with OpenTelemetry allows the OpenTelemetry Collector to auto-detect what language your function is written in, and start capturing traces for those applications.
8+
9+
### The Auto-Instrumentation Workshop Directory & Contents
10+
First, let us take a look at the `o11y-lambda-workshop/auto` directory, and some of its files. This is where all the content for the auto-instrumentation portion of our workshop resides.
11+
12+
#### The `auto` Directory
13+
- Run the following command to get into the `o11y-lambda-workshop/auto` directory:
14+
```bash
15+
cd ~/o11y-lambda-workshop/auto
16+
```
17+
18+
- Inspect the contents of this directory:
19+
```bash
20+
ls
21+
```
22+
- _The output should include the following files and directories:_
23+
```bash
24+
get_logs.py main.tf send_message.py
25+
handler outputs.tf terraform.tf
26+
```
27+
28+
#### The `main.tf` file
29+
- Take a closer look at the `main.tf` file:
30+
```bash
31+
cat main.tf
32+
```
33+
34+
{{% notice title="Workshop Questions" style="tip" icon="question" %}}
35+
36+
* Can you identify which AWS resources are being created by this template?
37+
* Can you identify where OpenTelemetry instrumentation is being set up?
38+
* _Hint: study the lambda function definitions_
39+
* Can you determine which instrumentation information is being provided by the environment variables we set earlier?
40+
41+
{{% /notice %}}
42+
43+
You should see a section where the environment variables for each lambda function are being set.
44+
```bash
45+
environment {
46+
variables = {
47+
SPLUNK_ACCESS_TOKEN = var.o11y_access_token
48+
SPLUNK_REALM = var.o11y_realm
49+
OTEL_SERVICE_NAME = "producer-lambda"
50+
OTEL_RESOURCE_ATTRIBUTES = "deployment.environment=${var.prefix}-lambda-shop"
51+
AWS_LAMBDA_EXEC_WRAPPER = "/opt/nodejs-otel-handler"
52+
KINESIS_STREAM = aws_kinesis_stream.lambda_streamer.name
53+
}
54+
}
55+
```
56+
57+
By using these environment variables, we are configuring our auto-instrumentation in a few ways:
58+
- We are setting environment variables to inform the OpenTelemetry collector of which Splunk Observability Cloud organization we would like to have our data exported to.
59+
```bash
60+
SPLUNK_ACCESS_TOKEN = var.o11y_access_token
61+
SPLUNK_ACCESS_TOKEN = var.o11y_realm
62+
```
63+
64+
- We are also setting variables that help OpenTelemetry identify our function/service, as well as the environment/application it is a part of.
65+
```bash
66+
OTEL_SERVICE_NAME = "producer-lambda" # consumer-lambda in the case of the consumer function
67+
OTEL_RESOURCE_ATTRIBUTES = "deployment.environment=${var.prefix}-lambda-shop"
68+
```
69+
70+
- We are setting an environment variable that lets OpenTelemetry know what wrappers it needs to apply to our function's handler so as to capture trace data automatically, based on our code language.
71+
```bash
72+
AWS_LAMBDA_EXEC_WRAPPER - "/opt/nodejs-otel-handler"
73+
```
74+
75+
- In the case of the `producer-lambda` function, we are setting an environment variable to let the function know what Kinesis Stream to put our record to.
76+
```bash
77+
KINESIS_STREAM = aws_kinesis_stream.lambda_streamer.name
78+
```
79+
80+
- These values are sourced from the environment variables we set in the Prerequisites section, as well as resources that will be deployed as a part of this Terraform configuration file.
81+
82+
You should also see an argument for setting the Splunk OpenTelemetry Lambda layer on each function
83+
```bash
84+
layers = var.otel_lambda_layer
85+
```
86+
- The OpenTelemetry Lambda layer is a package that contains the libraries and dependencies necessary to collector, process and export telemetry data for Lambda functions at the moment of invocation.
87+
88+
- While there is a general OTel Lambda layer that has all the libraries and dependencies for all OpenTelemetry-supported languages, there are also language-specific Lambda layers, to help make your function even more lightweight.
89+
90+
- _You can see the relevant Splunk OpenTelemetry Lambda layer ARNs (Amazon Resource Name) and latest versions for each AWS region [HERE](https://github.com/signalfx/lambda-layer-versions/blob/main/splunk-apm/splunk-apm.md)_
91+
92+
#### The `producer.mjs` file
93+
Next, let's take a look at the `producer-lambda` function code:
94+
95+
- Run the following command to view the contents of the `producer.mjs` file:
96+
```bash
97+
cat ~/o11y-lambda-workshop/auto/handler/producer.mjs
98+
```
99+
100+
- This NodeJS module contains the code for the producer function.
101+
- Essentially, this function receives a message, and puts that message as a record to the targeted Kinesis Stream
102+
103+
### Deploying the Lambda Functions & Generating Trace Data
104+
Now that we are familiar with the contents of our `auto` directory, we can deploy the resources for our workshop, and generate some trace data from our Lambda functions.
105+
106+
#### Initialize Terraform in the `auto` directory
107+
In order to deploy the resources defined in the `main.tf` file, you first need to make sure that Terraform is initialized in the same folder as that file.
108+
109+
- Ensure you are in the `auto` directory:
110+
```bash
111+
pwd
112+
```
113+
- _The expected output would be **~/o11y-lambda-workshop/auto**_
114+
115+
- If you are not in the `auto` directory, run the following command:
116+
```bash
117+
cd ~/o11y-lambda-workshop/auto
118+
```
119+
120+
- Run the following command to initialize Terraform in this directory
121+
```bash
122+
terraform init
123+
```
124+
- This command will create a number of elements in the same folder:
125+
- `.terraform.lock.hcl` file: to record the providers it will use to provide resources
126+
- `.terraform` directory: to store the provider configurations
127+
128+
- In addition to the above files, when terraform is run using the `apply` subcommand, the `terraform.tfstate` file will be created to track the state of your deployed resources.
129+
130+
- This enables Terraform to manage the creation, state and destruction of resources, as defined within the `main.tf` file of the `auto` directory
131+
132+
#### Deploy the Lambda functions and other AWS resources
133+
Once we've initialized Terraform in this directory, we can go ahead and deploy our resources.
134+
135+
- Run the Terraform command to have the Lambda function and other supporting resources deployed from the `main.tf` file:
136+
```bash
137+
terraform apply
138+
```
139+
- respond `yes` when you see the `Enter a value:` prompt
140+
141+
- This will result in the following outputs:
142+
```bash
143+
Outputs:
144+
145+
lambda_bucket_name = "lambda-shop-______-______"
146+
base_url = "https://______.amazonaws.com/serverless_stage/producer"
147+
producer_function_name = "______-producer"
148+
producer_log_group_arn = "arn:aws:logs:us-east-1:############:log-group:/aws/lambda/______-producer"
149+
consumer_function_name = "_____-consumer"
150+
consumer_log_group_arn = "arn:aws:logs:us-east-1:############:log-group:/aws/lambda/______-consumer"
151+
environment = "______-lambda-shop"
152+
```
153+
154+
#### Send some traffic to the `producer-lambda` endpoint (`base_url`)
155+
To start getting some traces from our deployed Lambda functions, we would need to generate some traffic. We will send a message to our `producer-lambda` function's endpoint, which should be put as a record into our Kinesis Stream, and then pulled from the Stream by the `consumer-lambda` function.
156+
157+
- Ensure you are in the `auto` directory:
158+
```bash
159+
pwd
160+
```
161+
- _The expected output would be **~/o11y-lambda-workshop/auto**_
162+
163+
- If you are not in the `auto` directory, run the following command
164+
```bash
165+
cd ~/o11y-lambda-workshop/auto
166+
```
167+
168+
The `send_message.py` script is a Python script that will take input at the command line, add it to a JSON dictionary, and send it to your `producer-lambda` function's endpoint repeatedly, as part of a while loop.
169+
170+
- Run the `send_message.py` script as a background process
171+
- _It requires the `--name` and `--superpower` arguments_
172+
```bash
173+
nohup ./send_message.py --name CHANGEME --superpower CHANGEME &
174+
```
175+
- You should see an output similar to the following if your message is successful
176+
```bash
177+
[1] 79829
178+
user@host manual % appending output to nohup.out
179+
```
180+
- _The two most import bits of information here are:_
181+
- _The process ID on the first line (`79829` in the case of my example), and_
182+
- _The `appending output to nohup.out` message_
183+
184+
- _The `nohup` command ensures the script will not hang up when sent to the background. It also captures any output from our command in a nohup.out file in the same folder as the one you're currently in._
185+
186+
- _The `&` tells our shell process to run this process in the background, thus freeing our shell to run other commands._
187+
188+
- Next, check the contents of the `nohup.out` file, to ensure your output confirms your requests to your `producer-lambda` endpoint are successful:
189+
```bash
190+
cat nohup.out
191+
```
192+
- You should see the following output among the lines printed to your screen if your message is successful:
193+
```bash
194+
{"message": "Message placed in the Event Stream: hostname-eventStream"}
195+
```
196+
197+
- If unsuccessful, you will see:
198+
```bash
199+
{"message": "Internal server error"}
200+
```
201+
202+
> [!IMPORTANT]
203+
> If this occurs, ask one of the workshop facilitators for assistance.
204+
205+
#### View the Lambda Function Logs
206+
Next, let's take a look at the logs for our Lambda functions.
207+
208+
- Run the following script to view your `producer-lambda` logs:
209+
```bash
210+
./get_logs.py --function producer
211+
```
212+
- Hit `[CONTROL-C]` to stop the live stream after some log events show up
213+
214+
- Run the following to view your `consumer-lambda` logs:
215+
```bash
216+
./get_logs.py --function consumer
217+
```
218+
- Hit `[CONTROL-C]` to stop the live stream after some log events show up
219+
220+
Examine the logs carefully.
221+
222+
{{% notice title="Workshop Question" style="tip" icon="question" %}}
223+
224+
* Do you see OpenTelemetry being loaded? Look out for the lines with `splunk-extension-wrapper`
225+
226+
{{% /notice %}}

0 commit comments

Comments
 (0)