diff --git a/lib/datadog/di/contrib/active_record.rb b/lib/datadog/di/contrib/active_record.rb index 635e80acb45..db817d343c7 100644 --- a/lib/datadog/di/contrib/active_record.rb +++ b/lib/datadog/di/contrib/active_record.rb @@ -2,6 +2,8 @@ Datadog::DI::Serializer.register(condition: lambda { |value| ActiveRecord::Base === value }) \ do |serializer, value, name:, depth:| - serializer.type_serialized_entry(value.class, - serializer.serialize_value(value.attributes, depth: depth)) + value_to_serialize = { + attributes: value.attributes, + } + serializer.serialize_value(value_to_serialize, depth: depth ? depth - 1 : nil, type: value.class) end diff --git a/lib/datadog/di/serializer.rb b/lib/datadog/di/serializer.rb index 6cb5375a6b0..fcbe108a85a 100644 --- a/lib/datadog/di/serializer.rb +++ b/lib/datadog/di/serializer.rb @@ -100,8 +100,8 @@ def type_serialized_entry(cls, serialized) # (integers, strings, arrays, hashes). # # Respects string length, collection size and traversal depth limits. - def serialize_value(value, name: nil, depth: settings.dynamic_instrumentation.max_capture_depth) - cls = value.class + def serialize_value(value, name: nil, depth: settings.dynamic_instrumentation.max_capture_depth, type: nil) + cls = type || value.class if redactor.redact_type?(value) return {type: class_name(cls), notCapturedReason: "redactedType"} diff --git a/spec/datadog/di/serializer_rails_spec.rb b/spec/datadog/di/serializer_rails_spec.rb index 52ab009b5ed..eee7408f8fb 100644 --- a/spec/datadog/di/serializer_rails_spec.rb +++ b/spec/datadog/di/serializer_rails_spec.rb @@ -5,7 +5,10 @@ require 'sqlite3' require "datadog/di/contrib/active_record" -class SerializerRailsSpecTestModel < ActiveRecord::Base +class SerializerRailsSpecTestEmptyModel < ActiveRecord::Base +end + +class SerializerRailsSpecTestBasicModel < ActiveRecord::Base end RSpec.describe Datadog::DI::Serializer do @@ -26,7 +29,10 @@ class SerializerRailsSpecTestModel < ActiveRecord::Base ActiveRecord::Base.establish_connection('sqlite3::memory:') ActiveRecord::Schema.define(version: 20161003090450) do - create_table 'serializer_rails_spec_test_models', force: :cascade do |t| + create_table 'serializer_rails_spec_test_empty_models', force: :cascade do |t| + end + + create_table 'serializer_rails_spec_test_basic_models', force: :cascade do |t| t.string 'title' t.datetime 'created_at', null: false t.datetime 'updated_at', null: false @@ -55,7 +61,36 @@ class SerializerRailsSpecTestModel < ActiveRecord::Base end cases = [ - {name: "AR model", input: -> { SerializerRailsSpecTestModel.new }, expected: {type: "NilClass", isNull: true}}, + {name: "AR model with no attributes", + input: -> { SerializerRailsSpecTestEmptyModel.new }, + expected: {type: "SerializerRailsSpecTestEmptyModel", entries: [[ + {type: 'Symbol', value: 'attributes'}, + {type: 'Hash', entries: [[{type: 'String', value: 'id'}, {type: 'NilClass', isNull: true}]]}, + ]]}}, + {name: "AR model with empty attributes", + input: -> { SerializerRailsSpecTestBasicModel.new }, + expected: {type: "SerializerRailsSpecTestBasicModel", entries: [[ + {type: 'Symbol', value: 'attributes'}, + {type: 'Hash', entries: [ + [{type: 'String', value: 'id'}, {type: 'NilClass', isNull: true}], + [{type: 'String', value: 'title'}, {type: 'NilClass', isNull: true}], + [{type: 'String', value: 'created_at'}, {type: 'NilClass', isNull: true}], + [{type: 'String', value: 'updated_at'}, {type: 'NilClass', isNull: true}], + ]}, + ]]}}, + {name: "AR model with filled out attributes", + input: -> { SerializerRailsSpecTestBasicModel.new( + title: 'Hello, world!', created_at: Time.now, updated_at: Time.now) }, + expected: {type: "SerializerRailsSpecTestBasicModel", entries: [[ + {type: 'Symbol', value: 'attributes'}, + {type: 'Hash', entries: [ + [{type: 'String', value: 'id'}, {type: 'NilClass', isNull: true}], + [{type: 'String', value: 'title'}, {type: 'String', value: 'Hello, world!'}], + # TODO serialize Time, Date, DateTime types + [{type: 'String', value: 'created_at'}, {type: 'Time', notCapturedReason: 'depth'}], + [{type: 'String', value: 'updated_at'}, {type: 'Time', notCapturedReason: 'depth'}], + ]}, + ]]}}, ] define_serialize_value_cases(cases)