aws_lambda_ric 3.1.3 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +51 -12
- data/aws_lambda_ric.gemspec +1 -0
- data/lib/aws_lambda_ric/lambda_log_formatter.rb +59 -2
- data/lib/aws_lambda_ric/logger_patch.rb +49 -11
- data/lib/aws_lambda_ric/version.rb +1 -1
- data/lib/aws_lambda_ric.rb +24 -16
- metadata +22 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: aebcc51bb69e0146bf4fe0c2361e55967d773569e9a75b5edfee8e59926dca71
|
|
4
|
+
data.tar.gz: ee94ca25bd713f8dca2a08a876b6b8e9512a02953ade9d14cfa79c38b3eaee4b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 29f94ab802c88332d74581db2303c2b64b9864a3a5a2abdef0bdc7e1c4df810ed4248790d371d0dd55d934765928972a27a0b11976c66c86f468465b2bf62bb5
|
|
7
|
+
data.tar.gz: 82dada5e5cab9d9e85e0d0d44f65e8ccfbada3a633a491ccf25fb32b8ed0e812355be7c8fe6fa973c38e6cd0e6efeca81bf9b4a914f9a7d42b453fac50c35a57
|
data/README.md
CHANGED
|
@@ -11,6 +11,17 @@ You can include this package in your preferred base image to make that base imag
|
|
|
11
11
|
|
|
12
12
|
## Requirements
|
|
13
13
|
The Ruby Runtime Interface Client package currently supports ruby 3.0 and above.
|
|
14
|
+
|
|
15
|
+
## Migration from 2.x to 3.x
|
|
16
|
+
|
|
17
|
+
**Important**: Version 2.x is deprecated. Please upgrade to version 3.x. For more information about Lambda runtime support, see the [AWS Lambda runtimes documentation](https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html).
|
|
18
|
+
|
|
19
|
+
**Breaking Change**: Version 3.0.0 introduced a change in how the handler is specified:
|
|
20
|
+
|
|
21
|
+
- **Version 2.x**: Handler was passed as a command line argument
|
|
22
|
+
- **Version 3.x+**: Handler must be specified via the `_HANDLER` environment variable
|
|
23
|
+
|
|
24
|
+
If you're upgrading from 2.x, update your Dockerfile to use the `_HANDLER` environment variable instead of relying on `CMD` arguments.
|
|
14
25
|
|
|
15
26
|
## Usage
|
|
16
27
|
|
|
@@ -39,7 +50,9 @@ Or install it manually as:
|
|
|
39
50
|
|
|
40
51
|
The next step would be to copy your Lambda function code into the image's working directory.
|
|
41
52
|
You will need to set the `ENTRYPOINT` property of the Docker image to invoke the Runtime Interface Client and
|
|
42
|
-
|
|
53
|
+
set the `_HANDLER` environment variable to specify the desired handler.
|
|
54
|
+
|
|
55
|
+
**Important**: The Runtime Interface Client requires the handler to be specified via the `_HANDLER` environment variable.
|
|
43
56
|
|
|
44
57
|
Example Dockerfile:
|
|
45
58
|
```dockerfile
|
|
@@ -57,23 +70,16 @@ RUN gem install bundler
|
|
|
57
70
|
# Install the Runtime Interface Client
|
|
58
71
|
RUN gem install aws_lambda_ric
|
|
59
72
|
|
|
60
|
-
# If you want to install Runtime Interface Client From Source, you can uncomment the following `ADD` and `RUN` layers.
|
|
61
|
-
# Do not forget to comment/remove the above `RUN gem install aws_lambda_ric` command.
|
|
62
|
-
# ADD https://github.com/aws/aws-lambda-ruby-runtime-interface-client.git /aws_lambda_ric
|
|
63
|
-
# RUN cd /aws_lambda_ric && \
|
|
64
|
-
# make init && \
|
|
65
|
-
# make build && \
|
|
66
|
-
# gem install --local /aws_lambda_ric/pkg/aws_lambda_ric-3.0.0.gem && \
|
|
67
|
-
# rm -rf /aws_lambda_ric
|
|
68
|
-
|
|
69
73
|
# Copy function code
|
|
70
74
|
RUN mkdir -p ${FUNCTION_DIR}
|
|
71
75
|
COPY app.rb ${FUNCTION_DIR}
|
|
72
76
|
|
|
73
77
|
WORKDIR ${FUNCTION_DIR}
|
|
74
78
|
|
|
79
|
+
# Set the handler via environment variable
|
|
80
|
+
ENV _HANDLER="app.App::Handler.process"
|
|
81
|
+
|
|
75
82
|
ENTRYPOINT ["/usr/local/bin/aws_lambda_ric"]
|
|
76
|
-
CMD ["app.App::Handler.process"]
|
|
77
83
|
```
|
|
78
84
|
|
|
79
85
|
Note that the `ENTRYPOINT` may differ based on the base image used. You can find the correct path by running an
|
|
@@ -119,9 +125,10 @@ mkdir -p ~/.aws-lambda-rie && \
|
|
|
119
125
|
|
|
120
126
|
```shell script
|
|
121
127
|
docker run -d -v ~/.aws-lambda-rie:/aws-lambda -p 9000:8080 \
|
|
128
|
+
-e _HANDLER="app.App::Handler.process" \
|
|
122
129
|
--entrypoint /aws-lambda/aws-lambda-rie \
|
|
123
130
|
myfunction:latest \
|
|
124
|
-
/usr/local/bin/aws_lambda_ric
|
|
131
|
+
/usr/local/bin/aws_lambda_ric
|
|
125
132
|
```
|
|
126
133
|
|
|
127
134
|
This runs the image as a container and starts up an endpoint locally at `http://localhost:9000/2015-03-31/functions/function/invocations`.
|
|
@@ -136,6 +143,28 @@ This command invokes the function running in the container image and returns a r
|
|
|
136
143
|
|
|
137
144
|
*Alternately, you can also include RIE as a part of your base image. See the AWS documentation on how to [Build RIE into your base image](https://docs.aws.amazon.com/lambda/latest/dg/images-test.html#images-test-alternative).*
|
|
138
145
|
|
|
146
|
+
### Automated Local Testing
|
|
147
|
+
|
|
148
|
+
For a simple approach to run your local RIC changes, use the one-command setup:
|
|
149
|
+
|
|
150
|
+
```shell script
|
|
151
|
+
make run-local-ric
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
This command will:
|
|
155
|
+
1. Build a Docker image with your local RIC code
|
|
156
|
+
2. Compile the gem inside the Linux container (avoiding OS compatibility issues)
|
|
157
|
+
3. Start the Lambda Runtime Interface Emulator on port 9000
|
|
158
|
+
4. Run a test Lambda function using your RIC
|
|
159
|
+
|
|
160
|
+
Once running, invoke the function from another terminal:
|
|
161
|
+
|
|
162
|
+
```shell script
|
|
163
|
+
curl -X POST "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{}'
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Modify the test handler in `test/integration/test-handlers/echo/app.rb` to test different scenarios.
|
|
167
|
+
|
|
139
168
|
## Development
|
|
140
169
|
|
|
141
170
|
### Building the package
|
|
@@ -157,6 +186,16 @@ Then,
|
|
|
157
186
|
* to run integration tests: `make test-integ`
|
|
158
187
|
* to run smoke tests: `make test-smoke`
|
|
159
188
|
|
|
189
|
+
### Running Dockerized Harness Tests
|
|
190
|
+
|
|
191
|
+
To run the containerized test harness locally, use:
|
|
192
|
+
|
|
193
|
+
```shell script
|
|
194
|
+
make test-dockerized RUBY_VERSION=3.4
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
This command builds your Lambda function in a Docker container using the specified Ruby version, sets up the containerized test runner, and executes the test suites defined in `test/dockerized/suites/`.
|
|
198
|
+
|
|
160
199
|
### Troubleshooting
|
|
161
200
|
While running integration tests, you might encounter the Docker Hub rate limit error with the following body:
|
|
162
201
|
```
|
data/aws_lambda_ric.gemspec
CHANGED
|
@@ -31,6 +31,7 @@ Gem::Specification.new do |spec|
|
|
|
31
31
|
spec.executables = 'aws_lambda_ric'
|
|
32
32
|
spec.require_paths = ['lib']
|
|
33
33
|
|
|
34
|
+
spec.add_runtime_dependency "logger", ">= 1.4", "< 2.0"
|
|
34
35
|
spec.add_development_dependency 'bundler', '~> 2.0'
|
|
35
36
|
spec.add_development_dependency 'minitest', '~> 5.0'
|
|
36
37
|
spec.add_development_dependency 'rake', '~> 13.0'
|
|
@@ -1,12 +1,69 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'json'
|
|
3
4
|
require 'logger'
|
|
4
5
|
|
|
5
6
|
class LogFormatter < Logger::Formatter
|
|
6
7
|
FORMAT = '%<sev>s, [%<datetime>s #%<process>d] %<severity>5s %<request_id>s -- %<progname>s: %<msg>s'
|
|
7
8
|
|
|
8
9
|
def call(severity, time, progname, msg)
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
formatted = FORMAT % {
|
|
11
|
+
sev: severity[0..0],
|
|
12
|
+
datetime: format_datetime(time),
|
|
13
|
+
process: $$,
|
|
14
|
+
severity: severity,
|
|
15
|
+
request_id: $_global_aws_request_id,
|
|
16
|
+
progname: progname,
|
|
17
|
+
msg: msg2str(msg)
|
|
18
|
+
}
|
|
19
|
+
"#{formatted.encode('UTF-8', invalid: :replace, undef: :replace, replace: '�')}\n"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
class JsonLogFormatter < Logger::Formatter
|
|
24
|
+
DATETIME_FORMAT = '%Y-%m-%dT%H:%M:%S.%6NZ'
|
|
25
|
+
|
|
26
|
+
def call(severity, time, progname, msg)
|
|
27
|
+
payload = {
|
|
28
|
+
timestamp: time.utc.strftime(DATETIME_FORMAT),
|
|
29
|
+
level: severity,
|
|
30
|
+
message: message_for(msg),
|
|
31
|
+
requestId: $_global_aws_request_id
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
logger_name = sanitize_utf8(progname) unless progname.nil?
|
|
35
|
+
payload[:logger] = logger_name unless logger_name.nil? || logger_name.empty?
|
|
36
|
+
|
|
37
|
+
if msg.is_a?(Exception)
|
|
38
|
+
payload[:errorType] = msg.class.to_s
|
|
39
|
+
payload[:errorMessage] = sanitize_utf8(msg.message)
|
|
40
|
+
payload[:stackTrace] = Array(msg.backtrace).map { |line| sanitize_utf8(line) }
|
|
41
|
+
location = location_for(msg)
|
|
42
|
+
payload[:location] = location unless location.nil?
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
"#{JSON.generate(payload.compact)}\n"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
def message_for(msg)
|
|
51
|
+
result = msg.is_a?(Exception) ? msg.message : msg2str(msg)
|
|
52
|
+
sanitize_utf8(result)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def location_for(exception)
|
|
56
|
+
first_backtrace_line = exception.backtrace&.first
|
|
57
|
+
return nil if first_backtrace_line.nil?
|
|
58
|
+
|
|
59
|
+
sanitized_line = sanitize_utf8(first_backtrace_line)
|
|
60
|
+
matched = sanitized_line.match(/\A(?<file>.+):(?<line>\d+):in [`'](?<method>.+)'\z/)
|
|
61
|
+
return "#{matched[:file]}:#{matched[:method]}:#{matched[:line]}" if matched
|
|
62
|
+
|
|
63
|
+
sanitized_line
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def sanitize_utf8(value)
|
|
67
|
+
value.to_s.encode('UTF-8', invalid: :replace, undef: :replace, replace: '�')
|
|
11
68
|
end
|
|
12
69
|
end
|
|
@@ -1,19 +1,57 @@
|
|
|
1
1
|
# Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
2
|
|
|
3
|
+
# frozen_string_literal: true
|
|
4
|
+
|
|
5
|
+
require 'logger'
|
|
6
|
+
require_relative 'lambda_log_formatter'
|
|
7
|
+
|
|
3
8
|
module LoggerPatch
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
LOG_LEVEL_MAP = {
|
|
10
|
+
'TRACE' => Logger::DEBUG,
|
|
11
|
+
'DEBUG' => Logger::DEBUG,
|
|
12
|
+
'INFO' => Logger::INFO,
|
|
13
|
+
'WARN' => Logger::WARN,
|
|
14
|
+
'ERROR' => Logger::ERROR,
|
|
15
|
+
'FATAL' => Logger::FATAL
|
|
16
|
+
}.freeze
|
|
17
|
+
|
|
18
|
+
class << self
|
|
19
|
+
attr_reader :aws_lambda_log_format, :aws_lambda_log_level
|
|
20
|
+
|
|
21
|
+
def refresh_runtime_config!
|
|
22
|
+
@aws_lambda_log_format = ENV.fetch('AWS_LAMBDA_LOG_FORMAT', '').upcase
|
|
23
|
+
env_level = ENV.fetch('AWS_LAMBDA_LOG_LEVEL', nil)
|
|
24
|
+
@aws_lambda_log_level = LOG_LEVEL_MAP[env_level&.upcase]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def json_format?
|
|
28
|
+
@aws_lambda_log_format == 'JSON'
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
refresh_runtime_config!
|
|
33
|
+
|
|
34
|
+
# shift_size default to 1 megabyte, matching Ruby Logger's default log rotation size.
|
|
35
|
+
def initialize(logdev, shift_age = 0, shift_size = 1_048_576, **kwargs)
|
|
36
|
+
level_was_provided = kwargs.key?(:level)
|
|
37
|
+
kwargs = {
|
|
38
|
+
level: Logger::DEBUG,
|
|
39
|
+
progname: nil,
|
|
40
|
+
formatter: nil,
|
|
41
|
+
datetime_format: nil,
|
|
42
|
+
binmode: false,
|
|
43
|
+
shift_period_suffix: '%Y%m%d'
|
|
44
|
+
}.merge(kwargs)
|
|
45
|
+
|
|
46
|
+
logdev_override = logdev
|
|
47
|
+
|
|
10
48
|
if !logdev || logdev == $stdout || logdev == $stderr
|
|
11
|
-
|
|
12
|
-
|
|
49
|
+
telemetry_sink = AwsLambdaRIC::TelemetryLogger.telemetry_log_sink
|
|
50
|
+
logdev_override = telemetry_sink || logdev
|
|
51
|
+
kwargs[:formatter] ||= LoggerPatch.json_format? ? JsonLogFormatter.new : LogFormatter.new
|
|
52
|
+
kwargs[:level] = LoggerPatch.aws_lambda_log_level if !level_was_provided && LoggerPatch.aws_lambda_log_level
|
|
13
53
|
end
|
|
14
54
|
|
|
15
|
-
super(
|
|
16
|
-
formatter: formatter_override, datetime_format: datetime_format,
|
|
17
|
-
binmode: binmode, shift_period_suffix: shift_period_suffix)
|
|
55
|
+
super(logdev_override, shift_age, shift_size, **kwargs)
|
|
18
56
|
end
|
|
19
57
|
end
|
data/lib/aws_lambda_ric.rb
CHANGED
|
@@ -131,10 +131,19 @@ module AwsLambdaRIC
|
|
|
131
131
|
ENV_VAR_TELEMETRY_LOG_FD = '_LAMBDA_TELEMETRY_LOG_FD'
|
|
132
132
|
|
|
133
133
|
class << self
|
|
134
|
-
attr_accessor :telemetry_log_fd_file, :telemetry_log_sink
|
|
135
|
-
|
|
134
|
+
attr_accessor :telemetry_log_fd_file, :telemetry_log_sink, :logger_patch_applied
|
|
136
135
|
def close
|
|
137
136
|
telemetry_log_fd_file&.close
|
|
137
|
+
self.telemetry_log_fd_file = nil
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def mutate_std_logger
|
|
141
|
+
return if logger_patch_applied
|
|
142
|
+
|
|
143
|
+
Logger.class_eval do
|
|
144
|
+
prepend LoggerPatch
|
|
145
|
+
end
|
|
146
|
+
self.logger_patch_applied = true
|
|
138
147
|
end
|
|
139
148
|
end
|
|
140
149
|
|
|
@@ -145,28 +154,28 @@ module AwsLambdaRIC
|
|
|
145
154
|
|
|
146
155
|
AwsLambdaRIC::TelemetryLogger.telemetry_log_sink = TelemetryLogSink.new(file: AwsLambdaRIC::TelemetryLogger.telemetry_log_fd_file)
|
|
147
156
|
|
|
148
|
-
mutate_std_logger
|
|
149
157
|
mutate_kernel_puts
|
|
158
|
+
|
|
150
159
|
rescue Errno::ENOENT, Errno::EBADF
|
|
151
|
-
|
|
160
|
+
AwsLambdaRIC::TelemetryLogger.telemetry_log_fd_file = nil
|
|
161
|
+
AwsLambdaRIC::TelemetryLogger.telemetry_log_sink = nil
|
|
152
162
|
end
|
|
153
163
|
|
|
154
164
|
def self.from_env()
|
|
155
|
-
if ENV.key?(ENV_VAR_TELEMETRY_LOG_FD)
|
|
156
|
-
fd = ENV.fetch(AwsLambdaRIC::TelemetryLogger::ENV_VAR_TELEMETRY_LOG_FD)
|
|
157
|
-
ENV.delete(AwsLambdaRIC::TelemetryLogger::ENV_VAR_TELEMETRY_LOG_FD)
|
|
158
|
-
AwsLambdaRIC::TelemetryLogger.new(fd)
|
|
159
|
-
end
|
|
160
|
-
end
|
|
161
165
|
|
|
162
|
-
|
|
166
|
+
LoggerPatch.refresh_runtime_config!
|
|
167
|
+
mutate_std_logger
|
|
168
|
+
AwsLambdaRIC::TelemetryLogger.telemetry_log_sink = nil
|
|
163
169
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
170
|
+
return unless ENV.key?(ENV_VAR_TELEMETRY_LOG_FD)
|
|
171
|
+
|
|
172
|
+
fd = ENV.fetch(AwsLambdaRIC::TelemetryLogger::ENV_VAR_TELEMETRY_LOG_FD)
|
|
173
|
+
ENV.delete(AwsLambdaRIC::TelemetryLogger::ENV_VAR_TELEMETRY_LOG_FD)
|
|
174
|
+
AwsLambdaRIC::TelemetryLogger.new(fd)
|
|
168
175
|
end
|
|
169
176
|
|
|
177
|
+
private
|
|
178
|
+
|
|
170
179
|
def mutate_kernel_puts
|
|
171
180
|
Kernel.module_eval do
|
|
172
181
|
def puts(*arg)
|
|
@@ -180,7 +189,6 @@ module AwsLambdaRIC
|
|
|
180
189
|
end
|
|
181
190
|
end
|
|
182
191
|
end
|
|
183
|
-
|
|
184
192
|
# Represents a single Lambda Invocation Request
|
|
185
193
|
class LambdaInvocationRequest
|
|
186
194
|
|
metadata
CHANGED
|
@@ -1,15 +1,35 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: aws_lambda_ric
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- AWS Lambda
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-04-15 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: logger
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '1.4'
|
|
20
|
+
- - "<"
|
|
21
|
+
- !ruby/object:Gem::Version
|
|
22
|
+
version: '2.0'
|
|
23
|
+
type: :runtime
|
|
24
|
+
prerelease: false
|
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
26
|
+
requirements:
|
|
27
|
+
- - ">="
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: '1.4'
|
|
30
|
+
- - "<"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '2.0'
|
|
13
33
|
- !ruby/object:Gem::Dependency
|
|
14
34
|
name: bundler
|
|
15
35
|
requirement: !ruby/object:Gem::Requirement
|