From 3d827d5cb515bfb21a31f84658448c01e4b2385a Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Thu, 30 Apr 2026 20:07:32 +0200 Subject: [PATCH 01/15] Add AppSec integration for AWS Lambda Initialize AppSec context around each Lambda invocation, push request and response events through the AppSec gateway, and record security events on the aws.lambda span. The extension handles tag propagation to inferred spans. Co-Authored-By: Claude Opus 4.6 (1M context) --- .rubocop.yml | 2 + lib/datadog/lambda.rb | 5 + lib/datadog/lambda/appsec.rb | 72 +++++++ lib/datadog/lambda/appsec/request.rb | 47 +++++ lib/datadog/lambda/trace/listener.rb | 3 + test/datadog/lambda/appsec.spec.rb | 218 +++++++++++++++++++++ test/datadog/lambda/appsec/request.spec.rb | 63 ++++++ 7 files changed, 410 insertions(+) create mode 100644 lib/datadog/lambda/appsec.rb create mode 100644 lib/datadog/lambda/appsec/request.rb create mode 100644 test/datadog/lambda/appsec.spec.rb create mode 100644 test/datadog/lambda/appsec/request.spec.rb diff --git a/.rubocop.yml b/.rubocop.yml index 2d9f108..64ecb10 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,5 +1,7 @@ AllCops: TargetRubyVersion: 3.2 + Exclude: + - 'test/**/*' Metrics/MethodLength: Max: 20 diff --git a/lib/datadog/lambda.rb b/lib/datadog/lambda.rb index 4eee6d4..26d9fb5 100644 --- a/lib/datadog/lambda.rb +++ b/lib/datadog/lambda.rb @@ -29,6 +29,8 @@ module Lambda # Configures Datadog's APM tracer with lambda specific defaults. # Same options can be given as Datadog.configure in tracer # See https://github.com/DataDog/dd-trace-rb/blob/master/docs/GettingStarted.md#quickstart-for-ruby-applications + # + # rubocop:disable Metrics/AbcSize def self.configure_apm require 'datadog/tracing' require 'datadog/tracing/transport/io' @@ -48,8 +50,11 @@ def self.configure_apm c.tracing.instrument :aws if trace_managed_services? yield(c) if block_given? + + c.appsec.instrument(:aws_lambda) end end + # rubocop:enable Metrics/AbcSize # Wrap the body of a lambda invocation # @param event [Object] event sent to lambda diff --git a/lib/datadog/lambda/appsec.rb b/lib/datadog/lambda/appsec.rb new file mode 100644 index 0000000..3017c03 --- /dev/null +++ b/lib/datadog/lambda/appsec.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +require_relative 'appsec/request' + +module Datadog + module Lambda + # AppSec integration for AWS Lambda invocations. + module AppSec + class << self + def on_start(event, trace:, span:) + @request = nil + return unless enabled? + + context = create_context(trace, span) + return unless Datadog::AppSec::Context.active + + @request = Request.from_event(event) + + payload = Datadog::AppSec::Instrumentation::Gateway::DataContainer.new( + event, context: context + ) + Datadog::AppSec::Instrumentation.gateway.push('aws_lambda.request.start', payload) + rescue StandardError => e + Datadog::Utils.logger.debug "failed to start AppSec: #{e}" + end + + def on_finish(response) + return unless enabled? + + context = Datadog::AppSec::Context.active + return unless context + + payload = Datadog::AppSec::Instrumentation::Gateway::DataContainer.new( + response, context: context + ) + + Datadog::AppSec::Instrumentation.gateway.push('aws_lambda.response.start', payload) + Datadog::AppSec::Event.record(context, request: @request) + + context.export_metrics + context.export_request_telemetry + rescue StandardError => e + Datadog::Utils.logger.debug "failed to finish AppSec: #{e}" + ensure + Datadog::AppSec::Context.deactivate if context + end + + private + + def enabled? + defined?(Datadog::AppSec) && + Datadog::AppSec.respond_to?(:enabled?) && + Datadog::AppSec.enabled? + end + + def create_context(trace, span) + return if trace.nil? || span.nil? + + security_engine = Datadog::AppSec.security_engine + return unless security_engine + + context = Datadog::AppSec::Context.new(trace, span, security_engine.new_runner) + Datadog::AppSec::Context.activate(context) + + span.set_metric(Datadog::AppSec::Ext::TAG_APPSEC_ENABLED, 1) + + context + end + end + end + end +end diff --git a/lib/datadog/lambda/appsec/request.rb b/lib/datadog/lambda/appsec/request.rb new file mode 100644 index 0000000..c74d55a --- /dev/null +++ b/lib/datadog/lambda/appsec/request.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +module Datadog + module Lambda + module AppSec + # Minimal request object for AppSec event recording. + # + # WARNING: It's a minimal data for interface compliance + # + # @see Datadog::AppSec::Event.record + # @see Datadog::AppSec::Contrib::Rack::Gateway::Request + class Request + attr_reader :host, :user_agent, :remote_addr, :headers + + class << self + def from_event(event) + headers = normalize_headers(event) + remote_addres = event.dig('requestContext', 'identity', 'sourceIp') || + event.dig('requestContext', 'http', 'sourceIp') + + new( + host: headers['host'], + user_agent: headers['user-agent'], + remote_addr: remote_addres, + headers: headers + ) + end + + private + + def normalize_headers(event) + event.fetch('headers', {}).each_with_object({}) do |(key, value), hash| + hash[key.downcase] = value + end + end + end + + def initialize(host:, user_agent:, remote_addr:, headers:) + @host = host + @user_agent = user_agent + @remote_addr = remote_addr + @headers = headers + end + end + end + end +end diff --git a/lib/datadog/lambda/trace/listener.rb b/lib/datadog/lambda/trace/listener.rb index e4ac564..df5f91e 100644 --- a/lib/datadog/lambda/trace/listener.rb +++ b/lib/datadog/lambda/trace/listener.rb @@ -11,6 +11,7 @@ require 'datadog/lambda/trace/context' require 'datadog/lambda/trace/patch_http' require 'datadog/lambda/trace/ddtrace' +require 'datadog/lambda/appsec' module Datadog module Trace @@ -50,10 +51,12 @@ def on_start(event:, request_context:, cold_start:) @trace = Datadog::Tracing.trace('aws.lambda', **options) Datadog::Trace.apply_datadog_trace_context(Datadog::Trace.trace_context) + Datadog::Lambda::AppSec.on_start(event, trace: Datadog::Tracing.active_trace, span: @trace) end # rubocop:enable Metrics/AbcSize def on_end(response:, request_context:) + Datadog::Lambda::AppSec.on_finish(response) Datadog::Utils.send_end_invocation_request(response:, span_id: @trace.id, request_context:) @trace&.finish end diff --git a/test/datadog/lambda/appsec.spec.rb b/test/datadog/lambda/appsec.spec.rb new file mode 100644 index 0000000..3d56ea5 --- /dev/null +++ b/test/datadog/lambda/appsec.spec.rb @@ -0,0 +1,218 @@ +# frozen_string_literal: true + +require 'datadog/lambda' +require 'datadog/lambda/appsec' + +RSpec.describe Datadog::Lambda::AppSec do + before do + allow(Datadog::AppSec::Instrumentation).to receive(:gateway).and_return(gateway) + allow(gateway).to receive(:push) + end + + let(:gateway) { instance_double(Datadog::AppSec::Instrumentation::Gateway) } + let(:appsec_context) do + instance_double( + Datadog::AppSec::Context, + span: instance_double(Datadog::Tracing::SpanOperation, get_tag: nil, get_metric: nil), + state: {}, + export_metrics: nil, + export_request_telemetry: nil + ) + end + + describe '.on_start' do + subject(:on_start) { described_class.on_start(event, trace: trace, span: span) } + + let(:event) { { 'httpMethod' => 'GET', 'path' => '/' } } + let(:trace) { instance_double(Datadog::Tracing::TraceOperation) } + let(:span) { instance_double(Datadog::Tracing::SpanOperation, set_metric: nil) } + + context 'when appsec is disabled' do + before { allow(Datadog::AppSec).to receive(:enabled?).and_return(false) } + + it 'does not push to gateway' do + on_start + + expect(gateway).not_to have_received(:push) + end + end + + context 'when appsec is enabled' do + before do + allow(Datadog::AppSec).to receive(:enabled?).and_return(true) + allow(Datadog::AppSec).to receive(:security_engine).and_return(security_engine) + allow(Datadog::AppSec::Context).to receive(:activate) + allow(Datadog::AppSec::Context).to receive(:active).and_return(appsec_context) + end + + let(:security_engine) { instance_double(Datadog::AppSec::SecurityEngine::Engine, new_runner: waf_runner) } + let(:waf_runner) { instance_double(Datadog::AppSec::SecurityEngine::Runner) } + + it 'marks span as appsec-enabled' do + on_start + + expect(span).to have_received(:set_metric).with(Datadog::AppSec::Ext::TAG_APPSEC_ENABLED, 1) + end + + it 'pushes event to gateway' do + on_start + + expect(gateway).to have_received(:push).with( + 'aws_lambda.request.start', kind_of(Datadog::AppSec::Instrumentation::Gateway::DataContainer) + ) + end + + context 'when security_engine is nil' do + before do + allow(Datadog::AppSec).to receive(:security_engine).and_return(nil) + allow(Datadog::AppSec::Context).to receive(:active).and_return(nil) + end + + it 'skips context activation and gateway push' do + on_start + + aggregate_failures('skipped activation') do + expect(Datadog::AppSec::Context).not_to have_received(:activate) + expect(gateway).not_to have_received(:push) + end + end + end + + context 'when trace is nil' do + subject(:on_start) { described_class.on_start(event, trace: nil, span: span) } + + before { allow(Datadog::AppSec::Context).to receive(:active).and_return(nil) } + + it 'skips context activation and gateway push' do + on_start + + aggregate_failures('skipped activation') do + expect(Datadog::AppSec::Context).not_to have_received(:activate) + expect(gateway).not_to have_received(:push) + end + end + end + + context 'when span is nil' do + subject(:on_start) { described_class.on_start(event, trace: trace, span: nil) } + + before { allow(Datadog::AppSec::Context).to receive(:active).and_return(nil) } + + it 'skips context activation and gateway push' do + on_start + + aggregate_failures('skipped activation') do + expect(Datadog::AppSec::Context).not_to have_received(:activate) + expect(gateway).not_to have_received(:push) + end + end + end + + context 'when an error occurs' do + before { allow(Datadog::AppSec::Context).to receive(:new).and_raise(StandardError, 'boom') } + + it { expect { on_start }.not_to raise_error } + end + end + end + + describe '.on_finish' do + subject(:on_finish) { described_class.on_finish(response) } + + let(:response) { { 'statusCode' => 200 } } + + context 'when appsec is disabled' do + before do + allow(Datadog::AppSec).to receive(:enabled?).and_return(false) + allow(Datadog::AppSec::Context).to receive(:active).and_return(appsec_context) + end + + it 'does not push to gateway' do + on_finish + + expect(gateway).not_to have_received(:push) + end + end + + context 'when no active context exists' do + before do + allow(Datadog::AppSec).to receive(:enabled?).and_return(true) + allow(Datadog::AppSec::Context).to receive(:active).and_return(nil) + end + + it 'does not push to gateway' do + on_finish + + expect(gateway).not_to have_received(:push) + end + end + + context 'when active context exists' do + before do + allow(Datadog::AppSec).to receive(:enabled?).and_return(true) + allow(Datadog::AppSec::Context).to receive(:active).and_return(appsec_context) + allow(Datadog::AppSec::Context).to receive(:deactivate) + allow(Datadog::AppSec::Event).to receive(:record) + end + + it 'pushes response and records events' do + on_finish + + aggregate_failures('response processing') do + expect(gateway).to have_received(:push).with( + 'aws_lambda.response.start', kind_of(Datadog::AppSec::Instrumentation::Gateway::DataContainer) + ) + expect(Datadog::AppSec::Event).to have_received(:record).with(appsec_context, request: nil) + end + end + + it 'exports telemetry and deactivates' do + on_finish + + aggregate_failures('AppSec deactivation') do + expect(appsec_context).to have_received(:export_metrics) + expect(appsec_context).to have_received(:export_request_telemetry) + expect(Datadog::AppSec::Context).to have_received(:deactivate) + end + end + + context 'when a security event occurs' do + before do + allow(Datadog::AppSec).to receive(:security_engine).and_return(security_engine) + allow(Datadog::AppSec::Context).to receive(:activate) + + described_class.on_start(event, trace: trace, span: span) + end + + let(:event) do + { + 'headers' => { 'Host' => 'example.com', 'User-Agent' => 'TestBot' }, + 'requestContext' => { 'identity' => { 'sourceIp' => '1.2.3.4' } } + } + end + let(:trace) { instance_double(Datadog::Tracing::TraceOperation) } + let(:span) { instance_double(Datadog::Tracing::SpanOperation, set_metric: nil) } + let(:security_engine) { instance_double(Datadog::AppSec::SecurityEngine::Engine, new_runner: waf_runner) } + let(:waf_runner) { instance_double(Datadog::AppSec::SecurityEngine::Runner) } + + it 'records security event with request' do + on_finish + + expect(Datadog::AppSec::Event).to have_received(:record).with( + appsec_context, request: kind_of(Datadog::Lambda::AppSec::Request) + ) + end + end + + context 'when an error occurs' do + before { allow(gateway).to receive(:push).and_raise(StandardError, 'boom') } + + it 'still deactivates the context' do + on_finish + + expect(Datadog::AppSec::Context).to have_received(:deactivate) + end + end + end + end +end diff --git a/test/datadog/lambda/appsec/request.spec.rb b/test/datadog/lambda/appsec/request.spec.rb new file mode 100644 index 0000000..eaf9524 --- /dev/null +++ b/test/datadog/lambda/appsec/request.spec.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +require 'datadog/lambda/appsec/request' + +RSpec.describe Datadog::Lambda::AppSec::Request do + subject(:request) { described_class.from_event(event) } + + let(:event) do + { + 'headers' => { 'Host' => 'example.com', 'User-Agent' => 'TestBot/1.0', 'Accept' => 'text/html' }, + 'requestContext' => { + 'identity' => { 'sourceIp' => '10.0.0.1' } + } + } + end + + describe '#headers' do + it 'normalizes header keys to lowercase' do + expect(request.headers).to eq( + 'host' => 'example.com', + 'user-agent' => 'TestBot/1.0', + 'accept' => 'text/html' + ) + end + + context 'when event has no headers' do + let(:event) { { 'requestContext' => {} } } + + it { expect(request.headers).to eq({}) } + end + end + + describe '#host' do + it { expect(request.host).to eq('example.com') } + end + + describe '#user_agent' do + it { expect(request.user_agent).to eq('TestBot/1.0') } + end + + describe '#remote_addr' do + it { expect(request.remote_addr).to eq('10.0.0.1') } + + context 'when event is API Gateway v2 format' do + let(:event) do + { + 'headers' => {}, + 'requestContext' => { + 'http' => { 'sourceIp' => '10.0.0.2' } + } + } + end + + it { expect(request.remote_addr).to eq('10.0.0.2') } + end + + context 'when event has no requestContext' do + let(:event) { { 'headers' => {} } } + + it { expect(request.remote_addr).to be_nil } + end + end +end From ea2cf316218036ee77eadd879e0b08e1d683f403 Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Thu, 30 Apr 2026 20:33:27 +0200 Subject: [PATCH 02/15] Add vendor to rubocop excludes Adding an Exclude key overrides rubocop's default excludes, which includes vendor/**. Re-add it explicitly so CI lint passes. Co-Authored-By: Claude Opus 4.6 (1M context) --- .rubocop.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.rubocop.yml b/.rubocop.yml index 64ecb10..4f079a0 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -2,6 +2,7 @@ AllCops: TargetRubyVersion: 3.2 Exclude: - 'test/**/*' + - 'vendor/**/*' Metrics/MethodLength: Max: 20 From 56b913ab7d171a2ec1dd868bd9cf9813078630df Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Thu, 30 Apr 2026 21:15:48 +0200 Subject: [PATCH 03/15] Recompile FFI from source in layer build Precompiled FFI binaries have glibc mismatch with Lambda AL2 runtime, causing crashes when AppSec loads the libddwaf chain. Force source compilation and remove precompiled variants. Co-Authored-By: Claude Opus 4.6 (1M context) --- Dockerfile | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Dockerfile b/Dockerfile index d6e2867..959e300 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,6 +14,13 @@ RUN gem build datadog-lambda RUN gem install datadog-lambda --install-dir "/opt/ruby/gems/$runtime" RUN gem install datadog -v 2.12 --install-dir "/opt/ruby/gems/$runtime" +# Recompile FFI from source — precompiled binaries have glibc mismatch with Lambda AL2 +# NOTE: runs after datadog gem as a defensive measure — force-replaces whatever +# transitive FFI variant was pulled, regardless of version resolution. +RUN gem install ffi --platform ruby --force --install-dir "/opt/ruby/gems/$runtime" --no-document +RUN rm -rf /opt/ruby/gems/$runtime/gems/ffi-*-*-linux-* \ + /opt/ruby/gems/$runtime/specifications/ffi-*-*-linux-*.gemspec + WORKDIR /opt # Remove native extension debase-ruby_core_source (25MB) runtimes below Ruby 2.6 RUN rm -rf ./ruby/gems/$runtime/gems/debase-ruby_core_source*/ From 1d8fdbb8ed6297e54f3c2de46d8c133808da4b48 Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Thu, 30 Apr 2026 21:25:41 +0200 Subject: [PATCH 04/15] Add AppSec integration test handler Add appsec-request handler with DD_APPSEC_ENABLED=true and an input event containing Arachni user-agent to trigger WAF detection. Snapshots will be recorded on first AWS deploy. Co-Authored-By: Claude Opus 4.6 (1M context) --- integration_tests/appsec_request.rb | 19 ++++++++++++ .../input_events/api-gateway-appsec.json | 31 +++++++++++++++++++ integration_tests/serverless.yml | 12 +++++++ scripts/run_integration_tests.sh | 2 +- 4 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 integration_tests/appsec_request.rb create mode 100644 integration_tests/input_events/api-gateway-appsec.json diff --git a/integration_tests/appsec_request.rb b/integration_tests/appsec_request.rb new file mode 100644 index 0000000..9b51090 --- /dev/null +++ b/integration_tests/appsec_request.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require 'datadog/lambda' + +Datadog::Lambda.configure_apm do |c| + c.appsec.enabled = true +end + +def handle(event:, context:) + Datadog::Lambda.wrap(event, context) do + Datadog::Lambda.metric('serverless.integration_test.execution', 1, function: 'appsec-request') + + { + 'statusCode' => 200, + 'message' => 'hello, dog!', + 'eventType' => 'APIGateway' + } + end +end diff --git a/integration_tests/input_events/api-gateway-appsec.json b/integration_tests/input_events/api-gateway-appsec.json new file mode 100644 index 0000000..f369c56 --- /dev/null +++ b/integration_tests/input_events/api-gateway-appsec.json @@ -0,0 +1,31 @@ +{ + "path": "/test/hello", + "headers": { + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", + "Host": "wt6mne2s9k.execute-api.us-west-2.amazonaws.com", + "User-Agent": "Arachni/v1.0", + "X-Forwarded-For": "192.168.100.1, 192.168.1.1", + "X-Forwarded-Port": "443", + "X-Forwarded-Proto": "https" + }, + "pathParameters": { + "proxy": "hello" + }, + "requestContext": { + "accountId": "123456789012", + "resourceId": "us4z18", + "stage": "test", + "requestId": "41b45ea3-70b5-11e6-b7bd-69b5aaebc7d9", + "identity": { + "sourceIp": "192.168.100.1", + "userAgent": "Arachni/v1.0" + }, + "resourcePath": "/{proxy+}", + "httpMethod": "GET", + "apiId": "wt6mne2s9k" + }, + "resource": "/{proxy+}", + "httpMethod": "GET", + "queryStringParameters": null, + "stageVariables": null +} diff --git a/integration_tests/serverless.yml b/integration_tests/serverless.yml index ec15e1a..e87bf86 100644 --- a/integration_tests/serverless.yml +++ b/integration_tests/serverless.yml @@ -60,3 +60,15 @@ functions: - { Ref: RubyLambdaLayer } environment: DD_FLUSH_TO_LOG: true + + # appsec-request + appsec-request_ruby: + name: integration-tests-rb-${sls:stage}-appsec-request_${env:RUNTIME} + handler: appsec_request.handle + runtime: ${env:SERVERLESS_RUNTIME} + memorySize: 1024 + layers: + - { Ref: RubyLambdaLayer } + environment: + DD_FLUSH_TO_LOG: true + DD_APPSEC_ENABLED: true diff --git a/scripts/run_integration_tests.sh b/scripts/run_integration_tests.sh index 52bdfb7..b094ba2 100755 --- a/scripts/run_integration_tests.sh +++ b/scripts/run_integration_tests.sh @@ -10,7 +10,7 @@ set -e # These values need to be in sync with serverless.yml, where there needs to be a function # defined for every handler_runtime combination -LAMBDA_HANDLERS=("async-metrics" "sync-metrics" "http-requests" "process-input-traced") +LAMBDA_HANDLERS=("async-metrics" "sync-metrics" "http-requests" "process-input-traced" "appsec-request") RUNTIMES=("ruby32" "ruby33") LOGS_WAIT_SECONDS=45 From 50a23ff5948410d78c45aa90fdf86ae32ea8b5c1 Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Mon, 4 May 2026 12:43:05 +0200 Subject: [PATCH 05/15] Handle AppSec blocking interrupt in Lambda Wrap gateway pushes in catch(Datadog::AppSec::Ext::INTERRUPT) in both on_start and on_finish. When WAF decides to block, build a Lambda-shaped response override (statusCode/headers/body) via AppSec::Response. The listener exposes response_override for wrap to short-circuit the handler on request-phase blocks or replace the response on response-phase blocks. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../api-gateway-appsec-blocking.json | 31 +++++++++++++ lib/datadog/lambda.rb | 5 ++- lib/datadog/lambda/appsec.rb | 36 +++++++++++++-- lib/datadog/lambda/trace/listener.rb | 10 ++++- test/datadog/lambda/appsec.spec.rb | 45 +++++++++++++++++++ 5 files changed, 120 insertions(+), 7 deletions(-) create mode 100644 integration_tests/input_events/api-gateway-appsec-blocking.json diff --git a/integration_tests/input_events/api-gateway-appsec-blocking.json b/integration_tests/input_events/api-gateway-appsec-blocking.json new file mode 100644 index 0000000..b6f9490 --- /dev/null +++ b/integration_tests/input_events/api-gateway-appsec-blocking.json @@ -0,0 +1,31 @@ +{ + "path": "/test/hello", + "headers": { + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", + "Host": "wt6mne2s9k.execute-api.us-west-2.amazonaws.com", + "X-Forwarded-For": "192.168.100.1, 192.168.1.1", + "X-Forwarded-Port": "443", + "X-Forwarded-Proto": "https" + }, + "pathParameters": { + "proxy": "hello" + }, + "requestContext": { + "accountId": "123456789012", + "resourceId": "us4z18", + "stage": "test", + "requestId": "41b45ea3-70b5-11e6-b7bd-69b5aaebc7d9", + "identity": { + "sourceIp": "192.168.100.1" + }, + "resourcePath": "/{proxy+}", + "httpMethod": "GET", + "apiId": "wt6mne2s9k" + }, + "resource": "/{proxy+}", + "httpMethod": "GET", + "queryStringParameters": { + "q": "1' OR '1'='1" + }, + "stageVariables": null +} diff --git a/lib/datadog/lambda.rb b/lib/datadog/lambda.rb index 26d9fb5..604c385 100644 --- a/lib/datadog/lambda.rb +++ b/lib/datadog/lambda.rb @@ -60,23 +60,26 @@ def self.configure_apm # @param event [Object] event sent to lambda # @param context [Object] lambda context # @param block [Proc] implementation of the handler function. + # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity def self.wrap(event, context, &block) @listener ||= initialize_listener record_enhanced('invocations', context) begin cold = @is_cold_start @listener&.on_start(event:, request_context: context, cold_start: cold) - @response = block.call + @response = @listener&.response_override || block.call rescue StandardError => e record_enhanced('errors', context) raise e ensure @listener&.on_end(response: @response, request_context: context) + @response = @listener&.response_override || @response @is_cold_start = false @metrics_client.close end @response end + # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity # Gets the current tracing context def self.trace_context diff --git a/lib/datadog/lambda/appsec.rb b/lib/datadog/lambda/appsec.rb index 3017c03..93a5d5d 100644 --- a/lib/datadog/lambda/appsec.rb +++ b/lib/datadog/lambda/appsec.rb @@ -19,9 +19,18 @@ def on_start(event, trace:, span:) payload = Datadog::AppSec::Instrumentation::Gateway::DataContainer.new( event, context: context ) - Datadog::AppSec::Instrumentation.gateway.push('aws_lambda.request.start', payload) + + interrupt_params = catch(Datadog::AppSec::Ext::INTERRUPT) do + Datadog::AppSec::Instrumentation.gateway.push('aws_lambda.request.start', payload) + nil + end + + return unless interrupt_params + + context.mark_as_interrupted! + response_override(interrupt_params, headers: @request.headers) rescue StandardError => e - Datadog::Utils.logger.debug "failed to start AppSec: #{e}" + Datadog::Utils.logger.debug("failed to start AppSec: #{e}") end def on_finish(response) @@ -34,11 +43,18 @@ def on_finish(response) response, context: context ) - Datadog::AppSec::Instrumentation.gateway.push('aws_lambda.response.start', payload) - Datadog::AppSec::Event.record(context, request: @request) + interrupt_params = catch(Datadog::AppSec::Ext::INTERRUPT) do + Datadog::AppSec::Instrumentation.gateway.push('aws_lambda.response.start', payload) + nil + end + + context.mark_as_interrupted! if interrupt_params + Datadog::AppSec::Event.record(context, request: @request) context.export_metrics context.export_request_telemetry + + response_override(interrupt_params, headers: @request.headers) if interrupt_params rescue StandardError => e Datadog::Utils.logger.debug "failed to finish AppSec: #{e}" ensure @@ -66,6 +82,18 @@ def create_context(trace, span) context end + + def response_override(interrupt_params, headers:) + response = Datadog::AppSec::Response.from_interrupt_params( + interrupt_params, headers['accept'] + ) + + { + 'statusCode' => response.status, + 'headers' => response.headers, + 'body' => response.body.join + } + end end end end diff --git a/lib/datadog/lambda/trace/listener.rb b/lib/datadog/lambda/trace/listener.rb index df5f91e..89c1b4b 100644 --- a/lib/datadog/lambda/trace/listener.rb +++ b/lib/datadog/lambda/trace/listener.rb @@ -17,6 +17,10 @@ module Datadog module Trace # TraceListener tracks tracing context information class Listener + # AppSec blocking response that replaces the handler result. + # Set during either on_start or on_end when WAF decides to block. + attr_reader :response_override + @trace = nil def initialize(handler_name:, function_name:, patch_http:, merge_xray_traces:) @@ -51,12 +55,14 @@ def on_start(event:, request_context:, cold_start:) @trace = Datadog::Tracing.trace('aws.lambda', **options) Datadog::Trace.apply_datadog_trace_context(Datadog::Trace.trace_context) - Datadog::Lambda::AppSec.on_start(event, trace: Datadog::Tracing.active_trace, span: @trace) + @response_override = Datadog::Lambda::AppSec.on_start( + event, trace: Datadog::Tracing.active_trace, span: @trace + ) end # rubocop:enable Metrics/AbcSize def on_end(response:, request_context:) - Datadog::Lambda::AppSec.on_finish(response) + @response_override = Datadog::Lambda::AppSec.on_finish(response) Datadog::Utils.send_end_invocation_request(response:, span_id: @trace.id, request_context:) @trace&.finish end diff --git a/test/datadog/lambda/appsec.spec.rb b/test/datadog/lambda/appsec.spec.rb index 3d56ea5..30f9c15 100644 --- a/test/datadog/lambda/appsec.spec.rb +++ b/test/datadog/lambda/appsec.spec.rb @@ -108,6 +108,25 @@ end end + context 'when gateway push triggers a blocking interrupt' do + before do + allow(Datadog::AppSec::Context).to receive(:new).and_return(appsec_context) + allow(appsec_context).to receive(:mark_as_interrupted!) + + allow(gateway).to receive(:push).and_invoke(lambda { |_name, _payload| + throw(Datadog::AppSec::Ext::INTERRUPT, {'status_code' => 403, 'type' => 'auto'}) + }) + end + + it 'returns a Lambda-shaped blocking response' do + expect(on_start).to include( + 'statusCode' => 403, + 'headers' => {'Content-Type' => 'application/json'}, + 'body' => include('blocked') + ) + end + end + context 'when an error occurs' do before { allow(Datadog::AppSec::Context).to receive(:new).and_raise(StandardError, 'boom') } @@ -204,6 +223,32 @@ end end + context 'when gateway push triggers a blocking interrupt' do + before do + allow(gateway).to receive(:push).and_invoke(lambda { |_name, _payload| + throw(Datadog::AppSec::Ext::INTERRUPT, {'status_code' => 403, 'type' => 'auto'}) + }) + allow(appsec_context).to receive(:mark_as_interrupted!) + end + + it 'returns a Lambda-shaped blocking response' do + expect(on_finish).to include( + 'statusCode' => 403, + 'headers' => {'Content-Type' => 'application/json'} + ) + end + + it 'still records events and deactivates' do + on_finish + + aggregate_failures('cleanup after interrupt') do + expect(Datadog::AppSec::Event).to have_received(:record) + expect(appsec_context).to have_received(:export_metrics) + expect(Datadog::AppSec::Context).to have_received(:deactivate) + end + end + end + context 'when an error occurs' do before { allow(gateway).to receive(:push).and_raise(StandardError, 'boom') } From d2d97d5b0b6c69e55681d36780c802da48a25d82 Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Tue, 5 May 2026 11:39:25 +0200 Subject: [PATCH 06/15] Add EventNormalizer for API Gateway v1/v2 events Normalize raw AWS event payloads into a standard key set before passing to DataContainer and Request. This removes v1/v2 detection from Request and aligns with dd-trace-rb's simplified WAFAddresses that consume standard keys. Co-Authored-By: Claude Opus 4.6 (1M context) --- lib/datadog/lambda/appsec.rb | 4 +- lib/datadog/lambda/appsec/event_normalizer.rb | 47 +++++++ lib/datadog/lambda/appsec/request.rb | 12 +- test/datadog/lambda/appsec.spec.rb | 5 +- .../lambda/appsec/event_normalizer.spec.rb | 118 ++++++++++++++++++ test/datadog/lambda/appsec/request.spec.rb | 29 ++--- 6 files changed, 183 insertions(+), 32 deletions(-) create mode 100644 lib/datadog/lambda/appsec/event_normalizer.rb create mode 100644 test/datadog/lambda/appsec/event_normalizer.spec.rb diff --git a/lib/datadog/lambda/appsec.rb b/lib/datadog/lambda/appsec.rb index 93a5d5d..be3a50e 100644 --- a/lib/datadog/lambda/appsec.rb +++ b/lib/datadog/lambda/appsec.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require_relative 'appsec/request' +require_relative 'appsec/event_normalizer' module Datadog module Lambda @@ -14,7 +15,8 @@ def on_start(event, trace:, span:) context = create_context(trace, span) return unless Datadog::AppSec::Context.active - @request = Request.from_event(event) + event = EventNormalizer.normalize(event) + @request = Request.from_normalized(event) payload = Datadog::AppSec::Instrumentation::Gateway::DataContainer.new( event, context: context diff --git a/lib/datadog/lambda/appsec/event_normalizer.rb b/lib/datadog/lambda/appsec/event_normalizer.rb new file mode 100644 index 0000000..5fa9ce4 --- /dev/null +++ b/lib/datadog/lambda/appsec/event_normalizer.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +module Datadog + module Lambda + module AppSec + # Normalizes API Gateway v1/v2 event payloads into a standard key set. + module EventNormalizer + module_function + + def normalize(event) + event.key?('httpMethod') ? normalize_v1(event) : normalize_v2(event) + end + + def normalize_v1(event) + data = { + 'method' => event['httpMethod'], + 'path' => event['path'], + 'headers' => event['headers'], + 'query' => event['multiValueQueryStringParameters'] || event['queryStringParameters'], + 'source_ip' => event.dig('requestContext', 'identity', 'sourceIp'), + 'body' => event['body'], + 'base64_encoded' => event['isBase64Encoded'], + 'path_params' => event['pathParameters'] + } + data.compact! + data + end + + def normalize_v2(event) + data = { + 'method' => event.dig('requestContext', 'http', 'method'), + 'path' => event['rawPath'], + 'headers' => event['headers'], + 'cookies' => event['cookies'], + 'query_string' => event['rawQueryString'], + 'source_ip' => event.dig('requestContext', 'http', 'sourceIp'), + 'body' => event['body'], + 'base64_encoded' => event['isBase64Encoded'], + 'path_params' => event['pathParameters'] + } + data.compact! + data + end + end + end + end +end diff --git a/lib/datadog/lambda/appsec/request.rb b/lib/datadog/lambda/appsec/request.rb index c74d55a..42926f2 100644 --- a/lib/datadog/lambda/appsec/request.rb +++ b/lib/datadog/lambda/appsec/request.rb @@ -13,23 +13,21 @@ class Request attr_reader :host, :user_agent, :remote_addr, :headers class << self - def from_event(event) - headers = normalize_headers(event) - remote_addres = event.dig('requestContext', 'identity', 'sourceIp') || - event.dig('requestContext', 'http', 'sourceIp') + def from_normalized(event) + headers = lowercase_headers(event) new( host: headers['host'], user_agent: headers['user-agent'], - remote_addr: remote_addres, + remote_addr: event['source_ip'], headers: headers ) end private - def normalize_headers(event) - event.fetch('headers', {}).each_with_object({}) do |(key, value), hash| + def lowercase_headers(event) + (event['headers'] || {}).each_with_object({}) do |(key, value), hash| hash[key.downcase] = value end end diff --git a/test/datadog/lambda/appsec.spec.rb b/test/datadog/lambda/appsec.spec.rb index 30f9c15..19ddda1 100644 --- a/test/datadog/lambda/appsec.spec.rb +++ b/test/datadog/lambda/appsec.spec.rb @@ -205,8 +205,9 @@ let(:event) do { - 'headers' => { 'Host' => 'example.com', 'User-Agent' => 'TestBot' }, - 'requestContext' => { 'identity' => { 'sourceIp' => '1.2.3.4' } } + 'httpMethod' => 'GET', + 'headers' => {'Host' => 'example.com', 'User-Agent' => 'TestBot'}, + 'requestContext' => {'identity' => {'sourceIp' => '1.2.3.4'}}, } end let(:trace) { instance_double(Datadog::Tracing::TraceOperation) } diff --git a/test/datadog/lambda/appsec/event_normalizer.spec.rb b/test/datadog/lambda/appsec/event_normalizer.spec.rb new file mode 100644 index 0000000..38b5686 --- /dev/null +++ b/test/datadog/lambda/appsec/event_normalizer.spec.rb @@ -0,0 +1,118 @@ +# frozen_string_literal: true + +require 'datadog/lambda/appsec/event_normalizer' + +RSpec.describe Datadog::Lambda::AppSec::EventNormalizer do + describe '.normalize' do + subject(:result) { described_class.normalize(event) } + + context 'when event is API Gateway v1' do + let(:event) do + { + 'httpMethod' => 'POST', + 'path' => '/users/123', + 'headers' => {'Host' => 'example.com', 'Cookie' => 'session=abc'}, + 'queryStringParameters' => {'page' => '1'}, + 'multiValueQueryStringParameters' => {'page' => ['1']}, + 'pathParameters' => {'id' => '123'}, + 'body' => '{"name":"john"}', + 'isBase64Encoded' => false, + 'requestContext' => {'identity' => {'sourceIp' => '10.0.0.1'}}, + } + end + + it { expect(result['method']).to eq('POST') } + it { expect(result['path']).to eq('/users/123') } + it { expect(result['headers']).to eq('Host' => 'example.com', 'Cookie' => 'session=abc') } + it { expect(result['query']).to eq('page' => ['1']) } + it { expect(result['source_ip']).to eq('10.0.0.1') } + it { expect(result['body']).to eq('{"name":"john"}') } + it { expect(result['base64_encoded']).to eq(false) } + it { expect(result['path_params']).to eq('id' => '123') } + it { expect(result).not_to have_key('cookies') } + it { expect(result).not_to have_key('query_string') } + end + + context 'when event is API Gateway v1 without multiValueQueryStringParameters' do + let(:event) do + { + 'httpMethod' => 'GET', + 'path' => '/health', + 'headers' => {}, + 'queryStringParameters' => {'page' => '1'}, + 'requestContext' => {'identity' => {}}, + } + end + + it { expect(result['query']).to eq('page' => '1') } + end + + context 'when event is API Gateway v2' do + let(:event) do + { + 'rawPath' => '/users/123', + 'rawQueryString' => 'page=1&sort=asc', + 'headers' => {'host' => 'example.com'}, + 'cookies' => ['session=abc', 'theme=dark'], + 'pathParameters' => {'id' => '123'}, + 'body' => 'hello', + 'isBase64Encoded' => false, + 'requestContext' => {'http' => {'method' => 'GET', 'sourceIp' => '10.0.0.2'}}, + } + end + + it { expect(result['method']).to eq('GET') } + it { expect(result['path']).to eq('/users/123') } + it { expect(result['headers']).to eq('host' => 'example.com') } + it { expect(result['cookies']).to eq(['session=abc', 'theme=dark']) } + it { expect(result['query_string']).to eq('page=1&sort=asc') } + it { expect(result['source_ip']).to eq('10.0.0.2') } + it { expect(result['body']).to eq('hello') } + it { expect(result['base64_encoded']).to eq(false) } + it { expect(result['path_params']).to eq('id' => '123') } + it { expect(result).not_to have_key('query') } + end + + context 'when v1 event has nil fields' do + let(:event) do + { + 'httpMethod' => 'GET', + 'path' => '/health', + 'headers' => nil, + 'queryStringParameters' => nil, + 'multiValueQueryStringParameters' => nil, + 'pathParameters' => nil, + 'body' => nil, + 'isBase64Encoded' => false, + 'requestContext' => {'identity' => {'sourceIp' => '127.0.0.1'}}, + } + end + + it { expect(result['method']).to eq('GET') } + it { expect(result['path']).to eq('/health') } + it { expect(result['source_ip']).to eq('127.0.0.1') } + it { expect(result).not_to have_key('headers') } + it { expect(result).not_to have_key('query') } + it { expect(result).not_to have_key('path_params') } + it { expect(result).not_to have_key('body') } + end + + context 'when v2 event has minimal fields' do + let(:event) do + { + 'rawPath' => '/health', + 'headers' => {}, + 'requestContext' => {'http' => {'method' => 'GET', 'sourceIp' => '127.0.0.1'}}, + } + end + + it { expect(result['method']).to eq('GET') } + it { expect(result['path']).to eq('/health') } + it { expect(result['source_ip']).to eq('127.0.0.1') } + it { expect(result).not_to have_key('cookies') } + it { expect(result).not_to have_key('query_string') } + it { expect(result).not_to have_key('body') } + it { expect(result).not_to have_key('path_params') } + end + end +end diff --git a/test/datadog/lambda/appsec/request.spec.rb b/test/datadog/lambda/appsec/request.spec.rb index eaf9524..265f6e2 100644 --- a/test/datadog/lambda/appsec/request.spec.rb +++ b/test/datadog/lambda/appsec/request.spec.rb @@ -3,19 +3,17 @@ require 'datadog/lambda/appsec/request' RSpec.describe Datadog::Lambda::AppSec::Request do - subject(:request) { described_class.from_event(event) } + subject(:request) { described_class.from_normalized(event) } let(:event) do { - 'headers' => { 'Host' => 'example.com', 'User-Agent' => 'TestBot/1.0', 'Accept' => 'text/html' }, - 'requestContext' => { - 'identity' => { 'sourceIp' => '10.0.0.1' } - } + 'headers' => {'Host' => 'example.com', 'User-Agent' => 'TestBot/1.0', 'Accept' => 'text/html'}, + 'source_ip' => '10.0.0.1', } end describe '#headers' do - it 'normalizes header keys to lowercase' do + it 'lowercases header keys' do expect(request.headers).to eq( 'host' => 'example.com', 'user-agent' => 'TestBot/1.0', @@ -24,7 +22,7 @@ end context 'when event has no headers' do - let(:event) { { 'requestContext' => {} } } + let(:event) { {'source_ip' => '10.0.0.1'} } it { expect(request.headers).to eq({}) } end @@ -41,21 +39,8 @@ describe '#remote_addr' do it { expect(request.remote_addr).to eq('10.0.0.1') } - context 'when event is API Gateway v2 format' do - let(:event) do - { - 'headers' => {}, - 'requestContext' => { - 'http' => { 'sourceIp' => '10.0.0.2' } - } - } - end - - it { expect(request.remote_addr).to eq('10.0.0.2') } - end - - context 'when event has no requestContext' do - let(:event) { { 'headers' => {} } } + context 'when source_ip is absent' do + let(:event) { {'headers' => {}} } it { expect(request.remote_addr).to be_nil } end From 4a48b2ed85e70bf04b5d33f00228fd712d13dfdd Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Wed, 6 May 2026 14:43:13 +0200 Subject: [PATCH 07/15] Add queryStringParameters to V2 event normalization V2 events were missing the `query` key, causing `server.request.query` WAF address to be empty for API Gateway V2 payloads. Co-Authored-By: Claude Opus 4.6 (1M context) --- lib/datadog/lambda/appsec/event_normalizer.rb | 1 + test/datadog/lambda/appsec/event_normalizer.spec.rb | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/datadog/lambda/appsec/event_normalizer.rb b/lib/datadog/lambda/appsec/event_normalizer.rb index 5fa9ce4..e05eeb1 100644 --- a/lib/datadog/lambda/appsec/event_normalizer.rb +++ b/lib/datadog/lambda/appsec/event_normalizer.rb @@ -32,6 +32,7 @@ def normalize_v2(event) 'path' => event['rawPath'], 'headers' => event['headers'], 'cookies' => event['cookies'], + 'query' => event['queryStringParameters'], 'query_string' => event['rawQueryString'], 'source_ip' => event.dig('requestContext', 'http', 'sourceIp'), 'body' => event['body'], diff --git a/test/datadog/lambda/appsec/event_normalizer.spec.rb b/test/datadog/lambda/appsec/event_normalizer.spec.rb index 38b5686..2a421b0 100644 --- a/test/datadog/lambda/appsec/event_normalizer.spec.rb +++ b/test/datadog/lambda/appsec/event_normalizer.spec.rb @@ -52,6 +52,7 @@ { 'rawPath' => '/users/123', 'rawQueryString' => 'page=1&sort=asc', + 'queryStringParameters' => {'page' => '1', 'sort' => 'asc'}, 'headers' => {'host' => 'example.com'}, 'cookies' => ['session=abc', 'theme=dark'], 'pathParameters' => {'id' => '123'}, @@ -65,12 +66,12 @@ it { expect(result['path']).to eq('/users/123') } it { expect(result['headers']).to eq('host' => 'example.com') } it { expect(result['cookies']).to eq(['session=abc', 'theme=dark']) } + it { expect(result['query']).to eq('page' => '1', 'sort' => 'asc') } it { expect(result['query_string']).to eq('page=1&sort=asc') } it { expect(result['source_ip']).to eq('10.0.0.2') } it { expect(result['body']).to eq('hello') } it { expect(result['base64_encoded']).to eq(false) } it { expect(result['path_params']).to eq('id' => '123') } - it { expect(result).not_to have_key('query') } end context 'when v1 event has nil fields' do @@ -110,6 +111,7 @@ it { expect(result['path']).to eq('/health') } it { expect(result['source_ip']).to eq('127.0.0.1') } it { expect(result).not_to have_key('cookies') } + it { expect(result).not_to have_key('query') } it { expect(result).not_to have_key('query_string') } it { expect(result).not_to have_key('body') } it { expect(result).not_to have_key('path_params') } From 7561c1ebcc836c0478e41eddde2b33438b8288c7 Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Wed, 6 May 2026 21:03:39 +0200 Subject: [PATCH 08/15] Refactor AppSec tag_and_keep with cold_start parameter - Rename add_appsec_tags to tag_and_keep, move from create_context to on_start for visibility - Pass cold_start flag from listener through to AppSec.on_start instead of tracking @oneshot_tags_sent module state - Align guard clause with Rack: return unless trace && span - Improve test quality: inline event values, use receive_messages, remove instance_variable_set for @request, relax unrelated assertions Co-Authored-By: Claude Opus 4.6 (1M context) --- lib/datadog/lambda/appsec.rb | 33 ++++- lib/datadog/lambda/trace/listener.rb | 2 +- test/datadog/lambda/appsec.spec.rb | 191 +++++++++++++++++++++++---- 3 files changed, 194 insertions(+), 32 deletions(-) diff --git a/lib/datadog/lambda/appsec.rb b/lib/datadog/lambda/appsec.rb index be3a50e..1adffde 100644 --- a/lib/datadog/lambda/appsec.rb +++ b/lib/datadog/lambda/appsec.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true +require 'json' require_relative 'appsec/request' require_relative 'appsec/event_normalizer' @@ -8,13 +9,15 @@ module Lambda # AppSec integration for AWS Lambda invocations. module AppSec class << self - def on_start(event, trace:, span:) + def on_start(event, trace:, span:, cold_start: false) @request = nil return unless enabled? context = create_context(trace, span) return unless Datadog::AppSec::Context.active + tag_and_keep(context, cold_start: cold_start) + event = EventNormalizer.normalize(event) @request = Request.from_normalized(event) @@ -80,9 +83,35 @@ def create_context(trace, span) context = Datadog::AppSec::Context.new(trace, span, security_engine.new_runner) Datadog::AppSec::Context.activate(context) + context + end + + def tag_and_keep(context, cold_start:) + span = context.span + trace = context.trace + + return unless trace && span + span.set_metric(Datadog::AppSec::Ext::TAG_APPSEC_ENABLED, 1) + span.set_tag('_dd.runtime_family', 'ruby') + span.set_tag('_dd.appsec.waf.version', Datadog::AppSec::WAF::VERSION::BASE_STRING) - context + ruleset_version = context.waf_runner_ruleset_version + return unless ruleset_version + + span.set_tag('_dd.appsec.event_rules.version', ruleset_version) + + return unless cold_start + + span.set_tag( + '_dd.appsec.event_rules.addresses', JSON.dump(context.waf_runner_known_addresses) + ) + + trace.keep! + trace.set_tag( + Datadog::Tracing::Metadata::Ext::Distributed::TAG_DECISION_MAKER, + Datadog::Tracing::Sampling::Ext::Decision::ASM + ) end def response_override(interrupt_params, headers:) diff --git a/lib/datadog/lambda/trace/listener.rb b/lib/datadog/lambda/trace/listener.rb index 89c1b4b..078e3de 100644 --- a/lib/datadog/lambda/trace/listener.rb +++ b/lib/datadog/lambda/trace/listener.rb @@ -56,7 +56,7 @@ def on_start(event:, request_context:, cold_start:) Datadog::Trace.apply_datadog_trace_context(Datadog::Trace.trace_context) @response_override = Datadog::Lambda::AppSec.on_start( - event, trace: Datadog::Tracing.active_trace, span: @trace + event, trace: Datadog::Tracing.active_trace, span: @trace, cold_start: cold_start ) end # rubocop:enable Metrics/AbcSize diff --git a/test/datadog/lambda/appsec.spec.rb b/test/datadog/lambda/appsec.spec.rb index 19ddda1..c1d3eea 100644 --- a/test/datadog/lambda/appsec.spec.rb +++ b/test/datadog/lambda/appsec.spec.rb @@ -5,15 +5,17 @@ RSpec.describe Datadog::Lambda::AppSec do before do + stub_const('Datadog::AppSec::WAF::VERSION::BASE_STRING', '1.30.0') allow(Datadog::AppSec::Instrumentation).to receive(:gateway).and_return(gateway) allow(gateway).to receive(:push) end let(:gateway) { instance_double(Datadog::AppSec::Instrumentation::Gateway) } + let(:context_span) { instance_double(Datadog::Tracing::SpanOperation, set_tag: nil, set_metric: nil) } let(:appsec_context) do instance_double( Datadog::AppSec::Context, - span: instance_double(Datadog::Tracing::SpanOperation, get_tag: nil, get_metric: nil), + span: context_span, state: {}, export_metrics: nil, export_request_telemetry: nil @@ -21,11 +23,12 @@ end describe '.on_start' do - subject(:on_start) { described_class.on_start(event, trace: trace, span: span) } + subject(:on_start) do + described_class.on_start({'httpMethod' => 'GET', 'path' => '/'}, trace: trace, span: span) + end - let(:event) { { 'httpMethod' => 'GET', 'path' => '/' } } let(:trace) { instance_double(Datadog::Tracing::TraceOperation) } - let(:span) { instance_double(Datadog::Tracing::SpanOperation, set_metric: nil) } + let(:span) { instance_double(Datadog::Tracing::SpanOperation, set_metric: nil, set_tag: nil) } context 'when appsec is disabled' do before { allow(Datadog::AppSec).to receive(:enabled?).and_return(false) } @@ -39,14 +42,12 @@ context 'when appsec is enabled' do before do - allow(Datadog::AppSec).to receive(:enabled?).and_return(true) - allow(Datadog::AppSec).to receive(:security_engine).and_return(security_engine) - allow(Datadog::AppSec::Context).to receive(:activate) - allow(Datadog::AppSec::Context).to receive(:active).and_return(appsec_context) + allow(Datadog::AppSec).to receive_messages(enabled?: true, security_engine: security_engine) + allow(Datadog::AppSec::Context).to receive_messages(activate: nil, active: appsec_context) end let(:security_engine) { instance_double(Datadog::AppSec::SecurityEngine::Engine, new_runner: waf_runner) } - let(:waf_runner) { instance_double(Datadog::AppSec::SecurityEngine::Runner) } + let(:waf_runner) { instance_double(Datadog::AppSec::SecurityEngine::Runner, ruleset_version: nil) } it 'marks span as appsec-enabled' do on_start @@ -79,7 +80,9 @@ end context 'when trace is nil' do - subject(:on_start) { described_class.on_start(event, trace: nil, span: span) } + subject(:on_start) do + described_class.on_start({'httpMethod' => 'GET', 'path' => '/'}, trace: nil, span: span) + end before { allow(Datadog::AppSec::Context).to receive(:active).and_return(nil) } @@ -94,7 +97,9 @@ end context 'when span is nil' do - subject(:on_start) { described_class.on_start(event, trace: trace, span: nil) } + subject(:on_start) do + described_class.on_start({'httpMethod' => 'GET', 'path' => '/'}, trace: trace, span: nil) + end before { allow(Datadog::AppSec::Context).to receive(:active).and_return(nil) } @@ -111,7 +116,11 @@ context 'when gateway push triggers a blocking interrupt' do before do allow(Datadog::AppSec::Context).to receive(:new).and_return(appsec_context) - allow(appsec_context).to receive(:mark_as_interrupted!) + allow(appsec_context).to receive_messages( + trace: trace, + waf_runner_ruleset_version: nil, + mark_as_interrupted!: nil + ) allow(gateway).to receive(:push).and_invoke(lambda { |_name, _payload| throw(Datadog::AppSec::Ext::INTERRUPT, {'status_code' => 403, 'type' => 'auto'}) @@ -132,13 +141,126 @@ it { expect { on_start }.not_to raise_error } end + + context 'when waf ruleset is loaded' do + before do + allow(Datadog::AppSec::Context).to receive(:new).and_return(appsec_context) + allow(appsec_context).to receive_messages( + waf_runner_ruleset_version: '1.12.0', + waf_runner_known_addresses: ['server.request.headers.no_cookies'] + ) + + allow(trace).to receive_messages(keep!: nil, set_tag: nil) + allow(span).to receive(:set_tag) + end + + let(:appsec_context) do + instance_double( + Datadog::AppSec::Context, + span: span, + trace: trace, + state: {}, + export_metrics: nil, + export_request_telemetry: nil + ) + end + + it 'sets runtime family and WAF version on the span' do + on_start + + aggregate_failures('appsec span tags') do + expect(span).to have_received(:set_tag).with('_dd.runtime_family', 'ruby') + expect(span).to have_received(:set_tag).with('_dd.appsec.waf.version', '1.30.0') + end + end + + it 'sets event rules version from the WAF runner' do + on_start + + expect(span).to have_received(:set_tag).with('_dd.appsec.event_rules.version', '1.12.0') + end + + context 'when cold_start is true' do + subject(:on_start) do + described_class.on_start( + {'httpMethod' => 'GET', 'path' => '/'}, + trace: trace, span: span, cold_start: true + ) + end + + it 'sets known addresses and keeps trace' do + on_start + + aggregate_failures('cold start tags') do + expect(span).to have_received(:set_tag).with( + '_dd.appsec.event_rules.addresses', + '["server.request.headers.no_cookies"]' + ) + expect(trace).to have_received(:keep!) + expect(trace).to have_received(:set_tag).with( + Datadog::Tracing::Metadata::Ext::Distributed::TAG_DECISION_MAKER, + Datadog::Tracing::Sampling::Ext::Decision::ASM + ) + end + end + end + + context 'when cold_start is false' do + it 'does not send cold start tags' do + on_start + + aggregate_failures('no cold start tags') do + expect(span).not_to have_received(:set_tag).with('_dd.appsec.event_rules.addresses', anything) + expect(trace).not_to have_received(:keep!) + end + end + end + + context 'when ruleset version is not set' do + before { allow(appsec_context).to receive(:waf_runner_ruleset_version).and_return(nil) } + + it 'skips event rules tags' do + on_start + + aggregate_failures('skipped rules tags') do + expect(span).not_to have_received(:set_tag).with('_dd.appsec.event_rules.version', anything) + expect(span).not_to have_received(:set_tag).with('_dd.appsec.event_rules.addresses', anything) + end + end + end + + context 'when span is not set' do + subject(:on_start) do + described_class.on_start({'httpMethod' => 'GET', 'path' => '/'}, trace: trace, span: nil) + end + + before { allow(Datadog::AppSec::Context).to receive(:active).and_return(nil) } + + it 'does not set any appsec tags' do + on_start + + expect(span).not_to have_received(:set_tag) + end + end + + context 'when context trace is not set' do + before { allow(appsec_context).to receive(:trace).and_return(nil) } + + it 'does not set any tags' do + on_start + + aggregate_failures('no tags when trace nil') do + expect(span).not_to have_received(:set_tag) + expect(span).not_to have_received(:set_metric).with(Datadog::AppSec::Ext::TAG_APPSEC_ENABLED, anything) + end + end + end + end end end describe '.on_finish' do - subject(:on_finish) { described_class.on_finish(response) } - - let(:response) { { 'statusCode' => 200 } } + subject(:on_finish) { described_class.on_finish({ 'statusCode' => 200 }) } context 'when appsec is disabled' do before do @@ -169,8 +291,7 @@ context 'when active context exists' do before do allow(Datadog::AppSec).to receive(:enabled?).and_return(true) - allow(Datadog::AppSec::Context).to receive(:active).and_return(appsec_context) - allow(Datadog::AppSec::Context).to receive(:deactivate) + allow(Datadog::AppSec::Context).to receive_messages(active: appsec_context, deactivate: nil) allow(Datadog::AppSec::Event).to receive(:record) end @@ -181,7 +302,7 @@ expect(gateway).to have_received(:push).with( 'aws_lambda.response.start', kind_of(Datadog::AppSec::Instrumentation::Gateway::DataContainer) ) - expect(Datadog::AppSec::Event).to have_received(:record).with(appsec_context, request: nil) + expect(Datadog::AppSec::Event).to have_received(:record).with(appsec_context, request: anything) end end @@ -200,20 +321,20 @@ allow(Datadog::AppSec).to receive(:security_engine).and_return(security_engine) allow(Datadog::AppSec::Context).to receive(:activate) - described_class.on_start(event, trace: trace, span: span) + described_class.on_start( + { + 'httpMethod' => 'GET', + 'headers' => {'Host' => 'example.com', 'User-Agent' => 'TestBot'}, + 'requestContext' => {'identity' => {'sourceIp' => '1.2.3.4'}} + }, + trace: trace, span: span + ) end - let(:event) do - { - 'httpMethod' => 'GET', - 'headers' => {'Host' => 'example.com', 'User-Agent' => 'TestBot'}, - 'requestContext' => {'identity' => {'sourceIp' => '1.2.3.4'}}, - } - end let(:trace) { instance_double(Datadog::Tracing::TraceOperation) } - let(:span) { instance_double(Datadog::Tracing::SpanOperation, set_metric: nil) } + let(:span) { instance_double(Datadog::Tracing::SpanOperation, set_metric: nil, set_tag: nil) } let(:security_engine) { instance_double(Datadog::AppSec::SecurityEngine::Engine, new_runner: waf_runner) } - let(:waf_runner) { instance_double(Datadog::AppSec::SecurityEngine::Runner) } + let(:waf_runner) { instance_double(Datadog::AppSec::SecurityEngine::Runner, ruleset_version: nil) } it 'records security event with request' do on_finish @@ -226,12 +347,24 @@ context 'when gateway push triggers a blocking interrupt' do before do + allow(Datadog::AppSec).to receive(:security_engine).and_return(security_engine) + allow(Datadog::AppSec::Context).to receive(:activate) + allow(appsec_context).to receive(:mark_as_interrupted!) allow(gateway).to receive(:push).and_invoke(lambda { |_name, _payload| throw(Datadog::AppSec::Ext::INTERRUPT, {'status_code' => 403, 'type' => 'auto'}) }) - allow(appsec_context).to receive(:mark_as_interrupted!) + + described_class.on_start( + {'httpMethod' => 'GET', 'headers' => {'Accept' => 'application/json'}}, + trace: trace, span: span + ) end + let(:trace) { instance_double(Datadog::Tracing::TraceOperation) } + let(:span) { instance_double(Datadog::Tracing::SpanOperation, set_metric: nil, set_tag: nil) } + let(:security_engine) { instance_double(Datadog::AppSec::SecurityEngine::Engine, new_runner: waf_runner) } + let(:waf_runner) { instance_double(Datadog::AppSec::SecurityEngine::Runner, ruleset_version: nil) } + it 'returns a Lambda-shaped blocking response' do expect(on_finish).to include( 'statusCode' => 403, From 9eb28ca5ab00a24c0414950536d14ed9557f0226 Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Thu, 7 May 2026 10:04:05 +0200 Subject: [PATCH 09/15] Pin FFI gem version to 1.17.4 --- Dockerfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 959e300..ce7d637 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,13 +11,13 @@ RUN apt-get install -y gcc zip binutils RUN gem build datadog-lambda # Install ddtrace gem -RUN gem install datadog-lambda --install-dir "/opt/ruby/gems/$runtime" -RUN gem install datadog -v 2.12 --install-dir "/opt/ruby/gems/$runtime" +RUN gem install datadog-lambda --install-dir "/opt/ruby/gems/$runtime" --no-document +RUN gem install datadog -v 2.12 --install-dir "/opt/ruby/gems/$runtime" --no-document # Recompile FFI from source — precompiled binaries have glibc mismatch with Lambda AL2 # NOTE: runs after datadog gem as a defensive measure — force-replaces whatever # transitive FFI variant was pulled, regardless of version resolution. -RUN gem install ffi --platform ruby --force --install-dir "/opt/ruby/gems/$runtime" --no-document +RUN gem install ffi -v 1.17.4 --platform ruby --force --install-dir "/opt/ruby/gems/$runtime" --no-document RUN rm -rf /opt/ruby/gems/$runtime/gems/ffi-*-*-linux-* \ /opt/ruby/gems/$runtime/specifications/ffi-*-*-linux-*.gemspec @@ -29,7 +29,7 @@ RUN rm -rf ./ruby/gems/$runtime/gems/aws*/ # Remove binaries not needed in AWS Lambda RUN find . -name '*linux-musl*' -prune -exec rm -rf {} + -# Cache files zipped gem files, that aren't used by during runtime, only during +# Cache files zipped gem files, that aren't used by during runtime, only during # installation, so they are safe to delete RUN rm -rf "/opt/ruby/gems/${runtime}/cache" RUN cd /opt From 5f54d76e6608d51e92f933de3b526622c0193129 Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Thu, 7 May 2026 10:09:06 +0200 Subject: [PATCH 10/15] Disable Rubocop ABC size metric on AppSec --- lib/datadog/lambda/appsec.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/datadog/lambda/appsec.rb b/lib/datadog/lambda/appsec.rb index 1adffde..a27831a 100644 --- a/lib/datadog/lambda/appsec.rb +++ b/lib/datadog/lambda/appsec.rb @@ -9,6 +9,7 @@ module Lambda # AppSec integration for AWS Lambda invocations. module AppSec class << self + # rubocop:disable Metrics/AbcSize def on_start(event, trace:, span:, cold_start: false) @request = nil return unless enabled? @@ -37,6 +38,7 @@ def on_start(event, trace:, span:, cold_start: false) rescue StandardError => e Datadog::Utils.logger.debug("failed to start AppSec: #{e}") end + # rubocop:enable Metrics/AbcSize def on_finish(response) return unless enabled? From d636d44df2e03d3bcbc85bf469dcd22d3e4499b9 Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Thu, 7 May 2026 10:30:31 +0200 Subject: [PATCH 11/15] Add parallelisation for native-compiled gems --- Dockerfile | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index ce7d637..4302634 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,13 +11,16 @@ RUN apt-get install -y gcc zip binutils RUN gem build datadog-lambda # Install ddtrace gem -RUN gem install datadog-lambda --install-dir "/opt/ruby/gems/$runtime" --no-document -RUN gem install datadog -v 2.12 --install-dir "/opt/ruby/gems/$runtime" --no-document +RUN MAKEFLAGS="-j$(nproc)" \ + gem install datadog-lambda --install-dir "/opt/ruby/gems/$runtime" --no-document +RUN MAKEFLAGS="-j$(nproc)" \ + gem install datadog -v 2.12 --install-dir "/opt/ruby/gems/$runtime" --no-document # Recompile FFI from source — precompiled binaries have glibc mismatch with Lambda AL2 # NOTE: runs after datadog gem as a defensive measure — force-replaces whatever # transitive FFI variant was pulled, regardless of version resolution. -RUN gem install ffi -v 1.17.4 --platform ruby --force --install-dir "/opt/ruby/gems/$runtime" --no-document +RUN MAKEFLAGS="-j$(nproc)" \ + gem install ffi -v 1.17.4 --platform ruby --force --install-dir "/opt/ruby/gems/$runtime" --no-document RUN rm -rf /opt/ruby/gems/$runtime/gems/ffi-*-*-linux-* \ /opt/ruby/gems/$runtime/specifications/ffi-*-*-linux-*.gemspec From 14839ed29fe9b25eb8a4cc58f188e06100fcb881 Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Fri, 8 May 2026 11:34:47 +0200 Subject: [PATCH 12/15] Use Lambda AL2 base image for layer build The layer was built on ruby:X.Y (Debian Bookworm) which has libffi.so.8, but Lambda AL2 runtime only has libffi.so.6. Source-compiled FFI linked against .so.8 and crashed at runtime. Switch to public.ecr.aws/lambda/ruby:X.Y as builder so native extensions compile against the same system libraries available at runtime. Co-Authored-By: Claude Opus 4.6 (1M context) --- .gitlab/scripts/build_layer.sh | 2 +- Dockerfile | 5 +++-- scripts/build_layers.sh | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.gitlab/scripts/build_layer.sh b/.gitlab/scripts/build_layer.sh index 36a2d24..b826eeb 100755 --- a/.gitlab/scripts/build_layer.sh +++ b/.gitlab/scripts/build_layer.sh @@ -42,7 +42,7 @@ function docker_build_zip { # between different ruby runtimes. temp_dir=$(mktemp -d) docker buildx build -t datadog-lambda-ruby-${arch}:$1 . --no-cache \ - --build-arg "image=ruby:${1}" \ + --build-arg "image=public.ecr.aws/lambda/ruby:${1}" \ --build-arg "runtime=${1}.0" \ --platform linux/${arch} \ --progress=plain \ diff --git a/Dockerfile b/Dockerfile index 4302634..b15f3ec 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,8 +4,9 @@ ARG runtime # Install dev dependencies COPY . /var/task/datadog-lambda-rb WORKDIR /var/task/datadog-lambda-rb -RUN apt-get update -RUN apt-get install -y gcc zip binutils +# NOTE: AL2 (Ruby 3.2) uses yum, AL2023 (Ruby 3.3+) uses dnf +RUN PKG=$(command -v dnf || command -v yum) && \ + $PKG install -y gcc gcc-c++ make zip binutils libffi-devel # Install this gem RUN gem build datadog-lambda diff --git a/scripts/build_layers.sh b/scripts/build_layers.sh index 304b334..4bb6409 100755 --- a/scripts/build_layers.sh +++ b/scripts/build_layers.sh @@ -38,7 +38,7 @@ function docker_build_zip { # between different ruby runtimes. temp_dir=$(mktemp -d) docker buildx build -t datadog-lambda-ruby-${arch}:$1 . --no-cache \ - --build-arg "image=ruby:${1}" \ + --build-arg "image=public.ecr.aws/lambda/ruby:${1}" \ --build-arg "runtime=${1}.0" \ --platform linux/${arch} \ --progress=plain \ From 52643af2c365fbc49a362a93edc6c6e58630f978 Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Fri, 8 May 2026 11:34:55 +0200 Subject: [PATCH 13/15] Update integration test snapshots for AppSec Generated with unreleased dd-trace-rb (appsec aws_lambda contrib). These snapshots will pass once the tracer is released and pinned. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../snapshots/logs/appsec-request_ruby32.log | 29 ++++++++++++++ .../snapshots/logs/appsec-request_ruby33.log | 29 ++++++++++++++ .../snapshots/logs/appsec-request_ruby34.log | 29 ++++++++++++++ .../snapshots/logs/async-metrics_ruby34.log | 38 ++++++++++++------- .../snapshots/logs/http-requests_ruby34.log | 38 ++++++++++++------- .../logs/process-input-traced_ruby34.log | 30 ++++++++++----- .../snapshots/logs/sync-metrics_ruby34.log | 38 ++++++++++++------- ...c-request_api-gateway-appsec-blocking.json | 5 +++ .../appsec-request_api-gateway-appsec.json | 5 +++ .../appsec-request_api-gateway-get.json | 5 +++ .../return_values/appsec-request_sns.json | 5 +++ .../return_values/appsec-request_sqs.json | 5 +++ ...c-metrics_api-gateway-appsec-blocking.json | 5 +++ .../async-metrics_api-gateway-appsec.json | 5 +++ ...-requests_api-gateway-appsec-blocking.json | 3 ++ .../http-requests_api-gateway-appsec.json | 3 ++ ...ut-traced_api-gateway-appsec-blocking.json | 5 +++ ...ocess-input-traced_api-gateway-appsec.json | 5 +++ ...c-metrics_api-gateway-appsec-blocking.json | 5 +++ .../sync-metrics_api-gateway-appsec.json | 5 +++ 20 files changed, 243 insertions(+), 49 deletions(-) create mode 100644 integration_tests/snapshots/logs/appsec-request_ruby32.log create mode 100644 integration_tests/snapshots/logs/appsec-request_ruby33.log create mode 100644 integration_tests/snapshots/logs/appsec-request_ruby34.log create mode 100644 integration_tests/snapshots/return_values/appsec-request_api-gateway-appsec-blocking.json create mode 100644 integration_tests/snapshots/return_values/appsec-request_api-gateway-appsec.json create mode 100644 integration_tests/snapshots/return_values/appsec-request_api-gateway-get.json create mode 100644 integration_tests/snapshots/return_values/appsec-request_sns.json create mode 100644 integration_tests/snapshots/return_values/appsec-request_sqs.json create mode 100644 integration_tests/snapshots/return_values/async-metrics_api-gateway-appsec-blocking.json create mode 100644 integration_tests/snapshots/return_values/async-metrics_api-gateway-appsec.json create mode 100644 integration_tests/snapshots/return_values/http-requests_api-gateway-appsec-blocking.json create mode 100644 integration_tests/snapshots/return_values/http-requests_api-gateway-appsec.json create mode 100644 integration_tests/snapshots/return_values/process-input-traced_api-gateway-appsec-blocking.json create mode 100644 integration_tests/snapshots/return_values/process-input-traced_api-gateway-appsec.json create mode 100644 integration_tests/snapshots/return_values/sync-metrics_api-gateway-appsec-blocking.json create mode 100644 integration_tests/snapshots/return_values/sync-metrics_api-gateway-appsec.json diff --git a/integration_tests/snapshots/logs/appsec-request_ruby32.log b/integration_tests/snapshots/logs/appsec-request_ruby32.log new file mode 100644 index 0000000..9716a17 --- /dev/null +++ b/integration_tests/snapshots/logs/appsec-request_ruby32.log @@ -0,0 +1,29 @@ + +END Duration: XXXX ms (init: XXXX ms) Memory Used: XXXX MB +END Duration: XXXX ms (init: XXXX) Memory Used: XXXX MB +END Duration: XXXX ms (init: XXXX) Memory Used: XXXX MB +END Duration: XXXX ms (init: XXXX) Memory Used: XXXX MB +END Duration: XXXX ms (init: XXXX) Memory Used: XXXX MB +I, [XXXX] INFO XXXX[datadog] DATADOG CONFIGURATION - CORE - {"date":"XXXX","os_name":"XXXX","version":"2.32.0","lang":"ruby","lang_version":"3.2.X","env":null,"service":"index","dd_version":null,"debug":false,"tags":"_dd.origin:lambda","runtime_metrics_enabled":false,"vm":"ruby-3.2.X","health_metrics_enabled":false,"profiling_enabled":false,"dynamic_instrumentation_enabled":false} +I, [XXXX] INFO XXXX[datadog] DATADOG CONFIGURATION - TRACING - {"enabled":true,"agent_url":null,"analytics_enabled":false,"sample_rate":null,"sampling_rules":null,"integrations_loaded":"aws@","partial_flushing_enabled":false} +START +START +START +START +START +W, [XXXX] WARN XXXX[datadog] Unable to patch Datadog::Tracing::Contrib::Aws::Integration (Available?: false, Loaded? false, Compatible? false, Patchable? false) +{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby32","functionname:integration-tests-rb-XXXX-appsec-request_ruby32","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:false","runtime:Ruby 3.2.X","resource:integration-tests-rb-XXXX-appsec-request_ruby32","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} +{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby32","functionname:integration-tests-rb-XXXX-appsec-request_ruby32","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:false","runtime:Ruby 3.2.X","resource:integration-tests-rb-XXXX-appsec-request_ruby32","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} +{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby32","functionname:integration-tests-rb-XXXX-appsec-request_ruby32","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:false","runtime:Ruby 3.2.X","resource:integration-tests-rb-XXXX-appsec-request_ruby32","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} +{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby32","functionname:integration-tests-rb-XXXX-appsec-request_ruby32","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:false","runtime:Ruby 3.2.X","resource:integration-tests-rb-XXXX-appsec-request_ruby32","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} +{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby32","functionname:integration-tests-rb-XXXX-appsec-request_ruby32","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:true","runtime:Ruby 3.2.X","resource:integration-tests-rb-XXXX-appsec-request_ruby32","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} +{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby32","function:appsec-request"],"v":1} +{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby32","function:appsec-request"],"v":1} +{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby32","function:appsec-request"],"v":1} +{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby32","function:appsec-request"],"v":1} +{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby32","function:appsec-request"],"v":1} +{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} +{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} +{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} +{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},\"on_match\":[]},\"rule_matches\":[{\"operator\":\"is_sqli\",\"operator_value\":\"\",\"parameters\":[{\"address\":\"server.request.query\",\"key_path\":[\"q\"],\"value\":\"1' OR '1'='1\",\"highlight\":[\"s&sos\"]}]}]}]}"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} +{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},\"on_match\":[]},\"rule_matches\":[{\"operator\":\"match_regex\",\"operator_value\":\"^Arachni\\\\/v\",\"parameters\":[{\"address\":\"server.request.headers.no_cookies\",\"key_path\":[\"user-agent\"],\"value\":\"Arachni/v1.0\",\"highlight\":[\"Arachni/v\"]}]}]}]}"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} diff --git a/integration_tests/snapshots/logs/appsec-request_ruby33.log b/integration_tests/snapshots/logs/appsec-request_ruby33.log new file mode 100644 index 0000000..cbacf26 --- /dev/null +++ b/integration_tests/snapshots/logs/appsec-request_ruby33.log @@ -0,0 +1,29 @@ + +END Duration: XXXX ms (init: XXXX ms) Memory Used: XXXX MB +END Duration: XXXX ms (init: XXXX) Memory Used: XXXX MB +END Duration: XXXX ms (init: XXXX) Memory Used: XXXX MB +END Duration: XXXX ms (init: XXXX) Memory Used: XXXX MB +END Duration: XXXX ms (init: XXXX) Memory Used: XXXX MB +I, [XXXX] INFO XXXX[datadog] DATADOG CONFIGURATION - CORE - {"date":"XXXX","os_name":"XXXX","version":"2.32.0","lang":"ruby","lang_version":"3.3.X","env":null,"service":"index","dd_version":null,"debug":false,"tags":"_dd.origin:lambda","runtime_metrics_enabled":false,"vm":"ruby-3.3.X","health_metrics_enabled":false,"profiling_enabled":false,"dynamic_instrumentation_enabled":false} +I, [XXXX] INFO XXXX[datadog] DATADOG CONFIGURATION - TRACING - {"enabled":true,"agent_url":null,"analytics_enabled":false,"sample_rate":null,"sampling_rules":null,"integrations_loaded":"aws@","partial_flushing_enabled":false} +START +START +START +START +START +W, [XXXX] WARN XXXX[datadog] Unable to patch Datadog::Tracing::Contrib::Aws::Integration (Available?: false, Loaded? false, Compatible? false, Patchable? false) +{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby33","functionname:integration-tests-rb-XXXX-appsec-request_ruby33","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:false","runtime:Ruby 3.3.X","resource:integration-tests-rb-XXXX-appsec-request_ruby33","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} +{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby33","functionname:integration-tests-rb-XXXX-appsec-request_ruby33","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:false","runtime:Ruby 3.3.X","resource:integration-tests-rb-XXXX-appsec-request_ruby33","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} +{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby33","functionname:integration-tests-rb-XXXX-appsec-request_ruby33","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:false","runtime:Ruby 3.3.X","resource:integration-tests-rb-XXXX-appsec-request_ruby33","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} +{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby33","functionname:integration-tests-rb-XXXX-appsec-request_ruby33","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:false","runtime:Ruby 3.3.X","resource:integration-tests-rb-XXXX-appsec-request_ruby33","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} +{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby33","functionname:integration-tests-rb-XXXX-appsec-request_ruby33","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:true","runtime:Ruby 3.3.X","resource:integration-tests-rb-XXXX-appsec-request_ruby33","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} +{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby33","function:appsec-request"],"v":1} +{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby33","function:appsec-request"],"v":1} +{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby33","function:appsec-request"],"v":1} +{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby33","function:appsec-request"],"v":1} +{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby33","function:appsec-request"],"v":1} +{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} +{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} +{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} +{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},\"on_match\":[]},\"rule_matches\":[{\"operator\":\"is_sqli\",\"operator_value\":\"\",\"parameters\":[{\"address\":\"server.request.query\",\"key_path\":[\"q\"],\"value\":\"1' OR '1'='1\",\"highlight\":[\"s&sos\"]}]}]}]}"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} +{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},\"on_match\":[]},\"rule_matches\":[{\"operator\":\"match_regex\",\"operator_value\":\"^Arachni\\\\/v\",\"parameters\":[{\"address\":\"server.request.headers.no_cookies\",\"key_path\":[\"user-agent\"],\"value\":\"Arachni/v1.0\",\"highlight\":[\"Arachni/v\"]}]}]}]}"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} diff --git a/integration_tests/snapshots/logs/appsec-request_ruby34.log b/integration_tests/snapshots/logs/appsec-request_ruby34.log new file mode 100644 index 0000000..64534ce --- /dev/null +++ b/integration_tests/snapshots/logs/appsec-request_ruby34.log @@ -0,0 +1,29 @@ + +END Duration: XXXX ms (init: XXXX ms) Memory Used: XXXX MB +END Duration: XXXX ms (init: XXXX) Memory Used: XXXX MB +END Duration: XXXX ms (init: XXXX) Memory Used: XXXX MB +END Duration: XXXX ms (init: XXXX) Memory Used: XXXX MB +END Duration: XXXX ms (init: XXXX) Memory Used: XXXX MB +I, [XXXX] INFO XXXX[datadog] DATADOG CONFIGURATION - CORE - {"date":"XXXX","os_name":"XXXX","version":"2.32.0","lang":"ruby","lang_version":"3.4.X","env":null,"service":"index","dd_version":null,"debug":false,"tags":"_dd.origin:lambda","runtime_metrics_enabled":false,"vm":"ruby-3.4.X","health_metrics_enabled":false,"profiling_enabled":false,"dynamic_instrumentation_enabled":false} +I, [XXXX] INFO XXXX[datadog] DATADOG CONFIGURATION - TRACING - {"enabled":true,"agent_url":null,"analytics_enabled":false,"sample_rate":null,"sampling_rules":null,"integrations_loaded":"aws@","partial_flushing_enabled":false} +START +START +START +START +START +W, [XXXX] WARN XXXX[datadog] Unable to patch Datadog::Tracing::Contrib::Aws::Integration (Available?: false, Loaded? false, Compatible? false, Patchable? false) +{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby34","functionname:integration-tests-rb-XXXX-appsec-request_ruby34","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:false","runtime:Ruby 3.4.X","resource:integration-tests-rb-XXXX-appsec-request_ruby34","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} +{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby34","functionname:integration-tests-rb-XXXX-appsec-request_ruby34","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:false","runtime:Ruby 3.4.X","resource:integration-tests-rb-XXXX-appsec-request_ruby34","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} +{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby34","functionname:integration-tests-rb-XXXX-appsec-request_ruby34","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:false","runtime:Ruby 3.4.X","resource:integration-tests-rb-XXXX-appsec-request_ruby34","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} +{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby34","functionname:integration-tests-rb-XXXX-appsec-request_ruby34","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:false","runtime:Ruby 3.4.X","resource:integration-tests-rb-XXXX-appsec-request_ruby34","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} +{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby34","functionname:integration-tests-rb-XXXX-appsec-request_ruby34","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:true","runtime:Ruby 3.4.X","resource:integration-tests-rb-XXXX-appsec-request_ruby34","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} +{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby34","function:appsec-request"],"v":1} +{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby34","function:appsec-request"],"v":1} +{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby34","function:appsec-request"],"v":1} +{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby34","function:appsec-request"],"v":1} +{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby34","function:appsec-request"],"v":1} +{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} +{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} +{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} +{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},\"on_match\":[]},\"rule_matches\":[{\"operator\":\"is_sqli\",\"operator_value\":\"\",\"parameters\":[{\"address\":\"server.request.query\",\"key_path\":[\"q\"],\"value\":\"1' OR '1'='1\",\"highlight\":[\"s&sos\"]}]}]}]}"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} +{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},\"on_match\":[]},\"rule_matches\":[{\"operator\":\"match_regex\",\"operator_value\":\"^Arachni\\\\/v\",\"parameters\":[{\"address\":\"server.request.headers.no_cookies\",\"key_path\":[\"user-agent\"],\"value\":\"Arachni/v1.0\",\"highlight\":[\"Arachni/v\"]}]}]}]}"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} diff --git a/integration_tests/snapshots/logs/async-metrics_ruby34.log b/integration_tests/snapshots/logs/async-metrics_ruby34.log index 4eaabe5..5d93eb1 100644 --- a/integration_tests/snapshots/logs/async-metrics_ruby34.log +++ b/integration_tests/snapshots/logs/async-metrics_ruby34.log @@ -1,25 +1,37 @@ -{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby34","functionname:integration-tests-rb-XXXX-async-metrics_ruby34","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:false","runtime:Ruby 3.4.X","resource:integration-tests-rb-XXXX-async-metrics_ruby34","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} -{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby34","functionname:integration-tests-rb-XXXX-async-metrics_ruby34","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:false","runtime:Ruby 3.4.X","resource:integration-tests-rb-XXXX-async-metrics_ruby34","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} -{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby34","functionname:integration-tests-rb-XXXX-async-metrics_ruby34","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:true","runtime:Ruby 3.4.X","resource:integration-tests-rb-XXXX-async-metrics_ruby34","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} -{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby34","tagkey:tagvalue","eventsource:APIGateway"],"v":1} -{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby34","tagkey:tagvalue","eventsource:SNS"],"v":1} -{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby34","tagkey:tagvalue","eventsource:SQS"],"v":1} -{"e":XXXX,"m":"serverless.integration_test.records_processed","t":["dd_lambda_layer:datadog-ruby34","tagkey:tagvalue","eventsource:SNS"],"v":1} -{"e":XXXX,"m":"serverless.integration_test.records_processed","t":["dd_lambda_layer:datadog-ruby34","tagkey:tagvalue","eventsource:SQS"],"v":1} -{"e":XXXX,"m":"serverless.integration_test.records_processed","t":["dd_lambda_layer:datadog-ruby34","tagkey:tagvalue","eventsource:SQS"],"v":1} -{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} -{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} -{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} END Duration: XXXX ms (init: XXXX ms) Memory Used: XXXX MB END Duration: XXXX ms (init: XXXX) Memory Used: XXXX MB END Duration: XXXX ms (init: XXXX) Memory Used: XXXX MB -I, [XXXX] INFO XXXX[datadog] DATADOG CONFIGURATION - CORE - {"date":"XXXX","os_name":"XXXX","version":"2.12.0","lang":"ruby","lang_version":"3.4.X","env":null,"service":"index","dd_version":null,"debug":false,"tags":"_dd.origin:lambda","runtime_metrics_enabled":false,"vm":"ruby-3.4.X","health_metrics_enabled":false,"profiling_enabled":false,"dynamic_instrumentation_enabled":false} +END Duration: XXXX ms (init: XXXX) Memory Used: XXXX MB +END Duration: XXXX ms (init: XXXX) Memory Used: XXXX MB +I, [XXXX] INFO XXXX[datadog] DATADOG CONFIGURATION - CORE - {"date":"XXXX","os_name":"XXXX","version":"2.32.0","lang":"ruby","lang_version":"3.4.X","env":null,"service":"index","dd_version":null,"debug":false,"tags":"_dd.origin:lambda","runtime_metrics_enabled":false,"vm":"ruby-3.4.X","health_metrics_enabled":false,"profiling_enabled":false,"dynamic_instrumentation_enabled":false} I, [XXXX] INFO XXXX[datadog] DATADOG CONFIGURATION - TRACING - {"enabled":true,"agent_url":null,"analytics_enabled":false,"sample_rate":null,"sampling_rules":null,"integrations_loaded":"aws@","partial_flushing_enabled":false} Processed APIGateway request +Processed APIGateway request +Processed APIGateway request Processed SNS request Processed SQS request START START START +START +START W, [XXXX] WARN XXXX[datadog] Unable to patch Datadog::Tracing::Contrib::Aws::Integration (Available?: false, Loaded? false, Compatible? false, Patchable? false) +{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby34","functionname:integration-tests-rb-XXXX-async-metrics_ruby34","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:false","runtime:Ruby 3.4.X","resource:integration-tests-rb-XXXX-async-metrics_ruby34","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} +{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby34","functionname:integration-tests-rb-XXXX-async-metrics_ruby34","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:false","runtime:Ruby 3.4.X","resource:integration-tests-rb-XXXX-async-metrics_ruby34","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} +{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby34","functionname:integration-tests-rb-XXXX-async-metrics_ruby34","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:false","runtime:Ruby 3.4.X","resource:integration-tests-rb-XXXX-async-metrics_ruby34","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} +{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby34","functionname:integration-tests-rb-XXXX-async-metrics_ruby34","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:false","runtime:Ruby 3.4.X","resource:integration-tests-rb-XXXX-async-metrics_ruby34","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} +{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby34","functionname:integration-tests-rb-XXXX-async-metrics_ruby34","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:true","runtime:Ruby 3.4.X","resource:integration-tests-rb-XXXX-async-metrics_ruby34","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} +{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby34","tagkey:tagvalue","eventsource:APIGateway"],"v":1} +{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby34","tagkey:tagvalue","eventsource:APIGateway"],"v":1} +{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby34","tagkey:tagvalue","eventsource:APIGateway"],"v":1} +{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby34","tagkey:tagvalue","eventsource:SNS"],"v":1} +{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby34","tagkey:tagvalue","eventsource:SQS"],"v":1} +{"e":XXXX,"m":"serverless.integration_test.records_processed","t":["dd_lambda_layer:datadog-ruby34","tagkey:tagvalue","eventsource:SNS"],"v":1} +{"e":XXXX,"m":"serverless.integration_test.records_processed","t":["dd_lambda_layer:datadog-ruby34","tagkey:tagvalue","eventsource:SQS"],"v":1} +{"e":XXXX,"m":"serverless.integration_test.records_processed","t":["dd_lambda_layer:datadog-ruby34","tagkey:tagvalue","eventsource:SQS"],"v":1} +{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} +{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} +{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} +{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} +{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} diff --git a/integration_tests/snapshots/logs/http-requests_ruby34.log b/integration_tests/snapshots/logs/http-requests_ruby34.log index b0be88d..5258c71 100644 --- a/integration_tests/snapshots/logs/http-requests_ruby34.log +++ b/integration_tests/snapshots/logs/http-requests_ruby34.log @@ -1,22 +1,34 @@ -{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby34","functionname:integration-tests-rb-XXXX-http-requests_ruby34","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:false","runtime:Ruby 3.4.X","resource:integration-tests-rb-XXXX-http-requests_ruby34","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} -{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby34","functionname:integration-tests-rb-XXXX-http-requests_ruby34","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:false","runtime:Ruby 3.4.X","resource:integration-tests-rb-XXXX-http-requests_ruby34","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} -{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby34","functionname:integration-tests-rb-XXXX-http-requests_ruby34","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:true","runtime:Ruby 3.4.X","resource:integration-tests-rb-XXXX-http-requests_ruby34","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} -{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby34","function:http-request"],"v":1} -{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby34","function:http-request"],"v":1} -{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby34","function:http-request"],"v":1} -{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} -{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} -{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} END Duration: XXXX ms (init: XXXX ms) Memory Used: XXXX MB END Duration: XXXX ms (init: XXXX) Memory Used: XXXX MB END Duration: XXXX ms (init: XXXX) Memory Used: XXXX MB -I, [XXXX] INFO XXXX[datadog] DATADOG CONFIGURATION - CORE - {"date":"XXXX","os_name":"XXXX","version":"2.12.0","lang":"ruby","lang_version":"3.4.X","env":null,"service":"index","dd_version":null,"debug":false,"tags":"_dd.origin:lambda","runtime_metrics_enabled":false,"vm":"ruby-3.4.X","health_metrics_enabled":false,"profiling_enabled":false,"dynamic_instrumentation_enabled":false} +END Duration: XXXX ms (init: XXXX) Memory Used: XXXX MB +END Duration: XXXX ms (init: XXXX) Memory Used: XXXX MB +I, [XXXX] INFO XXXX[datadog] DATADOG CONFIGURATION - CORE - {"date":"XXXX","os_name":"XXXX","version":"2.32.0","lang":"ruby","lang_version":"3.4.X","env":null,"service":"index","dd_version":null,"debug":false,"tags":"_dd.origin:lambda","runtime_metrics_enabled":false,"vm":"ruby-3.4.X","health_metrics_enabled":false,"profiling_enabled":false,"dynamic_instrumentation_enabled":false} I, [XXXX] INFO XXXX[datadog] DATADOG CONFIGURATION - TRACING - {"enabled":true,"agent_url":null,"analytics_enabled":false,"sample_rate":null,"sampling_rules":null,"integrations_loaded":"aws@","partial_flushing_enabled":false} -Snapshot test http requests successfully made to URLs: ["ip-ranges.datadoghq.com", "ip-ranges.datadoghq.eu"] -Snapshot test http requests successfully made to URLs: ["ip-ranges.datadoghq.com", "ip-ranges.datadoghq.eu"] -Snapshot test http requests successfully made to URLs: ["ip-ranges.datadoghq.com", "ip-ranges.datadoghq.eu"] START START START +START +START +Snapshot test http requests successfully made to URLs: ["ip-ranges.datadoghq.com", "ip-ranges.datadoghq.eu"] +Snapshot test http requests successfully made to URLs: ["ip-ranges.datadoghq.com", "ip-ranges.datadoghq.eu"] +Snapshot test http requests successfully made to URLs: ["ip-ranges.datadoghq.com", "ip-ranges.datadoghq.eu"] +Snapshot test http requests successfully made to URLs: ["ip-ranges.datadoghq.com", "ip-ranges.datadoghq.eu"] +Snapshot test http requests successfully made to URLs: ["ip-ranges.datadoghq.com", "ip-ranges.datadoghq.eu"] W, [XXXX] WARN XXXX[datadog] Unable to patch Datadog::Tracing::Contrib::Aws::Integration (Available?: false, Loaded? false, Compatible? false, Patchable? false) +{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby34","functionname:integration-tests-rb-XXXX-http-requests_ruby34","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:false","runtime:Ruby 3.4.X","resource:integration-tests-rb-XXXX-http-requests_ruby34","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} +{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby34","functionname:integration-tests-rb-XXXX-http-requests_ruby34","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:false","runtime:Ruby 3.4.X","resource:integration-tests-rb-XXXX-http-requests_ruby34","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} +{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby34","functionname:integration-tests-rb-XXXX-http-requests_ruby34","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:false","runtime:Ruby 3.4.X","resource:integration-tests-rb-XXXX-http-requests_ruby34","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} +{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby34","functionname:integration-tests-rb-XXXX-http-requests_ruby34","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:false","runtime:Ruby 3.4.X","resource:integration-tests-rb-XXXX-http-requests_ruby34","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} +{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby34","functionname:integration-tests-rb-XXXX-http-requests_ruby34","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:true","runtime:Ruby 3.4.X","resource:integration-tests-rb-XXXX-http-requests_ruby34","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} +{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby34","function:http-request"],"v":1} +{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby34","function:http-request"],"v":1} +{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby34","function:http-request"],"v":1} +{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby34","function:http-request"],"v":1} +{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby34","function:http-request"],"v":1} +{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} +{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} +{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} +{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} +{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} diff --git a/integration_tests/snapshots/logs/process-input-traced_ruby34.log b/integration_tests/snapshots/logs/process-input-traced_ruby34.log index 58e3c3f..3ba48d3 100644 --- a/integration_tests/snapshots/logs/process-input-traced_ruby34.log +++ b/integration_tests/snapshots/logs/process-input-traced_ruby34.log @@ -1,19 +1,29 @@ -{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby34","functionname:integration-tests-rb-XXXX-process-input-traced_ruby34","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:false","runtime:Ruby 3.4.X","resource:integration-tests-rb-XXXX-process-input-traced_ruby34","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} -{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby34","functionname:integration-tests-rb-XXXX-process-input-traced_ruby34","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:false","runtime:Ruby 3.4.X","resource:integration-tests-rb-XXXX-process-input-traced_ruby34","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} -{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby34","functionname:integration-tests-rb-XXXX-process-input-traced_ruby34","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:true","runtime:Ruby 3.4.X","resource:integration-tests-rb-XXXX-process-input-traced_ruby34","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} -{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby34","function:http-request"],"v":1} -{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby34","function:http-request"],"v":1} -{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby34","function:http-request"],"v":1} -{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"name":"get_record_ids","parent_id":"XXXX","resource":"get_record_ids","service":"index","span_id":"XXXX","trace_id":"XXXX","type":null,"span_links":[],"start":XXXX,"duration":XXXX},{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} -{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"name":"get_record_ids","parent_id":"XXXX","resource":"get_record_ids","service":"index","span_id":"XXXX","trace_id":"XXXX","type":null,"span_links":[],"start":XXXX,"duration":XXXX},{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} -{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"name":"get_record_ids","parent_id":"XXXX","resource":"get_record_ids","service":"index","span_id":"XXXX","trace_id":"XXXX","type":null,"span_links":[],"start":XXXX,"duration":XXXX},{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"name":"get_api_gateway_request_id","parent_id":"XXXX","resource":"get_api_gateway_request_id","service":"index","span_id":"XXXX","trace_id":"XXXX","type":null,"span_links":[],"start":XXXX,"duration":XXXX},{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} END Duration: XXXX ms (init: XXXX ms) Memory Used: XXXX MB END Duration: XXXX ms (init: XXXX) Memory Used: XXXX MB END Duration: XXXX ms (init: XXXX) Memory Used: XXXX MB -I, [XXXX] INFO XXXX[datadog] DATADOG CONFIGURATION - CORE - {"date":"XXXX","os_name":"XXXX","version":"2.12.0","lang":"ruby","lang_version":"3.4.X","env":null,"service":"index","dd_version":null,"debug":false,"tags":"_dd.origin:lambda","runtime_metrics_enabled":false,"vm":"ruby-3.4.X","health_metrics_enabled":false,"profiling_enabled":false,"dynamic_instrumentation_enabled":false} +END Duration: XXXX ms (init: XXXX) Memory Used: XXXX MB +END Duration: XXXX ms (init: XXXX) Memory Used: XXXX MB +I, [XXXX] INFO XXXX[datadog] DATADOG CONFIGURATION - CORE - {"date":"XXXX","os_name":"XXXX","version":"2.32.0","lang":"ruby","lang_version":"3.4.X","env":null,"service":"index","dd_version":null,"debug":false,"tags":"_dd.origin:lambda","runtime_metrics_enabled":false,"vm":"ruby-3.4.X","health_metrics_enabled":false,"profiling_enabled":false,"dynamic_instrumentation_enabled":false} I, [XXXX] INFO XXXX[datadog] DATADOG CONFIGURATION - TRACING - {"enabled":true,"agent_url":null,"analytics_enabled":false,"sample_rate":null,"sampling_rules":null,"integrations_loaded":"aws@","partial_flushing_enabled":false} START START START +START +START W, [XXXX] WARN XXXX[datadog] Unable to patch Datadog::Tracing::Contrib::Aws::Integration (Available?: false, Loaded? false, Compatible? false, Patchable? false) +{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby34","functionname:integration-tests-rb-XXXX-process-input-traced_ruby34","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:false","runtime:Ruby 3.4.X","resource:integration-tests-rb-XXXX-process-input-traced_ruby34","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} +{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby34","functionname:integration-tests-rb-XXXX-process-input-traced_ruby34","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:false","runtime:Ruby 3.4.X","resource:integration-tests-rb-XXXX-process-input-traced_ruby34","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} +{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby34","functionname:integration-tests-rb-XXXX-process-input-traced_ruby34","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:false","runtime:Ruby 3.4.X","resource:integration-tests-rb-XXXX-process-input-traced_ruby34","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} +{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby34","functionname:integration-tests-rb-XXXX-process-input-traced_ruby34","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:false","runtime:Ruby 3.4.X","resource:integration-tests-rb-XXXX-process-input-traced_ruby34","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} +{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby34","functionname:integration-tests-rb-XXXX-process-input-traced_ruby34","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:true","runtime:Ruby 3.4.X","resource:integration-tests-rb-XXXX-process-input-traced_ruby34","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} +{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby34","function:http-request"],"v":1} +{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby34","function:http-request"],"v":1} +{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby34","function:http-request"],"v":1} +{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby34","function:http-request"],"v":1} +{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby34","function:http-request"],"v":1} +{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"get_record_ids","parent_id":"XXXX","resource":"get_record_ids","service":"index","span_id":"XXXX","trace_id":"XXXX","type":null,"span_links":[],"start":XXXX,"duration":XXXX},{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} +{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"get_record_ids","parent_id":"XXXX","resource":"get_record_ids","service":"index","span_id":"XXXX","trace_id":"XXXX","type":null,"span_links":[],"start":XXXX,"duration":XXXX},{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} +{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"get_record_ids","parent_id":"XXXX","resource":"get_record_ids","service":"index","span_id":"XXXX","trace_id":"XXXX","type":null,"span_links":[],"start":XXXX,"duration":XXXX},{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"get_api_gateway_request_id","parent_id":"XXXX","resource":"get_api_gateway_request_id","service":"index","span_id":"XXXX","trace_id":"XXXX","type":null,"span_links":[],"start":XXXX,"duration":XXXX},{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} +{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"get_record_ids","parent_id":"XXXX","resource":"get_record_ids","service":"index","span_id":"XXXX","trace_id":"XXXX","type":null,"span_links":[],"start":XXXX,"duration":XXXX},{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"get_api_gateway_request_id","parent_id":"XXXX","resource":"get_api_gateway_request_id","service":"index","span_id":"XXXX","trace_id":"XXXX","type":null,"span_links":[],"start":XXXX,"duration":XXXX},{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} +{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"get_record_ids","parent_id":"XXXX","resource":"get_record_ids","service":"index","span_id":"XXXX","trace_id":"XXXX","type":null,"span_links":[],"start":XXXX,"duration":XXXX},{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"get_api_gateway_request_id","parent_id":"XXXX","resource":"get_api_gateway_request_id","service":"index","span_id":"XXXX","trace_id":"XXXX","type":null,"span_links":[],"start":XXXX,"duration":XXXX},{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} diff --git a/integration_tests/snapshots/logs/sync-metrics_ruby34.log b/integration_tests/snapshots/logs/sync-metrics_ruby34.log index 1dfc212..bd32213 100644 --- a/integration_tests/snapshots/logs/sync-metrics_ruby34.log +++ b/integration_tests/snapshots/logs/sync-metrics_ruby34.log @@ -1,25 +1,37 @@ -{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby34","functionname:integration-tests-rb-XXXX-sync-metrics_ruby34","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:false","runtime:Ruby 3.4.X","resource:integration-tests-rb-XXXX-sync-metrics_ruby34","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} -{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby34","functionname:integration-tests-rb-XXXX-sync-metrics_ruby34","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:false","runtime:Ruby 3.4.X","resource:integration-tests-rb-XXXX-sync-metrics_ruby34","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} -{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby34","functionname:integration-tests-rb-XXXX-sync-metrics_ruby34","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:true","runtime:Ruby 3.4.X","resource:integration-tests-rb-XXXX-sync-metrics_ruby34","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} -{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby34","tagkey:tagvalue","eventsource:APIGateway"],"v":1} -{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby34","tagkey:tagvalue","eventsource:SNS"],"v":1} -{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby34","tagkey:tagvalue","eventsource:SQS"],"v":1} -{"e":XXXX,"m":"serverless.integration_test.records_processed","t":["dd_lambda_layer:datadog-ruby34","tagkey:tagvalue","eventsource:SNS"],"v":1} -{"e":XXXX,"m":"serverless.integration_test.records_processed","t":["dd_lambda_layer:datadog-ruby34","tagkey:tagvalue","eventsource:SQS"],"v":1} -{"e":XXXX,"m":"serverless.integration_test.records_processed","t":["dd_lambda_layer:datadog-ruby34","tagkey:tagvalue","eventsource:SQS"],"v":1} -{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} -{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} -{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} END Duration: XXXX ms (init: XXXX ms) Memory Used: XXXX MB END Duration: XXXX ms (init: XXXX) Memory Used: XXXX MB END Duration: XXXX ms (init: XXXX) Memory Used: XXXX MB -I, [XXXX] INFO XXXX[datadog] DATADOG CONFIGURATION - CORE - {"date":"XXXX","os_name":"XXXX","version":"2.12.0","lang":"ruby","lang_version":"3.4.X","env":null,"service":"index","dd_version":null,"debug":false,"tags":"_dd.origin:lambda","runtime_metrics_enabled":false,"vm":"ruby-3.4.X","health_metrics_enabled":false,"profiling_enabled":false,"dynamic_instrumentation_enabled":false} +END Duration: XXXX ms (init: XXXX) Memory Used: XXXX MB +END Duration: XXXX ms (init: XXXX) Memory Used: XXXX MB +I, [XXXX] INFO XXXX[datadog] DATADOG CONFIGURATION - CORE - {"date":"XXXX","os_name":"XXXX","version":"2.32.0","lang":"ruby","lang_version":"3.4.X","env":null,"service":"index","dd_version":null,"debug":false,"tags":"_dd.origin:lambda","runtime_metrics_enabled":false,"vm":"ruby-3.4.X","health_metrics_enabled":false,"profiling_enabled":false,"dynamic_instrumentation_enabled":false} I, [XXXX] INFO XXXX[datadog] DATADOG CONFIGURATION - TRACING - {"enabled":true,"agent_url":null,"analytics_enabled":false,"sample_rate":null,"sampling_rules":null,"integrations_loaded":"aws@","partial_flushing_enabled":false} Processed APIGateway request +Processed APIGateway request +Processed APIGateway request Processed SNS request Processed SQS request START START START +START +START W, [XXXX] WARN XXXX[datadog] Unable to patch Datadog::Tracing::Contrib::Aws::Integration (Available?: false, Loaded? false, Compatible? false, Patchable? false) +{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby34","functionname:integration-tests-rb-XXXX-sync-metrics_ruby34","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:false","runtime:Ruby 3.4.X","resource:integration-tests-rb-XXXX-sync-metrics_ruby34","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} +{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby34","functionname:integration-tests-rb-XXXX-sync-metrics_ruby34","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:false","runtime:Ruby 3.4.X","resource:integration-tests-rb-XXXX-sync-metrics_ruby34","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} +{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby34","functionname:integration-tests-rb-XXXX-sync-metrics_ruby34","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:false","runtime:Ruby 3.4.X","resource:integration-tests-rb-XXXX-sync-metrics_ruby34","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} +{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby34","functionname:integration-tests-rb-XXXX-sync-metrics_ruby34","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:false","runtime:Ruby 3.4.X","resource:integration-tests-rb-XXXX-sync-metrics_ruby34","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} +{"e":XXXX,"m":"aws.lambda.enhanced.invocations","t":["dd_lambda_layer:datadog-ruby34","functionname:integration-tests-rb-XXXX-sync-metrics_ruby34","region:eu-west-1","account_id:XXXX","memorysize:1024","cold_start:true","runtime:Ruby 3.4.X","resource:integration-tests-rb-XXXX-sync-metrics_ruby34","datadog_lambda:X.X.X","dd_trace:2.XX.X"],"v":1} +{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby34","tagkey:tagvalue","eventsource:APIGateway"],"v":1} +{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby34","tagkey:tagvalue","eventsource:APIGateway"],"v":1} +{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby34","tagkey:tagvalue","eventsource:APIGateway"],"v":1} +{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby34","tagkey:tagvalue","eventsource:SNS"],"v":1} +{"e":XXXX,"m":"serverless.integration_test.execution","t":["dd_lambda_layer:datadog-ruby34","tagkey:tagvalue","eventsource:SQS"],"v":1} +{"e":XXXX,"m":"serverless.integration_test.records_processed","t":["dd_lambda_layer:datadog-ruby34","tagkey:tagvalue","eventsource:SNS"],"v":1} +{"e":XXXX,"m":"serverless.integration_test.records_processed","t":["dd_lambda_layer:datadog-ruby34","tagkey:tagvalue","eventsource:SQS"],"v":1} +{"e":XXXX,"m":"serverless.integration_test.records_processed","t":["dd_lambda_layer:datadog-ruby34","tagkey:tagvalue","eventsource:SQS"],"v":1} +{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} +{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} +{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} +{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} +{"traces":[[{"error":0,"meta":{"XXXX": "XXXX"},"metrics":{"XXXX": "XXXX"},"meta_struct":{},"name":"aws.lambda","parent_id":"XXXX","resource":"dd-tracer-serverless-span","service":"aws.lambda","span_id":"XXXX","trace_id":"XXXX","type":"serverless","span_links":[],"start":XXXX,"duration":XXXX}]]} diff --git a/integration_tests/snapshots/return_values/appsec-request_api-gateway-appsec-blocking.json b/integration_tests/snapshots/return_values/appsec-request_api-gateway-appsec-blocking.json new file mode 100644 index 0000000..eb8ee03 --- /dev/null +++ b/integration_tests/snapshots/return_values/appsec-request_api-gateway-appsec-blocking.json @@ -0,0 +1,5 @@ +{ + "statusCode": 200, + "message": "hello, dog!", + "eventType": "APIGateway" +} diff --git a/integration_tests/snapshots/return_values/appsec-request_api-gateway-appsec.json b/integration_tests/snapshots/return_values/appsec-request_api-gateway-appsec.json new file mode 100644 index 0000000..eb8ee03 --- /dev/null +++ b/integration_tests/snapshots/return_values/appsec-request_api-gateway-appsec.json @@ -0,0 +1,5 @@ +{ + "statusCode": 200, + "message": "hello, dog!", + "eventType": "APIGateway" +} diff --git a/integration_tests/snapshots/return_values/appsec-request_api-gateway-get.json b/integration_tests/snapshots/return_values/appsec-request_api-gateway-get.json new file mode 100644 index 0000000..eb8ee03 --- /dev/null +++ b/integration_tests/snapshots/return_values/appsec-request_api-gateway-get.json @@ -0,0 +1,5 @@ +{ + "statusCode": 200, + "message": "hello, dog!", + "eventType": "APIGateway" +} diff --git a/integration_tests/snapshots/return_values/appsec-request_sns.json b/integration_tests/snapshots/return_values/appsec-request_sns.json new file mode 100644 index 0000000..eb8ee03 --- /dev/null +++ b/integration_tests/snapshots/return_values/appsec-request_sns.json @@ -0,0 +1,5 @@ +{ + "statusCode": 200, + "message": "hello, dog!", + "eventType": "APIGateway" +} diff --git a/integration_tests/snapshots/return_values/appsec-request_sqs.json b/integration_tests/snapshots/return_values/appsec-request_sqs.json new file mode 100644 index 0000000..eb8ee03 --- /dev/null +++ b/integration_tests/snapshots/return_values/appsec-request_sqs.json @@ -0,0 +1,5 @@ +{ + "statusCode": 200, + "message": "hello, dog!", + "eventType": "APIGateway" +} diff --git a/integration_tests/snapshots/return_values/async-metrics_api-gateway-appsec-blocking.json b/integration_tests/snapshots/return_values/async-metrics_api-gateway-appsec-blocking.json new file mode 100644 index 0000000..6f453e9 --- /dev/null +++ b/integration_tests/snapshots/return_values/async-metrics_api-gateway-appsec-blocking.json @@ -0,0 +1,5 @@ +{ + "message": "hello, dog!", + "eventType": "APIGateway", + "requestId": "41b45ea3-70b5-11e6-b7bd-69b5aaebc7d9" +} diff --git a/integration_tests/snapshots/return_values/async-metrics_api-gateway-appsec.json b/integration_tests/snapshots/return_values/async-metrics_api-gateway-appsec.json new file mode 100644 index 0000000..6f453e9 --- /dev/null +++ b/integration_tests/snapshots/return_values/async-metrics_api-gateway-appsec.json @@ -0,0 +1,5 @@ +{ + "message": "hello, dog!", + "eventType": "APIGateway", + "requestId": "41b45ea3-70b5-11e6-b7bd-69b5aaebc7d9" +} diff --git a/integration_tests/snapshots/return_values/http-requests_api-gateway-appsec-blocking.json b/integration_tests/snapshots/return_values/http-requests_api-gateway-appsec-blocking.json new file mode 100644 index 0000000..eb1e9d3 --- /dev/null +++ b/integration_tests/snapshots/return_values/http-requests_api-gateway-appsec-blocking.json @@ -0,0 +1,3 @@ +{ + "message": "hello, dog!" +} diff --git a/integration_tests/snapshots/return_values/http-requests_api-gateway-appsec.json b/integration_tests/snapshots/return_values/http-requests_api-gateway-appsec.json new file mode 100644 index 0000000..eb1e9d3 --- /dev/null +++ b/integration_tests/snapshots/return_values/http-requests_api-gateway-appsec.json @@ -0,0 +1,3 @@ +{ + "message": "hello, dog!" +} diff --git a/integration_tests/snapshots/return_values/process-input-traced_api-gateway-appsec-blocking.json b/integration_tests/snapshots/return_values/process-input-traced_api-gateway-appsec-blocking.json new file mode 100644 index 0000000..12d7e1a --- /dev/null +++ b/integration_tests/snapshots/return_values/process-input-traced_api-gateway-appsec-blocking.json @@ -0,0 +1,5 @@ +{ + "message": "hello, dog!", + "recordIds": [], + "eventType": "APIGateway" +} diff --git a/integration_tests/snapshots/return_values/process-input-traced_api-gateway-appsec.json b/integration_tests/snapshots/return_values/process-input-traced_api-gateway-appsec.json new file mode 100644 index 0000000..12d7e1a --- /dev/null +++ b/integration_tests/snapshots/return_values/process-input-traced_api-gateway-appsec.json @@ -0,0 +1,5 @@ +{ + "message": "hello, dog!", + "recordIds": [], + "eventType": "APIGateway" +} diff --git a/integration_tests/snapshots/return_values/sync-metrics_api-gateway-appsec-blocking.json b/integration_tests/snapshots/return_values/sync-metrics_api-gateway-appsec-blocking.json new file mode 100644 index 0000000..6f453e9 --- /dev/null +++ b/integration_tests/snapshots/return_values/sync-metrics_api-gateway-appsec-blocking.json @@ -0,0 +1,5 @@ +{ + "message": "hello, dog!", + "eventType": "APIGateway", + "requestId": "41b45ea3-70b5-11e6-b7bd-69b5aaebc7d9" +} diff --git a/integration_tests/snapshots/return_values/sync-metrics_api-gateway-appsec.json b/integration_tests/snapshots/return_values/sync-metrics_api-gateway-appsec.json new file mode 100644 index 0000000..6f453e9 --- /dev/null +++ b/integration_tests/snapshots/return_values/sync-metrics_api-gateway-appsec.json @@ -0,0 +1,5 @@ +{ + "message": "hello, dog!", + "eventType": "APIGateway", + "requestId": "41b45ea3-70b5-11e6-b7bd-69b5aaebc7d9" +} From 442d864e1d0de010e35ff9337d8545103962840f Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Fri, 8 May 2026 12:54:16 +0200 Subject: [PATCH 14/15] Add notes about the new layer building aspects --- .gitlab/scripts/build_layer.sh | 3 +++ Dockerfile | 2 ++ scripts/build_layers.sh | 3 +++ 3 files changed, 8 insertions(+) diff --git a/.gitlab/scripts/build_layer.sh b/.gitlab/scripts/build_layer.sh index b826eeb..6c80cd4 100755 --- a/.gitlab/scripts/build_layer.sh +++ b/.gitlab/scripts/build_layer.sh @@ -40,6 +40,9 @@ function docker_build_zip { # Install datadog ruby in a docker container to avoid the mess from switching # between different ruby runtimes. + # + # NOTE: using the Lambda base image so native extensions (FFI, libddwaf) + # compile against the same libffi available at runtime on Lambda. temp_dir=$(mktemp -d) docker buildx build -t datadog-lambda-ruby-${arch}:$1 . --no-cache \ --build-arg "image=public.ecr.aws/lambda/ruby:${1}" \ diff --git a/Dockerfile b/Dockerfile index b15f3ec..d7dec98 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,6 +4,7 @@ ARG runtime # Install dev dependencies COPY . /var/task/datadog-lambda-rb WORKDIR /var/task/datadog-lambda-rb + # NOTE: AL2 (Ruby 3.2) uses yum, AL2023 (Ruby 3.3+) uses dnf RUN PKG=$(command -v dnf || command -v yum) && \ $PKG install -y gcc gcc-c++ make zip binutils libffi-devel @@ -18,6 +19,7 @@ RUN MAKEFLAGS="-j$(nproc)" \ gem install datadog -v 2.12 --install-dir "/opt/ruby/gems/$runtime" --no-document # Recompile FFI from source — precompiled binaries have glibc mismatch with Lambda AL2 +# # NOTE: runs after datadog gem as a defensive measure — force-replaces whatever # transitive FFI variant was pulled, regardless of version resolution. RUN MAKEFLAGS="-j$(nproc)" \ diff --git a/scripts/build_layers.sh b/scripts/build_layers.sh index 4bb6409..3d67092 100755 --- a/scripts/build_layers.sh +++ b/scripts/build_layers.sh @@ -36,6 +36,9 @@ function docker_build_zip { # Install datadog ruby in a docker container to avoid the mess from switching # between different ruby runtimes. + # + # NOTE: using the Lambda base image so native extensions (FFI, libddwaf) + # compile against the same libffi available at runtime on Lambda. temp_dir=$(mktemp -d) docker buildx build -t datadog-lambda-ruby-${arch}:$1 . --no-cache \ --build-arg "image=public.ecr.aws/lambda/ruby:${1}" \ From 29ae63bcf5aa6198cfbafc2d5ea55726305960ca Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Wed, 13 May 2026 13:09:46 +0200 Subject: [PATCH 15/15] Use latest tracer version with AWS Lambda support --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index d7dec98..52d2bd2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,7 +16,7 @@ RUN gem build datadog-lambda RUN MAKEFLAGS="-j$(nproc)" \ gem install datadog-lambda --install-dir "/opt/ruby/gems/$runtime" --no-document RUN MAKEFLAGS="-j$(nproc)" \ - gem install datadog -v 2.12 --install-dir "/opt/ruby/gems/$runtime" --no-document + gem install datadog -v 2.33 --install-dir "/opt/ruby/gems/$runtime" --no-document # Recompile FFI from source — precompiled binaries have glibc mismatch with Lambda AL2 #