skylight 4.3.2 → 5.0.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +35 -3
- data/CONTRIBUTING.md +2 -8
- data/ext/extconf.rb +6 -5
- data/ext/libskylight.yml +7 -6
- data/ext/skylight_native.c +22 -99
- data/lib/skylight.rb +211 -14
- data/lib/skylight/api.rb +10 -3
- data/lib/skylight/cli.rb +4 -3
- data/lib/skylight/cli/doctor.rb +13 -14
- data/lib/skylight/cli/merger.rb +6 -4
- data/lib/skylight/config.rb +597 -127
- data/lib/skylight/deprecation.rb +17 -0
- data/lib/skylight/errors.rb +21 -6
- data/lib/skylight/extensions.rb +107 -0
- data/lib/skylight/extensions/source_location.rb +291 -0
- data/lib/skylight/formatters/http.rb +20 -0
- data/lib/skylight/gc.rb +109 -0
- data/lib/skylight/helpers.rb +69 -26
- data/lib/skylight/instrumenter.rb +326 -15
- data/lib/skylight/middleware.rb +138 -1
- data/lib/skylight/native.rb +52 -2
- data/lib/skylight/native_ext_fetcher.rb +4 -3
- data/lib/skylight/normalizers.rb +153 -0
- data/lib/skylight/normalizers/action_controller/process_action.rb +69 -0
- data/lib/skylight/normalizers/action_controller/send_file.rb +50 -0
- data/lib/skylight/normalizers/action_dispatch/process_middleware.rb +22 -0
- data/lib/skylight/normalizers/action_dispatch/route_set.rb +27 -0
- data/lib/skylight/normalizers/action_view/render_collection.rb +24 -0
- data/lib/skylight/normalizers/action_view/render_layout.rb +25 -0
- data/lib/skylight/normalizers/action_view/render_partial.rb +23 -0
- data/lib/skylight/normalizers/action_view/render_template.rb +23 -0
- data/lib/skylight/normalizers/active_job/perform.rb +86 -0
- data/lib/skylight/normalizers/active_model_serializers/render.rb +28 -0
- data/lib/skylight/normalizers/active_record/instantiation.rb +16 -0
- data/lib/skylight/normalizers/active_record/sql.rb +12 -0
- data/lib/skylight/normalizers/active_storage.rb +30 -0
- data/lib/skylight/normalizers/active_support/cache.rb +22 -0
- data/lib/skylight/normalizers/active_support/cache_clear.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_decrement.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_delete.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_exist.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_fetch_hit.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_generate.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_increment.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_read.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_read_multi.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_write.rb +16 -0
- data/lib/skylight/normalizers/coach/handler_finish.rb +46 -0
- data/lib/skylight/normalizers/coach/middleware_finish.rb +33 -0
- data/lib/skylight/normalizers/couch_potato/query.rb +20 -0
- data/lib/skylight/normalizers/data_mapper/sql.rb +12 -0
- data/lib/skylight/normalizers/default.rb +32 -0
- data/lib/skylight/normalizers/elasticsearch/request.rb +20 -0
- data/lib/skylight/normalizers/faraday/request.rb +40 -0
- data/lib/skylight/normalizers/grape/endpoint.rb +34 -0
- data/lib/skylight/normalizers/grape/endpoint_render.rb +25 -0
- data/lib/skylight/normalizers/grape/endpoint_run.rb +41 -0
- data/lib/skylight/normalizers/grape/endpoint_run_filters.rb +22 -0
- data/lib/skylight/normalizers/grape/format_response.rb +20 -0
- data/lib/skylight/normalizers/graphiti/render.rb +22 -0
- data/lib/skylight/normalizers/graphiti/resolve.rb +31 -0
- data/lib/skylight/normalizers/graphql/base.rb +132 -0
- data/lib/skylight/normalizers/render.rb +81 -0
- data/lib/skylight/normalizers/sequel/sql.rb +12 -0
- data/lib/skylight/normalizers/shrine.rb +34 -0
- data/lib/skylight/normalizers/sql.rb +45 -0
- data/lib/skylight/probes.rb +181 -0
- data/lib/skylight/probes/action_controller.rb +48 -0
- data/lib/skylight/probes/action_dispatch.rb +2 -0
- data/lib/skylight/probes/action_dispatch/request_id.rb +29 -0
- data/lib/skylight/probes/action_dispatch/routing/route_set.rb +28 -0
- data/lib/skylight/probes/action_view.rb +43 -0
- data/lib/skylight/probes/active_job.rb +27 -0
- data/lib/skylight/probes/active_job_enqueue.rb +41 -0
- data/lib/skylight/probes/active_model_serializers.rb +50 -0
- data/lib/skylight/probes/delayed_job.rb +149 -0
- data/lib/skylight/probes/elasticsearch.rb +38 -0
- data/lib/skylight/probes/excon.rb +25 -0
- data/lib/skylight/probes/excon/middleware.rb +66 -0
- data/lib/skylight/probes/faraday.rb +23 -0
- data/lib/skylight/probes/graphql.rb +43 -0
- data/lib/skylight/probes/httpclient.rb +44 -0
- data/lib/skylight/probes/middleware.rb +126 -0
- data/lib/skylight/probes/mongo.rb +164 -0
- data/lib/skylight/probes/mongoid.rb +13 -0
- data/lib/skylight/probes/net_http.rb +54 -0
- data/lib/skylight/probes/redis.rb +63 -0
- data/lib/skylight/probes/sequel.rb +33 -0
- data/lib/skylight/probes/sinatra.rb +63 -0
- data/lib/skylight/probes/sinatra_add_middleware.rb +10 -10
- data/lib/skylight/probes/tilt.rb +27 -0
- data/lib/skylight/railtie.rb +162 -18
- data/lib/skylight/sidekiq.rb +48 -0
- data/lib/skylight/subscriber.rb +110 -0
- data/lib/skylight/test.rb +146 -0
- data/lib/skylight/trace.rb +307 -10
- data/lib/skylight/user_config.rb +61 -0
- data/lib/skylight/util.rb +12 -0
- data/lib/skylight/util/allocation_free.rb +26 -0
- data/lib/skylight/util/clock.rb +56 -0
- data/lib/skylight/util/component.rb +5 -2
- data/lib/skylight/util/deploy.rb +7 -10
- data/lib/skylight/util/gzip.rb +20 -0
- data/lib/skylight/util/http.rb +4 -10
- data/lib/skylight/util/instrumenter_method.rb +26 -0
- data/lib/skylight/util/logging.rb +138 -0
- data/lib/skylight/util/lru_cache.rb +40 -0
- data/lib/skylight/util/platform.rb +1 -1
- data/lib/skylight/vendor/cli/thor/rake_compat.rb +1 -1
- data/lib/skylight/version.rb +5 -1
- data/lib/skylight/vm/gc.rb +68 -0
- metadata +126 -13
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Skylight
|
|
2
|
+
module Probes
|
|
3
|
+
module Excon
|
|
4
|
+
# Probe for instrumenting Excon requests. Installs {Excon::Middleware} to achieve this.
|
|
5
|
+
class Probe
|
|
6
|
+
def install
|
|
7
|
+
if defined?(::Excon::Middleware)
|
|
8
|
+
# Don't require until installation since it depends on Excon being loaded
|
|
9
|
+
require "skylight/probes/excon/middleware"
|
|
10
|
+
|
|
11
|
+
idx = ::Excon.defaults[:middlewares].index(::Excon::Middleware::Instrumentor)
|
|
12
|
+
|
|
13
|
+
# TODO: Handle possibility of idx being nil
|
|
14
|
+
::Excon.defaults[:middlewares].insert(idx, Probes::Excon::Middleware)
|
|
15
|
+
else
|
|
16
|
+
Skylight.error "The installed version of Excon doesn't support Middlewares. " \
|
|
17
|
+
"The Excon probe will be disabled."
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
register(:excon, "Excon", "excon", Excon::Probe.new)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
require "skylight/formatters/http"
|
|
2
|
+
|
|
3
|
+
module Skylight
|
|
4
|
+
module Probes
|
|
5
|
+
module Excon
|
|
6
|
+
# Middleware for Excon that instruments requests
|
|
7
|
+
class Middleware < ::Excon::Middleware::Base
|
|
8
|
+
def initialize(*)
|
|
9
|
+
@requests = {}.compare_by_identity
|
|
10
|
+
super
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# TODO: Review the following:
|
|
14
|
+
# - Consider whether a LIFO queue would be sufficient
|
|
15
|
+
# - Check that errors can't be called without a request
|
|
16
|
+
|
|
17
|
+
def request_call(datum)
|
|
18
|
+
begin_instrumentation(datum)
|
|
19
|
+
super
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def response_call(datum)
|
|
23
|
+
super
|
|
24
|
+
ensure
|
|
25
|
+
end_instrumentation(datum)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def error_call(datum)
|
|
29
|
+
super
|
|
30
|
+
ensure
|
|
31
|
+
end_instrumentation(datum)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def begin_instrumentation(datum)
|
|
37
|
+
method = datum[:method].to_s
|
|
38
|
+
scheme = datum[:scheme]
|
|
39
|
+
host = datum[:host]
|
|
40
|
+
# TODO: Maybe don't show other default ports like 443
|
|
41
|
+
port = datum[:port] == 80 ? nil : datum[:port]
|
|
42
|
+
path = datum[:path]
|
|
43
|
+
query = datum[:query]
|
|
44
|
+
|
|
45
|
+
opts = Formatters::HTTP.build_opts(method, scheme, host, port, path, query)
|
|
46
|
+
|
|
47
|
+
@requests[datum] = Skylight.instrument(opts)
|
|
48
|
+
rescue Exception => e
|
|
49
|
+
Skylight.error "failed to begin instrumentation for Excon; msg=%s", e.message
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def end_instrumentation(datum)
|
|
53
|
+
if (request = @requests.delete(datum))
|
|
54
|
+
meta = {}
|
|
55
|
+
if datum[:error].is_a?(Exception)
|
|
56
|
+
meta[:exception_object] = datum[:error]
|
|
57
|
+
end
|
|
58
|
+
Skylight.done(request, meta)
|
|
59
|
+
end
|
|
60
|
+
rescue Exception => e
|
|
61
|
+
Skylight.error "failed to end instrumentation for Excon; msg=%s", e.message
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Skylight
|
|
2
|
+
module Probes
|
|
3
|
+
module Faraday
|
|
4
|
+
module Instrumentation
|
|
5
|
+
def builder
|
|
6
|
+
unless defined?(@__sk__setup)
|
|
7
|
+
@__sk__setup = true
|
|
8
|
+
@builder.insert 0, ::Faraday::Request::Instrumentation
|
|
9
|
+
end
|
|
10
|
+
@builder
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class Probe
|
|
15
|
+
def install
|
|
16
|
+
::Faraday::Connection.prepend(Instrumentation)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
register(:faraday, "Faraday", "faraday", Faraday::Probe.new)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/inflector"
|
|
4
|
+
|
|
5
|
+
module Skylight
|
|
6
|
+
module Probes
|
|
7
|
+
module GraphQL
|
|
8
|
+
module Instrumentation
|
|
9
|
+
def initialize(*, **)
|
|
10
|
+
super
|
|
11
|
+
|
|
12
|
+
return unless defined?(@tracers)
|
|
13
|
+
|
|
14
|
+
unless @tracers.include?(::GraphQL::Tracing::ActiveSupportNotificationsTracing)
|
|
15
|
+
@tracers << ::GraphQL::Tracing::ActiveSupportNotificationsTracing
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class Probe
|
|
21
|
+
def install
|
|
22
|
+
tracing_klass_name = "::GraphQL::Tracing::ActiveSupportNotificationsTracing"
|
|
23
|
+
klasses_to_probe = %w[
|
|
24
|
+
::GraphQL::Execution::Multiplex
|
|
25
|
+
::GraphQL::Query
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
return unless ([tracing_klass_name] + klasses_to_probe).all?(&method(:safe_constantize))
|
|
29
|
+
|
|
30
|
+
klasses_to_probe.each do |klass_name|
|
|
31
|
+
safe_constantize(klass_name).prepend(Instrumentation)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def safe_constantize(klass_name)
|
|
36
|
+
ActiveSupport::Inflector.safe_constantize(klass_name)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
register(:graphql, "GraphQL", "graphql", GraphQL::Probe.new)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
require "skylight/formatters/http"
|
|
2
|
+
|
|
3
|
+
module Skylight
|
|
4
|
+
module Probes
|
|
5
|
+
module HTTPClient
|
|
6
|
+
module Instrumentation
|
|
7
|
+
# HTTPClient has request methods on the class object itself,
|
|
8
|
+
# but they internally instantiate a client and perform the method
|
|
9
|
+
# on that, so this instance method override will cover both
|
|
10
|
+
# `HTTPClient.get(...)` and `HTTPClient.new.get(...)`
|
|
11
|
+
|
|
12
|
+
def do_request(method, uri, *)
|
|
13
|
+
return super if Probes::HTTPClient::Probe.disabled?
|
|
14
|
+
|
|
15
|
+
opts = Formatters::HTTP.build_opts(method, uri.scheme, uri.host, uri.port, uri.path, uri.query)
|
|
16
|
+
|
|
17
|
+
Skylight.instrument(opts) { super }
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
class Probe
|
|
22
|
+
DISABLED_KEY = :__skylight_httpclient_disabled
|
|
23
|
+
|
|
24
|
+
def self.disable
|
|
25
|
+
old_value = Thread.current[DISABLED_KEY]
|
|
26
|
+
Thread.current[DISABLED_KEY] = true
|
|
27
|
+
yield
|
|
28
|
+
ensure
|
|
29
|
+
Thread.current[DISABLED_KEY] = old_value
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def self.disabled?
|
|
33
|
+
!!Thread.current[DISABLED_KEY]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def install
|
|
37
|
+
::HTTPClient.prepend(Instrumentation)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
register(:httpclient, "HTTPClient", "httpclient", HTTPClient::Probe.new)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
module Skylight
|
|
2
|
+
module Probes
|
|
3
|
+
module Middleware
|
|
4
|
+
# for Rails >= 6.0, which includes InstrumentationProxy
|
|
5
|
+
module InstrumentationExtensions
|
|
6
|
+
def initialize(middleware, class_name)
|
|
7
|
+
super
|
|
8
|
+
|
|
9
|
+
# NOTE: Caching here leads to better performance, but will not notice if the method is overridden
|
|
10
|
+
# We don't have access to the config here so we can't check whether source locations are enabled.
|
|
11
|
+
# However, this only happens once per middleware so it should be minimal impact.
|
|
12
|
+
@payload[:sk_source_location] =
|
|
13
|
+
begin
|
|
14
|
+
if middleware.is_a?(Proc)
|
|
15
|
+
middleware.source_location
|
|
16
|
+
elsif middleware.respond_to?(:call)
|
|
17
|
+
middleware.method(:call).source_location
|
|
18
|
+
end
|
|
19
|
+
rescue
|
|
20
|
+
nil
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# for Rails <= 5.2 ActionDispatch::MiddlewareStack::Middleware
|
|
26
|
+
module Instrumentation
|
|
27
|
+
def build(*)
|
|
28
|
+
sk_instrument_middleware(super)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def sk_instrument_middleware(middleware)
|
|
32
|
+
return middleware if middleware.is_a?(Skylight::Middleware)
|
|
33
|
+
|
|
34
|
+
# Not sure how this would actually happen
|
|
35
|
+
return middleware if middleware.respond_to?(:__has_sk__)
|
|
36
|
+
|
|
37
|
+
# On Rails 3, ActionDispatch::Session::CookieStore is frozen, for one
|
|
38
|
+
return middleware if middleware.frozen?
|
|
39
|
+
|
|
40
|
+
Skylight::Probes::Middleware::Probe.add_instrumentation(middleware)
|
|
41
|
+
|
|
42
|
+
middleware
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
class Probe
|
|
47
|
+
DISABLED_KEY = :__skylight_middleware_disabled
|
|
48
|
+
|
|
49
|
+
def self.disable!
|
|
50
|
+
@disabled = true
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def self.enable!
|
|
54
|
+
@disabled = false
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def self.disabled?
|
|
58
|
+
!!@disabled
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
module InstanceInstrumentation
|
|
62
|
+
def call(*args)
|
|
63
|
+
return super(*args) if Skylight::Probes::Middleware::Probe.disabled?
|
|
64
|
+
|
|
65
|
+
trace = Skylight.instrumenter&.current_trace
|
|
66
|
+
return super(*args) unless trace
|
|
67
|
+
|
|
68
|
+
begin
|
|
69
|
+
name = self.class.name || __sk_default_name
|
|
70
|
+
|
|
71
|
+
trace.endpoint = name
|
|
72
|
+
|
|
73
|
+
source_file, source_line = method(__method__).super_method.source_location
|
|
74
|
+
|
|
75
|
+
spans = Skylight.instrument(title: name, category: __sk_category,
|
|
76
|
+
source_file: source_file, source_line: source_line)
|
|
77
|
+
|
|
78
|
+
proxied_response =
|
|
79
|
+
Skylight::Middleware.with_after_close(super(*args), debug_identifier: "Middleware: #{name}") do
|
|
80
|
+
Skylight.done(spans)
|
|
81
|
+
end
|
|
82
|
+
rescue Exception => e
|
|
83
|
+
Skylight.done(spans, exception_object: e)
|
|
84
|
+
raise
|
|
85
|
+
ensure
|
|
86
|
+
unless e || proxied_response
|
|
87
|
+
# If we've gotten to this point, the most likely scenario is that
|
|
88
|
+
# a throw/catch has bypassed a portion of the callstack. Since these spans would not otherwise
|
|
89
|
+
# be closed, mark them deferred to indicate that they should be implicitly closed.
|
|
90
|
+
# See Trace#deferred_spans or Trace#stop for more information.
|
|
91
|
+
Skylight.done(spans, defer: true)
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def __sk_default_name
|
|
97
|
+
"Anonymous Middleware"
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def __sk_category
|
|
101
|
+
"rack.middleware"
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def __has_sk__
|
|
105
|
+
true
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def self.add_instrumentation(middleware)
|
|
110
|
+
middleware.singleton_class.prepend(InstanceInstrumentation)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def install
|
|
114
|
+
if defined?(::ActionDispatch::MiddlewareStack::InstrumentationProxy)
|
|
115
|
+
::ActionDispatch::MiddlewareStack::InstrumentationProxy.prepend(InstrumentationExtensions)
|
|
116
|
+
else
|
|
117
|
+
::ActionDispatch::MiddlewareStack::Middleware.prepend(Instrumentation)
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
register(:middleware, "ActionDispatch::MiddlewareStack::Middleware", "actionpack/action_dispatch",
|
|
124
|
+
Middleware::Probe.new)
|
|
125
|
+
end
|
|
126
|
+
end
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
module Skylight
|
|
2
|
+
module Probes
|
|
3
|
+
module Mongo
|
|
4
|
+
CAT = "db.mongo.command".freeze
|
|
5
|
+
|
|
6
|
+
class Probe
|
|
7
|
+
def install
|
|
8
|
+
::Mongo::Monitoring::Global.subscribe(::Mongo::Monitoring::COMMAND, Subscriber.new)
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class Subscriber
|
|
13
|
+
include Skylight::Util::Logging
|
|
14
|
+
|
|
15
|
+
COMMANDS = %i[insert find count distinct update findandmodify findAndModify delete aggregate].freeze
|
|
16
|
+
|
|
17
|
+
COMMAND_NAMES = {
|
|
18
|
+
findandmodify: "findAndModify".freeze
|
|
19
|
+
}.freeze
|
|
20
|
+
|
|
21
|
+
def initialize
|
|
22
|
+
@events = {}
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def started(event)
|
|
26
|
+
begin_instrumentation(event)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def succeeded(event)
|
|
30
|
+
end_instrumentation(event)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def failed(event)
|
|
34
|
+
end_instrumentation(event)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# For logging
|
|
38
|
+
def config
|
|
39
|
+
Skylight.config
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def begin_instrumentation(event)
|
|
45
|
+
return unless COMMANDS.include?(event.command_name.to_sym)
|
|
46
|
+
|
|
47
|
+
command_name = COMMAND_NAMES[event.command_name] || event.command_name.to_s
|
|
48
|
+
|
|
49
|
+
title = "#{event.database_name}.#{command_name}"
|
|
50
|
+
|
|
51
|
+
command = event.command
|
|
52
|
+
|
|
53
|
+
# Not sure if this will always exist
|
|
54
|
+
# Delete so the description will be less redundant
|
|
55
|
+
if (target = command[event.command_name])
|
|
56
|
+
title << " #{target}"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
payload = {}
|
|
60
|
+
|
|
61
|
+
# Ruby Hashes are ordered based on insertion so do the most important ones first
|
|
62
|
+
|
|
63
|
+
add_value("key".freeze, command, payload)
|
|
64
|
+
add_bound("query".freeze, command, payload)
|
|
65
|
+
add_bound("filter".freeze, command, payload)
|
|
66
|
+
add_value("sort".freeze, command, payload)
|
|
67
|
+
|
|
68
|
+
if command_name == "findAndModify".freeze
|
|
69
|
+
add_bound("update".freeze, command, payload)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
add_value("remove".freeze, command, payload)
|
|
73
|
+
add_value("new".freeze, command, payload)
|
|
74
|
+
|
|
75
|
+
if (updates = command["updates".freeze])
|
|
76
|
+
# AFAICT the gem generally just sends one item in the updates array
|
|
77
|
+
update = updates[0]
|
|
78
|
+
update_payload = {}
|
|
79
|
+
add_bound("q".freeze, update, update_payload)
|
|
80
|
+
add_bound("u".freeze, update, update_payload)
|
|
81
|
+
add_value("multi".freeze, update, update_payload)
|
|
82
|
+
add_value("upsert".freeze, update, update_payload)
|
|
83
|
+
|
|
84
|
+
payload["updates".freeze] = [update_payload]
|
|
85
|
+
|
|
86
|
+
if updates.length > 1
|
|
87
|
+
payload["updates".freeze] << "..."
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
if (deletes = command["deletes".freeze])
|
|
92
|
+
# AFAICT the gem generally just sends one item in the updates array
|
|
93
|
+
delete = deletes[0]
|
|
94
|
+
delete_payload = {}
|
|
95
|
+
add_bound("q".freeze, delete, delete_payload)
|
|
96
|
+
add_value("limit".freeze, delete, delete_payload)
|
|
97
|
+
|
|
98
|
+
payload["deletes".freeze] = [delete_payload]
|
|
99
|
+
|
|
100
|
+
if deletes.length > 1
|
|
101
|
+
payload["deletes".freeze] << "..."
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
if (pipeline = command["pipeline".freeze])
|
|
106
|
+
payload["pipeline".freeze] = pipeline.map { |segment| extract_binds(segment) }
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# We're ignoring documents from insert because they could have completely inconsistent
|
|
110
|
+
# format which would make it hard to merge.
|
|
111
|
+
|
|
112
|
+
opts = {
|
|
113
|
+
category: CAT,
|
|
114
|
+
title: title,
|
|
115
|
+
description: payload.empty? ? nil : payload.to_json,
|
|
116
|
+
meta: { database: event.database_name },
|
|
117
|
+
internal: true
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
@events[event.operation_id] = Skylight.instrument(opts)
|
|
121
|
+
rescue Exception => e
|
|
122
|
+
error "failed to begin instrumentation for Mongo; msg=%s", e.message
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def end_instrumentation(event)
|
|
126
|
+
if (original_event = @events.delete(event.operation_id))
|
|
127
|
+
meta = {}
|
|
128
|
+
if event.is_a?(::Mongo::Monitoring::Event::CommandFailed)
|
|
129
|
+
meta[:exception] = ["CommandFailed", event.message]
|
|
130
|
+
end
|
|
131
|
+
Skylight.done(original_event, meta)
|
|
132
|
+
end
|
|
133
|
+
rescue Exception => e
|
|
134
|
+
error "failed to end instrumentation for Mongo; msg=%s", e.message
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def add_value(key, command, payload)
|
|
138
|
+
if command.key?(key)
|
|
139
|
+
value = command[key]
|
|
140
|
+
payload[key] = value
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def add_bound(key, command, payload)
|
|
145
|
+
if (value = command[key])
|
|
146
|
+
payload[key] = extract_binds(value)
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def extract_binds(hash)
|
|
151
|
+
ret = {}
|
|
152
|
+
|
|
153
|
+
hash.each do |k, v|
|
|
154
|
+
ret[k] = v.is_a?(Hash) ? extract_binds(v) : "?".freeze
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
ret
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
register(:mongo, "Mongo", "mongo", Mongo::Probe.new)
|
|
163
|
+
end
|
|
164
|
+
end
|