diff --git a/lib/datadog/appsec/event.rb b/lib/datadog/appsec/event.rb index 62a2247bda8..b598241979a 100644 --- a/lib/datadog/appsec/event.rb +++ b/lib/datadog/appsec/event.rb @@ -37,6 +37,9 @@ module Event ].map!(&:downcase).freeze MAX_ENCODED_SCHEMA_SIZE = 25000 + # For more information about this number + # please check https://github.com/DataDog/dd-trace-rb/pull/3177#issuecomment-1747221082 + MIN_SCHEMA_SIZE_FOR_COMPRESSION = 260 # Record events for a trace # @@ -75,7 +78,7 @@ def record_via_span(span, *events) end end - # rubocop: disable Metrics/MethodLength + # rubocop:disable Metrics/MethodLength def build_service_entry_tags(event_group) waf_events = [] entry_tags = event_group.each_with_object({ '_dd.origin' => 'appsec' }) do |event, tags| @@ -106,19 +109,21 @@ def build_service_entry_tags(event_group) parsed_value_size = parsed_value.size - compressed_data = compressed_and_base64_encoded(parsed_value) - compressed_data_size = compressed_data.size + schema_value = if parsed_value_size >= MIN_SCHEMA_SIZE_FOR_COMPRESSION + compressed_and_base64_encoded(parsed_value) + else + parsed_value + end + next unless schema_value - if compressed_data_size >= MAX_ENCODED_SCHEMA_SIZE && parsed_value_size >= MAX_ENCODED_SCHEMA_SIZE + if schema_value.size >= MAX_ENCODED_SCHEMA_SIZE Datadog.logger.debug do "Schema key: #{key} exceeds the max size value. It will not be included as part of the span tags" end next end - derivative_value = parsed_value_size > compressed_data_size ? compressed_data : parsed_value - - tags[key] = derivative_value + tags[key] = schema_value end tags @@ -128,25 +133,32 @@ def build_service_entry_tags(event_group) entry_tags['_dd.appsec.json'] = appsec_events if appsec_events entry_tags end - # rubocop: enable Metrics/MethodLength + # rubocop:enable Metrics/MethodLength private def compressed_and_base64_encoded(value) Base64.encode64(gzip(value)) - rescue TypeError + rescue TypeError => e + Datadog.logger.debug do + "Failed to compress and encode value when populating AppSec::Event. Error: #{e.message}" + end nil end def json_parse(value) JSON.dump(value) - rescue ArgumentError + rescue ArgumentError => e + Datadog.logger.debug do + "Failed to parse value to JSON when populating AppSec::Event. Error: #{e.message}" + end nil end def gzip(value) sio = StringIO.new - gz = Zlib::GzipWriter.new(sio, Zlib::DEFAULT_COMPRESSION, Zlib::DEFAULT_STRATEGY) + # For an in depth comparison of Zlib options check https://github.com/DataDog/dd-trace-rb/pull/3177#issuecomment-1747215473 + gz = Zlib::GzipWriter.new(sio, Zlib::BEST_SPEED, Zlib::DEFAULT_STRATEGY) gz.write(value) gz.close sio.string diff --git a/sig/datadog/appsec/event.rbs b/sig/datadog/appsec/event.rbs index 9f30df5d97a..36d75ca6e55 100644 --- a/sig/datadog/appsec/event.rbs +++ b/sig/datadog/appsec/event.rbs @@ -6,6 +6,7 @@ module Datadog ALLOWED_RESPONSE_HEADERS: untyped MAX_ENCODED_SCHEMA_SIZE: Numeric + MIN_SCHEMA_SIZE_FOR_COMPRESSION: Numeric def self.record: (Datadog::Tracing::SpanOperation, *untyped events) -> (nil | untyped) diff --git a/spec/datadog/appsec/event_spec.rb b/spec/datadog/appsec/event_spec.rb index 3ffd927a7a8..e79ecfbde1e 100644 --- a/spec/datadog/appsec/event_spec.rb +++ b/spec/datadog/appsec/event_spec.rb @@ -113,7 +113,8 @@ end context 'JSON payload' do - it 'uses JSON string as is smaller than the compressed value' do + it 'uses JSON string when do not exceeds MIN_SCHEMA_SIZE_FOR_COMPRESSION' do + stub_const('Datadog::AppSec::Event::MIN_SCHEMA_SIZE_FOR_COMPRESSION', 3000) meta = top_level_span.meta expect(meta['_dd.appsec.s.req.headers']).to eq('[{"host":[8],"version":[8]}]') @@ -121,8 +122,9 @@ end context 'Compressed payload' do - it 'uses compressed value when is smaller than JSON string' do + it 'uses compressed value when JSON string is bigger than MIN_SCHEMA_SIZE_FOR_COMPRESSION' do result = "H4sIAOYoHGUAA4aphwAAAA=\n" + stub_const('Datadog::AppSec::Event::MIN_SCHEMA_SIZE_FOR_COMPRESSION', 1) expect(described_class).to receive(:compressed_and_base64_encoded).and_return(result) meta = top_level_span.meta