|
| 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