appmap 0.78.0 → 0.80.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +4 -16
- data/CHANGELOG.md +30 -0
- data/{spec/fixtures/rails5_users_app/Dockerfile.pg → Dockerfile.pg} +0 -0
- data/README.md +14 -44
- data/README_CI.md +0 -7
- data/Rakefile +12 -150
- data/appmap.gemspec +3 -2
- data/docker-compose.yml +10 -0
- data/lib/appmap/agent.rb +8 -0
- data/lib/appmap/event.rb +26 -12
- data/lib/appmap/gem_hooks/actionpack.yml +6 -0
- data/lib/appmap/handler/rails/render_handler.rb +29 -0
- data/lib/appmap/handler/rails/request_handler.rb +13 -11
- data/lib/appmap/handler/rails/sql_handler.rb +43 -1
- data/lib/appmap/handler.rb +3 -0
- data/lib/appmap/hook/method.rb +0 -1
- data/lib/appmap/version.rb +1 -1
- data/spec/config_spec.rb +1 -1
- data/spec/depends/api_spec.rb +13 -5
- data/spec/depends/spec_helper.rb +0 -9
- data/spec/fixtures/database.yml +11 -0
- data/spec/fixtures/rails5_users_app/config/database.yml +1 -0
- data/spec/fixtures/rails6_users_app/Gemfile +1 -25
- data/spec/fixtures/rails6_users_app/config/database.yml +1 -0
- data/spec/fixtures/rails7_users_app/Gemfile +1 -25
- data/spec/fixtures/rails7_users_app/config/database.yml +1 -0
- data/spec/handler/eval_spec.rb +1 -1
- data/spec/hook_spec.rb +6 -1
- data/spec/rails_recording_spec.rb +7 -21
- data/spec/rails_spec_helper.rb +76 -63
- data/spec/rails_test_spec.rb +7 -17
- data/spec/railtie_spec.rb +4 -18
- data/spec/record_sql_rails_pg_spec.rb +44 -75
- data/spec/remote_recording_spec.rb +18 -30
- data/spec/spec_helper.rb +1 -0
- data/spec/swagger/swagger_spec.rb +1 -16
- data/spec/util_spec.rb +1 -1
- data/test/expectations/openssl_test_key_sign2-3.1.json +2 -1
- metadata +22 -21
- data/Dockerfile.appmap +0 -5
- data/spec/fixtures/rack_users_app/Dockerfile +0 -32
- data/spec/fixtures/rack_users_app/docker-compose.yml +0 -9
- data/spec/fixtures/rails5_users_app/Dockerfile +0 -29
- data/spec/fixtures/rails5_users_app/config/database.yml +0 -18
- data/spec/fixtures/rails5_users_app/create_app +0 -33
- data/spec/fixtures/rails5_users_app/docker-compose.yml +0 -31
- data/spec/fixtures/rails6_users_app/.ruby-version +0 -1
- data/spec/fixtures/rails6_users_app/Dockerfile +0 -44
- data/spec/fixtures/rails6_users_app/Dockerfile.pg +0 -3
- data/spec/fixtures/rails6_users_app/config/database.yml +0 -18
- data/spec/fixtures/rails6_users_app/create_app +0 -33
- data/spec/fixtures/rails6_users_app/docker-compose.yml +0 -31
- data/spec/fixtures/rails7_users_app/.ruby-version +0 -1
- data/spec/fixtures/rails7_users_app/Dockerfile +0 -30
- data/spec/fixtures/rails7_users_app/Dockerfile.pg +0 -3
- data/spec/fixtures/rails7_users_app/config/database.yml +0 -86
- data/spec/fixtures/rails7_users_app/create_app +0 -31
- data/spec/fixtures/rails7_users_app/docker-compose.yml +0 -31
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: de1e5a636c3d6e807f11c54a29563e338804f3d101dc4779229596455cd60682
|
4
|
+
data.tar.gz: cf2aba805fdb427da2a642826f490b0002eb1892dd57a07693b119582a8cd7e1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6056dda497e69c32a6e7550c76b4b4e40a5cd5405d7244748af4f5f34ed7d6790eafa206470ac8c9a98019fec802944b4cec0cc274451028cf2c5d6f405bd626
|
7
|
+
data.tar.gz: '039ef96a6ae64cf641e58fb364a2777a65dc507ded48027752ca766c65204659b844cb6408d17a077947968d1fbf006f7c9b29e2fdfe03fc392d90c4495361ff'
|
data/.travis.yml
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
language: ruby
|
2
2
|
dist: bionic
|
3
|
+
cache:
|
4
|
+
- bundle
|
5
|
+
- yarn
|
3
6
|
|
4
7
|
# NB: if you update the ruby versions here, you also need to update
|
5
8
|
# them in the Rakefile.
|
@@ -9,25 +12,10 @@ rbenv:
|
|
9
12
|
- 3.0
|
10
13
|
- 3.1
|
11
14
|
|
12
|
-
addons:
|
13
|
-
apt:
|
14
|
-
packages:
|
15
|
-
# https://docs.travis-ci.com/user/docker/#installing-a-newer-docker-version
|
16
|
-
- docker-ce
|
17
|
-
|
18
15
|
services:
|
19
|
-
-
|
16
|
+
- postgresql
|
20
17
|
|
21
18
|
before_install:
|
22
|
-
- sudo apt-get update && sudo apt-get install apt-transport-https ca-certificates -y && sudo update-ca-certificates
|
23
|
-
# see https://blog.travis-ci.com/docker-rate-limits
|
24
|
-
# and also https://www.docker.com/blog/what-you-need-to-know-about-upcoming-docker-hub-rate-limiting/
|
25
|
-
# if we do not use authorized account,
|
26
|
-
# the pulls-per-IP quota is shared with other Travis users
|
27
|
-
- >
|
28
|
-
if [ ! -z "$DOCKERHUB_PASSWORD" ] && [ ! -z "$DOCKERHUB_USERNAME" ]; then
|
29
|
-
echo "$DOCKERHUB_PASSWORD" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin ;
|
30
|
-
fi
|
31
19
|
- |
|
32
20
|
nvm install --lts \
|
33
21
|
&& nvm use --lts \
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,33 @@
|
|
1
|
+
## [0.80.1](https://github.com/applandinc/appmap-ruby/compare/v0.80.0...v0.80.1) (2022-04-08)
|
2
|
+
|
3
|
+
|
4
|
+
### Bug Fixes
|
5
|
+
|
6
|
+
* Don't call #size on complex objects ([3f19d1e](https://github.com/applandinc/appmap-ruby/commit/3f19d1e67288379570dfa14d8758a0624d2c6c34))
|
7
|
+
|
8
|
+
# [0.80.0](https://github.com/applandinc/appmap-ruby/compare/v0.79.0...v0.80.0) (2022-04-08)
|
9
|
+
|
10
|
+
|
11
|
+
### Bug Fixes
|
12
|
+
|
13
|
+
* Don't record SQL within an existing event ([ff37a69](https://github.com/applandinc/appmap-ruby/commit/ff37a69af1af02263df216e49aea0d0954b93925))
|
14
|
+
|
15
|
+
|
16
|
+
### Features
|
17
|
+
|
18
|
+
* Env var to EXPLAIN queries ([740be75](https://github.com/applandinc/appmap-ruby/commit/740be75c2bc59e343d67ecf86b7715e61cddadba))
|
19
|
+
* Optionally record parameter schema ([b7f41b1](https://github.com/applandinc/appmap-ruby/commit/b7f41b15a4556a0ce78650a6a77301d365632bb8))
|
20
|
+
* query_plan is available whether a current transaction exists or not ([6edf774](https://github.com/applandinc/appmap-ruby/commit/6edf774fea858d825c4b971be2c4c15db1652446))
|
21
|
+
* Record parameter and return value size ([6e69754](https://github.com/applandinc/appmap-ruby/commit/6e697543cb421378832492e286f972dc4cb1e1aa))
|
22
|
+
* Save render return value to a thread-local ([f9d1e3f](https://github.com/applandinc/appmap-ruby/commit/f9d1e3f0aa9972482ff77233d38220104515b1d6))
|
23
|
+
|
24
|
+
# [0.79.0](https://github.com/applandinc/appmap-ruby/compare/v0.78.0...v0.79.0) (2022-04-06)
|
25
|
+
|
26
|
+
|
27
|
+
### Features
|
28
|
+
|
29
|
+
* Use a more unique test database name ([0eed036](https://github.com/applandinc/appmap-ruby/commit/0eed036460f0384698ff91c1112a4a9c3214f7f4))
|
30
|
+
|
1
31
|
# [0.78.0](https://github.com/applandinc/appmap-ruby/compare/v0.77.4...v0.78.0) (2022-04-04)
|
2
32
|
|
3
33
|
|
File without changes
|
data/README.md
CHANGED
@@ -28,7 +28,7 @@ Visit the [AppMap for Ruby](https://appland.com/docs/reference/appmap-ruby.html)
|
|
28
28
|
|
29
29
|
**Configuration**
|
30
30
|
|
31
|
-
*appmap.yml* is loaded into an `AppMap::Config`.
|
31
|
+
*appmap.yml* is loaded into an `AppMap::Config`.
|
32
32
|
|
33
33
|
**Hooking**
|
34
34
|
|
@@ -39,7 +39,7 @@ method with calls that record the parameters and return value.
|
|
39
39
|
**Builtins**
|
40
40
|
|
41
41
|
`Hook` begins by iterating over builtin classes and modules defined in the `Config`. Builtins include code
|
42
|
-
like `openssl` and `net/http`. This code is not dependent on any external libraries being present, and
|
42
|
+
like `openssl` and `net/http`. This code is not dependent on any external libraries being present, and
|
43
43
|
`appmap` cannot guarantee that it will be loaded before builtins. Therefore, it's necessary to require it and
|
44
44
|
hook it by looking up the classes and modules as constants in the `Object` namespace.
|
45
45
|
|
@@ -81,50 +81,20 @@ The fixture apps in `test/fixtures` are plain Ruby projects that exercise the ba
|
|
81
81
|
|
82
82
|
The fixture apps in `spec/fixtures` are simple Rack, Rails5, and Rails6 apps.
|
83
83
|
You can use them to interactively develop and test the recording features of the `appmap` gem.
|
84
|
-
These fixture apps are more sophisticated than `test/fixtures`, because they include additional
|
85
|
-
resources such as a PostgreSQL database.
|
84
|
+
These fixture apps are more sophisticated than `test/fixtures`, because they include additional
|
85
|
+
resources such as a PostgreSQL database. Still, you can simply enter the fixture directory and `bundle`.
|
86
86
|
|
87
|
-
|
87
|
+
If you don't have PostgreSQL on the local (default) socket, you can export `DATABASE_URL` to
|
88
|
+
point to the database server you want to use.
|
88
89
|
|
89
|
-
|
90
|
-
$ bundle exec rake build:fixtures:all
|
91
|
-
```
|
92
|
-
|
93
|
-
This will build the `appmap.gem`, along with a Docker image for each fixture app.
|
94
|
-
|
95
|
-
Then move to the directory of the fixture you want to use, and provision the environment.
|
96
|
-
In this example, we use Ruby 2.6.
|
97
|
-
|
98
|
-
```sh-session
|
99
|
-
$ export RUBY_VERSION=2.6
|
100
|
-
$ docker-compose up -d pg
|
101
|
-
$ sleep 10s # Or some reasonable amount of time
|
102
|
-
$ docker-compose run --rm app ./create_app
|
103
|
-
```
|
90
|
+
You can launch a database like this:
|
104
91
|
|
105
|
-
Now you can start a development container.
|
106
|
-
|
107
|
-
```sh-session
|
108
|
-
$ docker-compose run --rm -v $PWD:/app -v $PWD/../../..:/src/appmap-ruby app bash
|
109
|
-
Starting rails_users_app_pg_1 ... done
|
110
|
-
root@6fab5f89125f:/app# cd /src/appmap-ruby
|
111
|
-
root@6fab5f89125f:/src/appmap-ruby# rm ext/appmap/*.so ext/appmap/*.o
|
112
|
-
root@6fab5f89125f:/src/appmap-ruby# bundle
|
113
|
-
root@6fab5f89125f:/src/appmap-ruby# bundle exec rake compile
|
114
|
-
root@6fab5f89125f:/src/appmap-ruby# cd /src/app
|
115
|
-
root@6fab5f89125f:/src/app# bundle config local.appmap /src/appmap-ruby
|
116
|
-
root@6fab5f89125f:/src/app# bundle
|
117
92
|
```
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
Configuring AppMap from path appmap.yml
|
126
|
-
....
|
127
|
-
|
128
|
-
Finished in 0.07357 seconds (files took 2.1 seconds to load)
|
129
|
-
4 examples, 0 failures
|
93
|
+
➜ docker-compose -p appmap-ruby up -d
|
94
|
+
... stuff
|
95
|
+
➜ docker-compose ps pg
|
96
|
+
Name Command State Ports
|
97
|
+
-----------------------------------------------------------------------------------------
|
98
|
+
appmap-ruby_pg_1 docker-entrypoint.sh postgres Up (healthy) 0.0.0.0:59134->5432/tcp
|
99
|
+
➜ export DATABASE_URL=postgres://postgres@localhost:59134
|
130
100
|
```
|
data/README_CI.md
CHANGED
@@ -4,13 +4,6 @@
|
|
4
4
|
* `GEM_HOST_API_KEY`: rubygems API key
|
5
5
|
* `GEM_ALTERNATIVE_NAME` (optional): used for testing of CI flows,
|
6
6
|
to avoid publication of test releases under official package name
|
7
|
-
* `DOCKERHUB\_USERNAME`, `DOCKERHUB_PASSWORD`: optional dockerhub credentials,
|
8
|
-
to avoid throttling of dockerhub anonymous pulls
|
9
|
-
|
10
|
-
Note: for security reasons, it's better to use dedicated (not personal)
|
11
|
-
Dockerhub account,
|
12
|
-
and also use [access tokens](https://docs.docker.com/docker-hub/access-tokens/)
|
13
|
-
instead of primary password
|
14
7
|
|
15
8
|
# Release command
|
16
9
|
|
data/Rakefile
CHANGED
@@ -1,26 +1,8 @@
|
|
1
1
|
$: << File.join(__dir__, 'lib')
|
2
|
-
require 'appmap/version'
|
3
|
-
GEM_VERSION = AppMap::VERSION
|
4
|
-
|
5
|
-
# Make sure the local version is not behind the one on
|
6
|
-
# rubygems.org (it's ok if they're the same).
|
7
|
-
#
|
8
|
-
# If it is behind, the fixture images won't get updated with the gem
|
9
|
-
# built from the local source, so you'll wind up testing the rubygems
|
10
|
-
# version instead.
|
11
|
-
unless ENV['SKIP_VERSION_CHECK']
|
12
|
-
require 'json'
|
13
|
-
require 'net/http'
|
14
|
-
rubygems_version = JSON.parse(Net::HTTP.get(URI.parse('https://rubygems.org/api/v1/gems/appmap.json')))['version']
|
15
|
-
if Gem::Version.new(GEM_VERSION) < Gem::Version.new(rubygems_version)
|
16
|
-
raise "#{GEM_VERSION} < #{rubygems_version}. Rebase to avoid build issues."
|
17
|
-
end
|
18
|
-
end
|
19
2
|
|
3
|
+
require 'rspec/core/rake_task'
|
20
4
|
require 'rake/testtask'
|
21
5
|
require 'rdoc/task'
|
22
|
-
|
23
|
-
require 'open3'
|
24
6
|
require 'rake/extensiontask'
|
25
7
|
|
26
8
|
desc 'build the native extension'
|
@@ -28,138 +10,20 @@ Rake::ExtensionTask.new("appmap") do |ext|
|
|
28
10
|
ext.lib_dir = "lib/appmap"
|
29
11
|
end
|
30
12
|
|
31
|
-
RUBY_VERSIONS=%w[2.6 2.7 3.0 3.1].select do |version|
|
32
|
-
travis_ruby_version = ENV['TRAVIS_RUBY_VERSION']
|
33
|
-
next true unless travis_ruby_version
|
34
|
-
|
35
|
-
if travis_ruby_version.index(version) == 0
|
36
|
-
warn "Testing Ruby version #{version}, since it matches TRAVIS_RUBY_VERSION=#{travis_ruby_version}"
|
37
|
-
next true
|
38
|
-
end
|
39
|
-
|
40
|
-
false
|
41
|
-
end
|
42
|
-
FIXTURE_APPS=[:rack_users_app, :rails6_users_app, :rails5_users_app, :rails7_users_app => {:ruby_version => '>= 2.7'}]
|
43
|
-
|
44
|
-
def run_cmd(*cmd)
|
45
|
-
$stderr.puts "Running: #{cmd}"
|
46
|
-
out, s = Open3.capture2e(*cmd)
|
47
|
-
unless s.success?
|
48
|
-
$stderr.puts <<-END
|
49
|
-
Command failed:
|
50
|
-
<<< Output:
|
51
|
-
#{out}
|
52
|
-
>>> End of output
|
53
|
-
END
|
54
|
-
raise 'Docker build failed'
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def build_base_image(ruby_version)
|
59
|
-
run_cmd "docker build" \
|
60
|
-
" --build-arg RUBY_VERSION=#{ruby_version}" \
|
61
|
-
" --build-arg GEM_VERSION=#{GEM_VERSION}" \
|
62
|
-
" -t appmap:#{GEM_VERSION} -f Dockerfile.appmap ."
|
63
|
-
end
|
64
|
-
|
65
|
-
def build_app_image(app, ruby_version)
|
66
|
-
Dir.chdir "spec/fixtures/#{app}" do
|
67
|
-
env = {"RUBY_VERSION" => ruby_version, "GEM_VERSION" => GEM_VERSION}
|
68
|
-
run_cmd(env,
|
69
|
-
"docker-compose build" \
|
70
|
-
" --build-arg RUBY_VERSION=#{ruby_version}" \
|
71
|
-
" --build-arg GEM_VERSION=#{GEM_VERSION}" )
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
13
|
desc 'Install non-Ruby dependencies'
|
76
14
|
task :install do
|
77
15
|
system 'yarn install' or raise 'yarn install failed'
|
78
16
|
end
|
79
17
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
build_base_image(ruby_version)
|
90
|
-
end.tap do |t|
|
91
|
-
desc "Build all images"
|
92
|
-
task all: t
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
namespace :fixtures do
|
98
|
-
RUBY_VERSIONS.each do |ruby_version|
|
99
|
-
namespace ruby_version do
|
100
|
-
desc "build:fixtures:#{ruby_version}"
|
101
|
-
FIXTURE_APPS.each do |app_spec|
|
102
|
-
app = if app_spec.instance_of?(Hash)
|
103
|
-
app_spec = app_spec.flatten
|
104
|
-
version_rqt = Gem::Requirement.create(app_spec[1][:ruby_version])
|
105
|
-
next unless version_rqt =~ (Gem::Version.new(ruby_version))
|
106
|
-
app = app_spec[0]
|
107
|
-
else
|
108
|
-
app = app_spec
|
109
|
-
end.to_s
|
110
|
-
|
111
|
-
|
112
|
-
desc app
|
113
|
-
task app => ["base:#{ruby_version}"] do
|
114
|
-
build_app_image(app, ruby_version)
|
115
|
-
end.tap do |t|
|
116
|
-
desc "Build all fixture images for #{ruby_version}"
|
117
|
-
task all: t
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
desc "Build all fixture images"
|
123
|
-
task all: ["#{ruby_version}:all"]
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
task all: ["fixtures:all"]
|
128
|
-
end
|
129
|
-
|
130
|
-
def run_specs(ruby_version, task_args)
|
131
|
-
require 'rspec/core/rake_task'
|
132
|
-
require 'climate_control'
|
133
|
-
# Define an rspec rake task for the specified Ruby version. It's hidden (i.e. doesn't have a
|
134
|
-
# description), because it's not intended to be invoked directly
|
135
|
-
RSpec::Core::RakeTask.new("rspec_#{ruby_version}", [:specs]) do |task, args|
|
136
|
-
task.exclude_pattern = 'spec/fixtures/**/*_spec.rb'
|
137
|
-
task.rspec_opts = '-f doc'
|
138
|
-
if args.count > 0
|
139
|
-
# There doesn't appear to be a value for +pattern+ that will
|
140
|
-
# cause it to be ignored. Setting it to '' or +nil+ causes an
|
141
|
-
# empty argument to get passed to rspec, which confuses it.
|
142
|
-
task.pattern = 'never match this'
|
143
|
-
task.rspec_opts += " " + args.to_a.join(' ')
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
|
-
# Set up the environment, then execute the rspec task we
|
148
|
-
# created above.
|
149
|
-
ClimateControl.modify(RUBY_VERSION: ruby_version) do
|
150
|
-
Rake::Task["rspec_#{ruby_version}"].execute(task_args)
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
namespace :spec do
|
155
|
-
RUBY_VERSIONS.each do |ruby_version|
|
156
|
-
desc ruby_version
|
157
|
-
task ruby_version, [:specs] => ["install", "compile", "build:fixtures:#{ruby_version}:all"] do |_, task_args|
|
158
|
-
run_specs(ruby_version, task_args)
|
159
|
-
end.tap do |t|
|
160
|
-
desc "Run all specs"
|
161
|
-
task :all, [:specs] => t
|
162
|
-
end
|
18
|
+
RSpec::Core::RakeTask.new spec: %i[compile install] do |task, args|
|
19
|
+
task.exclude_pattern = 'spec/fixtures/**/*_spec.rb'
|
20
|
+
task.rspec_opts = '-f doc'
|
21
|
+
if args.count > 0
|
22
|
+
# There doesn't appear to be a value for +pattern+ that will
|
23
|
+
# cause it to be ignored. Setting it to '' or +nil+ causes an
|
24
|
+
# empty argument to get passed to rspec, which confuses it.
|
25
|
+
task.pattern = 'never match this'
|
26
|
+
task.rspec_opts += [nil, *args].join(' ')
|
163
27
|
end
|
164
28
|
end
|
165
29
|
|
@@ -169,14 +33,12 @@ Rake::RDocTask.new do |rd|
|
|
169
33
|
rd.title = 'AppMap'
|
170
34
|
end
|
171
35
|
|
172
|
-
Rake::TestTask.new(minitest:
|
36
|
+
Rake::TestTask.new(minitest: :compile) do |t|
|
173
37
|
t.libs << 'test'
|
174
38
|
t.libs << 'lib'
|
175
39
|
t.test_files = FileList['test/*_test.rb']
|
176
40
|
end
|
177
41
|
|
178
|
-
task
|
179
|
-
|
180
|
-
task test: %i[spec:all minitest]
|
42
|
+
task test: %i[spec minitest]
|
181
43
|
|
182
44
|
task default: :test
|
data/appmap.gemspec
CHANGED
@@ -5,7 +5,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
5
5
|
require 'appmap/version'
|
6
6
|
|
7
7
|
Gem::Specification.new do |spec|
|
8
|
-
# ability to parameterize gem name is added intentionally,
|
8
|
+
# ability to parameterize gem name is added intentionally,
|
9
9
|
# to support the possibility of unofficial releases, e.g. during CI tests
|
10
10
|
spec.name = (ENV['GEM_ALTERNATIVE_NAME'].to_s.empty? ? 'appmap' : ENV["GEM_ALTERNATIVE_NAME"] )
|
11
11
|
spec.version = AppMap::VERSION
|
@@ -32,7 +32,7 @@ Gem::Specification.new do |spec|
|
|
32
32
|
spec.add_dependency 'reverse_markdown'
|
33
33
|
|
34
34
|
spec.add_development_dependency 'bundler', '>= 1.16'
|
35
|
-
spec.add_development_dependency 'minitest', '~> 5.
|
35
|
+
spec.add_development_dependency 'minitest', '~> 5.15'
|
36
36
|
spec.add_development_dependency 'pry-byebug'
|
37
37
|
spec.add_development_dependency 'rake', '>= 12.3.3'
|
38
38
|
spec.add_development_dependency 'rdoc'
|
@@ -48,5 +48,6 @@ Gem::Specification.new do |spec|
|
|
48
48
|
spec.add_development_dependency 'webdrivers', '~> 4.0'
|
49
49
|
spec.add_development_dependency 'timecop'
|
50
50
|
spec.add_development_dependency 'hashie'
|
51
|
+
spec.add_development_dependency 'random-port', '~> 0.5.1'
|
51
52
|
spec.add_development_dependency 'webrick'
|
52
53
|
end
|
data/docker-compose.yml
ADDED
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
|
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
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
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
|
-
|
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::
|
70
|
+
class HTTPServerResponse < AppMap::Event::MethodReturn
|
71
71
|
attr_accessor :status, :headers
|
72
72
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
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
|
-
|
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).
|
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
|
|