Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Current code from a Ruby 3.3 Lambda #37

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions aws_lambda_ric.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ require './lib/aws_lambda_ric/version'

Gem::Specification.new do |spec|
spec.name = 'aws_lambda_ric'
spec.version = AwsLambdaRuntimeInterfaceClient::VERSION
spec.version = AwsLambdaRIC::VERSION
spec.authors = ['AWS Lambda']

spec.summary = 'AWS Lambda Runtime Interface Client for Ruby'
spec.description = 'The AWS Lambda Ruby Runtime Interface Client implements the Lambda programming model for Ruby.'
spec.homepage = 'https://github.com/aws/aws-lambda-ruby-runtime-interface-client'

spec.license = 'Apache-2.0'
spec.required_ruby_version = '>= 2.5'
spec.required_ruby_version = '>= 3.0'

# Specify which files should be added to the gem when it is released.
spec.files = %w[
Expand All @@ -33,8 +33,9 @@ Gem::Specification.new do |spec|
spec.executables = 'aws_lambda_ric'
spec.require_paths = ['lib']

spec.add_development_dependency 'bundler', '>= 2.0'
spec.add_development_dependency 'bundler', '~> 2.0'
spec.add_development_dependency 'minitest', '~> 5.0'
spec.add_development_dependency 'rake', '~> 13.0'
spec.add_development_dependency 'activesupport', '~> 6.0.1'
spec.add_development_dependency 'test-unit', '~> 3.5.5'
end
6 changes: 4 additions & 2 deletions bin/aws_lambda_ric
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
# frozen_string_literal: true

require 'bundler/setup'
require_relative '../lib/aws_lambda_ric/bootstrap'
require_relative '../lib/aws_lambda_ric'

Bootstrap.start
lambda_ric = AwsLambdaRIC::Bootstrap.new

lambda_ric.start
67 changes: 56 additions & 11 deletions lib/aws_lambda_ric.rb
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,24 @@

$stdout.sync = true # Ensures that logs are flushed promptly.

module AwsLambdaRuntimeInterfaceClient
module AwsLambdaRIC

class Error < StandardError; end

def self.get_user_agent
ruby_version = RUBY_VERSION.to_s
version = AwsLambdaRIC::VERSION

"aws-lambda-ruby/#{ruby_version}-#{version}"
end

# Loads the user code and runs it upon invocation
class LambdaRunner

ENV_VAR_RUNTIME_API = 'AWS_LAMBDA_RUNTIME_API'

def initialize(runtime_server_addr, user_agent)
@lambda_server = LambdaServer.new(runtime_server_addr, user_agent)
@lambda_server = RapidClient.new(runtime_server_addr, user_agent)
@runtime_loop_active = true # if false, we will exit the program
@exit_code = 0
end
Expand All @@ -45,7 +52,7 @@ def run(app_root, handler)
@exit_code = -4
send_init_error_to_server(e)
ensure
TelemetryLoggingHelper.close
TelemetryLogger.close
end

exit(@exit_code)
Expand Down Expand Up @@ -121,7 +128,7 @@ def send_error_response(lambda_invocation, err, exit_code = nil, runtime_loop_ac
end

# Helper class to for mutating std logger with TelemetryLog
class TelemetryLoggingHelper
class TelemetryLogger

ENV_VAR_TELEMETRY_LOG_FD = '_LAMBDA_TELEMETRY_LOG_FD'

Expand All @@ -133,19 +140,27 @@ def close
end
end

def initialize(telemetry_log_fd, path_to_fd='/proc/self/fd/')
fd = "#{path_to_fd}#{telemetry_log_fd}"
AwsLambdaRuntimeInterfaceClient::TelemetryLoggingHelper.telemetry_log_fd_file = File.open(fd, 'wb')
AwsLambdaRuntimeInterfaceClient::TelemetryLoggingHelper.telemetry_log_fd_file.sync = true
def initialize(telemetry_log_fd)
fd = telemetry_log_fd.to_i
AwsLambdaRIC::TelemetryLogger.telemetry_log_fd_file = IO.new(fd, 'wb')
AwsLambdaRIC::TelemetryLogger.telemetry_log_fd_file.sync = true

AwsLambdaRuntimeInterfaceClient::TelemetryLoggingHelper.telemetry_log_sink = TelemetryLogSink.new(file: AwsLambdaRuntimeInterfaceClient::TelemetryLoggingHelper.telemetry_log_fd_file)
AwsLambdaRIC::TelemetryLogger.telemetry_log_sink = TelemetryLogSink.new(file: AwsLambdaRIC::TelemetryLogger.telemetry_log_fd_file)

mutate_std_logger
mutate_kernel_puts
rescue Errno::ENOENT
rescue Errno::ENOENT, Errno::EBADF
# If File.open() fails, then the mutation won't happen and the default behaviour (print to stdout) will prevail
end

def self.from_env()
if ENV.key?(ENV_VAR_TELEMETRY_LOG_FD)
fd = ENV.fetch(AwsLambdaRIC::TelemetryLogger::ENV_VAR_TELEMETRY_LOG_FD)
ENV.delete(AwsLambdaRIC::TelemetryLogger::ENV_VAR_TELEMETRY_LOG_FD)
AwsLambdaRIC::TelemetryLogger.new(fd)
end
end

private

def mutate_std_logger
Expand All @@ -158,7 +173,11 @@ def mutate_kernel_puts
Kernel.module_eval do
def puts(*arg)
msg = arg.flatten.collect { |a| a.to_s.encode('UTF-8') }.join("\n")
AwsLambdaRuntimeInterfaceClient::TelemetryLoggingHelper.telemetry_log_sink.write(msg)
if msg[-1] != "\n"
msg += "\n"
end
AwsLambdaRIC::TelemetryLogger.telemetry_log_sink.write(msg)
return nil
end
end
end
Expand All @@ -176,4 +195,30 @@ def initialize(request_id, raw_request, request, trace_id)
@trace_id = trace_id
end
end

class Bootstrap

def start
AwsLambdaRIC::TelemetryLogger::from_env()
bootstrap_handler
end

def fetch_runtime_server
ENV.fetch(AwsLambdaRIC::LambdaRunner::ENV_VAR_RUNTIME_API)
rescue KeyError
puts 'Failed to get runtime server address from AWS_LAMBDA_RUNTIME_API env variable'
exit(-2)
end

def bootstrap_handler
if ENV['_HANDLER'] == nil
puts 'No handler specified, exiting Runtime Interface Client.'
exit
end
app_root = Dir.pwd
handler = ENV['_HANDLER']
lambda_runner = AwsLambdaRIC::LambdaRunner.new(fetch_runtime_server, AwsLambdaRIC::get_user_agent)
lambda_runner.run(app_root, handler)
end
end
end
45 changes: 0 additions & 45 deletions lib/aws_lambda_ric/bootstrap.rb

This file was deleted.

2 changes: 1 addition & 1 deletion lib/aws_lambda_ric/lambda_errors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def _sanitize_stacktrace(stacktrace)
if stacktrace
stacktrace.first(100).each do |line|
if safe_trace
if line.to_s.match(%r{^lib})
if line.to_s.match(%r{^/var/runtime/lib})
safe_trace = false
else
ret << line
Expand Down
4 changes: 2 additions & 2 deletions lib/aws_lambda_ric/lambda_log_formatter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

require 'logger'

class LambdaLogFormatter < Logger::Formatter
FORMAT = '%<sev>s, [%<datetime>s#%<process>d] %<severity>5s %<request_id>s -- %<progname>s: %<msg>s'
class LogFormatter < Logger::Formatter
FORMAT = '%<sev>s, [%<datetime>s #%<process>d] %<severity>5s %<request_id>s -- %<progname>s: %<msg>s'

def call(severity, time, progname, msg)
(FORMAT % {sev: severity[0..0], datetime: format_datetime(time), process: $$, severity: severity,
Expand Down
2 changes: 1 addition & 1 deletion lib/aws_lambda_ric/lambda_server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
require 'json'
require_relative 'lambda_errors'

class LambdaServer
class RapidClient
LAMBDA_DEFAULT_SERVER_ADDRESS = '127.0.0.1:9001'
LAMBDA_RUNTIME_API_VERSION = '2018-06-01'

Expand Down
5 changes: 3 additions & 2 deletions lib/aws_lambda_ric/logger_patch.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ def initialize(logdev, shift_age = 0, shift_size = 1048576, level: 'debug',
else
self.level = level
self.progname = progname
@default_formatter = LambdaLogFormatter.new
@default_formatter = LogFormatter.new
self.datetime_format = datetime_format
self.formatter = formatter
@logdev = AwsLambdaRuntimeInterfaceClient::TelemetryLoggingHelper.telemetry_log_sink
@logdev = AwsLambdaRIC::TelemetryLogger.telemetry_log_sink
@level_override = {}
end
end
end
25 changes: 15 additions & 10 deletions lib/aws_lambda_ric/telemetry_log_sink.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,38 @@
# frozen_string_literal: true

require 'logger'
require 'time'

class TelemetryLogSink < Logger::LogDevice

# TelemetryLogSink implements the logging contract between runtimes and the platform. It implements a simple
# framing protocol so message boundaries can be determined. Each frame can be visualized as follows:
#
# +----------------------+------------------------+-----------------------+
# | Frame Type - 4 bytes | Length (len) - 4 bytes | Message - \'len\' bytes |
# +----------------------+------------------------+-----------------------+
# +----------------------+------------------------+---------------------+-------------------------+
# | Frame Type - 4 bytes | Length (len) - 4 bytes | Timestamp - 8 bytes | Message - \'len\' bytes |
# +----------------------+------------------------+---------------------+-------------------------+
#
# The first 4 bytes indicate the type of the frame - log frames have a type defined as the hex value 0xa55a0001. The
# second 4 bytes should indicate the message\'s length. The next \'len\' bytes contain the message. The byte order is
# big-endian.
# The first 4 bytes indicate the type of the frame - log frames have a type defined as the hex value 0xa55a0003. The
# second 4 bytes should indicate the message\'s length. Next, the timestamp in microsecond precision, and finally
# \'len\' bytes contain the message. The byte order is big-endian.

def initialize(file:)
@file = file
end

FRAME_BYTES = [0xa55a0001].pack('L>')
FRAME_BYTES = [0xa55a0003].pack('L>')

def write(msg)
@semaphore ||= Mutex.new
if @file.nil? || @file.closed?
$stdout.write(msg)
else
@file.write(FRAME_BYTES)
@file.write([msg.bytesize].pack('L>'))
@file.write(msg)
@semaphore.synchronize do
@file.write(FRAME_BYTES)
@file.write([msg.bytesize].pack('L>'))
@file.write([(Time.new.to_f*1000000).to_i].pack('Q>'))
@file.write(msg)
end
end
end

Expand Down
4 changes: 2 additions & 2 deletions lib/aws_lambda_ric/version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

# frozen_string_literal: true

module AwsLambdaRuntimeInterfaceClient
VERSION = '2.0.0'
module AwsLambdaRIC
VERSION = '3.0.0'
end