Skip to content

Commit 0e9f9fb

Browse files
authored
feat: auto instrumentation for ruby lambda layer and add ruby 3.4.0 support (#1805)
1 parent 5708290 commit 0e9f9fb

File tree

4 files changed

+69
-26
lines changed

4 files changed

+69
-26
lines changed

ruby/README.md

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,21 @@
33
Scripts and files used to build AWS Lambda Layers for running OpenTelemetry on AWS Lambda for Ruby.
44

55
**Requirement**
6-
* [Ruby 3.2.0](https://www.ruby-lang.org/en/news/2022/12/25/ruby-3-2-0-released/) (only supported version)
6+
* Ruby 3.2.0/3.3.0/3.4.0
77
* [SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html)
88
* [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html)
99
* [Go](https://go.dev/doc/install)
1010
* [Docker](https://docs.docker.com/get-docker)
1111

1212
**Building Lambda Ruby Layer With OpenTelemetry Ruby Dependencies**
1313

14-
1. Pull and install all the gem dependencies in to `.aws-sam` folder
14+
1. Run build script
1515

1616
```bash
17-
sam build -u -t template.yml
17+
./build.sh
1818
```
1919

20-
2. Zip all the gems file, wrapper and handler into single zip file
21-
22-
```bash
23-
(cd .aws-sam/build/OTelLayer/ && zip -qr ../<your_layer_name>.zip .)
24-
mv .aws-sam/build/<your_layer_name>.zip .
25-
26-
# Or run the script
27-
zip_ruby_layer.sh -n <your_layer_name>
28-
```
20+
Layer is stored in `src/build` folder
2921

3022
**Default GEM_PATH**
3123

@@ -70,21 +62,28 @@ For more information about aws lambda wrapper and wrapper layer, check [aws lamb
7062

7163
### Sample App
7264

73-
1. Make sure the requirements are met (e.g. sam, aws, docker, ruby version.)
74-
2. Navigate to the path `cd ruby/sample-apps`
75-
3. Build the layer and function based on template.yml. You will see .aws-sam folder after executed the command
65+
1. Make sure the requirements are met (e.g. sam, aws, docker, ruby version.). Current sample app only support testing Ruby 3.2.0. If you wish to play with other ruby version, please modify ruby version from Runtime in sample-apps/template.yml and src/otel/layer/Makefile.
66+
67+
2. Navigate to the path `cd ruby/src` to build layer
68+
69+
```bash
70+
sam build -u -t template.yml
71+
```
72+
73+
3. Navigate to the path `cd ruby/sample-apps`
74+
4. Build the layer and function based on template.yml. You will see .aws-sam folder after executed the command
7675
```bash
7776
sam build -u -t template.yml
7877
# for different arch, define it in properties from template.yml
7978
# Architectures:
8079
# - arm64
8180
```
82-
4. Test with local simulation
81+
5. Test with local simulation
8382
```bash
8483
sam local start-api --skip-pull-image
8584
```
8685

87-
5. curl the lambda function
86+
6. curl the lambda function
8887
```bash
8988
curl http://127.0.0.1:3000
9089
# you should expect: Hello 1.4.1

ruby/src/otel/Dockerfile

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,28 +21,44 @@ RUN echo 'alias be="bundle exec"' >> ~/.profile
2121
RUN . ~/.profile \
2222
&& cd /root/.rbenv/plugins/ruby-build && git pull && cd - \
2323
&& rbenv install 3.2.0 \
24-
&& rbenv install 3.3.0
24+
&& rbenv install 3.3.0 \
25+
&& rbenv install 3.4.0
2526

2627
WORKDIR /build/layer
2728

2829
RUN . ~/.profile && rbenv local 3.2.0 && bundle install
2930
RUN . ~/.profile && rbenv local 3.3.0 && bundle install
31+
RUN . ~/.profile && rbenv local 3.4.0 && bundle install
3032

3133
WORKDIR /root/.rbenv/versions/3.2.0/lib/ruby/gems/
3234
RUN zip -r gems-3.2.0.zip 3.2.0/
3335

3436
WORKDIR /root/.rbenv/versions/3.3.0/lib/ruby/gems/
3537
RUN zip -r gems-3.3.0.zip 3.3.0/
3638

37-
RUN ls -al /root/.rbenv/versions/3.2.0/lib/ruby/gems && ls -al /root/.rbenv/versions/3.3.0/lib/ruby/gems
39+
WORKDIR /root/.rbenv/versions/3.4.0/lib/ruby/gems/
40+
41+
# rbenv install 3.4.0 get 3.4.0+1/, so need to change back to 3.4.0+1
42+
RUN mv 3.4.0+1/ 3.4.0/
43+
RUN set -e && \
44+
dir=$(find /root/.rbenv/versions/3.4.0/lib/ruby/gems/ -type d -name '3.4.0+1' | head -n 1) && \
45+
target=$(echo "$dir" | sed 's/3\.4\.0+1/3.4.0/') && \
46+
mv "$dir" "$target"
47+
RUN zip -r gems-3.4.0.zip 3.4.0/
3848

3949
# copy gems to /build/ruby/gems for zipping
4050
RUN mkdir /build/ruby && mkdir /build/ruby/gems
4151
WORKDIR /build/ruby/gems
4252
RUN cp /root/.rbenv/versions/3.2.0/lib/ruby/gems/gems-3.2.0.zip . && unzip gems-3.2.0.zip && rm gems-3.2.0.zip
4353
RUN cp /root/.rbenv/versions/3.3.0/lib/ruby/gems/gems-3.3.0.zip . && unzip gems-3.3.0.zip && rm gems-3.3.0.zip
54+
RUN cp /root/.rbenv/versions/3.4.0/lib/ruby/gems/gems-3.4.0.zip . && unzip gems-3.4.0.zip && rm gems-3.4.0.zip
4455
RUN ls -al /build/ruby/gems
4556

57+
# rm gem cache
58+
RUN rm /root/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/cache/* \
59+
&& rm /root/.rbenv/versions/3.3.0/lib/ruby/gems/3.3.0/cache/* \
60+
&& rm /root/.rbenv/versions/3.4.0/lib/ruby/gems/3.4.0/cache/*
61+
4662
# zip all the gems
4763
WORKDIR /build
4864
RUN cp layer/otel-handler . && cp layer/wrapper.rb .

ruby/src/otel/layer/Gemfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ source 'https://rubygems.org'
22

33
gem 'opentelemetry-sdk', '~> 1.8.0'
44
gem 'opentelemetry-exporter-otlp', '~> 0.30.0'
5-
gem 'opentelemetry-instrumentation-aws_lambda', '~> 0.3.0'
5+
gem 'opentelemetry-instrumentation-all', '~> 0.76.0'

ruby/src/otel/layer/wrapper.rb

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,40 @@
1-
require 'opentelemetry/sdk'
2-
require 'opentelemetry/exporter/otlp'
3-
require 'opentelemetry/instrumentation/aws_lambda'
1+
require 'opentelemetry-sdk'
2+
require 'opentelemetry-exporter-otlp'
3+
require 'opentelemetry-instrumentation-all'
4+
5+
# We need to load the function code's dependencies, and _before_ any dependencies might
6+
# be initialized outside of the function handler, bootstrap instrumentation.
7+
def preload_function_dependencies
8+
default_task_location = '/var/task'
9+
10+
handler_file = ENV.values_at('ORIG_HANDLER', '_HANDLER').compact.first&.split('.')&.first
11+
12+
unless handler_file && File.exist?("#{default_task_location}/#{handler_file}.rb")
13+
OpenTelemetry.logger.warn { 'Could not find the original handler file to preload libraries.' }
14+
return nil
15+
end
16+
17+
libraries = File.read("#{default_task_location}/#{handler_file}.rb")
18+
.scan(/^\s*require\s+['"]([^'"]+)['"]/)
19+
.flatten
20+
21+
libraries.each do |lib|
22+
require lib
23+
rescue StandardError => e
24+
OpenTelemetry.logger.warn { "Could not load library #{lib}: #{e.message}" }
25+
end
26+
handler_file
27+
end
28+
29+
handler_file = preload_function_dependencies
30+
31+
OpenTelemetry.logger.info { "Libraries in #{handler_file} have been preloaded." } if handler_file
432

533
OpenTelemetry::SDK.configure do |c|
6-
c.use 'OpenTelemetry::Instrumentation::AwsLambda'
34+
c.use_all()
735
end
836

937
def otel_wrapper(event:, context:)
10-
otel_wrapper = OpenTelemetry::Instrumentation::AwsLambda::Handler.new()
38+
otel_wrapper = OpenTelemetry::Instrumentation::AwsLambda::Handler.new
1139
otel_wrapper.call_wrapped(event: event, context: context)
12-
end
40+
end

0 commit comments

Comments
 (0)