skylight 5.0.1 → 5.1.1

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 (79) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +395 -364
  3. data/CLA.md +1 -1
  4. data/LICENSE.md +7 -17
  5. data/README.md +1 -1
  6. data/ext/extconf.rb +42 -54
  7. data/ext/libskylight.yml +9 -6
  8. data/lib/skylight.rb +20 -30
  9. data/lib/skylight/api.rb +22 -18
  10. data/lib/skylight/cli.rb +47 -46
  11. data/lib/skylight/cli/doctor.rb +50 -50
  12. data/lib/skylight/cli/helpers.rb +19 -19
  13. data/lib/skylight/cli/merger.rb +141 -139
  14. data/lib/skylight/config.rb +265 -300
  15. data/lib/skylight/deprecation.rb +4 -4
  16. data/lib/skylight/errors.rb +3 -4
  17. data/lib/skylight/extensions.rb +17 -29
  18. data/lib/skylight/extensions/source_location.rb +128 -128
  19. data/lib/skylight/formatters/http.rb +1 -3
  20. data/lib/skylight/gc.rb +30 -40
  21. data/lib/skylight/helpers.rb +43 -41
  22. data/lib/skylight/instrumenter.rb +25 -18
  23. data/lib/skylight/middleware.rb +31 -35
  24. data/lib/skylight/native.rb +8 -10
  25. data/lib/skylight/native_ext_fetcher.rb +10 -12
  26. data/lib/skylight/normalizers.rb +43 -39
  27. data/lib/skylight/normalizers/action_controller/process_action.rb +24 -25
  28. data/lib/skylight/normalizers/action_controller/send_file.rb +7 -6
  29. data/lib/skylight/normalizers/action_dispatch/route_set.rb +7 -7
  30. data/lib/skylight/normalizers/active_job/perform.rb +48 -44
  31. data/lib/skylight/normalizers/active_model_serializers/render.rb +7 -3
  32. data/lib/skylight/normalizers/active_storage.rb +11 -13
  33. data/lib/skylight/normalizers/active_support/cache.rb +1 -12
  34. data/lib/skylight/normalizers/coach/handler_finish.rb +1 -3
  35. data/lib/skylight/normalizers/default.rb +1 -9
  36. data/lib/skylight/normalizers/faraday/request.rb +1 -3
  37. data/lib/skylight/normalizers/grape/endpoint.rb +13 -19
  38. data/lib/skylight/normalizers/grape/endpoint_run.rb +16 -18
  39. data/lib/skylight/normalizers/grape/endpoint_run_filters.rb +1 -3
  40. data/lib/skylight/normalizers/graphql/base.rb +23 -28
  41. data/lib/skylight/normalizers/render.rb +19 -21
  42. data/lib/skylight/normalizers/shrine.rb +15 -17
  43. data/lib/skylight/normalizers/sql.rb +4 -4
  44. data/lib/skylight/probes.rb +38 -46
  45. data/lib/skylight/probes/action_controller.rb +32 -28
  46. data/lib/skylight/probes/action_dispatch/request_id.rb +9 -5
  47. data/lib/skylight/probes/action_dispatch/routing/route_set.rb +7 -5
  48. data/lib/skylight/probes/action_view.rb +9 -10
  49. data/lib/skylight/probes/active_job_enqueue.rb +3 -9
  50. data/lib/skylight/probes/active_model_serializers.rb +8 -8
  51. data/lib/skylight/probes/delayed_job.rb +37 -42
  52. data/lib/skylight/probes/elasticsearch.rb +3 -5
  53. data/lib/skylight/probes/excon.rb +1 -1
  54. data/lib/skylight/probes/excon/middleware.rb +22 -23
  55. data/lib/skylight/probes/graphql.rb +2 -7
  56. data/lib/skylight/probes/middleware.rb +14 -5
  57. data/lib/skylight/probes/mongo.rb +83 -91
  58. data/lib/skylight/probes/net_http.rb +1 -1
  59. data/lib/skylight/probes/redis.rb +5 -17
  60. data/lib/skylight/probes/sequel.rb +7 -11
  61. data/lib/skylight/probes/sinatra.rb +8 -5
  62. data/lib/skylight/probes/tilt.rb +2 -4
  63. data/lib/skylight/railtie.rb +121 -135
  64. data/lib/skylight/sidekiq.rb +4 -5
  65. data/lib/skylight/subscriber.rb +31 -33
  66. data/lib/skylight/test.rb +89 -84
  67. data/lib/skylight/trace.rb +121 -115
  68. data/lib/skylight/user_config.rb +14 -17
  69. data/lib/skylight/util/clock.rb +1 -0
  70. data/lib/skylight/util/component.rb +18 -21
  71. data/lib/skylight/util/deploy.rb +11 -13
  72. data/lib/skylight/util/http.rb +104 -105
  73. data/lib/skylight/util/logging.rb +4 -6
  74. data/lib/skylight/util/lru_cache.rb +2 -6
  75. data/lib/skylight/util/platform.rb +2 -6
  76. data/lib/skylight/util/ssl.rb +1 -25
  77. data/lib/skylight/version.rb +1 -1
  78. data/lib/skylight/vm/gc.rb +1 -9
  79. metadata +6 -6
@@ -14,27 +14,25 @@ module Skylight
14
14
 
15
15
  private
16
16
 
17
- def get_endpoint_name(endpoint)
18
- method = get_method(endpoint)
19
- path = get_path(endpoint)
20
- namespace = get_namespace(endpoint)
21
-
22
- if namespace && !namespace.empty?
23
- path = "/#{path}" if path[0] != "/"
24
- path = "#{namespace}#{path}"
25
- end
26
-
27
- "#{base_app_name(endpoint)} [#{method}] #{path}".strip
17
+ def get_endpoint_name(endpoint)
18
+ method = get_method(endpoint)
19
+ path = get_path(endpoint)
20
+ namespace = get_namespace(endpoint)
21
+
22
+ if namespace && !namespace.empty?
23
+ path = "/#{path}" if path[0] != "/"
24
+ path = "#{namespace}#{path}"
28
25
  end
29
26
 
30
- def base_app_name(endpoint)
31
- ep = endpoint.options[:for]
32
- return ep.name if ep.name
27
+ "#{base_app_name(endpoint)} [#{method}] #{path}".strip
28
+ end
29
+
30
+ def base_app_name(endpoint)
31
+ ep = endpoint.options[:for]
32
+ return ep.name if ep.name
33
33
 
34
- if ep.respond_to?(:base) && ep.base.respond_to?(:name)
35
- ep.base.name
36
- end
37
- end
34
+ ep.base.name if ep.respond_to?(:base) && ep.base.respond_to?(:name)
35
+ end
38
36
  end
39
37
  end
40
38
  end
@@ -10,9 +10,7 @@ module Skylight
10
10
  filters = payload[:filters]
11
11
  type = payload[:type]
12
12
 
13
- if (!filters || filters.empty?) || !type
14
- return :skip
15
- end
13
+ return :skip if (!filters || filters.empty?) || !type
16
14
 
17
15
  [CAT, "#{type.to_s.capitalize} Filters", nil]
18
16
  end
@@ -25,12 +25,7 @@ module Skylight::Normalizers::GraphQL
25
25
 
26
26
  def self.inherited(klass)
27
27
  super
28
- klass.const_set(
29
- :KEY,
30
- ActiveSupport::Inflector.underscore(
31
- ActiveSupport::Inflector.demodulize(klass.name)
32
- ).freeze
33
- )
28
+ klass.const_set(:KEY, ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(klass.name)).freeze)
34
29
  end
35
30
 
36
31
  def self.key
@@ -43,15 +38,13 @@ module Skylight::Normalizers::GraphQL
43
38
 
44
39
  private
45
40
 
46
- def key
47
- self.class.key
48
- end
41
+ def key
42
+ self.class.key
43
+ end
49
44
 
50
- def extract_query_name(query)
51
- query&.context&.[](:skylight_endpoint) ||
52
- query&.operation_name ||
53
- ANONYMOUS
54
- end
45
+ def extract_query_name(query)
46
+ query&.context&.[](:skylight_endpoint) || query&.operation_name || ANONYMOUS
47
+ end
55
48
  end
56
49
 
57
50
  class Lex < Base
@@ -82,17 +75,21 @@ module Skylight::Normalizers::GraphQL
82
75
  # In graphql-ruby's case, the calculation of the operation name is lazy, and
83
76
  # has not been done yet at the point where execute_multiplex starts.
84
77
  # [1] https://graphql.org/learn/serving-over-http/#post-request
85
- queries, has_errors = payload[:multiplex].queries.each_with_object([Set.new, Set.new]) do |query, (names, errors)|
86
- names << extract_query_name(query)
87
- errors << query.static_errors.any?
88
- end
89
-
90
- trace.endpoint = "graphql:#{queries.sort.join('+')}"
91
- trace.compound_response_error_status = if has_errors.all?
92
- :all
93
- elsif has_errors.any?
94
- :partial
95
- end
78
+ queries, has_errors =
79
+ payload[:multiplex]
80
+ .queries
81
+ .each_with_object([Set.new, Set.new]) do |query, (names, errors)|
82
+ names << extract_query_name(query)
83
+ errors << query.static_errors.any?
84
+ end
85
+
86
+ trace.endpoint = "graphql:#{queries.sort.join("+")}"
87
+ trace.compound_response_error_status =
88
+ if has_errors.all?
89
+ :all
90
+ elsif has_errors.any?
91
+ :partial
92
+ end
96
93
  end
97
94
  end
98
95
 
@@ -106,9 +103,7 @@ module Skylight::Normalizers::GraphQL
106
103
  def normalize(trace, _name, payload)
107
104
  query_name = extract_query_name(payload[:query])
108
105
 
109
- if query_name == ANONYMOUS
110
- meta = { mute_children: true }
111
- end
106
+ meta = { mute_children: true } if query_name == ANONYMOUS
112
107
 
113
108
  # This is probably always overriden by execute_multiplex#normalize_after,
114
109
  # but in the case of a single query, it will be the same value anyway.
@@ -50,32 +50,30 @@ module Skylight
50
50
 
51
51
  private
52
52
 
53
- def relative_path?(path)
54
- !absolute_path?(path)
55
- end
53
+ def relative_path?(path)
54
+ !absolute_path?(path)
55
+ end
56
56
 
57
- SEPARATOR_BYTE = File::SEPARATOR.ord
57
+ SEPARATOR_BYTE = File::SEPARATOR.ord
58
58
 
59
- if File.const_defined?(:NULL) ? File::NULL == "NUL" : RbConfig::CONFIG["host_os"] =~ /mingw|mswin32/
60
- # This is a DOSish environment
61
- ALT_SEPARATOR_BYTE = File::ALT_SEPARATOR&.ord
62
- COLON_BYTE = ":".ord
63
- SEPARATOR_BYTES = [SEPARATOR_BYTE, ALT_SEPARATOR_BYTE].freeze
59
+ if File.const_defined?(:NULL) ? File::NULL == "NUL" : RbConfig::CONFIG["host_os"] =~ /mingw|mswin32/
60
+ # This is a DOSish environment
61
+ ALT_SEPARATOR_BYTE = File::ALT_SEPARATOR&.ord
62
+ COLON_BYTE = ":".ord
63
+ SEPARATOR_BYTES = [SEPARATOR_BYTE, ALT_SEPARATOR_BYTE].freeze
64
64
 
65
- def absolute_path?(path)
66
- if alpha?(path.getbyte(0)) && path.getbyte(1) == COLON_BYTE
67
- SEPARATOR_BYTES.include?(path.getbyte(2))
68
- end
69
- end
65
+ def absolute_path?(path)
66
+ SEPARATOR_BYTES.include?(path.getbyte(2)) if alpha?(path.getbyte(0)) && path.getbyte(1) == COLON_BYTE
67
+ end
70
68
 
71
- def alpha?(byte)
72
- (byte >= 65 && byte <= 90) || (byte >= 97 && byte <= 122)
73
- end
74
- else
75
- def absolute_path?(path)
76
- path.getbyte(0) == SEPARATOR_BYTE
77
- end
69
+ def alpha?(byte)
70
+ (byte >= 65 && byte <= 90) || (byte >= 97 && byte <= 122)
71
+ end
72
+ else
73
+ def absolute_path?(path)
74
+ path.getbyte(0) == SEPARATOR_BYTE
78
75
  end
76
+ end
79
77
  end
80
78
  end
81
79
  end
@@ -2,30 +2,28 @@ module Skylight
2
2
  module Normalizers
3
3
  class Shrine < Normalizer
4
4
  TITLES = {
5
- "upload.shrine" => "Upload",
6
- "download.shrine" => "Download",
7
- "open.shrine" => "Open",
8
- "exists.shrine" => "Exists",
9
- "delete.shrine" => "Delete",
10
- "metadata.shrine" => "Metadata",
11
- "mime_type.shrine" => "MIME Type",
5
+ "upload.shrine" => "Upload",
6
+ "download.shrine" => "Download",
7
+ "open.shrine" => "Open",
8
+ "exists.shrine" => "Exists",
9
+ "delete.shrine" => "Delete",
10
+ "metadata.shrine" => "Metadata",
11
+ "mime_type.shrine" => "MIME Type",
12
12
  "image_dimensions.shrine" => "Image Dimensions",
13
- "signature.shrine" => "Signature",
14
- "extension.shrine" => "Extension",
15
- "derivation.shrine" => "Derivation",
16
- "derivatives.shrine" => "Derivatives",
17
- "data_uri.shrine" => "Data URI",
18
- "remote_url.shrine" => "Remote URL"
13
+ "signature.shrine" => "Signature",
14
+ "extension.shrine" => "Extension",
15
+ "derivation.shrine" => "Derivation",
16
+ "derivatives.shrine" => "Derivatives",
17
+ "data_uri.shrine" => "Data URI",
18
+ "remote_url.shrine" => "Remote URL"
19
19
  }.freeze
20
20
 
21
- TITLES.each_key do |key|
22
- register key
23
- end
21
+ TITLES.each_key { |key| register key }
24
22
 
25
23
  def normalize(_trace, name, _payload)
26
24
  title = ["Shrine", TITLES[name]].join(" ")
27
25
 
28
- cat = "app.#{name.split('.').reverse.join('.')}"
26
+ cat = "app.#{name.split(".").reverse.join(".")}"
29
27
 
30
28
  [cat, title, nil]
31
29
  end
@@ -19,7 +19,7 @@ module Skylight
19
19
  when "SCHEMA", "CACHE"
20
20
  return :skip
21
21
  else
22
- name = CAT
22
+ name = CAT
23
23
  title = payload[:name] || "SQL"
24
24
  end
25
25
 
@@ -30,9 +30,9 @@ module Skylight
30
30
  unless sql.valid_encoding?
31
31
  if config[:log_sql_parse_errors]
32
32
  config.logger.error "[#{Skylight::SqlLexError.formatted_code}] Unable to extract binds from non-UTF-8 " \
33
- "query. " \
34
- "encoding=#{payload[:sql].encoding.name} " \
35
- "sql=#{payload[:sql].inspect} "
33
+ "query. " \
34
+ "encoding=#{payload[:sql].encoding.name} " \
35
+ "sql=#{payload[:sql].inspect} "
36
36
  end
37
37
 
38
38
  sql = nil
@@ -26,31 +26,35 @@ module Skylight
26
26
 
27
27
  private
28
28
 
29
- def log_install_exception(err)
30
- description = err.class.to_s
31
- description << ": #{err.message}" unless err.message.empty?
32
-
33
- backtrace = err.backtrace.map { |l| " #{l}" }.join("\n")
34
-
35
- gems =
36
- begin
37
- Bundler.locked_gems.dependencies.map { |d| [d.name, d.requirement.to_s] }
38
- rescue # rubocop:disable Lint/SuppressedException
39
- end
40
-
41
- error = "[SKYLIGHT] [#{Skylight::VERSION}] Encountered an error while installing the " \
42
- "probe for #{const_name}. Please notify support@skylight.io with the debugging " \
43
- "information below. It's recommended that you disable this probe until the " \
44
- "issue is resolved." \
45
- "\n\nERROR: #{description}\n\n#{backtrace}\n\n"
46
-
47
- if gems
48
- gems_string = gems.map { |g| " #{g[0]} #{g[1]}" }.join("\n")
49
- error << "GEMS:\n\n#{gems_string}\n\n"
29
+ def log_install_exception(err)
30
+ description = err.class.to_s
31
+ description << ": #{err.message}" unless err.message.empty?
32
+
33
+ backtrace = err.backtrace.map { |l| " #{l}" }.join("\n")
34
+
35
+ # rubocop:disable Lint/SuppressedException
36
+ gems =
37
+ begin
38
+ Bundler.locked_gems.dependencies.map { |d| [d.name, d.requirement.to_s] }
39
+ rescue StandardError
50
40
  end
51
41
 
52
- $stderr.puts(error)
42
+ # rubocop:enable Lint/SuppressedException
43
+
44
+ error =
45
+ "[SKYLIGHT] [#{Skylight::VERSION}] Encountered an error while installing the " \
46
+ "probe for #{const_name}. Please notify support@skylight.io with the debugging " \
47
+ "information below. It's recommended that you disable this probe until the " \
48
+ "issue is resolved." \
49
+ "\n\nERROR: #{description}\n\n#{backtrace}\n\n"
50
+
51
+ if gems
52
+ gems_string = gems.map { |g| " #{g[0]} #{g[1]}" }.join("\n")
53
+ error << "GEMS:\n\n#{gems_string}\n\n"
53
54
  end
55
+
56
+ $stderr.puts(error)
57
+ end
54
58
  end
55
59
 
56
60
  class << self
@@ -62,11 +66,7 @@ module Skylight
62
66
  pending = registered.values - installed.values
63
67
 
64
68
  pending.each do |registration|
65
- if registration.constant_available?
66
- install_probe(registration)
67
- else
68
- register_require_hook(registration)
69
- end
69
+ registration.constant_available? ? install_probe(registration) : register_require_hook(registration)
70
70
  end
71
71
  end
72
72
 
@@ -79,14 +79,14 @@ module Skylight
79
79
 
80
80
  def add_path(path)
81
81
  root = Pathname.new(path)
82
- Pathname.glob(root.join("./**/*.rb")).each do |f|
83
- name = f.relative_path_from(root).sub_ext("").to_s
84
- if available.key?(name)
85
- raise "duplicate probe name: #{name}; original=#{available[name]}; new=#{f}"
86
- end
82
+ Pathname
83
+ .glob(root.join("./**/*.rb"))
84
+ .each do |f|
85
+ name = f.relative_path_from(root).sub_ext("").to_s
86
+ raise "duplicate probe name: #{name}; original=#{available[name]}; new=#{f}" if available.key?(name)
87
87
 
88
- available[name] = f
89
- end
88
+ available[name] = f
89
+ end
90
90
  end
91
91
 
92
92
  def available
@@ -95,13 +95,9 @@ module Skylight
95
95
 
96
96
  def probe(*probes)
97
97
  unknown = probes.map(&:to_s) - available.keys
98
- unless unknown.empty?
99
- raise ArgumentError, "unknown probes: #{unknown.join(', ')}"
100
- end
98
+ raise ArgumentError, "unknown probes: #{unknown.join(", ")}" unless unknown.empty?
101
99
 
102
- probes.each do |p|
103
- require available[p.to_s]
104
- end
100
+ probes.each { |p| require available[p.to_s] }
105
101
  end
106
102
 
107
103
  def registered
@@ -117,9 +113,7 @@ module Skylight
117
113
  end
118
114
 
119
115
  def register(name, *args)
120
- if registered.key?(name)
121
- raise "already registered: #{name}"
122
- end
116
+ raise "already registered: #{name}" if registered.key?(name)
123
117
 
124
118
  registered[name] = ProbeRegistration.new(name, *args)
125
119
 
@@ -156,9 +150,7 @@ module Skylight
156
150
  return unless require_hooks.key?(require_path)
157
151
 
158
152
  # dup because we may be mutating the array
159
- require_hooks[require_path].dup.each do |registration|
160
- yield registration
161
- end
153
+ require_hooks[require_path].dup.each { |registration| yield registration }
162
154
  end
163
155
  end
164
156
 
@@ -7,42 +7,46 @@ module Skylight
7
7
  ::ActionController::Instrumentation.class_eval do
8
8
  private
9
9
 
10
- alias_method :append_info_to_payload_without_sk, :append_info_to_payload
11
- def append_info_to_payload(payload)
12
- append_info_to_payload_without_sk(payload)
10
+ alias_method :append_info_to_payload_without_sk, :append_info_to_payload
11
+ def append_info_to_payload(payload)
12
+ append_info_to_payload_without_sk(payload)
13
13
 
14
- payload[:sk_rendered_format] = sk_rendered_mime.try(:ref)
15
- payload[:sk_variant] = request.respond_to?(:variant) ? request.variant : nil
16
- end
14
+ payload[:sk_rendered_format] = sk_rendered_mime.try(:ref)
15
+ payload[:sk_variant] = request.respond_to?(:variant) ? request.variant : nil
16
+ end
17
17
 
18
- def sk_rendered_mime
19
- if respond_to?(:media_type)
20
- mt = media_type
21
- return mt && Mime::Type.lookup(mt)
22
- end
18
+ def sk_rendered_mime
19
+ if respond_to?(:media_type)
20
+ mt = media_type
21
+ return mt && Mime::Type.lookup(mt)
22
+ end
23
23
 
24
- if content_type.is_a?(Mime::Type)
25
- content_type
26
- elsif content_type.respond_to?(:to_s)
27
- type_str = content_type.to_s.split(";").first
28
- Mime::Type.lookup(type_str) unless type_str.blank?
29
- elsif respond_to?(:rendered_format) && rendered_format
30
- rendered_format
31
- end
32
- rescue
33
- # There are cases in which actionpack can return
34
- # a stringified representation of a Mime::NullType instance,
35
- # which is invalid for a number of reasons. This string raises
36
- # errors when piped through Mime::Type.lookup, so it's probably
37
- # best to just return nil in those cases.
38
- nil
24
+ if content_type.is_a?(Mime::Type)
25
+ content_type
26
+ elsif content_type.respond_to?(:to_s)
27
+ type_str = content_type.to_s.split(";").first
28
+ Mime::Type.lookup(type_str) unless type_str.blank?
29
+ elsif respond_to?(:rendered_format) && rendered_format
30
+ rendered_format
39
31
  end
32
+ rescue StandardError
33
+ # There are cases in which actionpack can return
34
+ # a stringified representation of a Mime::NullType instance,
35
+ # which is invalid for a number of reasons. This string raises
36
+ # errors when piped through Mime::Type.lookup, so it's probably
37
+ # best to just return nil in those cases.
38
+ nil
39
+ end
40
40
  end
41
41
  end
42
42
  end
43
43
  end
44
44
 
45
- register(:action_controller, "ActionController::Instrumentation", "action_controller/metal/instrumentation",
46
- ActionController::Probe.new)
45
+ register(
46
+ :action_controller,
47
+ "ActionController::Instrumentation",
48
+ "action_controller/metal/instrumentation",
49
+ ActionController::Probe.new
50
+ )
47
51
  end
48
52
  end