appmap 0.88.0 → 0.90.0

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: 22745bf509f674a271a3bc42eb870813cf22d6e0c399a87e99377311a0ddaf67
4
- data.tar.gz: 482036f94bc62a732263ac7318e6c942efd22282d9b2ace1ae1245bda28de591
3
+ metadata.gz: 463d826fad7ff1f1f143f350e329e0d9f58c649c6a517b519c42e852d620318a
4
+ data.tar.gz: f1429c965be9a9913c2163245e3cee99b6b014d73c85d77c19b1d1198b5e92ec
5
5
  SHA512:
6
- metadata.gz: dd9fe2dc676c639487b19c5ad4c10e52d8dd1ff95ef10f0829077fc6a4100613d220df7bb8aea5c425e65158617112148827136bc2151cfd8e0a13666e49c347
7
- data.tar.gz: 5913ce200514ce676f26a6bf20e348fe9481ecd929ac9b8a5874b9f2e2d20d3bdc82722a535afebe7a153c7a7290ccf8e8e510a336f0b5d7265b6b3665b18a69
6
+ metadata.gz: 8fb3886bd1f864f4619f5dc0bd158381b4c959a385990d786d45228c0a2f01169511ef0a3ebafec6e01874af566bb286edfb38367f34b83facb7959ded3bd4ae
7
+ data.tar.gz: 96adc82206bf8fb319675a6107281c1ebfb19c8254daac59ae9e88ebceeec8adc446b459a68fa3483108426cb5a65bfbecb42205b4b797ae3301777b6e473233
data/.travis.yml CHANGED
@@ -5,7 +5,6 @@ cache:
5
5
  - yarn
6
6
 
7
7
  rbenv:
8
- - 2.5
9
8
  - 2.6
10
9
  - 2.7
11
10
  - 3.0
data/CHANGELOG.md CHANGED
@@ -1,3 +1,24 @@
1
+ # [0.90.0](https://github.com/applandinc/appmap-ruby/compare/v0.89.0...v0.90.0) (2022-09-15)
2
+
3
+
4
+ ### Features
5
+
6
+ * Include required_ruby_version in the gemspec ([a5d7c6b](https://github.com/applandinc/appmap-ruby/commit/a5d7c6b7b255f817f3ceec5924cd799d2565daa4))
7
+ * Save default appmap.yml ([77a08d5](https://github.com/applandinc/appmap-ruby/commit/77a08d5ebbe2f49f19237242a62d05aadcc84228))
8
+
9
+ # [0.89.0](https://github.com/applandinc/appmap-ruby/compare/v0.88.0...v0.89.0) (2022-09-07)
10
+
11
+
12
+ ### Bug Fixes
13
+
14
+ * Make Rack a runtime dependency ([3f2924d](https://github.com/applandinc/appmap-ruby/commit/3f2924d41af291bfe771829c2ea7978332ff1d44))
15
+
16
+
17
+ ### Features
18
+
19
+ * Add builtin labels for JWT ([3569333](https://github.com/applandinc/appmap-ruby/commit/3569333e99f82e03fff892001f2b65eb9e8aa52a))
20
+ * Write an AppMap for each observed HTTP request ([2e89eaf](https://github.com/applandinc/appmap-ruby/commit/2e89eaf1b1f327771d1f4f0642fa6c202e0f3afb))
21
+
1
22
  # [0.88.0](https://github.com/applandinc/appmap-ruby/compare/v0.87.0...v0.88.0) (2022-08-31)
2
23
 
3
24
 
data/Gemfile CHANGED
@@ -3,3 +3,5 @@ source "https://rubygems.org"
3
3
  git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
4
 
5
5
  gemspec
6
+
7
+ gem 'rack', '~> 2'
data/README.md CHANGED
@@ -92,9 +92,7 @@ You can launch a database like this:
92
92
  ```
93
93
  ➜ docker-compose -p appmap-ruby up -d
94
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
95
+ ➜ docker-compose port pg 5432
96
+ 0.0.0.0:64479
97
+ ➜ export DATABASE_URL=postgres://postgres@localhost:64479
100
98
  ```
data/appmap.gemspec CHANGED
@@ -12,6 +12,8 @@ Gem::Specification.new do |spec|
12
12
  spec.authors = ['Kevin Gilpin']
13
13
  spec.email = ['kgilpin@gmail.com']
14
14
 
15
+ spec.required_ruby_version = '>= 2.6.0'
16
+
15
17
  spec.summary = %q{Record the operation of a Ruby program, using the AppLand 'AppMap' format.}
16
18
  spec.homepage = AppMap::URL
17
19
  spec.license = 'MIT'
@@ -28,10 +30,10 @@ Gem::Specification.new do |spec|
28
30
  spec.require_paths = ['lib']
29
31
 
30
32
  spec.add_dependency 'method_source'
31
- spec.add_dependency 'rack'
32
33
  spec.add_dependency 'reverse_markdown'
33
34
 
34
35
  spec.add_runtime_dependency 'activesupport'
36
+ spec.add_runtime_dependency 'rack'
35
37
 
36
38
  spec.add_development_dependency 'bundler', '>= 1.16'
37
39
  spec.add_development_dependency 'minitest', '~> 5.15'
@@ -39,7 +41,7 @@ Gem::Specification.new do |spec|
39
41
  spec.add_development_dependency 'rake', '>= 12.3.3'
40
42
  spec.add_development_dependency 'rdoc'
41
43
  spec.add_development_dependency 'rubocop'
42
- spec.add_development_dependency "rake-compiler"
44
+ spec.add_development_dependency 'rake-compiler'
43
45
 
44
46
  # Testing
45
47
  spec.add_development_dependency 'climate_control'
data/lib/appmap/config.rb CHANGED
@@ -338,28 +338,34 @@ module AppMap
338
338
  AppMap uses this file to customize its behavior. For example, you can use
339
339
  the 'packages' setting to indicate which local file paths and dependency
340
340
  gems you want to include in the AppMap. Since you haven't provided specific
341
- settings, the appmap gem will try and guess some reasonable defaults.
342
- To suppress this message, create the file:
343
-
344
- #{Pathname.new(config_file_name).expand_path}
345
-
346
- Here are the default settings that will be used in the meantime. You can
347
- copy and paste this example to start your appmap.yml.
341
+ settings, the appmap gem will use these default options:
348
342
  MISSING_FILE_MSG
349
343
  {}
350
344
  end
351
345
 
352
346
  load(config_data).tap do |config|
353
- config_yaml = {
347
+ {
354
348
  'name' => config.name,
355
349
  'packages' => config.packages.select{|p| p.path}.map do |pkg|
356
350
  { 'path' => pkg.path }
357
351
  end,
358
352
  'exclude' => []
359
- }.compact
360
- unless config_present
361
- warn Util.color(YAML.dump(config_yaml), :magenta)
362
- warn logo.()
353
+ }.compact.tap do |config_yaml|
354
+ unless config_present
355
+ warn Util.color(YAML.dump(config_yaml), :magenta)
356
+ dirname = Pathname.new(config_file_name).dirname.expand_path
357
+ if Dir.exists?(dirname) && File.writable?(dirname)
358
+ warn Util.color(<<~CONFIG_FILE_MSG, :magenta)
359
+ This file will be saved to #{Pathname.new(config_file_name).expand_path},
360
+ where you can customize it.
361
+ CONFIG_FILE_MSG
362
+ File.write(config_file_name, YAML.dump(config_yaml))
363
+ end
364
+ warn Util.color(<<~CONFIG_FILE_MSG, :magenta)
365
+ For more information, see https://appmap.io/docs/reference/appmap-ruby.html#configuration
366
+ CONFIG_FILE_MSG
367
+ warn logo.()
368
+ end
363
369
  end
364
370
  end
365
371
  end
@@ -0,0 +1,8 @@
1
+ - method: JWT#decode
2
+ label: jwt.decode
3
+
4
+ - method: JWT#encode
5
+ label: jwt.encode
6
+
7
+ - method: JWT::Signature#verify
8
+ label: jwt.signature.verify
@@ -2,7 +2,8 @@
2
2
 
3
3
  module AppMap
4
4
  module Middleware
5
- # RemoteRecording adds `/_appmap/record` routes to control recordings via HTTP requests
5
+ # RemoteRecording adds `/_appmap/record` routes to control recordings via HTTP requests.
6
+ # It can also be enabled to emit an AppMap for each request.
6
7
  class RemoteRecording
7
8
  def initialize(app)
8
9
  require 'json'
@@ -21,7 +22,7 @@ module AppMap
21
22
  end
22
23
  end
23
24
 
24
- def start_recording
25
+ def ws_start_recording
25
26
  return [ 409, 'Recording is already in progress' ] if @tracer
26
27
 
27
28
  @events = []
@@ -32,7 +33,7 @@ module AppMap
32
33
  [ 200 ]
33
34
  end
34
35
 
35
- def stop_recording(req)
36
+ def ws_stop_recording(req)
36
37
  return [ 404, 'No recording is in progress' ] unless @tracer
37
38
 
38
39
  tracer = @tracer
@@ -75,10 +76,50 @@ module AppMap
75
76
  end
76
77
 
77
78
  def call(env)
79
+ # Note: Puma config is avaliable here. For example:
80
+ # $ env['puma.config'].final_options[:workers]
81
+ # 0
82
+
78
83
  req = Rack::Request.new(env)
79
84
  return handle_record_request(req) if req.path == '/_appmap/record'
80
85
 
81
- @app.call(env)
86
+ start_time = Time.now
87
+ # Support multi-threaded web server such as Puma by recording each thread
88
+ # into a separate Tracer.
89
+ tracer = AppMap.tracing.trace(thread: Thread.current) if record_all_requests?
90
+
91
+ @app.call(env).tap do |status, headers|
92
+ if tracer
93
+ AppMap.tracing.delete(tracer)
94
+
95
+ events = tracer.events.map(&:to_h)
96
+
97
+ appmap_name = "#{req.request_method} #{req.path} (#{status}) - #{start_time.strftime('%T.%L')}"
98
+ appmap_file_name = AppMap::Util.scenario_filename([ start_time.to_f, req.url ].join('_'))
99
+ output_dir = File.join(AppMap::DEFAULT_APPMAP_DIR, 'requests')
100
+ appmap_file_path = File.join(output_dir, appmap_file_name)
101
+
102
+ metadata = AppMap.detect_metadata
103
+ metadata[:name] = appmap_name
104
+ metadata[:timestamp] = start_time.to_f
105
+ metadata[:recorder] = {
106
+ name: 'record_requests'
107
+ }
108
+
109
+ appmap = {
110
+ version: AppMap::APPMAP_FORMAT_VERSION,
111
+ classMap: AppMap.class_map(tracer.event_methods),
112
+ metadata: metadata,
113
+ events: events
114
+ }
115
+
116
+ FileUtils.mkdir_p(output_dir)
117
+ File.write(appmap_file_path, JSON.generate(appmap))
118
+
119
+ headers['AppMap-Name'] = File.expand_path(appmap_name)
120
+ headers['AppMap-File-Name'] = File.expand_path(appmap_file_path)
121
+ end
122
+ end
82
123
  end
83
124
 
84
125
  def recording_state
@@ -92,9 +133,9 @@ module AppMap
92
133
  if method.eql?('GET')
93
134
  recording_state
94
135
  elsif method.eql?('POST')
95
- start_recording
136
+ ws_start_recording
96
137
  elsif method.eql?('DELETE')
97
- stop_recording(req)
138
+ ws_stop_recording(req)
98
139
  else
99
140
  [ 404, '' ]
100
141
  end
@@ -106,6 +147,10 @@ module AppMap
106
147
  headers['Content-Type'] && headers['Content-Type'] =~ /html/
107
148
  end
108
149
 
150
+ def record_all_requests?
151
+ ENV['APPMAP_RECORD_REQUESTS'] == 'true'
152
+ end
153
+
109
154
  def recording?
110
155
  !@event_thread.nil?
111
156
  end
data/lib/appmap/trace.rb CHANGED
@@ -48,8 +48,8 @@ module AppMap
48
48
  @tracers.empty?
49
49
  end
50
50
 
51
- def trace(enable: true)
52
- Tracer.new.tap do |tracer|
51
+ def trace(enable: true, thread: nil)
52
+ Tracer.new(thread_id: thread&.object_id).tap do |tracer|
53
53
  @tracers << tracer
54
54
  tracer.enable if enable
55
55
  end
@@ -64,7 +64,7 @@ module AppMap
64
64
  end
65
65
 
66
66
  def record_event(event, package: nil, defined_class: nil, method: nil)
67
- @tracers.each do |tracer|
67
+ @tracers.select { |tracer| tracer.thread_id.nil? || tracer.thread_id === event.thread_id }.each do |tracer|
68
68
  tracer.record_event(event, package: package, defined_class: defined_class, method: method)
69
69
  end
70
70
  end
@@ -114,14 +114,16 @@ module AppMap
114
114
 
115
115
  class Tracer
116
116
  attr_accessor :stacks
117
+ attr_reader :thread_id, :events
117
118
 
118
119
  # Records the events which happen in a program.
119
- def initialize
120
+ def initialize(thread_id: nil)
120
121
  @events = []
121
122
  @last_package_for_thread = {}
122
123
  @methods = Set.new
123
124
  @stack_printer = StackPrinter.new if StackPrinter.enabled?
124
125
  @enabled = false
126
+ @thread_id = thread_id
125
127
  end
126
128
 
127
129
  def enable
@@ -143,6 +145,8 @@ module AppMap
143
145
  def record_event(event, package: nil, defined_class: nil, method: nil)
144
146
  return unless @enabled
145
147
 
148
+ raise "Expected event in thread #{@thread_id}, got #{event.thread_id}" if @thread_id && @thread_id != event.thread_id
149
+
146
150
  @stack_printer.record(event) if @stack_printer
147
151
  @last_package_for_thread[Thread.current.object_id] = package if package
148
152
  @events << event
@@ -3,7 +3,7 @@
3
3
  module AppMap
4
4
  URL = 'https://github.com/applandinc/appmap-ruby'
5
5
 
6
- VERSION = '0.88.0'
6
+ VERSION = '0.90.0'
7
7
 
8
8
  APPMAP_FORMAT_VERSION = '1.7.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.88.0
4
+ version: 0.90.0
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-08-31 00:00:00.000000000 Z
11
+ date: 2022-09-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: method_source
@@ -25,7 +25,7 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: rack
28
+ name: reverse_markdown
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
@@ -39,7 +39,7 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: reverse_markdown
42
+ name: activesupport
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
@@ -53,7 +53,7 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: activesupport
56
+ name: rack
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
@@ -386,6 +386,7 @@ files:
386
386
  - lib/appmap/gem_hooks/activerecord.yml
387
387
  - lib/appmap/gem_hooks/cancancan.yml
388
388
  - lib/appmap/gem_hooks/devise.yml
389
+ - lib/appmap/gem_hooks/jwt.yml
389
390
  - lib/appmap/gem_hooks/pandoc-ruby.yml
390
391
  - lib/appmap/gem_hooks/rails.yml
391
392
  - lib/appmap/gem_hooks/railties.yml
@@ -445,7 +446,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
445
446
  requirements:
446
447
  - - ">="
447
448
  - !ruby/object:Gem::Version
448
- version: '0'
449
+ version: 2.6.0
449
450
  required_rubygems_version: !ruby/object:Gem::Requirement
450
451
  requirements:
451
452
  - - ">="