appmap 0.79.0 → 0.80.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f5c6a40273c5606504492f151b2feeb1addc83d92f6bec7a80ca51d3034cd79f
4
- data.tar.gz: b10a582926396930d2a980cd4323bd83f7c3444aa0b77bf2dd2dfa632203f65d
3
+ metadata.gz: 52ebea9f89c7f412123ff2473f0ed62f46f2be4e69e98574d59c3eb91f8ef29b
4
+ data.tar.gz: 823073540b9979ede52b30c0e70398894b284bf51d10fcce786f082258d363c8
5
5
  SHA512:
6
- metadata.gz: f56a49c05561a74ae2ee7512fbad2beadc1a0aa719e27b455ea330777c58e97b7c028f7eaaee13d52f20c8ace6bf9284ff8c717e17d922a45f2dca703781a737
7
- data.tar.gz: d35ac177b2b12ddd4f4e0517ed4101043c8e9d29f89f53721969d45e3e2be293ae7ad0b8466a2fae63329bb7a13e27d699b30a2464a663014d04a71a8d464293
6
+ metadata.gz: f837ad0b0ac7520c36c4ba2aa1c2d897235d316068461019a77a826dac5e8bf1401f44815d9cfb4fb47194c7b9090c70f3936073e1e99f0c7124fa9fe1d6baac
7
+ data.tar.gz: abb39a31ffd07bdccb0f5835cdd69bf5bacd5eb0844ea8836995017fe41716560243d1629bed2ed9fce046636586d35a17dc6abaaa5286d8532e41a3ad94f5ec
data/CHANGELOG.md CHANGED
@@ -1,3 +1,34 @@
1
+ ## [0.80.2](https://github.com/applandinc/appmap-ruby/compare/v0.80.1...v0.80.2) (2022-04-26)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * Ensure that request env key is a string ([721baef](https://github.com/applandinc/appmap-ruby/commit/721baefbb3ba083bf6c5a1b46e6ddffa51feebec))
7
+ * Fix method_display_name ([b05c7fe](https://github.com/applandinc/appmap-ruby/commit/b05c7fe027a981214b224852dc54c5e467e1f116))
8
+
9
+ ## [0.80.1](https://github.com/applandinc/appmap-ruby/compare/v0.80.0...v0.80.1) (2022-04-08)
10
+
11
+
12
+ ### Bug Fixes
13
+
14
+ * Don't call #size on complex objects ([3f19d1e](https://github.com/applandinc/appmap-ruby/commit/3f19d1e67288379570dfa14d8758a0624d2c6c34))
15
+
16
+ # [0.80.0](https://github.com/applandinc/appmap-ruby/compare/v0.79.0...v0.80.0) (2022-04-08)
17
+
18
+
19
+ ### Bug Fixes
20
+
21
+ * Don't record SQL within an existing event ([ff37a69](https://github.com/applandinc/appmap-ruby/commit/ff37a69af1af02263df216e49aea0d0954b93925))
22
+
23
+
24
+ ### Features
25
+
26
+ * Env var to EXPLAIN queries ([740be75](https://github.com/applandinc/appmap-ruby/commit/740be75c2bc59e343d67ecf86b7715e61cddadba))
27
+ * Optionally record parameter schema ([b7f41b1](https://github.com/applandinc/appmap-ruby/commit/b7f41b15a4556a0ce78650a6a77301d365632bb8))
28
+ * query_plan is available whether a current transaction exists or not ([6edf774](https://github.com/applandinc/appmap-ruby/commit/6edf774fea858d825c4b971be2c4c15db1652446))
29
+ * Record parameter and return value size ([6e69754](https://github.com/applandinc/appmap-ruby/commit/6e697543cb421378832492e286f972dc4cb1e1aa))
30
+ * Save render return value to a thread-local ([f9d1e3f](https://github.com/applandinc/appmap-ruby/commit/f9d1e3f0aa9972482ff77233d38220104515b1d6))
31
+
1
32
  # [0.79.0](https://github.com/applandinc/appmap-ruby/compare/v0.78.0...v0.79.0) (2022-04-06)
2
33
 
3
34
 
data/lib/appmap/agent.rb CHANGED
@@ -100,5 +100,13 @@ module AppMap
100
100
  @metadata ||= Metadata.detect.freeze
101
101
  Util.deep_dup(@metadata)
102
102
  end
103
+
104
+ def parameter_schema?
105
+ ENV['APPMAP_PARAMETER_SCHEMA'] == 'true'
106
+ end
107
+
108
+ def explain_queries?
109
+ ENV['APPMAP_EXPLAIN_QUERIES'] == 'true'
110
+ end
103
111
  end
104
112
  end
@@ -78,7 +78,7 @@ module AppMap
78
78
  end
79
79
 
80
80
  collapse_package = lambda do |package|
81
- return unless package.type == 'package'
81
+ next unless package.type == 'package'
82
82
 
83
83
  while package.children.length == 1 && package.children.all? { |child| child.type == 'package' }
84
84
  child = package.children[0]
data/lib/appmap/event.rb CHANGED
@@ -60,16 +60,25 @@ module AppMap
60
60
  final ? value_string : encode_display_string(value_string)
61
61
  end
62
62
 
63
- def object_properties(hash_like)
64
- hash = hash_like.to_h
65
- hash.keys.map do |key|
66
- {
67
- name: key,
68
- class: hash[key].class.name,
69
- }
63
+ def add_size(param, value)
64
+ # Don't risk calling #size on things like data-access objects, which can and will issue queries for this information.
65
+ if value.is_a?(Array) || value.is_a?(Hash)
66
+ param[:size] = value.size
67
+ end
68
+ end
69
+
70
+ def add_schema(param, value)
71
+ begin
72
+ if value.respond_to?(:keys)
73
+ param[:properties] = value.keys.map { |key| { name: key, class: best_class_name(value[key]) } }
74
+ elsif value.respond_to?(:first) && value.first
75
+ if value.first != value
76
+ add_schema param, value.first
77
+ end
78
+ end
79
+ rescue
80
+ warn "Error in add_schema(#{value.class})", $!
70
81
  end
71
- rescue
72
- nil
73
82
  end
74
83
 
75
84
  # Heuristic for dynamically defined class whose name can be nil
@@ -221,7 +230,9 @@ module AppMap
221
230
  object_id: value.__id__,
222
231
  value: display_string(value),
223
232
  kind: param_type
224
- }
233
+ }.tap do |param|
234
+ add_size param, value
235
+ end
225
236
  end
226
237
  event.receiver = {
227
238
  class: best_class_name(receiver),
@@ -276,7 +287,7 @@ module AppMap
276
287
  attr_accessor :return_value, :exceptions
277
288
 
278
289
  class << self
279
- def build_from_invocation(parent_id, return_value, exception, elapsed: nil, event: MethodReturn.new)
290
+ def build_from_invocation(parent_id, return_value, exception, elapsed: nil, event: MethodReturn.new, parameter_schema: false)
280
291
  event ||= MethodReturn.new
281
292
  event.tap do |_|
282
293
  if return_value
@@ -284,7 +295,10 @@ module AppMap
284
295
  class: best_class_name(return_value),
285
296
  value: display_string(return_value),
286
297
  object_id: return_value.__id__
287
- }
298
+ }.tap do |param|
299
+ add_size param, return_value
300
+ add_schema param, return_value if parameter_schema && !exception
301
+ end
288
302
  end
289
303
  if exception
290
304
  next_exception = exception
@@ -43,3 +43,9 @@
43
43
  - ActionController::Instrumentation#redirect_to
44
44
  label: mvc.controller
45
45
  require_name: action_controller
46
+ - methods:
47
+ - AbstractController::Rendering#render_to_body
48
+ - ActionController::Renderers#render_to_body
49
+ label: mvc.render
50
+ handler_class: AppMap::Handler::Rails::RenderHandler
51
+ require_name: action_controller
@@ -0,0 +1,29 @@
1
+ require 'appmap/handler/function'
2
+
3
+ module AppMap
4
+ module Handler
5
+ module Rails
6
+ class RenderHandler < AppMap::Handler::Function
7
+ def handle_call(receiver, args)
8
+ options, _ = args
9
+ # TODO: :file, :xml
10
+ # https://guides.rubyonrails.org/v5.1/layouts_and_rendering.html
11
+ if options[:json]
12
+ Thread.current[TEMPLATE_RENDER_FORMAT] = :json
13
+ end
14
+
15
+ super
16
+ end
17
+
18
+ def handle_return(call_event_id, elapsed, return_value, exception)
19
+ if Thread.current[TEMPLATE_RENDER_FORMAT] == :json
20
+ Thread.current[TEMPLATE_RENDER_VALUE] = JSON.parse(return_value) rescue nil
21
+ end
22
+ Thread.current[TEMPLATE_RENDER_FORMAT] = nil
23
+
24
+ super
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -7,6 +7,7 @@ require 'appmap/util'
7
7
  module AppMap
8
8
  module Handler
9
9
  module Rails
10
+
10
11
  module RequestHandler
11
12
  class HTTPServerRequest < AppMap::Event::MethodEvent
12
13
  attr_accessor :normalized_path_info, :request_method, :path_info, :params, :headers
@@ -46,8 +47,7 @@ module AppMap
46
47
  value: self.class.display_string(val),
47
48
  object_id: val.__id__,
48
49
  }.tap do |message|
49
- properties = object_properties(val)
50
- message[:properties] = properties if properties
50
+ AppMap::Event::MethodEvent.add_schema message, val
51
51
  end
52
52
  end
53
53
  end
@@ -67,16 +67,16 @@ module AppMap
67
67
  end
68
68
  end
69
69
 
70
- class HTTPServerResponse < AppMap::Event::MethodReturnIgnoreValue
70
+ class HTTPServerResponse < AppMap::Event::MethodReturn
71
71
  attr_accessor :status, :headers
72
72
 
73
- def initialize(response, parent_id, elapsed)
74
- super AppMap::Event.next_id_counter, :return, Thread.current.object_id
75
-
76
- self.status = response.status
77
- self.parent_id = parent_id
78
- self.elapsed = elapsed
79
- self.headers = response.headers.dup
73
+ class << self
74
+ def build_from_invocation(parent_id, return_value, elapsed, response, event: HTTPServerResponse.new)
75
+ event ||= HTTPServerResponse.new
76
+ event.status = response.status
77
+ event.headers = response.headers.dup
78
+ AppMap::Event::MethodReturn.build_from_invocation parent_id, return_value, nil, elapsed: elapsed, event: event, parameter_schema: true
79
+ end
80
80
  end
81
81
 
82
82
  def to_h
@@ -108,7 +108,9 @@ module AppMap
108
108
  end
109
109
 
110
110
  def after_hook(receiver, call_event, elapsed, *)
111
- return_event = HTTPServerResponse.new receiver.response, call_event.id, elapsed
111
+ return_value = Thread.current[TEMPLATE_RENDER_VALUE]
112
+ Thread.current[TEMPLATE_RENDER_VALUE] = nil
113
+ return_event = HTTPServerResponse.build_from_invocation call_event.id, return_value, elapsed, receiver.response
112
114
  AppMap.tracing.record_event return_event
113
115
  end
114
116
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'appmap/event'
4
+ require 'appmap/hook/method'
4
5
 
5
6
  module AppMap
6
7
  module Handler
@@ -21,6 +22,7 @@ module AppMap
21
22
  sql: payload[:sql],
22
23
  database_type: payload[:database_type]
23
24
  }.tap do |sql_query|
25
+ sql_query[:query_plan] = payload[:query_plan] if payload[:query_plan]
24
26
  %i[server_version].each do |attribute|
25
27
  sql_query[attribute] = payload[attribute] if payload[attribute]
26
28
  end
@@ -43,6 +45,36 @@ module AppMap
43
45
  def examine(payload, sql:)
44
46
  return unless (examiner = build_examiner)
45
47
 
48
+ in_transaction = examiner.in_transaction?
49
+
50
+ if AppMap.explain_queries? && examiner.database_type == :postgres
51
+ if sql =~ /\A(SELECT|INSERT|UPDATE|DELETE|WITH)/i
52
+ savepoint_established = \
53
+ begin
54
+ tx_query = in_transaction ? 'SAVEPOINT appmap_sql_examiner' : 'BEGIN TRANSACTION'
55
+ examiner.execute_query tx_query
56
+ true
57
+ rescue
58
+ # Probably: Sequel::DatabaseError: PG::InFailedSqlTransaction
59
+ warn $!
60
+ false
61
+ end
62
+
63
+ if savepoint_established
64
+ plan = nil
65
+ begin
66
+ plan = examiner.execute_query(%(EXPLAIN #{sql}))
67
+ payload[:query_plan] = plan.map { |line| line[:'QUERY PLAN'] }.join("\n")
68
+ rescue
69
+ warn "(appmap) Error explaining query: #{$!}"
70
+ ensure
71
+ tx_query = in_transaction ? 'ROLLBACK TO SAVEPOINT appmap_sql_examiner' : 'ROLLBACK'
72
+ examiner.execute_query tx_query
73
+ end
74
+ end
75
+ end
76
+ end
77
+
46
78
  payload[:server_version] = examiner.server_version
47
79
  payload[:database_type] = examiner.database_type.to_s
48
80
  end
@@ -67,6 +99,10 @@ module AppMap
67
99
  Sequel::Model.db.database_type.to_sym
68
100
  end
69
101
 
102
+ def in_transaction?
103
+ Sequel::Model.db.in_transaction?
104
+ end
105
+
70
106
  def execute_query(sql)
71
107
  Sequel::Model.db[sql].all
72
108
  end
@@ -93,8 +129,12 @@ module AppMap
93
129
  type
94
130
  end
95
131
 
132
+ def in_transaction?
133
+ ActiveRecord::Base.connection.open_transactions > 0
134
+ end
135
+
96
136
  def execute_query(sql)
97
- ActiveRecord::Base.connection.execute(sql).inject([]) { |memo, r| memo << r; memo }
137
+ ActiveRecord::Base.connection.execute(sql).to_a
98
138
  end
99
139
  end
100
140
  end
@@ -102,6 +142,8 @@ module AppMap
102
142
  def call(_, started, finished, _, payload) # (name, started, finished, unique_id, payload)
103
143
  return if AppMap.tracing.empty?
104
144
 
145
+ return if Thread.current[AppMap::Hook::Method::HOOK_DISABLE_KEY] == true
146
+
105
147
  reentry_key = "#{self.class.name}#call"
106
148
  return if Thread.current[reentry_key] == true
107
149
 
@@ -147,7 +147,7 @@ module AppMap
147
147
  else
148
148
  path_obj.inspect
149
149
  end
150
- path = path[Dir.pwd.length + 1..] if path.index(Dir.pwd) == 0
150
+ path = path[Dir.pwd.length + 1..-1] if path.index(Dir.pwd) == 0
151
151
  path
152
152
  end
153
153
  end
@@ -5,6 +5,9 @@ require 'active_support/inflector/methods'
5
5
  module AppMap
6
6
  # Specific hook handler classes and general related utilities.
7
7
  module Handler
8
+ TEMPLATE_RENDER_FORMAT = 'appmap.handler.template.return_value_format'
9
+ TEMPLATE_RENDER_VALUE = 'appmap.handler.template.return_value'
10
+
8
11
  # Try to find handler module with a given name.
9
12
  #
10
13
  # If the module is not loaded, tries to require the appropriate file
@@ -18,13 +18,14 @@ module AppMap
18
18
  method
19
19
  end
20
20
 
21
+ RUBY_MAJOR_VERSION, RUBY_MINOR_VERSION, _ = RUBY_VERSION.split('.').map(&:to_i)
22
+
21
23
  # Single hooked method.
22
24
  # Call #activate to override the original.
23
25
  class Method
24
26
  attr_reader :hook_package, :hook_class, :hook_method, :parameters, :arity
25
27
 
26
28
  HOOK_DISABLE_KEY = 'AppMap::Hook.disable'
27
- private_constant :HOOK_DISABLE_KEY
28
29
 
29
30
  def initialize(hook_package, hook_class, hook_method)
30
31
  @hook_package = hook_package
@@ -52,18 +53,31 @@ module AppMap
52
53
  if hook_class == Kernel
53
54
  hook_class.define_method_with_arity(hook_method.name, hook_method.arity, hook_method_def)
54
55
  else
55
- hook_class.ancestors.find { |cls| cls.method_defined?(hook_method.name, false) }.tap do |cls|
56
- if cls
57
- cls.define_method_with_arity(hook_method.name, hook_method.arity, hook_method_def)
58
- else
59
- warn "#{hook_method.name} not found on #{hook_class}"
60
- end
56
+ cls = defining_class(hook_class)
57
+ if cls
58
+ cls.define_method_with_arity(hook_method.name, hook_method.arity, hook_method_def)
61
59
  end
62
60
  end
63
61
  end
64
62
 
65
63
  protected
66
64
 
65
+ def defining_class(hook_class)
66
+ cls = \
67
+ if RUBY_MAJOR_VERSION == 2 && RUBY_MINOR_VERSION <= 5
68
+ hook_class
69
+ .ancestors
70
+ .select { |cls| cls.method_defined?(hook_method.name) }
71
+ .find { |cls| cls.instance_method(hook_method.name).owner == cls }
72
+ else
73
+ hook_class.ancestors.find { |cls| cls.method_defined?(hook_method.name, false) }
74
+ end
75
+
76
+ return cls if cls
77
+
78
+ warn "#{hook_method.name} not found on #{hook_class}"
79
+ end
80
+
67
81
  def gettime
68
82
  Process.clock_gettime Process::CLOCK_MONOTONIC
69
83
  end
@@ -79,7 +93,7 @@ module AppMap
79
93
  def method_display_name
80
94
  return @method_display_name if @method_display_name
81
95
 
82
- return @method_display_name = [defined_class, method_symbol, hook_method.name].join if defined_class
96
+ return @method_display_name = [defined_class, '#', hook_method.name].join if defined_class
83
97
 
84
98
  "#{hook_method.name} (class resolution deferred)"
85
99
  end
data/lib/appmap/rspec.rb CHANGED
@@ -78,7 +78,7 @@ module AppMap
78
78
  super
79
79
 
80
80
  webdriver_port = lambda do
81
- return unless defined?(page) && page&.driver
81
+ next unless defined?(page) && page&.driver
82
82
 
83
83
  # This is the ugliest thing ever but I don't want to lose it.
84
84
  # All the WebDriver calls are getting app-mapped and it's really unclear
@@ -15,8 +15,8 @@ module AppMap
15
15
 
16
16
  def perform
17
17
  to_markdown = lambda do |obj|
18
- return obj.each(&to_markdown) if obj.is_a?(Array)
19
- return unless obj.is_a?(Hash)
18
+ next obj.each(&to_markdown) if obj.is_a?(Array)
19
+ next unless obj.is_a?(Hash)
20
20
 
21
21
  description = obj['description']
22
22
  obj['description'] = converter.(description) if description
@@ -10,8 +10,8 @@ module AppMap
10
10
  def perform
11
11
  clean_only = nil
12
12
  clean = lambda do |obj, properties = %w[description example]|
13
- return obj.each(&clean_only.(properties)) if obj.is_a?(Array)
14
- return unless obj.is_a?(Hash)
13
+ next obj.each(&clean_only.(properties)) if obj.is_a?(Array)
14
+ next unless obj.is_a?(Hash)
15
15
 
16
16
  properties.each { |property| obj.delete property }
17
17
 
data/lib/appmap/util.rb CHANGED
@@ -122,7 +122,7 @@ module AppMap
122
122
  # Apparently, it's following the CGI spec in doing so.
123
123
  # https://datatracker.ietf.org/doc/html/rfc3875#section-4.1.18
124
124
  matching_headers = env
125
- .select { |k,v| k.start_with? 'HTTP_' }
125
+ .select { |k,v| k.to_s.start_with? 'HTTP_' }
126
126
  .merge(
127
127
  'CONTENT_TYPE' => env['CONTENT_TYPE'],
128
128
  'CONTENT_LENGTH' => env['CONTENT_LENGTH'],
@@ -3,7 +3,7 @@
3
3
  module AppMap
4
4
  URL = 'https://github.com/applandinc/appmap-ruby'
5
5
 
6
- VERSION = '0.79.0'
6
+ VERSION = '0.80.2'
7
7
 
8
8
  APPMAP_FORMAT_VERSION = '1.5.1'
9
9
 
@@ -32,7 +32,7 @@ describe 'AppMap::Handler::Eval' do
32
32
  expect(events[0]).to match hash_including \
33
33
  defined_class: 'Kernel',
34
34
  method_id: 'eval',
35
- parameters: [{ class: 'Array', kind: :rest, name: 'arg', value: '[12]' }]
35
+ parameters: [{ class: 'Array', kind: :rest, name: 'arg', size: 1, value: '[12]' }]
36
36
  end
37
37
 
38
38
  # a la Ruby 2.6.3 ruby-token.rb
data/spec/hook_spec.rb CHANGED
@@ -491,6 +491,7 @@ describe 'AppMap class Hooking' do
491
491
  :class: Array
492
492
  :value: "[4, 5]"
493
493
  :kind: :rest
494
+ :size: 2
494
495
  - :name: :kw1
495
496
  :class: String
496
497
  :value: one
@@ -503,6 +504,7 @@ describe 'AppMap class Hooking' do
503
504
  :class: Hash
504
505
  :value: "{:kw3=>:three}"
505
506
  :kind: :keyrest
507
+ :size: 1
506
508
  :receiver:
507
509
  :class: InstanceMethod
508
510
  :value: Instance Method fixture
@@ -1139,6 +1141,7 @@ describe 'AppMap class Hooking' do
1139
1141
  :class: Array
1140
1142
  :value: "[foo]"
1141
1143
  :kind: :rest
1144
+ :size: 1
1142
1145
  - :name: :kw1
1143
1146
  :class: String
1144
1147
  :value: kw1
@@ -1151,6 +1154,7 @@ describe 'AppMap class Hooking' do
1151
1154
  :class: Hash
1152
1155
  :value: "{}"
1153
1156
  :kind: :keyrest
1157
+ :size: 0
1154
1158
  :receiver:
1155
1159
  :class: ReportParameters
1156
1160
  :value: ReportParameters
@@ -1160,6 +1164,7 @@ describe 'AppMap class Hooking' do
1160
1164
  :return_value:
1161
1165
  :class: Array
1162
1166
  :value: "[[:rest, :args], [:keyreq, :kw1], [:key, :kw2], [:keyrest, :kws]]"
1167
+ :size: 4
1163
1168
  YAML
1164
1169
  parameters = [[:rest, :args], [:keyreq, :kw1], [:key, :kw2], [:keyrest, :kws]]
1165
1170
  test_hook_behavior 'spec/fixtures/hook/report_parameters.rb', events do
@@ -54,7 +54,8 @@ describe 'Rails' do
54
54
  'http_server_response' => hash_including(
55
55
  'status_code' => 201,
56
56
  'headers' => hash_including('Content-Type' => 'application/json; charset=utf-8'),
57
- )
57
+ ),
58
+ 'return_value' => hash_including('class' => 'Hash', 'object_id' => Integer, 'properties' => include({'name' => 'login', 'class' => 'String'})),
58
59
  )
59
60
  )
60
61
  end
@@ -72,6 +73,7 @@ describe 'Rails' do
72
73
  'name' => 'params',
73
74
  'class' => 'ActiveSupport::HashWithIndifferentAccess',
74
75
  'object_id' => Integer,
76
+ 'size' => 1,
75
77
  'value' => '{login=>alice}',
76
78
  'kind' => 'req'
77
79
  ),
@@ -26,7 +26,8 @@
26
26
  "name": "arg",
27
27
  "class": "Array",
28
28
  "value": "[e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855, the document]",
29
- "kind": "rest"
29
+ "kind": "rest",
30
+ "size": 2
30
31
  }
31
32
  ],
32
33
  "receiver": {
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: appmap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.79.0
4
+ version: 0.80.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin Gilpin
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-04-06 00:00:00.000000000 Z
11
+ date: 2022-04-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -394,6 +394,7 @@ files:
394
394
  - lib/appmap/handler/eval.rb
395
395
  - lib/appmap/handler/function.rb
396
396
  - lib/appmap/handler/net_http.rb
397
+ - lib/appmap/handler/rails/render_handler.rb
397
398
  - lib/appmap/handler/rails/request_handler.rb
398
399
  - lib/appmap/handler/rails/sql_handler.rb
399
400
  - lib/appmap/handler/rails/template.rb