appmap 0.53.0 → 0.54.0

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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -0
  3. data/lib/appmap.rb +28 -110
  4. data/lib/appmap/agent.rb +115 -0
  5. data/lib/appmap/class_map.rb +2 -2
  6. data/lib/appmap/config.rb +11 -3
  7. data/lib/appmap/handler/net_http.rb +2 -1
  8. data/lib/appmap/handler/rails/request_handler.rb +2 -1
  9. data/lib/appmap/metadata.rb +4 -2
  10. data/lib/appmap/minitest.rb +2 -0
  11. data/lib/appmap/railtie.rb +2 -2
  12. data/lib/appmap/rspec.rb +5 -3
  13. data/lib/appmap/swagger.rb +2 -0
  14. data/lib/appmap/swagger/configuration.rb +70 -0
  15. data/lib/appmap/swagger/markdown_descriptions.rb +43 -0
  16. data/lib/appmap/swagger/rake_tasks.rb +43 -0
  17. data/lib/appmap/swagger/stable.rb +37 -0
  18. data/lib/appmap/version.rb +1 -1
  19. data/package.json +0 -1
  20. data/spec/config_spec.rb +0 -1
  21. data/spec/fixtures/hook/.gitignore +2 -0
  22. data/spec/fixtures/hook/app/controllers/api/api_keys_controller.rb +1 -0
  23. data/spec/fixtures/hook/app/controllers/organizations_controller.rb +1 -0
  24. data/spec/fixtures/hook/app/models/api_key.rb +1 -0
  25. data/spec/fixtures/hook/app/models/configuration.rb +1 -0
  26. data/spec/fixtures/hook/app/models/show.rb +1 -0
  27. data/spec/fixtures/hook/app/models/user.rb +1 -0
  28. data/spec/fixtures/hook/revoke_api_key.appmap.json +847 -0
  29. data/spec/fixtures/hook/spec/api_spec.rb +1 -0
  30. data/spec/fixtures/hook/spec/user_spec.rb +1 -0
  31. data/spec/fixtures/hook/user_page_scenario.appmap.json +1722 -0
  32. data/spec/fixtures/rails5_users_app/config/environments/test.rb +3 -0
  33. data/spec/fixtures/rails6_users_app/Dockerfile +0 -1
  34. data/spec/fixtures/rails6_users_app/appmap.yml +3 -1
  35. data/spec/fixtures/rails6_users_app/config/environments/test.rb +3 -0
  36. data/spec/fixtures/rails6_users_app/lib/tasks/appmap.rake +13 -0
  37. data/spec/rails_recording_spec.rb +1 -1
  38. data/spec/swagger/swagger_spec.rb +47 -0
  39. data/test/gem_test.rb +1 -0
  40. metadata +21 -2
data/lib/appmap/rspec.rb CHANGED
@@ -62,8 +62,10 @@ module AppMap
62
62
  example_group_parent = \
63
63
  if example_group.respond_to?(:module_parent)
64
64
  example_group.module_parent
65
- else
65
+ elsif example_group.respond_to?(:parent)
66
66
  example_group.parent
67
+ elsif example_group.respond_to?(:parent_groups)
68
+ example_group.parent_groups.first
67
69
  end
68
70
 
69
71
  example_group_parent != example_group ? ScopeExampleGroup.new(example_group_parent) : nil
@@ -109,13 +111,13 @@ module AppMap
109
111
 
110
112
  description = []
111
113
  scope = ScopeExample.new(example)
112
-
113
114
  while scope
114
115
  description << scope.description
115
116
  scope = scope.parent
116
117
  end
117
118
 
118
- description.reject!(&:nil?).reject!(&:blank?)
119
+ description.reject!(&:nil?)
120
+ description.reject!(&Util.method(:blank?))
119
121
  default_description = description.last
120
122
  description.reverse!
121
123
 
@@ -0,0 +1,2 @@
1
+ require 'appmap/swagger/configuration'
2
+ require 'appmap/swagger/rake_tasks'
@@ -0,0 +1,70 @@
1
+ require 'yaml'
2
+
3
+ module AppMap
4
+ module Swagger
5
+ class Configuration
6
+ DEFAULT_VERSION = '1.0'
7
+ DEFAULT_OUTPUT_DIR = 'swagger'
8
+ DEFAULT_DESCRIPTION = 'Generate Swagger from AppMaps'
9
+
10
+ attr_accessor :project_version,
11
+ :output_dir,
12
+ :description
13
+ attr_writer :project_name, :template
14
+
15
+ class << self
16
+ def load(config_data)
17
+ Configuration.new.tap do |config|
18
+ config_data.each do |k,v|
19
+ config.send "#{k}=", v
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ def initialize
26
+ @project_name = nil
27
+ @project_version = DEFAULT_VERSION
28
+ @output_dir = DEFAULT_OUTPUT_DIR
29
+ @description = DEFAULT_DESCRIPTION
30
+ end
31
+
32
+ def project_name
33
+ @project_name || default_project_name
34
+ end
35
+
36
+ def template
37
+ @template || default_template
38
+ end
39
+
40
+ def default_template
41
+ YAML.load <<~TEMPLATE
42
+ openapi: 3.0.1
43
+ info:
44
+ title: #{project_name}
45
+ version: #{project_version}
46
+ paths:
47
+ components:
48
+ servers:
49
+ - url: http://{defaultHost}
50
+ variables:
51
+ defaultHost:
52
+ default: localhost:3000
53
+ TEMPLATE
54
+ end
55
+
56
+ def default_project_name
57
+ # https://www.rubydoc.info/docs/rails/Module#module_parent_name-instance_method
58
+ module_parent_name = ->(cls) { cls.name =~ /::[^:]+\Z/ ? $`.freeze : nil }
59
+
60
+ # Lazy-evaluate this so that Rails.application will be defined.
61
+ # If this code runs too early in the lifecycle, Rails.application is nil.
62
+ if defined?(::Rails)
63
+ [module_parent_name.(::Rails.application.class).humanize.titleize, "API"].join(" ")
64
+ else
65
+ "MyProject API"
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,43 @@
1
+ require 'rdoc'
2
+ require 'reverse_markdown'
3
+
4
+ module AppMap
5
+ module Swagger
6
+ # Transform description fields into Markdown.
7
+ class MarkdownDescriptions
8
+ def initialize(swagger_yaml)
9
+ @swagger_yaml = swagger_yaml
10
+ end
11
+
12
+ def converter
13
+ method(:rdoc_to_markdown)
14
+ end
15
+
16
+ def perform
17
+ to_markdown = lambda do |obj|
18
+ return obj.each(&to_markdown) if obj.is_a?(Array)
19
+ return unless obj.is_a?(Hash)
20
+
21
+ description = obj['description']
22
+ obj['description'] = converter.(description) if description
23
+
24
+ obj.reject { |k,v| k == 'properties' }.each_value(&to_markdown)
25
+
26
+ obj
27
+ end
28
+
29
+ to_markdown.(Util.deep_dup(@swagger_yaml))
30
+ end
31
+
32
+ protected
33
+
34
+ def rdoc_to_markdown(comment)
35
+ # Strip tags
36
+ comment = comment.split("\n").reject { |line| line =~ /^\s*@/ }.join("\n")
37
+ converter = ::RDoc::Markup::ToHtml.new(::RDoc::Options.new)
38
+ html = converter.convert(comment).strip
39
+ ::ReverseMarkdown.convert(html).strip
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,43 @@
1
+ require 'rake'
2
+ require 'yaml'
3
+ require 'appmap/node_cli'
4
+ require 'appmap/swagger/markdown_descriptions'
5
+ require 'appmap/swagger/stable'
6
+
7
+ module AppMap
8
+ module Swagger
9
+ module RakeTasks
10
+ extend self
11
+ extend Rake::DSL
12
+
13
+ def configuration
14
+ AppMap.configuration
15
+ end
16
+
17
+ def define_tasks
18
+ generate_swagger = lambda do |t, args|
19
+ appmap_js = AppMap::NodeCLI.new(verbose: Rake.verbose == true)
20
+
21
+ FileUtils.mkdir_p configuration.swagger_config.output_dir
22
+
23
+ cmd = %w[swagger]
24
+
25
+ swagger_raw, = appmap_js.command(cmd)
26
+
27
+ gen_swagger = YAML.load(swagger_raw)
28
+ gen_swagger_full = AppMap::Swagger::MarkdownDescriptions.new(gen_swagger).perform
29
+ gen_swagger_stable = AppMap::Swagger::Stable.new(gen_swagger).perform
30
+
31
+ swagger = configuration.swagger_config.template.merge(gen_swagger_full)
32
+ File.write File.join(configuration.swagger_config.output_dir, 'openapi.yaml'), YAML.dump(swagger)
33
+
34
+ swagger = configuration.swagger_config.template.merge(gen_swagger_stable)
35
+ File.write File.join(configuration.swagger_config.output_dir, 'openapi_stable.yaml'), YAML.dump(swagger)
36
+ end
37
+
38
+ desc configuration.swagger_config.description
39
+ task :swagger, &generate_swagger
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,37 @@
1
+ module AppMap
2
+ module Swagger
3
+ # Transform raw Swagger into a "stable" variant. For example, remove descriptions
4
+ # and parameter examples, whose variance does not substantially affect the API.
5
+ class Stable
6
+ def initialize(swagger_yaml)
7
+ @swagger_yaml = swagger_yaml
8
+ end
9
+
10
+ def perform
11
+ clean_only = nil
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)
15
+
16
+ properties.each { |property| obj.delete property }
17
+
18
+ obj.each do |key, value|
19
+ # Don't clean 'description' from within 'properties'
20
+ props = key == 'properties' ? %w[example] : properties
21
+ clean_only.(props).(value)
22
+ end
23
+
24
+ obj
25
+ end
26
+
27
+ clean_only = lambda do |properties|
28
+ lambda do |example|
29
+ clean.(example, properties)
30
+ end
31
+ end
32
+
33
+ clean.(@swagger_yaml.deep_dup)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -3,7 +3,7 @@
3
3
  module AppMap
4
4
  URL = 'https://github.com/applandinc/appmap-ruby'
5
5
 
6
- VERSION = '0.53.0'
6
+ VERSION = '0.54.0'
7
7
 
8
8
  APPMAP_FORMAT_VERSION = '1.5.1'
9
9
 
data/package.json CHANGED
@@ -20,4 +20,3 @@
20
20
  "@appland/cli": "^1.1.0"
21
21
  }
22
22
  }
23
-
data/spec/config_spec.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'rails_spec_helper'
4
- require 'active_support/core_ext'
5
4
  require 'appmap/config'
6
5
 
7
6
  describe AppMap::Config, docker: false do
@@ -0,0 +1,2 @@
1
+ user_page_scenario
2
+ revoke_api_key
@@ -0,0 +1 @@
1
+ # dummy
@@ -0,0 +1 @@
1
+ # dummy
@@ -0,0 +1 @@
1
+ # dummy
@@ -0,0 +1 @@
1
+ # dummy
@@ -0,0 +1,847 @@
1
+ {
2
+ "version": "1.3",
3
+ "metadata": {
4
+ "app": "appland/AppLand",
5
+ "language": {
6
+ "name": "ruby",
7
+ "engine": "ruby",
8
+ "version": "2.6.6"
9
+ },
10
+ "client": {
11
+ "name": "appmap",
12
+ "url": "https://github.com/applandinc/appmap-ruby",
13
+ "version": "0.38.1"
14
+ },
15
+ "frameworks": [
16
+ {
17
+ "name": "rails",
18
+ "version": "5.2.4.2"
19
+ },
20
+ {
21
+ "name": "rspec",
22
+ "version": "3.9.1"
23
+ }
24
+ ],
25
+ "git": {
26
+ "repository": "git@github.com:applandinc/appland.git",
27
+ "branch": "feature/show-sql-in-source-code-tab",
28
+ "commit": "d52bd55d5a08f0e9b27760780bf2737829f5f25f",
29
+ "status_code": [
30
+ "M Gemfile.lock"
31
+ ],
32
+ "git_last_annotated_tag": null,
33
+ "git_last_tag": "v0.17.1",
34
+ "git_commits_since_last_annotated_tag": null,
35
+ "git_commits_since_last_tag": 0
36
+ },
37
+ "name": "API::APIKeysController revoke an existing api key",
38
+ "feature": "API::APIKeysController revoke",
39
+ "feature_group": "API API keys",
40
+ "labels": [
41
+ "api key",
42
+ "api"
43
+ ],
44
+ "recorder": {
45
+ "name": "rspec"
46
+ },
47
+ "source_location": "spec/fixtures/spec/api_spec.rb",
48
+ "test_status": "succeeded",
49
+ "fingerprints": [
50
+ {
51
+ "appmap_digest": "7fecdd763d47626364364da02387f1fcbfe805123e806f08bacde96636cfc91d",
52
+ "canonicalization_algorithm": "info_v1",
53
+ "digest": "76ef6fcddad314962606f8161f73901beb9d6fa06468aee3a96eabb2b65132cb",
54
+ "fingerprint_algorithm": "sha256"
55
+ },
56
+ {
57
+ "appmap_digest": "7fecdd763d47626364364da02387f1fcbfe805123e806f08bacde96636cfc91d",
58
+ "canonicalization_algorithm": "trace_v1",
59
+ "digest": "18301be60081a8dbf2574f4226c095b395dd4c060e69da94c5ac20d2f002b23a",
60
+ "fingerprint_algorithm": "sha256"
61
+ },
62
+ {
63
+ "appmap_digest": "7fecdd763d47626364364da02387f1fcbfe805123e806f08bacde96636cfc91d",
64
+ "canonicalization_algorithm": "update_v1",
65
+ "digest": "9be5419782f4189c7fba3eb4eff7a4027bc6655b9ac43c45544ede554c7c5c82",
66
+ "fingerprint_algorithm": "sha256"
67
+ }
68
+ ]
69
+ },
70
+ "classMap": [
71
+ {
72
+ "name": "app/models",
73
+ "type": "package",
74
+ "children": [
75
+ {
76
+ "name": "ApiKey",
77
+ "type": "class",
78
+ "children": [
79
+ {
80
+ "name": "issue",
81
+ "type": "function",
82
+ "location": "app/models/api_key.rb:28",
83
+ "static": true,
84
+ "labels": [
85
+ "security"
86
+ ]
87
+ },
88
+ {
89
+ "name": "encode",
90
+ "type": "function",
91
+ "location": "app/models/api_key.rb:20",
92
+ "static": true
93
+ },
94
+ {
95
+ "name": "authenticate",
96
+ "type": "function",
97
+ "location": "app/models/api_key.rb:51",
98
+ "static": true,
99
+ "labels": [
100
+ "security",
101
+ "provider.authenticate"
102
+ ]
103
+ },
104
+ {
105
+ "name": "decode",
106
+ "type": "function",
107
+ "location": "app/models/api_key.rb:24",
108
+ "static": true
109
+ },
110
+ {
111
+ "name": "touch",
112
+ "type": "function",
113
+ "location": "app/models/api_key.rb:11",
114
+ "static": true
115
+ },
116
+ {
117
+ "name": "revoke",
118
+ "type": "function",
119
+ "location": "app/models/api_key.rb:40",
120
+ "static": true,
121
+ "labels": [
122
+ "security"
123
+ ]
124
+ }
125
+ ]
126
+ }
127
+ ]
128
+ },
129
+ {
130
+ "name": "app/controllers",
131
+ "type": "package",
132
+ "children": [
133
+ {
134
+ "name": "API",
135
+ "type": "class",
136
+ "children": [
137
+ {
138
+ "name": "APIKeysController",
139
+ "type": "class",
140
+ "children": [
141
+ {
142
+ "name": "destroy",
143
+ "type": "function",
144
+ "location": "app/controllers/api/api_keys_controller.rb:15",
145
+ "static": false
146
+ }
147
+ ]
148
+ }
149
+ ]
150
+ }
151
+ ]
152
+ },
153
+ {
154
+ "name": "json",
155
+ "type": "package",
156
+ "children": [
157
+ {
158
+ "name": "JSON",
159
+ "type": "class",
160
+ "children": [
161
+ {
162
+ "name": "Ext",
163
+ "type": "class",
164
+ "children": [
165
+ {
166
+ "name": "Generator",
167
+ "type": "class",
168
+ "children": [
169
+ {
170
+ "name": "State",
171
+ "type": "class",
172
+ "children": [
173
+ {
174
+ "name": "generate",
175
+ "type": "function",
176
+ "location": "JSON::Ext::Generator::State#generate",
177
+ "static": false,
178
+ "labels": [
179
+ "serialization",
180
+ "json"
181
+ ]
182
+ }
183
+ ]
184
+ }
185
+ ]
186
+ }
187
+ ]
188
+ }
189
+ ]
190
+ }
191
+ ]
192
+ }
193
+ ],
194
+ "events": [
195
+ {
196
+ "id": 1,
197
+ "event": "call",
198
+ "thread_id": 70143606759380,
199
+ "defined_class": "ApiKey",
200
+ "method_id": "issue",
201
+ "path": "app/models/api_key.rb",
202
+ "lineno": 28,
203
+ "static": true,
204
+ "parameters": [
205
+ {
206
+ "name": "login",
207
+ "class": "String",
208
+ "object_id": 70143707320560,
209
+ "value": "admin",
210
+ "kind": "req"
211
+ },
212
+ {
213
+ "name": "description",
214
+ "class": "String",
215
+ "object_id": 70143709034840,
216
+ "value": "example api key",
217
+ "kind": "key"
218
+ },
219
+ {
220
+ "name": "encode",
221
+ "class": "NilClass",
222
+ "object_id": 8,
223
+ "value": null,
224
+ "kind": "key"
225
+ }
226
+ ],
227
+ "receiver": {
228
+ "class": "Class",
229
+ "object_id": 70143710327480,
230
+ "value": "ApiKey"
231
+ }
232
+ },
233
+ {
234
+ "id": 2,
235
+ "event": "call",
236
+ "thread_id": 70143606759380,
237
+ "sql_query": {
238
+ "sql": "INSERT INTO \"api_keys\" (\"login\", \"description\") VALUES ('admin', 'example api key') RETURNING *",
239
+ "database_type": "postgres",
240
+ "server_version": 120003
241
+ }
242
+ },
243
+ {
244
+ "id": 3,
245
+ "event": "return",
246
+ "thread_id": 70143606759380,
247
+ "parent_id": 2,
248
+ "elapsed": 0.001786
249
+ },
250
+ {
251
+ "id": 4,
252
+ "event": "call",
253
+ "thread_id": 70143606759380,
254
+ "defined_class": "ApiKey",
255
+ "method_id": "encode",
256
+ "path": "app/models/api_key.rb",
257
+ "lineno": 20,
258
+ "static": true,
259
+ "parameters": [
260
+ {
261
+ "name": "api_key",
262
+ "class": "DAO::ApiKey",
263
+ "object_id": 70143624613220,
264
+ "value": "#<DAO::ApiKey:0x00007f972ba81ac8>",
265
+ "kind": "req"
266
+ }
267
+ ],
268
+ "receiver": {
269
+ "class": "Class",
270
+ "object_id": 70143710327480,
271
+ "value": "ApiKey"
272
+ }
273
+ },
274
+ {
275
+ "id": 5,
276
+ "event": "return",
277
+ "thread_id": 70143606759380,
278
+ "parent_id": 4,
279
+ "elapsed": 0.000024,
280
+ "return_value": {
281
+ "class": "String",
282
+ "value": "YWRtaW46ZTU3YTgzMTAtZTcxOC00OTE0LWIzZmEtYjExZDRhMDY4N2Vl",
283
+ "object_id": 70143608697140
284
+ }
285
+ },
286
+ {
287
+ "id": 6,
288
+ "event": "return",
289
+ "thread_id": 70143606759380,
290
+ "parent_id": 1,
291
+ "elapsed": 0.038045,
292
+ "return_value": {
293
+ "class": "String",
294
+ "value": "YWRtaW46ZTU3YTgzMTAtZTcxOC00OTE0LWIzZmEtYjExZDRhMDY4N2Vl",
295
+ "object_id": 70143608697140
296
+ }
297
+ },
298
+ {
299
+ "id": 7,
300
+ "event": "call",
301
+ "thread_id": 70143606759380,
302
+ "http_server_request": {
303
+ "request_method": "DELETE",
304
+ "path_info": "/api/api_keys"
305
+ },
306
+ "message": [
307
+ {
308
+ "name": "controller",
309
+ "class": "String",
310
+ "value": "api/api_keys",
311
+ "object_id": 70143625900420
312
+ },
313
+ {
314
+ "name": "action",
315
+ "class": "String",
316
+ "value": "destroy",
317
+ "object_id": 70143625903660
318
+ }
319
+ ]
320
+ },
321
+ {
322
+ "id": 8,
323
+ "event": "call",
324
+ "thread_id": 70143606759380,
325
+ "defined_class": "ApiKey",
326
+ "method_id": "authenticate",
327
+ "path": "app/models/api_key.rb",
328
+ "lineno": 51,
329
+ "static": true,
330
+ "parameters": [
331
+ {
332
+ "name": "api_key",
333
+ "class": "String",
334
+ "object_id": 70143626063440,
335
+ "value": "YWRtaW46ZTU3YTgzMTAtZTcxOC00OTE0LWIzZmEtYjExZDRhMDY4N2Vl",
336
+ "kind": "req"
337
+ }
338
+ ],
339
+ "receiver": {
340
+ "class": "Class",
341
+ "object_id": 70143710327480,
342
+ "value": "ApiKey"
343
+ }
344
+ },
345
+ {
346
+ "id": 9,
347
+ "event": "call",
348
+ "thread_id": 70143606759380,
349
+ "defined_class": "ApiKey",
350
+ "method_id": "decode",
351
+ "path": "app/models/api_key.rb",
352
+ "lineno": 24,
353
+ "static": true,
354
+ "parameters": [
355
+ {
356
+ "name": "api_key",
357
+ "class": "String",
358
+ "object_id": 70143626063440,
359
+ "value": "YWRtaW46ZTU3YTgzMTAtZTcxOC00OTE0LWIzZmEtYjExZDRhMDY4N2Vl",
360
+ "kind": "req"
361
+ }
362
+ ],
363
+ "receiver": {
364
+ "class": "Class",
365
+ "object_id": 70143710327480,
366
+ "value": "ApiKey"
367
+ }
368
+ },
369
+ {
370
+ "id": 10,
371
+ "event": "return",
372
+ "thread_id": 70143606759380,
373
+ "parent_id": 9,
374
+ "elapsed": 0.000019,
375
+ "return_value": {
376
+ "class": "Array",
377
+ "value": "[\"admin\", \"e57a8310-e718-4914-b3fa-b11d4a0687ee\"]",
378
+ "object_id": 70143626079020
379
+ }
380
+ },
381
+ {
382
+ "id": 11,
383
+ "event": "call",
384
+ "thread_id": 70143606759380,
385
+ "sql_query": {
386
+ "sql": "SELECT * FROM \"api_keys\" WHERE (\"login\" = 'admin')",
387
+ "database_type": "postgres",
388
+ "server_version": 120003
389
+ }
390
+ },
391
+ {
392
+ "id": 12,
393
+ "event": "return",
394
+ "thread_id": 70143606759380,
395
+ "parent_id": 11,
396
+ "elapsed": 0.001087
397
+ },
398
+ {
399
+ "id": 13,
400
+ "event": "call",
401
+ "thread_id": 70143606759380,
402
+ "defined_class": "ApiKey",
403
+ "method_id": "touch",
404
+ "path": "app/models/api_key.rb",
405
+ "lineno": 11,
406
+ "static": true,
407
+ "parameters": [
408
+ {
409
+ "name": "api_key",
410
+ "class": "DAO::ApiKey",
411
+ "object_id": 70143621442700,
412
+ "value": "#<DAO::ApiKey:0x00007f972b475918>",
413
+ "kind": "req"
414
+ }
415
+ ],
416
+ "receiver": {
417
+ "class": "Class",
418
+ "object_id": 70143710327480,
419
+ "value": "ApiKey"
420
+ }
421
+ },
422
+ {
423
+ "id": 14,
424
+ "event": "call",
425
+ "thread_id": 70143606759380,
426
+ "sql_query": {
427
+ "sql": "UPDATE \"api_keys\" SET \"last_used\" = '2021-01-12 18:48:00.281150+0000' WHERE (\"id\" = 9)",
428
+ "database_type": "postgres",
429
+ "server_version": 120003
430
+ }
431
+ },
432
+ {
433
+ "id": 15,
434
+ "event": "return",
435
+ "thread_id": 70143606759380,
436
+ "parent_id": 14,
437
+ "elapsed": 0.000805
438
+ },
439
+ {
440
+ "id": 16,
441
+ "event": "return",
442
+ "thread_id": 70143606759380,
443
+ "parent_id": 13,
444
+ "elapsed": 0.005023,
445
+ "return_value": {
446
+ "class": "DAO::ApiKey",
447
+ "value": "#<DAO::ApiKey:0x00007f972b475918>",
448
+ "object_id": 70143621442700
449
+ }
450
+ },
451
+ {
452
+ "id": 17,
453
+ "event": "call",
454
+ "thread_id": 70143606759380,
455
+ "sql_query": {
456
+ "sql": "SELECT * FROM \"users\" WHERE (\"users\".\"login\" = 'admin') LIMIT 1",
457
+ "database_type": "postgres",
458
+ "server_version": 120003
459
+ }
460
+ },
461
+ {
462
+ "id": 18,
463
+ "event": "return",
464
+ "thread_id": 70143606759380,
465
+ "parent_id": 17,
466
+ "elapsed": 0.00103
467
+ },
468
+ {
469
+ "id": 19,
470
+ "event": "call",
471
+ "thread_id": 70143606759380,
472
+ "sql_query": {
473
+ "sql": "SELECT \"pg_type\".\"oid\", \"typrelid\", \"typarray\" FROM \"pg_type\" WHERE ((\"typtype\" = 'c') AND (\"typname\" = 'q_class')) LIMIT 1",
474
+ "database_type": "postgres",
475
+ "server_version": 120003
476
+ }
477
+ },
478
+ {
479
+ "id": 20,
480
+ "event": "return",
481
+ "thread_id": 70143606759380,
482
+ "parent_id": 19,
483
+ "elapsed": 0.001234
484
+ },
485
+ {
486
+ "id": 21,
487
+ "event": "call",
488
+ "thread_id": 70143606759380,
489
+ "sql_query": {
490
+ "sql": "SELECT \"attname\", (CASE \"pg_type\".\"typbasetype\" WHEN 0 THEN \"atttypid\" ELSE \"pg_type\".\"typbasetype\" END) AS \"atttypid\" FROM \"pg_attribute\" INNER JOIN \"pg_type\" ON (\"pg_type\".\"oid\" = \"pg_attribute\".\"atttypid\") WHERE ((\"attrelid\" = 223731) AND (\"attnum\" > 0) AND NOT \"attisdropped\") ORDER BY \"attnum\"",
491
+ "database_type": "postgres",
492
+ "server_version": 120003
493
+ }
494
+ },
495
+ {
496
+ "id": 22,
497
+ "event": "return",
498
+ "thread_id": 70143606759380,
499
+ "parent_id": 21,
500
+ "elapsed": 0.001281
501
+ },
502
+ {
503
+ "id": 23,
504
+ "event": "call",
505
+ "thread_id": 70143606759380,
506
+ "sql_query": {
507
+ "sql": "SELECT \"pg_type\".\"oid\", \"typrelid\", \"typarray\" FROM \"pg_type\" WHERE ((\"typtype\" = 'c') AND (\"typname\" = 'fn_call')) LIMIT 1",
508
+ "database_type": "postgres",
509
+ "server_version": 120003
510
+ }
511
+ },
512
+ {
513
+ "id": 24,
514
+ "event": "return",
515
+ "thread_id": 70143606759380,
516
+ "parent_id": 23,
517
+ "elapsed": 0.000838
518
+ },
519
+ {
520
+ "id": 25,
521
+ "event": "call",
522
+ "thread_id": 70143606759380,
523
+ "sql_query": {
524
+ "sql": "SELECT \"attname\", (CASE \"pg_type\".\"typbasetype\" WHEN 0 THEN \"atttypid\" ELSE \"pg_type\".\"typbasetype\" END) AS \"atttypid\" FROM \"pg_attribute\" INNER JOIN \"pg_type\" ON (\"pg_type\".\"oid\" = \"pg_attribute\".\"atttypid\") WHERE ((\"attrelid\" = 223734) AND (\"attnum\" > 0) AND NOT \"attisdropped\") ORDER BY \"attnum\"",
525
+ "database_type": "postgres",
526
+ "server_version": 120003
527
+ }
528
+ },
529
+ {
530
+ "id": 26,
531
+ "event": "return",
532
+ "thread_id": 70143606759380,
533
+ "parent_id": 25,
534
+ "elapsed": 0.001017
535
+ },
536
+ {
537
+ "id": 27,
538
+ "event": "return",
539
+ "thread_id": 70143606759380,
540
+ "parent_id": 8,
541
+ "elapsed": 0.150356,
542
+ "return_value": {
543
+ "class": "User::Show",
544
+ "value": "#<User::Show:0x00007f972cee0d20>",
545
+ "object_id": 70143635293840
546
+ }
547
+ },
548
+ {
549
+ "id": 28,
550
+ "event": "call",
551
+ "thread_id": 70143606759380,
552
+ "defined_class": "API::APIKeysController",
553
+ "method_id": "destroy",
554
+ "path": "app/controllers/api/api_keys_controller.rb",
555
+ "lineno": 15,
556
+ "static": false,
557
+ "parameters": [],
558
+ "receiver": {
559
+ "class": "API::APIKeysController",
560
+ "object_id": 70143625216500,
561
+ "value": "#<API::APIKeysController:0x00007f972bba83e8>"
562
+ }
563
+ },
564
+ {
565
+ "id": 29,
566
+ "event": "call",
567
+ "thread_id": 70143606759380,
568
+ "defined_class": "ApiKey",
569
+ "method_id": "revoke",
570
+ "path": "app/models/api_key.rb",
571
+ "lineno": 40,
572
+ "static": true,
573
+ "parameters": [
574
+ {
575
+ "name": "api_key",
576
+ "class": "String",
577
+ "object_id": 70143626063440,
578
+ "value": "YWRtaW46ZTU3YTgzMTAtZTcxOC00OTE0LWIzZmEtYjExZDRhMDY4N2Vl",
579
+ "kind": "req"
580
+ }
581
+ ],
582
+ "receiver": {
583
+ "class": "Class",
584
+ "object_id": 70143710327480,
585
+ "value": "ApiKey"
586
+ }
587
+ },
588
+ {
589
+ "id": 30,
590
+ "event": "call",
591
+ "thread_id": 70143606759380,
592
+ "defined_class": "ApiKey",
593
+ "method_id": "decode",
594
+ "path": "app/models/api_key.rb",
595
+ "lineno": 24,
596
+ "static": true,
597
+ "parameters": [
598
+ {
599
+ "name": "api_key",
600
+ "class": "String",
601
+ "object_id": 70143626063440,
602
+ "value": "YWRtaW46ZTU3YTgzMTAtZTcxOC00OTE0LWIzZmEtYjExZDRhMDY4N2Vl",
603
+ "kind": "req"
604
+ }
605
+ ],
606
+ "receiver": {
607
+ "class": "Class",
608
+ "object_id": 70143710327480,
609
+ "value": "ApiKey"
610
+ }
611
+ },
612
+ {
613
+ "id": 31,
614
+ "event": "return",
615
+ "thread_id": 70143606759380,
616
+ "parent_id": 30,
617
+ "elapsed": 0.000011,
618
+ "return_value": {
619
+ "class": "Array",
620
+ "value": "[\"admin\", \"e57a8310-e718-4914-b3fa-b11d4a0687ee\"]",
621
+ "object_id": 70143613653900
622
+ }
623
+ },
624
+ {
625
+ "id": 32,
626
+ "event": "call",
627
+ "thread_id": 70143606759380,
628
+ "sql_query": {
629
+ "sql": "SELECT * FROM \"api_keys\" WHERE (\"login\" = 'admin')",
630
+ "database_type": "postgres",
631
+ "server_version": 120003
632
+ }
633
+ },
634
+ {
635
+ "id": 33,
636
+ "event": "return",
637
+ "thread_id": 70143606759380,
638
+ "parent_id": 32,
639
+ "elapsed": 0.001134
640
+ },
641
+ {
642
+ "id": 34,
643
+ "event": "call",
644
+ "thread_id": 70143606759380,
645
+ "sql_query": {
646
+ "sql": "DELETE FROM \"api_keys\" WHERE \"id\" = 9",
647
+ "database_type": "postgres",
648
+ "server_version": 120003
649
+ }
650
+ },
651
+ {
652
+ "id": 35,
653
+ "event": "return",
654
+ "thread_id": 70143606759380,
655
+ "parent_id": 34,
656
+ "elapsed": 0.001028
657
+ },
658
+ {
659
+ "id": 36,
660
+ "event": "return",
661
+ "thread_id": 70143606759380,
662
+ "parent_id": 29,
663
+ "elapsed": 0.008962,
664
+ "return_value": {
665
+ "class": "DAO::ApiKey",
666
+ "value": "#<DAO::ApiKey:0x00007f972cfa8de8>",
667
+ "object_id": 70143635703540
668
+ }
669
+ },
670
+ {
671
+ "id": 37,
672
+ "event": "return",
673
+ "thread_id": 70143606759380,
674
+ "parent_id": 28,
675
+ "elapsed": 0.009195,
676
+ "return_value": {
677
+ "class": "String",
678
+ "value": "",
679
+ "object_id": 70143606590020
680
+ }
681
+ },
682
+ {
683
+ "id": 38,
684
+ "event": "return",
685
+ "thread_id": 70143606759380,
686
+ "parent_id": 7,
687
+ "elapsed": 0.163302,
688
+ "http_server_response": {
689
+ "mime_type": "application/json; charset=utf-8",
690
+ "status": 200
691
+ }
692
+ },
693
+ {
694
+ "id": 39,
695
+ "event": "call",
696
+ "thread_id": 70143606759380,
697
+ "http_server_request": {
698
+ "request_method": "DELETE",
699
+ "path_info": "/api/api_keys"
700
+ },
701
+ "message": [
702
+ {
703
+ "name": "controller",
704
+ "class": "String",
705
+ "value": "api/api_keys",
706
+ "object_id": 70143625900420
707
+ },
708
+ {
709
+ "name": "action",
710
+ "class": "String",
711
+ "value": "destroy",
712
+ "object_id": 70143625903660
713
+ }
714
+ ]
715
+ },
716
+ {
717
+ "id": 40,
718
+ "event": "call",
719
+ "thread_id": 70143606759380,
720
+ "defined_class": "ApiKey",
721
+ "method_id": "authenticate",
722
+ "path": "app/models/api_key.rb",
723
+ "lineno": 51,
724
+ "static": true,
725
+ "parameters": [
726
+ {
727
+ "name": "api_key",
728
+ "class": "String",
729
+ "object_id": 70143707623380,
730
+ "value": "YWRtaW46ZTU3YTgzMTAtZTcxOC00OTE0LWIzZmEtYjExZDRhMDY4N2Vl",
731
+ "kind": "req"
732
+ }
733
+ ],
734
+ "receiver": {
735
+ "class": "Class",
736
+ "object_id": 70143710327480,
737
+ "value": "ApiKey"
738
+ }
739
+ },
740
+ {
741
+ "id": 41,
742
+ "event": "call",
743
+ "thread_id": 70143606759380,
744
+ "defined_class": "ApiKey",
745
+ "method_id": "decode",
746
+ "path": "app/models/api_key.rb",
747
+ "lineno": 24,
748
+ "static": true,
749
+ "parameters": [
750
+ {
751
+ "name": "api_key",
752
+ "class": "String",
753
+ "object_id": 70143707623380,
754
+ "value": "YWRtaW46ZTU3YTgzMTAtZTcxOC00OTE0LWIzZmEtYjExZDRhMDY4N2Vl",
755
+ "kind": "req"
756
+ }
757
+ ],
758
+ "receiver": {
759
+ "class": "Class",
760
+ "object_id": 70143710327480,
761
+ "value": "ApiKey"
762
+ }
763
+ },
764
+ {
765
+ "id": 42,
766
+ "event": "return",
767
+ "thread_id": 70143606759380,
768
+ "parent_id": 41,
769
+ "elapsed": 0.000015,
770
+ "return_value": {
771
+ "class": "Array",
772
+ "value": "[\"admin\", \"e57a8310-e718-4914-b3fa-b11d4a0687ee\"]",
773
+ "object_id": 70143707620080
774
+ }
775
+ },
776
+ {
777
+ "id": 43,
778
+ "event": "call",
779
+ "thread_id": 70143606759380,
780
+ "sql_query": {
781
+ "sql": "SELECT * FROM \"api_keys\" WHERE (\"login\" = 'admin')",
782
+ "database_type": "postgres",
783
+ "server_version": 120003
784
+ }
785
+ },
786
+ {
787
+ "id": 44,
788
+ "event": "return",
789
+ "thread_id": 70143606759380,
790
+ "parent_id": 43,
791
+ "elapsed": 0.001356
792
+ },
793
+ {
794
+ "id": 45,
795
+ "event": "return",
796
+ "thread_id": 70143606759380,
797
+ "parent_id": 40,
798
+ "elapsed": 0.005355
799
+ },
800
+ {
801
+ "id": 46,
802
+ "event": "call",
803
+ "thread_id": 70143606759380,
804
+ "defined_class": "JSON::Ext::Generator::State",
805
+ "method_id": "generate",
806
+ "path": "JSON::Ext::Generator::State#generate",
807
+ "static": false,
808
+ "parameters": [
809
+ {
810
+ "name": "arg",
811
+ "class": "Hash",
812
+ "object_id": 70143708130600,
813
+ "value": "{\"error\"=>\"must provide authorization\"}",
814
+ "kind": "req"
815
+ }
816
+ ],
817
+ "receiver": {
818
+ "class": "JSON::Ext::Generator::State",
819
+ "object_id": 70143708130560,
820
+ "value": "#<JSON::Ext::Generator::State:0x00007f97359cda00>"
821
+ }
822
+ },
823
+ {
824
+ "id": 47,
825
+ "event": "return",
826
+ "thread_id": 70143606759380,
827
+ "parent_id": 46,
828
+ "elapsed": 0.00005,
829
+ "return_value": {
830
+ "class": "String",
831
+ "value": "{\"error\":\"must provide authorization\"}",
832
+ "object_id": 70143708128640
833
+ }
834
+ },
835
+ {
836
+ "id": 48,
837
+ "event": "return",
838
+ "thread_id": 70143606759380,
839
+ "parent_id": 39,
840
+ "elapsed": 0.006339,
841
+ "http_server_response": {
842
+ "mime_type": "application/json; charset=utf-8",
843
+ "status": 401
844
+ }
845
+ }
846
+ ]
847
+ }