appmap 0.99.2 → 0.99.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c0d8aa81209b5f8d33fc480c3ff3b7f6cd61027dc51fad74c9ad4f19ba6c7faf
4
- data.tar.gz: 5d8ac162d8cf5eacfc045ff81a16c2b473df79ae0619ddaface5b4bab8d422cb
3
+ metadata.gz: eda0d23ff548aaa0e6e61eef0e7734a542660eeeb45e899f54a7287665baaf7e
4
+ data.tar.gz: 84dc9f162eeae76f58f0c6015ec47686509aabf9ac4cac727016957b69421daf
5
5
  SHA512:
6
- metadata.gz: 34c7b6b0fd6e45c33158776e3c3f1a8725031913ad49856f24aa5af50cbc41efd2e047face5c3c1f02a9c20670af08be43492e5bd665a17323578c735b07900b
7
- data.tar.gz: 0ea3f5be3436ea8eec1d8e14cd959b67e6e4547d03de6401c6e21250b3ba91b521b57f665298e1e4ec3be9616a1fbcf0a2f11b8ff09a5c53cd0d60c2d4a358f6
6
+ metadata.gz: af594c4d511623a7e9b37bc3bc45d5d2460de1410e9177f544e900c1d1cd5a555be04bef870c8c5e18a05f46fb242afd6dd9ce26646fc700f071c7a4d917da5a
7
+ data.tar.gz: 49a5e81dd6f504c1e5998f8dc2af53e1b657ddcef387005cd6f313f6c299eb46cc27b7a1c470356de8170435e459d3b1f5e06ef65a1d72f92cea5c0eed797607
data/CHANGELOG.md CHANGED
@@ -1,3 +1,18 @@
1
+ ## [0.99.4](https://github.com/getappmap/appmap-ruby/compare/v0.99.3...v0.99.4) (2023-05-15)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * More robust extraction of test failures ([3851f7c](https://github.com/getappmap/appmap-ruby/commit/3851f7cdf3daf27767f3eb161c69126b607b8a51))
7
+ * Use a copy of rack environment to probe the route ([7ec89a8](https://github.com/getappmap/appmap-ruby/commit/7ec89a8412dc8b9209322ebe9e246f22531b68ab)), closes [#329](https://github.com/getappmap/appmap-ruby/issues/329)
8
+
9
+ ## [0.99.3](https://github.com/getappmap/appmap-ruby/compare/v0.99.2...v0.99.3) (2023-05-10)
10
+
11
+
12
+ ### Bug Fixes
13
+
14
+ * Capture HTTP requests in Rails on Rack level if possible ([e50a280](https://github.com/getappmap/appmap-ruby/commit/e50a280829cd102b8eecbb83a4e2a76247ee6270)), closes [#323](https://github.com/getappmap/appmap-ruby/issues/323)
15
+
1
16
  ## [0.99.2](https://github.com/getappmap/appmap-ruby/compare/v0.99.1...v0.99.2) (2023-05-10)
2
17
 
3
18
 
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'appmap/handler'
4
+
5
+ module AppMap
6
+ module Handler
7
+ module Rails
8
+ # Context of a rails request tracking.
9
+ # Mostly a utility class to clean up and deduplicate request handler code.
10
+ class Context
11
+ def initialize(environment = nil)
12
+ environment[REQUEST_CONTEXT] = self if environment
13
+ @thread = Thread.current
14
+ end
15
+
16
+ def self.from(environment)
17
+ environment[REQUEST_CONTEXT]
18
+ end
19
+
20
+ def self.create(environment)
21
+ return if from environment
22
+
23
+ new environment
24
+ end
25
+
26
+ def self.remove(env)
27
+ env[REQUEST_CONTEXT] = nil
28
+ end
29
+
30
+ def find_template_render_value
31
+ @thread[TEMPLATE_RENDER_VALUE].tap do
32
+ @thread[TEMPLATE_RENDER_VALUE] = nil
33
+ end
34
+ end
35
+
36
+ # context is set on the rack environment to make sure a single request is only recorded once
37
+ # even if ActionDispatch::Executor is entered more than once (as can happen with engines)
38
+ REQUEST_CONTEXT = 'appmap.handler.request.context'
39
+ end
40
+ end
41
+ end
42
+ end
@@ -3,6 +3,7 @@
3
3
  require 'appmap/event'
4
4
  require 'appmap/hook'
5
5
  require 'appmap/util'
6
+ require 'appmap/handler/rails/context'
6
7
 
7
8
  module AppMap
8
9
  module Handler
@@ -57,6 +58,8 @@ module AppMap
57
58
  private
58
59
 
59
60
  def normalized_path(request, router = ::Rails.application.routes.router)
61
+ # use a cloned environment because the router can modify it
62
+ request = ActionDispatch::Request.new request.env.clone
60
63
  router.recognize request do |route, _|
61
64
  app = route.app
62
65
  next unless app.matches? request
@@ -101,8 +104,11 @@ module AppMap
101
104
  protected
102
105
 
103
106
  def before_hook(receiver, *)
107
+ req = receiver.request
108
+ return unless Context.create req.env
109
+
104
110
  before_hook_start_time = AppMap::Util.gettime()
105
- call_event = HTTPServerRequest.new(receiver.request)
111
+ call_event = HTTPServerRequest.new(req)
106
112
  call_event.call_elapsed_instrumentation = (AppMap::Util.gettime() - before_hook_start_time)
107
113
  # http_server_request events are i/o and do not require a package name.
108
114
  AppMap.tracing.record_event call_event, defined_class: defined_class, method: hook_method
@@ -111,13 +117,56 @@ module AppMap
111
117
 
112
118
  def after_hook(receiver, call_event, elapsed, *)
113
119
  after_hook_start_time = AppMap::Util.gettime()
114
- return_value = Thread.current[TEMPLATE_RENDER_VALUE]
115
- Thread.current[TEMPLATE_RENDER_VALUE] = nil
116
- return_event = HTTPServerResponse.build_from_invocation call_event.id, return_value, elapsed, receiver.response
120
+ return_event = HTTPServerResponse.build_from_invocation \
121
+ call_event.id, Context.new.find_template_render_value, elapsed, receiver.response
117
122
  return_event.elapsed_instrumentation = (AppMap::Util.gettime() - after_hook_start_time) + call_event.call_elapsed_instrumentation
118
123
  call_event.call_elapsed_instrumentation = nil # to stay consistent with elapsed_instrumentation only being stored in return
119
124
  AppMap.tracing.record_event return_event
125
+ Context.remove receiver.request.env
126
+ end
127
+ end
128
+
129
+ # Additional hook for the Rack stack in Rails applications.
130
+ #
131
+ # Hooking just in ActionController can be inaccurate if there's a middleware that
132
+ # intercepts the response and modifies it, or catches an exception
133
+ # or an object and does some other processing.
134
+ # For example, Devise catches a throw from warden on authentication error, then runs
135
+ # ActionController stack AGAIN to render a login page, which it then modifies to change
136
+ # the HTTP status code.
137
+ # ActionDispatch::Executor seems a good place to hook as the central entry point
138
+ # in a Rails application; there are a couple middleware that sometimes sit on top of it
139
+ # but they're usually inconsequential. One issue is that the executor can be entered several
140
+ # times in the stack (especially if Rails engines are used). To handle that, we set
141
+ # a context in the request environment the first time we enter it.
142
+ class RackHook < AppMap::Hook::Method
143
+ def initialize
144
+ super(nil, ActionDispatch::Executor, ActionDispatch::Executor.instance_method(:call))
145
+ end
146
+
147
+ protected
148
+
149
+ def before_hook(_receiver, env)
150
+ return unless Context.create env
151
+
152
+ before_hook_start_time = AppMap::Util.gettime
153
+ call_event = HTTPServerRequest.new ActionDispatch::Request.new(env)
154
+ # http_server_request events are i/o and do not require a package name.
155
+ AppMap.tracing.record_event call_event, defined_class: defined_class, method: hook_method
156
+ [call_event, (AppMap::Util.gettime - before_hook_start_time)]
157
+ end
158
+
159
+ # NOTE: this method smells of :reek:LongParameterList and :reek:UtilityFunction
160
+ # because of the interface it implements.
161
+ # rubocop:disable Metrics/ParameterLists
162
+ def after_hook(_receiver, call_event, elapsed_before, elapsed, after_hook_start_time, rack_return, _exception)
163
+ # TODO: handle exceptions
164
+ return_event = HTTPServerResponse.build_from_invocation \
165
+ call_event.id, Context.new.find_template_render_value, elapsed, ActionDispatch::Response.new(*rack_return)
166
+ return_event.elapsed_instrumentation = (AppMap::Util.gettime - after_hook_start_time) + elapsed_before
167
+ AppMap.tracing.record_event return_event
120
168
  end
169
+ # rubocop:enable Metrics/ParameterLists
121
170
  end
122
171
 
123
172
  # RequestListener listens to the 'start_processing.action_controller' notification as a
@@ -125,6 +174,8 @@ module AppMap
125
174
  # Rails >= 7 due to the hooked methods visibility dropping to private.
126
175
  class RequestListener
127
176
  def self.begin_request(_name, _started, _finished, _unique_id, payload)
177
+ return unless Context.create payload[:request].env
178
+
128
179
  RequestListener.new(payload)
129
180
  end
130
181
 
@@ -149,17 +200,16 @@ module AppMap
149
200
  return unless @request_id == payload[:request].request_id
150
201
 
151
202
  after_hook_start_time = AppMap::Util.gettime()
152
- return_value = Thread.current[TEMPLATE_RENDER_VALUE]
153
- Thread.current[TEMPLATE_RENDER_VALUE] = nil
154
203
  return_event = HTTPServerResponse.build_from_invocation(
155
204
  @call_event.id,
156
- return_value,
205
+ Context.new.find_template_render_value,
157
206
  finished - started,
158
207
  payload[:response] || payload
159
208
  )
160
209
  return_event.elapsed_instrumentation = (AppMap::Util.gettime() - after_hook_start_time) + @call_event.call_elapsed_instrumentation
161
210
 
162
211
  AppMap.tracing.record_event return_event
212
+ Context.remove payload[:request].env
163
213
  ActiveSupport::Notifications.unsubscribe(@subscriber)
164
214
  end
165
215
  end
@@ -32,6 +32,8 @@ module AppMap
32
32
  AppMap::Handler::Rails::RequestHandler::RequestListener.method(:begin_request)
33
33
  )
34
34
  end
35
+
36
+ AppMap::Handler::Rails::RequestHandler::RackHook.new.activate
35
37
  end
36
38
  end
37
39
  end if AppMap.recording_enabled?
data/lib/appmap/util.rb CHANGED
@@ -161,7 +161,9 @@ module AppMap
161
161
  return unless exception
162
162
 
163
163
  { message: exception.message }.tap do |test_failure|
164
- first_location = exception.backtrace_locations&.find { |location| !Pathname.new(normalize_path(location.absolute_path)).absolute? }
164
+ first_location = exception.backtrace_locations&.find do |location|
165
+ !Pathname.new(normalize_path(location.absolute_path || location.path)).absolute?
166
+ end
165
167
  test_failure[:location] = [ normalize_path(first_location.path), first_location.lineno ].join(':') if first_location
166
168
  end
167
169
  end
@@ -3,7 +3,7 @@
3
3
  module AppMap
4
4
  URL = 'https://github.com/applandinc/appmap-ruby'
5
5
 
6
- VERSION = '0.99.2'
6
+ VERSION = '0.99.4'
7
7
 
8
8
  APPMAP_FORMAT_VERSION = '1.12.0'
9
9
 
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.99.2
4
+ version: 0.99.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin Gilpin
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-05-10 00:00:00.000000000 Z
11
+ date: 2023-05-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: method_source
@@ -403,6 +403,7 @@ files:
403
403
  - lib/appmap/handler/marshal_load_handler.rb
404
404
  - lib/appmap/handler/net_http_handler.rb
405
405
  - lib/appmap/handler/open_ssl_handler.rb
406
+ - lib/appmap/handler/rails/context.rb
406
407
  - lib/appmap/handler/rails/render_handler.rb
407
408
  - lib/appmap/handler/rails/request_handler.rb
408
409
  - lib/appmap/handler/rails/sql_handler.rb