skylight 4.3.2 → 5.0.0.beta

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 (112) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +14 -5
  3. data/CONTRIBUTING.md +1 -7
  4. data/ext/extconf.rb +4 -3
  5. data/ext/libskylight.yml +5 -6
  6. data/ext/skylight_native.c +22 -99
  7. data/lib/skylight.rb +204 -14
  8. data/lib/skylight/api.rb +7 -3
  9. data/lib/skylight/cli.rb +4 -3
  10. data/lib/skylight/cli/doctor.rb +3 -2
  11. data/lib/skylight/cli/merger.rb +6 -4
  12. data/lib/skylight/config.rb +603 -126
  13. data/lib/skylight/deprecation.rb +15 -0
  14. data/lib/skylight/errors.rb +17 -2
  15. data/lib/skylight/extensions.rb +99 -0
  16. data/lib/skylight/extensions/source_location.rb +249 -0
  17. data/lib/skylight/fanout.rb +0 -0
  18. data/lib/skylight/formatters/http.rb +19 -0
  19. data/lib/skylight/gc.rb +109 -0
  20. data/lib/skylight/helpers.rb +18 -2
  21. data/lib/skylight/instrumenter.rb +325 -15
  22. data/lib/skylight/middleware.rb +138 -1
  23. data/lib/skylight/native.rb +51 -1
  24. data/lib/skylight/native_ext_fetcher.rb +2 -1
  25. data/lib/skylight/normalizers.rb +151 -0
  26. data/lib/skylight/normalizers/action_controller/process_action.rb +69 -0
  27. data/lib/skylight/normalizers/action_controller/send_file.rb +50 -0
  28. data/lib/skylight/normalizers/action_dispatch/process_middleware.rb +22 -0
  29. data/lib/skylight/normalizers/action_dispatch/route_set.rb +27 -0
  30. data/lib/skylight/normalizers/action_view/render_collection.rb +24 -0
  31. data/lib/skylight/normalizers/action_view/render_layout.rb +25 -0
  32. data/lib/skylight/normalizers/action_view/render_partial.rb +23 -0
  33. data/lib/skylight/normalizers/action_view/render_template.rb +23 -0
  34. data/lib/skylight/normalizers/active_job/perform.rb +81 -0
  35. data/lib/skylight/normalizers/active_model_serializers/render.rb +28 -0
  36. data/lib/skylight/normalizers/active_record/instantiation.rb +16 -0
  37. data/lib/skylight/normalizers/active_record/sql.rb +12 -0
  38. data/lib/skylight/normalizers/active_storage.rb +30 -0
  39. data/lib/skylight/normalizers/active_support/cache.rb +22 -0
  40. data/lib/skylight/normalizers/active_support/cache_clear.rb +16 -0
  41. data/lib/skylight/normalizers/active_support/cache_decrement.rb +16 -0
  42. data/lib/skylight/normalizers/active_support/cache_delete.rb +16 -0
  43. data/lib/skylight/normalizers/active_support/cache_exist.rb +16 -0
  44. data/lib/skylight/normalizers/active_support/cache_fetch_hit.rb +16 -0
  45. data/lib/skylight/normalizers/active_support/cache_generate.rb +16 -0
  46. data/lib/skylight/normalizers/active_support/cache_increment.rb +16 -0
  47. data/lib/skylight/normalizers/active_support/cache_read.rb +16 -0
  48. data/lib/skylight/normalizers/active_support/cache_read_multi.rb +16 -0
  49. data/lib/skylight/normalizers/active_support/cache_write.rb +16 -0
  50. data/lib/skylight/normalizers/coach/handler_finish.rb +46 -0
  51. data/lib/skylight/normalizers/coach/middleware_finish.rb +33 -0
  52. data/lib/skylight/normalizers/couch_potato/query.rb +20 -0
  53. data/lib/skylight/normalizers/data_mapper/sql.rb +12 -0
  54. data/lib/skylight/normalizers/default.rb +32 -0
  55. data/lib/skylight/normalizers/elasticsearch/request.rb +20 -0
  56. data/lib/skylight/normalizers/faraday/request.rb +40 -0
  57. data/lib/skylight/normalizers/grape/endpoint.rb +34 -0
  58. data/lib/skylight/normalizers/grape/endpoint_render.rb +25 -0
  59. data/lib/skylight/normalizers/grape/endpoint_run.rb +41 -0
  60. data/lib/skylight/normalizers/grape/endpoint_run_filters.rb +22 -0
  61. data/lib/skylight/normalizers/grape/format_response.rb +20 -0
  62. data/lib/skylight/normalizers/graphiti/render.rb +22 -0
  63. data/lib/skylight/normalizers/graphiti/resolve.rb +31 -0
  64. data/lib/skylight/normalizers/graphql/base.rb +131 -0
  65. data/lib/skylight/normalizers/render.rb +81 -0
  66. data/lib/skylight/normalizers/sequel/sql.rb +12 -0
  67. data/lib/skylight/normalizers/sql.rb +44 -0
  68. data/lib/skylight/probes.rb +153 -0
  69. data/lib/skylight/probes/action_controller.rb +48 -0
  70. data/lib/skylight/probes/action_dispatch.rb +2 -0
  71. data/lib/skylight/probes/action_dispatch/request_id.rb +29 -0
  72. data/lib/skylight/probes/action_dispatch/routing/route_set.rb +28 -0
  73. data/lib/skylight/probes/action_view.rb +43 -0
  74. data/lib/skylight/probes/active_job.rb +29 -0
  75. data/lib/skylight/probes/active_job_enqueue.rb +37 -0
  76. data/lib/skylight/probes/active_model_serializers.rb +54 -0
  77. data/lib/skylight/probes/delayed_job.rb +62 -0
  78. data/lib/skylight/probes/elasticsearch.rb +38 -0
  79. data/lib/skylight/probes/excon.rb +25 -0
  80. data/lib/skylight/probes/excon/middleware.rb +66 -0
  81. data/lib/skylight/probes/faraday.rb +23 -0
  82. data/lib/skylight/probes/graphql.rb +43 -0
  83. data/lib/skylight/probes/httpclient.rb +44 -0
  84. data/lib/skylight/probes/middleware.rb +125 -0
  85. data/lib/skylight/probes/mongo.rb +163 -0
  86. data/lib/skylight/probes/mongoid.rb +13 -0
  87. data/lib/skylight/probes/net_http.rb +55 -0
  88. data/lib/skylight/probes/redis.rb +60 -0
  89. data/lib/skylight/probes/sequel.rb +33 -0
  90. data/lib/skylight/probes/sinatra.rb +63 -0
  91. data/lib/skylight/probes/sinatra_add_middleware.rb +10 -10
  92. data/lib/skylight/probes/tilt.rb +27 -0
  93. data/lib/skylight/railtie.rb +162 -18
  94. data/lib/skylight/sidekiq.rb +43 -0
  95. data/lib/skylight/subscriber.rb +110 -0
  96. data/lib/skylight/test.rb +146 -0
  97. data/lib/skylight/trace.rb +301 -10
  98. data/lib/skylight/user_config.rb +61 -0
  99. data/lib/skylight/util.rb +12 -0
  100. data/lib/skylight/util/allocation_free.rb +26 -0
  101. data/lib/skylight/util/clock.rb +56 -0
  102. data/lib/skylight/util/component.rb +5 -2
  103. data/lib/skylight/util/deploy.rb +4 -4
  104. data/lib/skylight/util/gzip.rb +20 -0
  105. data/lib/skylight/util/http.rb +4 -10
  106. data/lib/skylight/util/instrumenter_method.rb +26 -0
  107. data/lib/skylight/util/logging.rb +138 -0
  108. data/lib/skylight/util/lru_cache.rb +42 -0
  109. data/lib/skylight/vendor/cli/thor/rake_compat.rb +1 -1
  110. data/lib/skylight/version.rb +5 -1
  111. data/lib/skylight/vm/gc.rb +68 -0
  112. metadata +110 -11
@@ -1,6 +1,55 @@
1
1
  require "skylight/util/platform"
2
2
 
3
3
  module Skylight
4
+ # Some methods exepected to be defined by the native code (OUTDATED)
5
+ #
6
+ # * Skylight::Util::Clock#native_hrtime
7
+ # - returns current time in nanoseconds
8
+ # * Skylight::Trace#native_new(start, uuid, endpoint)
9
+ # - start is milliseconds
10
+ # - uuid is currently unused
11
+ # - endpoint is the endpoint name
12
+ # - returns an instance of Trace
13
+ # * Skylight::Trace#native_get_started_at
14
+ # - returns the start time
15
+ # * Skylight::Trace#native_get_endpoint
16
+ # - returns the endpoint name
17
+ # * Skylight::Trace#native_set_endpoint(endpoint)
18
+ # - returns nil
19
+ # * Skylight::Trace#native_get_uuid
20
+ # - returns the uuid
21
+ # * Skylight::Trace#native_start_span(time, category)
22
+ # - time is milliseconds
23
+ # - category is a string
24
+ # - returns a numeric span id
25
+ # * Skylight::Trace#native_stop_span(span, time)
26
+ # - span is the span id
27
+ # - time is milliseconds
28
+ # - returns nil
29
+ # * Skylight::Trace#native_span_set_title(span, title)
30
+ # - span is the span id
31
+ # - title is a string
32
+ # - returns nil
33
+ # * Skylight::Trace#native_span_set_description(span, desc)
34
+ # - span is the span id
35
+ # - desc is a string
36
+ # - returns nil
37
+ # * Skylight::Instrumenter#native_new(env)
38
+ # - env is the config converted to a flattened array of ENV style values
39
+ # e.g. `["SKYLIGHT_AUTHENTICATION", "abc123", ...]
40
+ # - returns a new Instrumenter instance
41
+ # * Skylight::Instrumenter#native_start()
42
+ # - returns a truthy value if successful
43
+ # * Skylight::Instrumenter#native_stop()
44
+ # - returns nil
45
+ # * Skylight::Instrumenter#native_submit_trace(trace)
46
+ # - trace is a Trace instance
47
+ # - returns nil
48
+ # * Skylight::Instrumenter#native_track_desc(endpoint, description)
49
+ # - endpoint is a string
50
+ # - description is a string
51
+ # - returns truthy unless uniqueness cap exceeded
52
+
4
53
  # @api private
5
54
  # Whether or not the native extension is present
6
55
  @has_native_ext = false
@@ -40,7 +89,8 @@ module Skylight
40
89
  end
41
90
 
42
91
  if Skylight.native?
43
- Skylight::Core::Util::Clock.use_native!
92
+ require "skylight/util/clock"
93
+ Util::Clock.use_native!
44
94
  else
45
95
  class Instrumenter
46
96
  def self.native_new(*_args)
@@ -112,7 +112,8 @@ module Skylight
112
112
  rescue => e
113
113
  remaining_attempts -= 1
114
114
 
115
- error "failed to fetch native extension; uri=#{uri}; msg=#{e.message}; remaining-attempts=#{remaining_attempts}", e
115
+ error "failed to fetch native extension; uri=#{uri}; msg=#{e.message}; " \
116
+ "remaining-attempts=#{remaining_attempts}", e
116
117
 
117
118
  if remaining_attempts > 0
118
119
  sleep 2
@@ -0,0 +1,151 @@
1
+ module Skylight
2
+ # @api private
3
+ # Convert AS::N events to Skylight events
4
+ module Normalizers
5
+ def self.registry
6
+ @registry ||= {}
7
+ end
8
+
9
+ def self.register(name, klass, opts = {})
10
+ enabled = opts[:enabled] != false
11
+ registry[name] = [klass, enabled]
12
+ end
13
+
14
+ def self.unregister(name)
15
+ @registry.delete(name)
16
+ end
17
+
18
+ def self.enable(*names, enabled: true)
19
+ names.each do |name|
20
+ matches = registry.select { |n, _| n =~ /(^|\.)#{name}$/ }
21
+ raise ArgumentError, "no normalizers match #{name}" if matches.empty?
22
+
23
+ matches.values.each { |v| v[1] = enabled }
24
+ end
25
+ end
26
+
27
+ def self.disable(*names)
28
+ enable(*names, enabled: false)
29
+ end
30
+
31
+ def self.build(config)
32
+ normalizers = {}
33
+
34
+ registry.each do |key, (klass, enabled)|
35
+ next unless enabled
36
+
37
+ unless klass.method_defined?(:normalize)
38
+ # TODO: Warn
39
+ next
40
+ end
41
+
42
+ normalizers[key] = klass.new(config)
43
+ end
44
+
45
+ Container.new(normalizers)
46
+ end
47
+
48
+ class Normalizer
49
+ def self.register(name, opts = {})
50
+ Normalizers.register(name, self, opts)
51
+ end
52
+
53
+ attr_reader :config
54
+
55
+ include Util::Logging
56
+
57
+ def initialize(config)
58
+ @config = config
59
+ setup if respond_to?(:setup)
60
+ end
61
+
62
+ def normalize(_trace, _name, _payload)
63
+ :skip
64
+ end
65
+
66
+ def normalize_with_meta(trace, name, payload)
67
+ # If we have a normal response but no meta, add it
68
+ cat, title, desc, meta = ret = normalize(trace, name, payload)
69
+ return cat if cat == :skip
70
+
71
+ meta ||= {}
72
+ process_meta(trace, name, payload, meta, cache_key: ret.hash)
73
+
74
+ [cat, title, desc, meta]
75
+ end
76
+
77
+ def normalize_after(trace, span, name, payload); end
78
+
79
+ private
80
+
81
+ def process_meta(trace, name, payload, meta, cache_key: nil)
82
+ trace.instrumenter.extensions.process_normalizer_meta(
83
+ payload,
84
+ meta,
85
+ cache_key: cache_key,
86
+ **process_meta_options(payload)
87
+ )
88
+ end
89
+
90
+ def process_meta_options(_payload)
91
+ {}
92
+ end
93
+ end
94
+
95
+ require "skylight/normalizers/default"
96
+ DEFAULT = Default.new
97
+
98
+ class Container
99
+ def initialize(normalizers)
100
+ @normalizers = normalizers
101
+ end
102
+
103
+ def keys
104
+ @normalizers.keys
105
+ end
106
+
107
+ def normalize(trace, name, payload)
108
+ normalizer_for(name).normalize_with_meta(trace, name, payload)
109
+ end
110
+
111
+ def normalize_after(trace, span, name, payload)
112
+ normalizer_for(name).normalize_after(trace, span, name, payload)
113
+ end
114
+
115
+ def normalizer_for(name)
116
+ # We never expect to hit the default case since we only register listeners
117
+ # for items that we know have normalizers. For now, though, we'll play it
118
+ # safe and provide a fallback.
119
+ @normalizers.fetch(name, DEFAULT)
120
+ end
121
+ end
122
+
123
+ %w[ action_controller/process_action
124
+ action_controller/send_file
125
+ action_dispatch/process_middleware
126
+ action_dispatch/route_set
127
+ action_view/render_collection
128
+ action_view/render_partial
129
+ action_view/render_template
130
+ action_view/render_layout
131
+ active_job/perform
132
+ active_model_serializers/render
133
+ active_record/instantiation
134
+ active_record/sql
135
+ active_storage
136
+ active_support/cache
137
+ coach/handler_finish
138
+ coach/middleware_finish
139
+ couch_potato/query
140
+ data_mapper/sql
141
+ elasticsearch/request
142
+ faraday/request
143
+ grape/endpoint
144
+ graphiti/resolve
145
+ graphiti/render
146
+ graphql/base
147
+ sequel/sql].each do |file|
148
+ require "skylight/normalizers/#{file}"
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,69 @@
1
+ module Skylight
2
+ module Normalizers
3
+ module ActionController
4
+ # Normalizer for processing a Rails controller action
5
+ class ProcessAction < Normalizer
6
+ register "process_action.action_controller"
7
+
8
+ CAT = "app.controller.request".freeze
9
+
10
+ # Payload Keys: controller, action, params, format, method, path
11
+ # Additional keys available in `normalize_after`: status, view_runtime
12
+ # Along with ones added by probe: variant
13
+
14
+ # @param trace [Skylight::Messages::Trace::Builder]
15
+ # @param name [String] ignored, only present to match API
16
+ # @param payload [Hash]
17
+ # @option payload [String] :controller Controller name
18
+ # @option payload [String] :action Action name
19
+ # @return [Array]
20
+ def normalize(trace, _name, payload)
21
+ trace.endpoint = controller_action(payload)
22
+ [CAT, trace.endpoint, nil]
23
+ end
24
+
25
+ def normalize_after(trace, _span, _name, payload)
26
+ return unless config.enable_segments?
27
+
28
+ if (segment = segment_from_payload(payload))
29
+ trace.segment = segment
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def controller_action(payload)
36
+ "#{payload[:controller]}##{payload[:action]}"
37
+ end
38
+
39
+ def process_meta_options(payload)
40
+ # provide hints to override default source_location behavior
41
+ super.merge(source_location: [:instance_method, payload[:controller], payload[:action]])
42
+ end
43
+
44
+ def segment_from_payload(payload)
45
+ # Show 'error' if there's an unhandled exception or if the status is 4xx or 5xx
46
+ return "error" if payload[:exception] || payload[:exception_object]
47
+
48
+ segment_from_status(payload[:status]) ||
49
+ if payload[:sk_rendered_format]
50
+ # We only show the variant if we actually have a format
51
+ # We won't have a sk_rendered_format if it's a `head` outside of a `respond_to` block.
52
+ [payload[:sk_rendered_format], payload[:sk_variant]].compact.flatten.join("+")
53
+ end
54
+ end
55
+
56
+ def segment_from_status(status)
57
+ case status
58
+ when 304
59
+ "not modified"
60
+ when (300..399)
61
+ "redirect"
62
+ when (400..599)
63
+ "error"
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,50 @@
1
+ module Skylight
2
+ module Normalizers
3
+ module ActionController
4
+ enabled = true
5
+
6
+ # Temporary hacks
7
+ begin
8
+ require "action_dispatch/http/mime_type"
9
+ require "action_dispatch/http/mime_types"
10
+ require "rack/utils"
11
+ rescue LoadError
12
+ enabled = false
13
+ end
14
+
15
+ if enabled
16
+ class SendFile < Normalizer
17
+ register "send_file.action_controller"
18
+
19
+ CAT = "app.controller.send_file".freeze
20
+ TITLE = "send file".freeze
21
+
22
+ def normalize(_trace, _name, _payload)
23
+ title = TITLE
24
+
25
+ # depending on normalization, we probably want this to eventually
26
+ # include the full path, but we need to make sure we have a good
27
+ # deduping strategy first.
28
+ desc = nil
29
+
30
+ [CAT, title, desc]
31
+ end
32
+
33
+ private
34
+
35
+ OCTET_STREAM = "application/octet-stream".freeze
36
+ ATTACHMENT = "attachment".freeze
37
+
38
+ def initialize(*)
39
+ super
40
+
41
+ @mimes = Mime::SET.each_with_object({}) do |mime, hash|
42
+ hash[mime.symbol] = mime.to_s.dup.freeze
43
+ hash
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Skylight
4
+ module Normalizers
5
+ module ActionDispatch
6
+ class ProcessMiddleware < Normalizer
7
+ register "process_middleware.action_dispatch"
8
+
9
+ CAT = "rack.middleware"
10
+ ANONYMOUS_MIDDLEWARE = "Anonymous Middleware"
11
+ ANONYMOUS = /\A#<(Class|Module|Proc):/.freeze
12
+
13
+ def normalize(trace, _name, payload)
14
+ name = payload[:middleware].to_s
15
+ name = ANONYMOUS_MIDDLEWARE if name[ANONYMOUS]
16
+ trace.endpoint = name
17
+ [CAT, name, nil]
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,27 @@
1
+ module Skylight
2
+ module Normalizers
3
+ module ActionDispatch
4
+ class RouteSet < Normalizer
5
+ register "route_set.action_dispatch"
6
+
7
+ CAT = "rack.app".freeze
8
+
9
+ def normalize(trace, _name, _payload)
10
+ trace.endpoint = router_class_name
11
+ [CAT, trace.endpoint, nil]
12
+ end
13
+
14
+ private
15
+
16
+ def router_class_name
17
+ "ActionDispatch::Routing::RouteSet"
18
+ end
19
+
20
+ def process_meta_options(_payload)
21
+ # provide hints to override default source_location behavior
22
+ super.merge(source_location: [:own_instance_method, router_class_name, "call"])
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,24 @@
1
+ require "skylight/normalizers/render"
2
+
3
+ module Skylight
4
+ module Normalizers
5
+ module ActionView
6
+ # Normalizer for Rails collection rendering
7
+ class RenderCollection < RenderNormalizer
8
+ register "render_collection.action_view"
9
+
10
+ CAT = "view.render.collection".freeze
11
+
12
+ # @param trace [Skylight::Messages::Trace::Builder] ignored, only present to match API
13
+ # @param name [String] ignored, only present to match API
14
+ # @param payload (see RenderNormalizer#normalize_render)
15
+ # @option payload (see RenderNormalizer#normalize_render)
16
+ # @option payload [Integer] :count
17
+ # @return (see RenderNormalizer#normalize_render)
18
+ def normalize(_trace, _name, payload)
19
+ normalize_render(CAT, payload)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "skylight/normalizers/render"
4
+
5
+ module Skylight
6
+ module Normalizers
7
+ module ActionView
8
+ # Normalizer for Rails layout rendering
9
+ class RenderLayout < RenderNormalizer
10
+ register "render_layout.action_view"
11
+
12
+ CAT = "view.render.layout"
13
+
14
+ # @param trace [Skylight::Messages::Trace::Builder] ignored, only present to match API
15
+ # @param name [String] ignored, only present to match API
16
+ # @param payload (see RenderNormalizer#normalize_render)
17
+ # @option payload (see RenderNormalizer#normalize_render)
18
+ # @return (see RenderNormalizer#normalize_render)
19
+ def normalize(_trace, _name, payload)
20
+ normalize_render(CAT, payload)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end