skylight 5.0.1 → 5.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +395 -364
- data/CLA.md +1 -1
- data/LICENSE.md +7 -17
- data/README.md +1 -1
- data/ext/extconf.rb +42 -54
- data/ext/libskylight.yml +9 -6
- data/lib/skylight.rb +20 -30
- data/lib/skylight/api.rb +22 -18
- data/lib/skylight/cli.rb +47 -46
- data/lib/skylight/cli/doctor.rb +50 -50
- data/lib/skylight/cli/helpers.rb +19 -19
- data/lib/skylight/cli/merger.rb +141 -139
- data/lib/skylight/config.rb +265 -300
- data/lib/skylight/deprecation.rb +4 -4
- data/lib/skylight/errors.rb +3 -4
- data/lib/skylight/extensions.rb +17 -29
- data/lib/skylight/extensions/source_location.rb +128 -128
- data/lib/skylight/formatters/http.rb +1 -3
- data/lib/skylight/gc.rb +30 -40
- data/lib/skylight/helpers.rb +43 -41
- data/lib/skylight/instrumenter.rb +25 -18
- data/lib/skylight/middleware.rb +31 -35
- data/lib/skylight/native.rb +8 -10
- data/lib/skylight/native_ext_fetcher.rb +10 -12
- data/lib/skylight/normalizers.rb +43 -39
- data/lib/skylight/normalizers/action_controller/process_action.rb +24 -25
- data/lib/skylight/normalizers/action_controller/send_file.rb +7 -6
- data/lib/skylight/normalizers/action_dispatch/route_set.rb +7 -7
- data/lib/skylight/normalizers/active_job/perform.rb +48 -44
- data/lib/skylight/normalizers/active_model_serializers/render.rb +7 -3
- data/lib/skylight/normalizers/active_storage.rb +11 -13
- data/lib/skylight/normalizers/active_support/cache.rb +1 -12
- data/lib/skylight/normalizers/coach/handler_finish.rb +1 -3
- data/lib/skylight/normalizers/default.rb +1 -9
- data/lib/skylight/normalizers/faraday/request.rb +1 -3
- data/lib/skylight/normalizers/grape/endpoint.rb +13 -19
- data/lib/skylight/normalizers/grape/endpoint_run.rb +16 -18
- data/lib/skylight/normalizers/grape/endpoint_run_filters.rb +1 -3
- data/lib/skylight/normalizers/graphql/base.rb +23 -28
- data/lib/skylight/normalizers/render.rb +19 -21
- data/lib/skylight/normalizers/shrine.rb +15 -17
- data/lib/skylight/normalizers/sql.rb +4 -4
- data/lib/skylight/probes.rb +38 -46
- data/lib/skylight/probes/action_controller.rb +32 -28
- data/lib/skylight/probes/action_dispatch/request_id.rb +9 -5
- data/lib/skylight/probes/action_dispatch/routing/route_set.rb +7 -5
- data/lib/skylight/probes/action_view.rb +9 -10
- data/lib/skylight/probes/active_job_enqueue.rb +3 -9
- data/lib/skylight/probes/active_model_serializers.rb +8 -8
- data/lib/skylight/probes/delayed_job.rb +37 -42
- data/lib/skylight/probes/elasticsearch.rb +3 -5
- data/lib/skylight/probes/excon.rb +1 -1
- data/lib/skylight/probes/excon/middleware.rb +22 -23
- data/lib/skylight/probes/graphql.rb +2 -7
- data/lib/skylight/probes/middleware.rb +14 -5
- data/lib/skylight/probes/mongo.rb +83 -91
- data/lib/skylight/probes/net_http.rb +1 -1
- data/lib/skylight/probes/redis.rb +5 -17
- data/lib/skylight/probes/sequel.rb +7 -11
- data/lib/skylight/probes/sinatra.rb +8 -5
- data/lib/skylight/probes/tilt.rb +2 -4
- data/lib/skylight/railtie.rb +121 -135
- data/lib/skylight/sidekiq.rb +4 -5
- data/lib/skylight/subscriber.rb +31 -33
- data/lib/skylight/test.rb +89 -84
- data/lib/skylight/trace.rb +121 -115
- data/lib/skylight/user_config.rb +14 -17
- data/lib/skylight/util/clock.rb +1 -0
- data/lib/skylight/util/component.rb +18 -21
- data/lib/skylight/util/deploy.rb +11 -13
- data/lib/skylight/util/http.rb +104 -105
- data/lib/skylight/util/logging.rb +4 -6
- data/lib/skylight/util/lru_cache.rb +2 -6
- data/lib/skylight/util/platform.rb +2 -6
- data/lib/skylight/util/ssl.rb +1 -25
- data/lib/skylight/version.rb +1 -1
- data/lib/skylight/vm/gc.rb +1 -9
- metadata +6 -6
@@ -10,9 +10,9 @@ module Skylight
|
|
10
10
|
|
11
11
|
private
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
def internal_request_id
|
14
|
+
@skylight_request_id || super
|
15
|
+
end
|
16
16
|
end
|
17
17
|
|
18
18
|
class Probe
|
@@ -23,7 +23,11 @@ module Skylight
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
register(
|
27
|
-
|
26
|
+
register(
|
27
|
+
:action_dispatch,
|
28
|
+
"ActionDispatch::RequestId",
|
29
|
+
"action_dispatch/middleware/request_id",
|
30
|
+
ActionDispatch::RequestId::Probe.new
|
31
|
+
)
|
28
32
|
end
|
29
33
|
end
|
@@ -7,9 +7,7 @@ module Skylight
|
|
7
7
|
module RouteSet
|
8
8
|
module Instrumentation
|
9
9
|
def call(env)
|
10
|
-
ActiveSupport::Notifications.instrument("route_set.action_dispatch")
|
11
|
-
super
|
12
|
-
end
|
10
|
+
ActiveSupport::Notifications.instrument("route_set.action_dispatch") { super }
|
13
11
|
end
|
14
12
|
end
|
15
13
|
|
@@ -22,7 +20,11 @@ module Skylight
|
|
22
20
|
end
|
23
21
|
end
|
24
22
|
|
25
|
-
register(
|
26
|
-
|
23
|
+
register(
|
24
|
+
:rails_router,
|
25
|
+
"ActionDispatch::Routing::RouteSet",
|
26
|
+
"action_dispatch/routing/route_set",
|
27
|
+
ActionDispatch::Routing::RouteSet::Probe.new
|
28
|
+
)
|
27
29
|
end
|
28
30
|
end
|
@@ -5,19 +5,18 @@ module Skylight
|
|
5
5
|
module ActionView
|
6
6
|
module Instrumentation
|
7
7
|
def render_with_layout(*args) #:nodoc:
|
8
|
-
path, locals =
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
8
|
+
path, locals =
|
9
|
+
case args.length
|
10
|
+
when 2
|
11
|
+
args
|
12
|
+
when 4
|
13
|
+
# Rails > 6.0.0.beta3 arguments are (view, template, path, locals)
|
14
|
+
[args[2], args[3]]
|
15
|
+
end
|
15
16
|
|
16
17
|
layout = nil
|
17
18
|
|
18
|
-
if path
|
19
|
-
layout = find_layout(path, locals.keys, [formats.first])
|
20
|
-
end
|
19
|
+
layout = find_layout(path, locals.keys, [formats.first]) if path
|
21
20
|
|
22
21
|
if layout
|
23
22
|
ActiveSupport::Notifications.instrument("render_template.action_view", identifier: layout.identifier) do
|
@@ -14,17 +14,11 @@ module Skylight
|
|
14
14
|
name, job_class_name = Normalizers::ActiveJob::Perform.normalize_title(job)
|
15
15
|
descriptors = ["adapter: '#{adapter_name}'", "queue: '#{job.queue_name}'"]
|
16
16
|
descriptors << "job: '#{job_class_name}'" if job_class_name
|
17
|
-
desc = "{ #{descriptors.join(
|
18
|
-
rescue
|
17
|
+
desc = "{ #{descriptors.join(", ")} }"
|
18
|
+
rescue StandardError
|
19
19
|
block.call
|
20
20
|
else
|
21
|
-
Skylight.instrument(
|
22
|
-
title: "Enqueue #{name}",
|
23
|
-
category: CAT,
|
24
|
-
description: desc,
|
25
|
-
internal: true,
|
26
|
-
&block
|
27
|
-
)
|
21
|
+
Skylight.instrument(title: "Enqueue #{name}", category: CAT, description: desc, internal: true, &block)
|
28
22
|
end
|
29
23
|
|
30
24
|
self.class.instance_eval do
|
@@ -18,9 +18,7 @@ module Skylight
|
|
18
18
|
rescue LoadError # rubocop:disable Lint/SuppressedException
|
19
19
|
end
|
20
20
|
|
21
|
-
if Gem.loaded_specs["active_model_serializers"]
|
22
|
-
version = Gem.loaded_specs["active_model_serializers"].version
|
23
|
-
end
|
21
|
+
version = Gem.loaded_specs["active_model_serializers"].version if Gem.loaded_specs["active_model_serializers"]
|
24
22
|
|
25
23
|
if !version || version < Gem::Version.new("0.5.0")
|
26
24
|
Skylight.error "Instrumention is only available for ActiveModelSerializers version 0.5.0 and greater."
|
@@ -37,14 +35,16 @@ module Skylight
|
|
37
35
|
# End users could override as_json without calling super, but it's likely safer
|
38
36
|
# than overriding serializable_array/hash/object.
|
39
37
|
|
40
|
-
[::ActiveModel::Serializer, ::ActiveModel::ArraySerializer].each
|
41
|
-
klass.prepend(Instrumentation)
|
42
|
-
end
|
38
|
+
[::ActiveModel::Serializer, ::ActiveModel::ArraySerializer].each { |klass| klass.prepend(Instrumentation) }
|
43
39
|
end
|
44
40
|
end
|
45
41
|
end
|
46
42
|
|
47
|
-
register(
|
48
|
-
|
43
|
+
register(
|
44
|
+
:active_model_serializers,
|
45
|
+
"ActiveModel::Serializer",
|
46
|
+
"active_model/serializer",
|
47
|
+
ActiveModelSerializers::Probe.new
|
48
|
+
)
|
49
49
|
end
|
50
50
|
end
|
@@ -10,13 +10,9 @@ module Skylight
|
|
10
10
|
|
11
11
|
class Plugin < ::Delayed::Plugin
|
12
12
|
callbacks do |lifecycle|
|
13
|
-
lifecycle.around(:perform)
|
14
|
-
sk_instrument(worker, job, &block)
|
15
|
-
end
|
13
|
+
lifecycle.around(:perform) { |worker, job, &block| sk_instrument(worker, job, &block) }
|
16
14
|
|
17
|
-
lifecycle.after(:error)
|
18
|
-
Skylight.trace&.segment = "error"
|
19
|
-
end
|
15
|
+
lifecycle.after(:error) { |_worker, _job| Skylight.trace&.segment = "error" }
|
20
16
|
end
|
21
17
|
|
22
18
|
class << self
|
@@ -25,15 +21,19 @@ module Skylight
|
|
25
21
|
def sk_instrument(_worker, job)
|
26
22
|
endpoint = Skylight::Probes::DelayedJob.handler_name(job)
|
27
23
|
|
28
|
-
Skylight.trace(
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
24
|
+
Skylight.trace(
|
25
|
+
endpoint,
|
26
|
+
"app.delayed_job.worker",
|
27
|
+
"Delayed::Worker#run",
|
28
|
+
component: :worker,
|
29
|
+
segment: job.queue,
|
30
|
+
meta: {
|
31
|
+
source_location: "delayed_job"
|
32
|
+
}
|
33
|
+
) do
|
34
|
+
t { "Delayed::Job beginning trace" }
|
35
|
+
yield
|
36
|
+
end
|
37
37
|
end
|
38
38
|
end
|
39
39
|
end
|
@@ -44,11 +44,8 @@ module Skylight
|
|
44
44
|
UNKNOWN = "<Delayed::Job Unknown>"
|
45
45
|
|
46
46
|
def self.handler_name(job)
|
47
|
-
payload_object =
|
48
|
-
|
49
|
-
else
|
50
|
-
job.payload_object
|
51
|
-
end
|
47
|
+
payload_object =
|
48
|
+
job.respond_to?(:payload_object_without_sk) ? job.payload_object_without_sk : job.payload_object
|
52
49
|
|
53
50
|
payload_object_name(payload_object)
|
54
51
|
end
|
@@ -62,7 +59,7 @@ module Skylight
|
|
62
59
|
# Use class name instead to avoid this.
|
63
60
|
payload_object.class.name
|
64
61
|
end
|
65
|
-
rescue
|
62
|
+
rescue StandardError
|
66
63
|
UNKNOWN
|
67
64
|
end
|
68
65
|
|
@@ -84,8 +81,10 @@ module Skylight
|
|
84
81
|
|
85
82
|
opts = {
|
86
83
|
category: "app.delayed_job.job",
|
87
|
-
title:
|
88
|
-
meta:
|
84
|
+
title: format_source(*source_meta),
|
85
|
+
meta: {
|
86
|
+
source_location_hint: source_meta
|
87
|
+
},
|
89
88
|
internal: true
|
90
89
|
}
|
91
90
|
|
@@ -99,13 +98,9 @@ module Skylight
|
|
99
98
|
|
100
99
|
private
|
101
100
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
else
|
106
|
-
"#{constant_name}.#{method_name}"
|
107
|
-
end
|
108
|
-
end
|
101
|
+
def format_source(method_type, constant_name, method_name)
|
102
|
+
method_type == :instance_method ? "#{constant_name}##{method_name}" : "#{constant_name}.#{method_name}"
|
103
|
+
end
|
109
104
|
end
|
110
105
|
|
111
106
|
class Probe
|
@@ -124,23 +119,23 @@ module Skylight
|
|
124
119
|
|
125
120
|
private
|
126
121
|
|
127
|
-
|
128
|
-
|
129
|
-
|
122
|
+
def plugin_defined?
|
123
|
+
defined?(::Skylight::Probes::DelayedJob::Plugin)
|
124
|
+
end
|
130
125
|
|
131
|
-
|
132
|
-
|
133
|
-
|
126
|
+
def validate_version
|
127
|
+
spec = Gem.loaded_specs["delayed_job"]
|
128
|
+
version = spec&.version
|
134
129
|
|
135
|
-
|
136
|
-
|
130
|
+
if !version || version < Gem::Version.new("4.0.0")
|
131
|
+
Skylight.error "The installed version of DelayedJob is not supported on Skylight. " \
|
137
132
|
"Your jobs will not be tracked."
|
138
133
|
|
139
|
-
|
140
|
-
end
|
141
|
-
|
142
|
-
true
|
134
|
+
return false
|
143
135
|
end
|
136
|
+
|
137
|
+
true
|
138
|
+
end
|
144
139
|
end
|
145
140
|
end
|
146
141
|
|
@@ -9,16 +9,14 @@ module Skylight
|
|
9
9
|
def perform_request(method, path, *args, &block)
|
10
10
|
ActiveSupport::Notifications.instrument(
|
11
11
|
"request.elasticsearch",
|
12
|
-
name:
|
12
|
+
name: "Request",
|
13
13
|
method: method,
|
14
|
-
path:
|
14
|
+
path: path
|
15
15
|
) do
|
16
16
|
# Prevent HTTP-related probes from firing
|
17
17
|
Skylight::Normalizers::Faraday::Request.disable do
|
18
18
|
disable_skylight_probe(:NetHTTP) do
|
19
|
-
disable_skylight_probe(:HTTPClient)
|
20
|
-
perform_request_without_sk(method, path, *args, &block)
|
21
|
-
end
|
19
|
+
disable_skylight_probe(:HTTPClient) { perform_request_without_sk(method, path, *args, &block) }
|
22
20
|
end
|
23
21
|
end
|
24
22
|
end
|
@@ -14,7 +14,7 @@ module Skylight
|
|
14
14
|
::Excon.defaults[:middlewares].insert(idx, Probes::Excon::Middleware)
|
15
15
|
else
|
16
16
|
Skylight.error "The installed version of Excon doesn't support Middlewares. " \
|
17
|
-
|
17
|
+
"The Excon probe will be disabled."
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
@@ -33,33 +33,32 @@ module Skylight
|
|
33
33
|
|
34
34
|
private
|
35
35
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
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]
|
36
|
+
def begin_instrumentation(datum)
|
37
|
+
method = datum[:method].to_s
|
38
|
+
scheme = datum[:scheme]
|
39
|
+
host = datum[:host]
|
44
40
|
|
45
|
-
|
41
|
+
# TODO: Maybe don't show other default ports like 443
|
42
|
+
port = datum[:port] == 80 ? nil : datum[:port]
|
43
|
+
path = datum[:path]
|
44
|
+
query = datum[:query]
|
46
45
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
46
|
+
opts = Formatters::HTTP.build_opts(method, scheme, host, port, path, query)
|
47
|
+
|
48
|
+
@requests[datum] = Skylight.instrument(opts)
|
49
|
+
rescue Exception => e
|
50
|
+
Skylight.error "failed to begin instrumentation for Excon; msg=%s", e.message
|
51
|
+
end
|
51
52
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
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
|
53
|
+
def end_instrumentation(datum)
|
54
|
+
if (request = @requests.delete(datum))
|
55
|
+
meta = {}
|
56
|
+
meta[:exception_object] = datum[:error] if datum[:error].is_a?(Exception)
|
57
|
+
Skylight.done(request, meta)
|
62
58
|
end
|
59
|
+
rescue Exception => e
|
60
|
+
Skylight.error "failed to end instrumentation for Excon; msg=%s", e.message
|
61
|
+
end
|
63
62
|
end
|
64
63
|
end
|
65
64
|
end
|
@@ -20,16 +20,11 @@ module Skylight
|
|
20
20
|
class Probe
|
21
21
|
def install
|
22
22
|
tracing_klass_name = "::GraphQL::Tracing::ActiveSupportNotificationsTracing"
|
23
|
-
klasses_to_probe = %w[
|
24
|
-
::GraphQL::Execution::Multiplex
|
25
|
-
::GraphQL::Query
|
26
|
-
]
|
23
|
+
klasses_to_probe = %w[::GraphQL::Execution::Multiplex ::GraphQL::Query]
|
27
24
|
|
28
25
|
return unless ([tracing_klass_name] + klasses_to_probe).all?(&method(:safe_constantize))
|
29
26
|
|
30
|
-
klasses_to_probe.each
|
31
|
-
safe_constantize(klass_name).prepend(Instrumentation)
|
32
|
-
end
|
27
|
+
klasses_to_probe.each { |klass_name| safe_constantize(klass_name).prepend(Instrumentation) }
|
33
28
|
end
|
34
29
|
|
35
30
|
def safe_constantize(klass_name)
|
@@ -16,7 +16,7 @@ module Skylight
|
|
16
16
|
elsif middleware.respond_to?(:call)
|
17
17
|
middleware.method(:call).source_location
|
18
18
|
end
|
19
|
-
rescue
|
19
|
+
rescue StandardError
|
20
20
|
nil
|
21
21
|
end
|
22
22
|
end
|
@@ -72,8 +72,13 @@ module Skylight
|
|
72
72
|
|
73
73
|
source_file, source_line = method(__method__).super_method.source_location
|
74
74
|
|
75
|
-
spans =
|
76
|
-
|
75
|
+
spans =
|
76
|
+
Skylight.instrument(
|
77
|
+
title: name,
|
78
|
+
category: __sk_category,
|
79
|
+
source_file: source_file,
|
80
|
+
source_line: source_line
|
81
|
+
)
|
77
82
|
|
78
83
|
proxied_response =
|
79
84
|
Skylight::Middleware.with_after_close(super(*args), debug_identifier: "Middleware: #{name}") do
|
@@ -120,7 +125,11 @@ module Skylight
|
|
120
125
|
end
|
121
126
|
end
|
122
127
|
|
123
|
-
register(
|
124
|
-
|
128
|
+
register(
|
129
|
+
:middleware,
|
130
|
+
"ActionDispatch::MiddlewareStack::Middleware",
|
131
|
+
"actionpack/action_dispatch",
|
132
|
+
Middleware::Probe.new
|
133
|
+
)
|
125
134
|
end
|
126
135
|
end
|
@@ -14,9 +14,7 @@ module Skylight
|
|
14
14
|
|
15
15
|
COMMANDS = %i[insert find count distinct update findandmodify findAndModify delete aggregate].freeze
|
16
16
|
|
17
|
-
COMMAND_NAMES = {
|
18
|
-
findandmodify: "findAndModify".freeze
|
19
|
-
}.freeze
|
17
|
+
COMMAND_NAMES = { findandmodify: "findAndModify".freeze }.freeze
|
20
18
|
|
21
19
|
def initialize
|
22
20
|
@events = {}
|
@@ -41,121 +39,115 @@ module Skylight
|
|
41
39
|
|
42
40
|
private
|
43
41
|
|
44
|
-
|
45
|
-
|
42
|
+
def begin_instrumentation(event)
|
43
|
+
return unless COMMANDS.include?(event.command_name.to_sym)
|
46
44
|
|
47
|
-
|
45
|
+
command_name = COMMAND_NAMES[event.command_name] || event.command_name.to_s
|
48
46
|
|
49
|
-
|
47
|
+
title = "#{event.database_name}.#{command_name}"
|
50
48
|
|
51
|
-
|
49
|
+
command = event.command
|
52
50
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
payload = {}
|
60
|
-
|
61
|
-
# Ruby Hashes are ordered based on insertion so do the most important ones first
|
51
|
+
# Not sure if this will always exist
|
52
|
+
# Delete so the description will be less redundant
|
53
|
+
if (target = command[event.command_name])
|
54
|
+
title << " #{target}"
|
55
|
+
end
|
62
56
|
|
63
|
-
|
64
|
-
add_bound("query".freeze, command, payload)
|
65
|
-
add_bound("filter".freeze, command, payload)
|
66
|
-
add_value("sort".freeze, command, payload)
|
57
|
+
payload = {}
|
67
58
|
|
68
|
-
|
69
|
-
add_bound("update".freeze, command, payload)
|
70
|
-
end
|
59
|
+
# Ruby Hashes are ordered based on insertion so do the most important ones first
|
71
60
|
|
72
|
-
|
73
|
-
|
61
|
+
add_value("key".freeze, command, payload)
|
62
|
+
add_bound("query".freeze, command, payload)
|
63
|
+
add_bound("filter".freeze, command, payload)
|
64
|
+
add_value("sort".freeze, command, payload)
|
74
65
|
|
75
|
-
|
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)
|
66
|
+
add_bound("update".freeze, command, payload) if command_name == "findAndModify".freeze
|
83
67
|
|
84
|
-
|
68
|
+
add_value("remove".freeze, command, payload)
|
69
|
+
add_value("new".freeze, command, payload)
|
85
70
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
71
|
+
if (updates = command["updates".freeze])
|
72
|
+
# AFAICT the gem generally just sends one item in the updates array
|
73
|
+
update = updates[0]
|
74
|
+
update_payload = {}
|
75
|
+
add_bound("q".freeze, update, update_payload)
|
76
|
+
add_bound("u".freeze, update, update_payload)
|
77
|
+
add_value("multi".freeze, update, update_payload)
|
78
|
+
add_value("upsert".freeze, update, update_payload)
|
90
79
|
|
91
|
-
|
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)
|
80
|
+
payload["updates".freeze] = [update_payload]
|
97
81
|
|
98
|
-
|
82
|
+
payload["updates".freeze] << "..." if updates.length > 1
|
83
|
+
end
|
99
84
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
85
|
+
if (deletes = command["deletes".freeze])
|
86
|
+
# AFAICT the gem generally just sends one item in the updates array
|
87
|
+
delete = deletes[0]
|
88
|
+
delete_payload = {}
|
89
|
+
add_bound("q".freeze, delete, delete_payload)
|
90
|
+
add_value("limit".freeze, delete, delete_payload)
|
104
91
|
|
105
|
-
|
106
|
-
payload["pipeline".freeze] = pipeline.map { |segment| extract_binds(segment) }
|
107
|
-
end
|
92
|
+
payload["deletes".freeze] = [delete_payload]
|
108
93
|
|
109
|
-
|
110
|
-
|
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
|
-
}
|
94
|
+
payload["deletes".freeze] << "..." if deletes.length > 1
|
95
|
+
end
|
119
96
|
|
120
|
-
|
121
|
-
|
122
|
-
error "failed to begin instrumentation for Mongo; msg=%s", e.message
|
97
|
+
if (pipeline = command["pipeline".freeze])
|
98
|
+
payload["pipeline".freeze] = pipeline.map { |segment| extract_binds(segment) }
|
123
99
|
end
|
124
100
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
101
|
+
# We're ignoring documents from insert because they could have completely inconsistent
|
102
|
+
# format which would make it hard to merge.
|
103
|
+
|
104
|
+
opts = {
|
105
|
+
category: CAT,
|
106
|
+
title: title,
|
107
|
+
description: payload.empty? ? nil : payload.to_json,
|
108
|
+
meta: {
|
109
|
+
database: event.database_name
|
110
|
+
},
|
111
|
+
internal: true
|
112
|
+
}
|
113
|
+
|
114
|
+
@events[event.operation_id] = Skylight.instrument(opts)
|
115
|
+
rescue Exception => e
|
116
|
+
error "failed to begin instrumentation for Mongo; msg=%s", e.message
|
117
|
+
end
|
118
|
+
|
119
|
+
def end_instrumentation(event)
|
120
|
+
if (original_event = @events.delete(event.operation_id))
|
121
|
+
meta = {}
|
122
|
+
if event.is_a?(::Mongo::Monitoring::Event::CommandFailed)
|
123
|
+
meta[:exception] = ["CommandFailed", event.message]
|
132
124
|
end
|
133
|
-
|
134
|
-
error "failed to end instrumentation for Mongo; msg=%s", e.message
|
125
|
+
Skylight.done(original_event, meta)
|
135
126
|
end
|
127
|
+
rescue Exception => e
|
128
|
+
error "failed to end instrumentation for Mongo; msg=%s", e.message
|
129
|
+
end
|
136
130
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
end
|
131
|
+
def add_value(key, command, payload)
|
132
|
+
if command.key?(key)
|
133
|
+
value = command[key]
|
134
|
+
payload[key] = value
|
142
135
|
end
|
136
|
+
end
|
143
137
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
end
|
138
|
+
def add_bound(key, command, payload)
|
139
|
+
if (value = command[key])
|
140
|
+
payload[key] = extract_binds(value)
|
148
141
|
end
|
142
|
+
end
|
149
143
|
|
150
|
-
|
151
|
-
|
144
|
+
def extract_binds(hash)
|
145
|
+
ret = {}
|
152
146
|
|
153
|
-
|
154
|
-
ret[k] = v.is_a?(Hash) ? extract_binds(v) : "?".freeze
|
155
|
-
end
|
147
|
+
hash.each { |k, v| ret[k] = v.is_a?(Hash) ? extract_binds(v) : "?".freeze }
|
156
148
|
|
157
|
-
|
158
|
-
|
149
|
+
ret
|
150
|
+
end
|
159
151
|
end
|
160
152
|
end
|
161
153
|
|