Skip to content

Commit b7f41b1

Browse files
committed
feat: Optionally record parameter schema
1 parent f9d1e3f commit b7f41b1

File tree

5 files changed

+43
-13
lines changed

5 files changed

+43
-13
lines changed

lib/appmap/agent.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,5 +100,9 @@ def detect_metadata
100100
@metadata ||= Metadata.detect.freeze
101101
Util.deep_dup(@metadata)
102102
end
103+
104+
def parameter_schema?
105+
ENV['APPMAP_PARAMETER_SCHEMA'] == 'true'
106+
end
103107
end
104108
end

lib/appmap/event.rb

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -60,16 +60,37 @@ def display_string(value)
6060
final ? value_string : encode_display_string(value_string)
6161
end
6262

63-
def object_properties(hash_like)
64-
hash = hash_like.to_h
65-
hash.keys.map do |key|
66-
{
63+
def add_schema(param, value, always: false)
64+
return unless always || AppMap.parameter_schema?
65+
66+
if value.blank? || value.is_a?(String)
67+
# pass
68+
elsif value.is_a?(Enumerable)
69+
if value.is_a?(Hash)
70+
param[:properties] = object_properties(value)
71+
elsif value.respond_to?(:first) && value.first
72+
param[:properties] = object_properties(value.first)
73+
end
74+
elsif value.respond_to?(:as_json)
75+
add_schema param, JSON.parse(value.to_json), always: always
76+
end
77+
end
78+
79+
def object_properties(hash)
80+
hash = hash.attributes if hash.respond_to?(:attributes)
81+
hash = hash.to_h if hash.is_a?(Struct)
82+
83+
return unless hash.respond_to?(:each_with_object)
84+
85+
hash.each_with_object([]) do |entry, memo|
86+
key, value = entry
87+
memo << {
6788
name: key,
68-
class: hash[key].class.name,
89+
class: value.class.name,
6990
}
7091
end
7192
rescue
72-
nil
93+
warn $!
7394
end
7495

7596
# Heuristic for dynamically defined class whose name can be nil
@@ -221,7 +242,9 @@ def build_from_invocation(defined_class, method, receiver, arguments, event: Met
221242
object_id: value.__id__,
222243
value: display_string(value),
223244
kind: param_type
224-
}
245+
}.tap do |param|
246+
add_schema param, value
247+
end
225248
end
226249
event.receiver = {
227250
class: best_class_name(receiver),
@@ -276,15 +299,17 @@ class MethodReturn < MethodReturnIgnoreValue
276299
attr_accessor :return_value, :exceptions
277300

278301
class << self
279-
def build_from_invocation(parent_id, return_value, exception, elapsed: nil, event: MethodReturn.new)
302+
def build_from_invocation(parent_id, return_value, exception, elapsed: nil, event: MethodReturn.new, parameter_schema: false)
280303
event ||= MethodReturn.new
281304
event.tap do |_|
282305
if return_value
283306
event.return_value = {
284307
class: best_class_name(return_value),
285308
value: display_string(return_value),
286309
object_id: return_value.__id__
287-
}
310+
}.tap do |param|
311+
add_schema param, return_value, always: parameter_schema
312+
end
288313
end
289314
if exception
290315
next_exception = exception

lib/appmap/handler.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
module AppMap
66
# Specific hook handler classes and general related utilities.
77
module Handler
8+
TEMPLATE_RENDER_VALUE = 'appmap.handler.template.return_value'
9+
810
# Try to find handler module with a given name.
911
#
1012
# If the module is not loaded, tries to require the appropriate file

lib/appmap/handler/rails/request_handler.rb

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ module AppMap
88
module Handler
99
module Rails
1010

11-
TEMPLATE_RENDER_VALUE = 'appmap.handler.rails.template.return_value'
12-
1311
module RequestHandler
1412
class HTTPServerRequest < AppMap::Event::MethodEvent
1513
attr_accessor :normalized_path_info, :request_method, :path_info, :params, :headers
@@ -77,7 +75,7 @@ def build_from_invocation(parent_id, return_value, elapsed, response, event: HTT
7775
event ||= HTTPServerResponse.new
7876
event.status = response.status
7977
event.headers = response.headers.dup
80-
AppMap::Event::MethodReturn.build_from_invocation parent_id, return_value, nil, elapsed: elapsed, event: event
78+
AppMap::Event::MethodReturn.build_from_invocation parent_id, return_value, nil, elapsed: elapsed, event: event, parameter_schema: true
8179
end
8280
end
8381

spec/rails_recording_spec.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ def rails_versions
5454
'http_server_response' => hash_including(
5555
'status_code' => 201,
5656
'headers' => hash_including('Content-Type' => 'application/json; charset=utf-8'),
57-
)
57+
),
58+
'return_value' => hash_including('class' => 'User', 'object_id' => Integer, 'properties' => include({'name' => 'login', 'class' => 'String'})),
5859
)
5960
)
6061
end

0 commit comments

Comments
 (0)