plain_apm 0.9.1 → 0.9.3
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/lib/plain_apm/agent.rb +73 -31
- data/lib/plain_apm/config.rb +0 -2
- data/lib/plain_apm/event_attributes.rb +70 -56
- data/lib/plain_apm/extensions/context/railtie.rb +11 -17
- data/lib/plain_apm/extensions/context.rb +4 -0
- data/lib/plain_apm/extensions/exceptions/active_job.rb +1 -1
- data/lib/plain_apm/extensions/exceptions/rack.rb +2 -2
- data/lib/plain_apm/extensions/exceptions/railtie.rb +5 -11
- data/lib/plain_apm/extensions/exceptions.rb +3 -0
- data/lib/plain_apm/extensions/thread_allocations/active_support_event.rb +2 -8
- data/lib/plain_apm/extensions/thread_allocations/railtie.rb +9 -13
- data/lib/plain_apm/extensions/thread_allocations.rb +2 -0
- data/lib/plain_apm/helpers.rb +2 -1
- data/lib/plain_apm/hooks/action_mailer.rb +11 -9
- data/lib/plain_apm/hooks/action_pack.rb +11 -9
- data/lib/plain_apm/hooks/action_view.rb +20 -18
- data/lib/plain_apm/hooks/active_job.rb +21 -19
- data/lib/plain_apm/hooks/active_record.rb +10 -2
- data/lib/plain_apm/hooks/active_support.rb +23 -21
- data/lib/plain_apm/hooks/active_support_subscriber.rb +0 -7
- data/lib/plain_apm/hooks/error_reporter.rb +2 -2
- data/lib/plain_apm/hooks/manual.rb +6 -6
- data/lib/plain_apm/queue.rb +123 -0
- data/lib/plain_apm/transport.rb +15 -12
- data/lib/plain_apm/version.rb +1 -1
- data/lib/plain_apm.rb +23 -26
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a2950f7d2e02a813b67a5bfb4c2ff7cc522acb8770404e3ef3dcef4e13aa4c4c
|
4
|
+
data.tar.gz: 4af16bf90b9904db8f5adf9efc6438aec2a6f31954a481f1a3384fbdadddf1d4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6ceba3781efda4b4b60dc66f85ed07a065b47c624d7c6da2fbd42d52bc525cf2b95204d9030aa6e5540e7f6e5e6112b387a40008b29c69236cedcbeb9ae62e69
|
7
|
+
data.tar.gz: '08dcda87123a5e006442cfe574da4ee41c011a28880b559a19bb65871785eb06154ba19f86c00d159c7d0c3e40b22c9758b6a373150de1344a001062fab0cd96'
|
data/lib/plain_apm/agent.rb
CHANGED
@@ -1,62 +1,82 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "singleton"
|
4
|
-
require "json"
|
5
4
|
|
6
5
|
module PlainApm
|
7
6
|
class Agent
|
8
7
|
include Singleton
|
9
8
|
|
10
|
-
def
|
11
|
-
|
9
|
+
def enabled?
|
10
|
+
@config && @config.enabled
|
12
11
|
end
|
13
12
|
|
14
|
-
def
|
15
|
-
|
16
|
-
end
|
13
|
+
def collect(event)
|
14
|
+
return unless enabled?
|
17
15
|
|
18
|
-
|
19
|
-
|
20
|
-
end
|
16
|
+
# stop accepting events when shutting down / shutdown.
|
17
|
+
return if @status != :running
|
21
18
|
|
22
|
-
|
23
|
-
return unless @config.enabled
|
19
|
+
publisher_start if @pid != $$
|
24
20
|
|
25
21
|
@events << event
|
26
22
|
end
|
27
23
|
|
28
24
|
def start
|
29
|
-
|
30
|
-
|
25
|
+
if !defined?(@started)
|
26
|
+
@started = true
|
27
|
+
else
|
28
|
+
return
|
29
|
+
end
|
31
30
|
|
32
31
|
configure
|
33
32
|
|
34
|
-
return unless
|
33
|
+
return unless enabled?
|
34
|
+
|
35
|
+
warn("PlainAPM agent enabled.")
|
36
|
+
|
37
|
+
setup_at_exit_hooks
|
38
|
+
publisher_start
|
39
|
+
install_hooks
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def stop
|
45
|
+
uninstall_hooks
|
46
|
+
publisher_shutdown
|
47
|
+
end
|
48
|
+
|
49
|
+
def publisher_start
|
50
|
+
# Store PID for fork detection
|
51
|
+
@pid = $$
|
52
|
+
|
53
|
+
# Already running
|
54
|
+
return if @publisher&.alive?
|
35
55
|
|
36
|
-
# TODO: sized queue
|
37
|
-
@events =
|
56
|
+
# TODO: sized queue.
|
57
|
+
@events = PlainApm::Queue.new
|
38
58
|
|
39
59
|
# TODO: Multiple threads
|
40
60
|
@publisher = Thread.new { publisher_loop }
|
41
61
|
|
42
|
-
|
62
|
+
@status = :running
|
63
|
+
end
|
43
64
|
|
44
|
-
|
65
|
+
def setup_at_exit_hooks
|
45
66
|
at_exit { stop }
|
46
67
|
end
|
47
68
|
|
48
|
-
def
|
69
|
+
def publisher_shutdown
|
49
70
|
return if @publisher.nil?
|
50
71
|
|
51
|
-
|
52
|
-
|
72
|
+
# FIXME: raise in / kill the threads after a pre-determined timeout not
|
73
|
+
# to block
|
74
|
+
@status = :shutting_down
|
53
75
|
@events << nil
|
54
76
|
@publisher.join
|
55
77
|
@publisher = nil
|
56
78
|
end
|
57
79
|
|
58
|
-
private
|
59
|
-
|
60
80
|
def configure
|
61
81
|
@config = Config.new
|
62
82
|
end
|
@@ -92,16 +112,38 @@ module PlainApm
|
|
92
112
|
app_key: @config.app_key
|
93
113
|
)
|
94
114
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
break if event.nil?
|
115
|
+
buf = []
|
116
|
+
timeout = 1.0
|
99
117
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
118
|
+
loop do
|
119
|
+
event = @events.pop(timeout: timeout)
|
120
|
+
|
121
|
+
buf << event if event
|
122
|
+
|
123
|
+
case @status
|
124
|
+
when :running
|
125
|
+
# not a timeout or full buffer
|
126
|
+
next if !event.nil? && buf.size < 128
|
127
|
+
send(transport, buf)
|
128
|
+
buf = []
|
129
|
+
when :shutting_down
|
130
|
+
send(transport, buf)
|
131
|
+
buf = []
|
132
|
+
@status = :shutdown
|
133
|
+
break
|
134
|
+
when :shutdown
|
135
|
+
nil
|
136
|
+
else
|
137
|
+
# ?
|
138
|
+
end
|
104
139
|
end
|
105
140
|
end
|
141
|
+
|
142
|
+
# TODO: retries / drops
|
143
|
+
def send(transport, buf)
|
144
|
+
return if buf.empty?
|
145
|
+
meta = { queue: @events.size, pid: $$, thread: Thread.current.object_id, sent_at: Time.now.to_f }
|
146
|
+
_response, _error, _retriable = transport.deliver(buf, meta)
|
147
|
+
end
|
106
148
|
end
|
107
149
|
end
|
data/lib/plain_apm/config.rb
CHANGED
@@ -21,34 +21,45 @@ module PlainApm
|
|
21
21
|
|
22
22
|
return [source, nil] if IGNORED_EXCEPTIONS.include?(e.class.name)
|
23
23
|
|
24
|
-
attrs =
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
24
|
+
attrs = context_attributes
|
25
|
+
|
26
|
+
attrs[:class] = e.class.name
|
27
|
+
attrs[:message] = e.message
|
28
|
+
attrs[:backtrace] = e.backtrace
|
29
29
|
|
30
30
|
if error_source
|
31
|
-
attrs[
|
31
|
+
attrs[:event_source] = error_source
|
32
32
|
end
|
33
33
|
|
34
34
|
if context[:env]
|
35
|
-
attrs[
|
35
|
+
attrs[:params] = context[:env]["action_dispatch.request.parameters"]
|
36
36
|
end
|
37
37
|
|
38
38
|
if context[:job]&.is_a?(ActiveJob::Base)
|
39
|
-
attrs[
|
40
|
-
attrs[
|
39
|
+
attrs[:job_class] = context[:job].class.name
|
40
|
+
attrs[:queue_name] = context[:job].queue_name
|
41
|
+
end
|
42
|
+
|
43
|
+
# https://bugs.ruby-lang.org/issues/19197
|
44
|
+
root_cause = e
|
45
|
+
root_cause = root_cause.cause while root_cause.cause
|
46
|
+
|
47
|
+
if root_cause != e
|
48
|
+
attrs[:root_cause_class] = root_cause.class.name
|
49
|
+
attrs[:root_cause_message] = root_cause.message
|
50
|
+
attrs[:root_cause_backtrace] = root_cause.backtrace
|
51
|
+
loc = source_location(root_cause.backtrace)
|
52
|
+
if !loc.nil?
|
53
|
+
attrs[:root_cause_location] = loc
|
54
|
+
end
|
41
55
|
end
|
42
56
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
"cause_message" => e.cause.message,
|
47
|
-
"cause_backtrace" => e.cause.backtrace
|
48
|
-
})
|
57
|
+
loc = source_location(e.backtrace)
|
58
|
+
if !loc.nil?
|
59
|
+
attrs[:source_location] = loc
|
49
60
|
end
|
50
61
|
|
51
|
-
attrs
|
62
|
+
add_trace_attributes(attrs)
|
52
63
|
|
53
64
|
[source, attrs]
|
54
65
|
end
|
@@ -57,70 +68,73 @@ module PlainApm
|
|
57
68
|
name, source = *event.name.split(".")
|
58
69
|
loc = source_location
|
59
70
|
|
60
|
-
attrs =
|
61
|
-
"source" => source,
|
62
|
-
"name" => name,
|
63
|
-
"allocations" => event.allocations,
|
64
|
-
"event_time" => event.time,
|
65
|
-
"duration" => event.duration
|
66
|
-
}
|
71
|
+
attrs = context_attributes
|
67
72
|
|
68
|
-
attrs[
|
69
|
-
attrs[
|
73
|
+
attrs[:source] = source
|
74
|
+
attrs[:name] = name
|
75
|
+
attrs[:allocations] = event.allocations
|
76
|
+
attrs[:event_time] = event.time
|
77
|
+
attrs[:duration] = event.duration
|
70
78
|
|
71
|
-
|
79
|
+
if event.respond_to?(:thread_allocations)
|
80
|
+
attrs[:thread_allocations] = event.thread_allocations
|
81
|
+
end
|
82
|
+
|
83
|
+
if !loc.nil?
|
84
|
+
attrs[:source_location] = loc
|
85
|
+
end
|
86
|
+
|
87
|
+
add_trace_attributes(attrs)
|
72
88
|
|
73
89
|
[name, attrs]
|
74
90
|
end
|
75
91
|
|
76
92
|
private
|
77
93
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
# the feature.
|
89
|
-
"pid" => Process.pid,
|
90
|
-
"version" => PlainApm::VERSION
|
91
|
-
}.merge(
|
92
|
-
cached_attributes
|
93
|
-
)
|
94
|
+
# TODO: There is a perf cost in Rubies for Process.pid until 3.3, so it
|
95
|
+
# might be a good idea to cache this. See
|
96
|
+
# https://bugs.ruby-lang.org/issues/19443 for the feature.
|
97
|
+
def add_trace_attributes(attrs)
|
98
|
+
attrs[:thread_id] = Thread.current.object_id
|
99
|
+
attrs[:collected_at] = Time.now.to_f
|
100
|
+
attrs[:pid] = Process.pid
|
101
|
+
attrs[:version] = PlainApm::VERSION
|
102
|
+
attrs[:hostname] = cached_attributes[:hostname]
|
103
|
+
attrs[:revision] = cached_attributes[:revision]
|
94
104
|
end
|
95
105
|
|
96
106
|
def cached_attributes
|
97
107
|
@cached_attributes ||= {
|
98
|
-
|
99
|
-
|
108
|
+
hostname: Socket.gethostname,
|
109
|
+
revision: PlainApm::DeployTracking.revision
|
100
110
|
}
|
101
111
|
end
|
102
112
|
|
113
|
+
##
|
114
|
+
# Context contains the trace ID (which comes from either
|
115
|
+
# HTTP_X_REQUEST_ID header, the deserialized job,
|
116
|
+
# or is generated by the trace_id middleware).
|
117
|
+
# It can also carry user inserted app data.
|
103
118
|
def context_attributes
|
104
|
-
##
|
105
|
-
# Context contains the trace ID (which comes from either
|
106
|
-
# HTTP_X_REQUEST_ID header, the deserialized job,
|
107
|
-
# or is generated by the trace_id middleware).
|
108
|
-
# It can also carry user inserted app data.
|
109
119
|
if defined?(PlainApm::Extensions::Context)
|
110
|
-
PlainApm::Extensions::Context.current.
|
120
|
+
PlainApm::Extensions::Context.current.dup
|
111
121
|
else
|
112
122
|
{}
|
113
123
|
end
|
114
124
|
end
|
115
125
|
|
116
|
-
def source_location
|
117
|
-
|
126
|
+
def source_location(backtrace = nil)
|
127
|
+
return if self.class.rails_root.nil?
|
128
|
+
call = (backtrace || caller).find { |frame| frame.start_with?(self.class.rails_root) } || return
|
129
|
+
call[(self.class.rails_root.size + 1)..-1]
|
118
130
|
end
|
119
131
|
|
120
|
-
def
|
121
|
-
|
122
|
-
|
123
|
-
|
132
|
+
def self.included(other)
|
133
|
+
other.class_eval do
|
134
|
+
def self.rails_root
|
135
|
+
return @rails_root if defined?(@rails_root)
|
136
|
+
@rails_root = (defined?(Rails) && Rails.root.to_s.present?) ? Rails.root.to_s.freeze : nil
|
137
|
+
end
|
124
138
|
end
|
125
139
|
end
|
126
140
|
end
|
@@ -7,27 +7,21 @@
|
|
7
7
|
#
|
8
8
|
# See LICENSE.txt in the current directory for the license.
|
9
9
|
|
10
|
-
begin
|
11
|
-
require "rails/railtie"
|
12
|
-
rescue LoadError
|
13
|
-
nil
|
14
|
-
end
|
15
|
-
|
16
10
|
module PlainApm
|
17
11
|
module Extensions
|
18
12
|
module Context
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
13
|
+
class Railtie < Rails::Railtie
|
14
|
+
initializer(:plain_apm_thread_context, after: :plain_apm_agent_start) do |app|
|
15
|
+
next if !PlainApm.agent.enabled?
|
16
|
+
|
17
|
+
ActiveSupport.on_load(:active_job, run_once: true) do |klass|
|
18
|
+
klass.prepend(PlainApm::Extensions::Context::ActiveJob)
|
19
|
+
end
|
25
20
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
end
|
21
|
+
if defined?(ActionDispatch::RequestId)
|
22
|
+
app.config.middleware.insert_after ActionDispatch::RequestId, PlainApm::Extensions::Context::Rack
|
23
|
+
else
|
24
|
+
app.config.middleware.insert_after Rack::MethodOverride, PlainApm::Extensions::Context::Rack
|
31
25
|
end
|
32
26
|
end
|
33
27
|
end
|
@@ -1,19 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
begin
|
4
|
-
require "rails/railtie"
|
5
|
-
rescue LoadError
|
6
|
-
nil
|
7
|
-
end
|
8
|
-
|
9
3
|
module PlainApm
|
10
4
|
module Extensions
|
11
5
|
module Exceptions
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
6
|
+
class Railtie < Rails::Railtie
|
7
|
+
initializer(:plain_apm_exceptions_middleware, after: :plain_apm_agent_start) do |app|
|
8
|
+
next if !PlainApm.agent.enabled?
|
9
|
+
|
10
|
+
app.config.middleware.insert(0, PlainApm::Extensions::Exceptions::Rack)
|
17
11
|
end
|
18
12
|
end
|
19
13
|
end
|
@@ -16,14 +16,8 @@ module PlainApm
|
|
16
16
|
@thread_allocation_count_finish - @thread_allocation_count_start
|
17
17
|
end
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
PlainApm::ObjectTracing.total_thread_allocated_objects
|
22
|
-
end
|
23
|
-
else
|
24
|
-
def now_thread_allocations
|
25
|
-
0
|
26
|
-
end
|
19
|
+
def now_thread_allocations
|
20
|
+
PlainApm::ObjectTracing.total_thread_allocated_objects
|
27
21
|
end
|
28
22
|
end
|
29
23
|
end
|
@@ -1,21 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
begin
|
4
|
-
require "rails/railtie"
|
5
|
-
rescue LoadError
|
6
|
-
nil
|
7
|
-
end
|
8
|
-
|
9
3
|
module PlainApm
|
10
4
|
module Extensions
|
11
5
|
module ThreadAllocations
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
6
|
+
class Railtie < Rails::Railtie
|
7
|
+
initializer(:plain_apm_thread_allocationss, after: :plain_apm_agent_start) do
|
8
|
+
next if !PlainApm.agent.enabled?
|
9
|
+
|
10
|
+
require "object_tracing"
|
11
|
+
|
12
|
+
ActiveSupport::Notifications::Event.prepend(
|
13
|
+
PlainApm::Extensions::ThreadAllocations::ActiveSupportEvent
|
14
|
+
)
|
19
15
|
end
|
20
16
|
end
|
21
17
|
end
|
data/lib/plain_apm/helpers.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
module PlainApm
|
2
2
|
module Helpers
|
3
3
|
def plain_apm_context(context = {})
|
4
|
+
return unless PlainApm.agent.enabled?
|
4
5
|
PlainApm::Extensions::Context.context.merge!(context)
|
5
6
|
end
|
6
7
|
|
7
8
|
def plain_apm_instrument(name, context = {}, &block)
|
9
|
+
return unless PlainApm.agent.enabled? && defined?(ActiveSupport::Notifications)
|
8
10
|
sanitized_name = name.gsub(/\W/, "_").gsub(/(?!^)([A-Z])/) { |m| "_#{m}" }.squeeze("_").downcase
|
9
|
-
return unless defined?(ActiveSupport::Notifications)
|
10
11
|
ActiveSupport::Notifications.instrument("#{sanitized_name}.manual_plain_apm", **context, &block)
|
11
12
|
end
|
12
13
|
end
|
@@ -17,16 +17,18 @@ module PlainApm
|
|
17
17
|
|
18
18
|
case name
|
19
19
|
when "deliver"
|
20
|
-
base.
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
20
|
+
base.tap do |o|
|
21
|
+
o[:message_id] = payload[:message_id]
|
22
|
+
o[:mailer] = payload[:mailer]
|
23
|
+
o[:perform_deliveries] = payload[:perform_deliveries]
|
24
|
+
end
|
25
25
|
when "process"
|
26
|
-
base.
|
27
|
-
|
28
|
-
|
29
|
-
|
26
|
+
base.tap do |o|
|
27
|
+
o[:mailer] = payload[:mailer]
|
28
|
+
o[:action] = payload[:action]
|
29
|
+
end
|
30
|
+
else
|
31
|
+
nil
|
30
32
|
end
|
31
33
|
end
|
32
34
|
end
|
@@ -17,20 +17,22 @@ module PlainApm
|
|
17
17
|
|
18
18
|
case name
|
19
19
|
when "process_action"
|
20
|
-
base.
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
20
|
+
base.tap do |o|
|
21
|
+
o[:controller] = payload[:controller]
|
22
|
+
o[:action] = payload[:action]
|
23
|
+
o[:params] = payload[:params]
|
24
|
+
o[:format] = payload[:format]
|
25
|
+
o[:method] = payload[:method]
|
26
|
+
o[:path] = payload[:path]
|
27
|
+
o[:status] = payload[:status]
|
28
|
+
end
|
29
29
|
when "redirect_to", "start_processing", "halted_callback", "send_file", "send_data"
|
30
30
|
nil
|
31
31
|
when "read_fragment", "write_fragment", "exist_fragment?", "expire_fragment"
|
32
32
|
# controller, action, key
|
33
33
|
nil
|
34
|
+
else
|
35
|
+
nil
|
34
36
|
end
|
35
37
|
end
|
36
38
|
end
|
@@ -17,27 +17,29 @@ module PlainApm
|
|
17
17
|
|
18
18
|
case name
|
19
19
|
when "render_collection"
|
20
|
-
base.
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
20
|
+
base.tap do |o|
|
21
|
+
o[:identifier] = identifier(payload[:identifier])
|
22
|
+
o[:layout] = payload[:layout]
|
23
|
+
o[:count] = payload[:count]
|
24
|
+
o[:cache_hits] = payload[:cache_hits]
|
25
|
+
end
|
26
26
|
when "render_layout"
|
27
|
-
base.
|
28
|
-
|
29
|
-
|
27
|
+
base.tap do |o|
|
28
|
+
o[:identifier] = identifier(payload[:identifier])
|
29
|
+
end
|
30
30
|
when "render_template"
|
31
|
-
base.
|
32
|
-
|
33
|
-
|
34
|
-
|
31
|
+
base.tap do |o|
|
32
|
+
o[:identifier] = identifier(payload[:identifier])
|
33
|
+
o[:layout] = payload[:layout]
|
34
|
+
end
|
35
35
|
when "render_partial"
|
36
|
-
base.
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
36
|
+
base.tap do |o|
|
37
|
+
o[:identifier] = identifier(payload[:identifier])
|
38
|
+
o[:layout] = payload[:layout]
|
39
|
+
o[:cache_hit] = payload[:cache_hit]
|
40
|
+
end
|
41
|
+
else
|
42
|
+
nil
|
41
43
|
end
|
42
44
|
end
|
43
45
|
|
@@ -16,33 +16,35 @@ module PlainApm
|
|
16
16
|
payload = event.payload
|
17
17
|
job = payload[:job]
|
18
18
|
|
19
|
-
base.
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
19
|
+
base.tap do |o|
|
20
|
+
o[:queue_name] = job.queue_name
|
21
|
+
o[:job_id] = job.job_id
|
22
|
+
o[:job_class] = job.class.name
|
23
|
+
o[:job_arguments] = job.arguments
|
24
|
+
o[:executions] = job.executions
|
25
|
+
o[:enqueued_at] = enqueued_at(job)
|
26
|
+
o[:dequeued_at] = dequeued_at(job)
|
27
|
+
o[:scheduled_at] = job.scheduled_at
|
28
|
+
o[:adapter] = payload[:adapter].class.name
|
29
|
+
o[:aborted] = payload[:aborted]
|
30
|
+
end
|
31
31
|
|
32
32
|
case name
|
33
33
|
when "enqueue", "enqueue_at", "perform"
|
34
34
|
base
|
35
35
|
when "enqueue_retry"
|
36
|
-
base.
|
37
|
-
|
38
|
-
|
39
|
-
|
36
|
+
base.tap do |o|
|
37
|
+
o[:error] = payload[:error]
|
38
|
+
o[:wait] = payload[:wait]
|
39
|
+
end
|
40
40
|
when "retry_stopped", "discard"
|
41
|
-
base.
|
42
|
-
|
43
|
-
|
41
|
+
base.tap do |o|
|
42
|
+
o[:error] = payload[:error]
|
43
|
+
end
|
44
44
|
when "perform_start"
|
45
45
|
nil
|
46
|
+
else
|
47
|
+
nil
|
46
48
|
end
|
47
49
|
end
|
48
50
|
|
@@ -22,9 +22,17 @@ module PlainApm
|
|
22
22
|
|
23
23
|
case name
|
24
24
|
when "sql"
|
25
|
-
base.
|
25
|
+
base.tap do |o|
|
26
|
+
o[:sql] = payload[:sql]
|
27
|
+
o[:sql_name] = payload[:name]
|
28
|
+
end
|
26
29
|
when "instantiation"
|
27
|
-
base.
|
30
|
+
base.tap do |o|
|
31
|
+
o[:class_name] = payload[:class_name]
|
32
|
+
o[:record_count] = payload[:record_count]
|
33
|
+
end
|
34
|
+
else
|
35
|
+
nil
|
28
36
|
end
|
29
37
|
end
|
30
38
|
end
|
@@ -15,34 +15,36 @@ module PlainApm
|
|
15
15
|
name, base = attributes_from_notification(event)
|
16
16
|
payload = event.payload
|
17
17
|
|
18
|
-
base[
|
18
|
+
base[:store] = payload[:store]
|
19
19
|
|
20
20
|
case name
|
21
21
|
when "cache_read"
|
22
|
-
base.
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
22
|
+
base.tap do |o|
|
23
|
+
o[:key] = payload[:key]
|
24
|
+
o[:hit] = payload[:hit]
|
25
|
+
o[:trigger] = payload[:super_operation]
|
26
|
+
end
|
27
27
|
when "cache_read_multi"
|
28
|
-
base.
|
29
|
-
|
30
|
-
|
31
|
-
|
28
|
+
base.tap do |o|
|
29
|
+
o[:keys] = payload[:key]
|
30
|
+
o[:hits] = payload[:hits]
|
31
|
+
end
|
32
32
|
when "cache_fetch_hit"
|
33
|
-
base.
|
34
|
-
|
35
|
-
|
36
|
-
|
33
|
+
base.tap do |o|
|
34
|
+
o[:key] = payload[:key]
|
35
|
+
o[:hit] = true
|
36
|
+
end
|
37
37
|
when "cache_write", "cache_write_multi", "cache_generate", "cache_delete", "cache_delete_matched", "cache_exist?"
|
38
|
-
base.
|
39
|
-
|
40
|
-
|
38
|
+
base.tap do |o|
|
39
|
+
o[:key] = payload[:key]
|
40
|
+
end
|
41
41
|
when "cache_increment", "cache_decrement"
|
42
|
-
base.
|
43
|
-
|
44
|
-
|
45
|
-
|
42
|
+
base.tap do |o|
|
43
|
+
o[:key] = payload[:key]
|
44
|
+
o[:amount] = payload[:amount]
|
45
|
+
end
|
46
|
+
else
|
47
|
+
nil
|
46
48
|
end
|
47
49
|
end
|
48
50
|
end
|
@@ -14,12 +14,12 @@ module PlainApm
|
|
14
14
|
def payload(event)
|
15
15
|
name, base = attributes_from_notification(event)
|
16
16
|
|
17
|
-
base.
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
17
|
+
base.tap do |o|
|
18
|
+
o[:source] = "user"
|
19
|
+
o[:name] = "manual"
|
20
|
+
o[:payload_name] = name
|
21
|
+
o[:payload] = event.payload
|
22
|
+
end
|
23
23
|
end
|
24
24
|
end
|
25
25
|
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
module PlainApm
|
2
|
+
if RUBY_VERSION >= "3.2.0"
|
3
|
+
Queue = Thread::Queue
|
4
|
+
else
|
5
|
+
# The queue is made to conform to the ruby/spec
|
6
|
+
class Queue
|
7
|
+
ClosedQueueError = Class.new(StopIteration)
|
8
|
+
|
9
|
+
def initialize(initial = nil)
|
10
|
+
@data = []
|
11
|
+
@num_waiting = 0
|
12
|
+
@closed = false
|
13
|
+
@mutex = Mutex.new
|
14
|
+
@cv = ConditionVariable.new
|
15
|
+
|
16
|
+
return if initial.nil?
|
17
|
+
|
18
|
+
raise TypeError, "can't convert #{initial.class} into Array" unless initial.respond_to?(:to_a)
|
19
|
+
|
20
|
+
elems = initial.to_a
|
21
|
+
raise TypeError, "can't convert #{initial.class} into Array (#{initial.class}#to_a gives #{elems.class})" unless elems.is_a?(Array)
|
22
|
+
|
23
|
+
@data.concat(elems)
|
24
|
+
end
|
25
|
+
|
26
|
+
def close
|
27
|
+
@mutex.synchronize do
|
28
|
+
return if @closed
|
29
|
+
@closed = true
|
30
|
+
# Wake up everyone waiting on this.
|
31
|
+
@cv.broadcast
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def closed?
|
36
|
+
@closed
|
37
|
+
end
|
38
|
+
|
39
|
+
def clear
|
40
|
+
@data = []
|
41
|
+
end
|
42
|
+
|
43
|
+
def num_waiting
|
44
|
+
@num_waiting
|
45
|
+
end
|
46
|
+
|
47
|
+
def empty?
|
48
|
+
@data.empty?
|
49
|
+
end
|
50
|
+
|
51
|
+
def length
|
52
|
+
@data.length
|
53
|
+
end
|
54
|
+
|
55
|
+
alias_method :size, :length
|
56
|
+
|
57
|
+
def push(obj)
|
58
|
+
@mutex.synchronize do
|
59
|
+
raise ClosedQueueError if closed?
|
60
|
+
@data << obj
|
61
|
+
@cv.signal
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
alias_method :<<, :push
|
66
|
+
alias_method :enq, :push
|
67
|
+
|
68
|
+
def pop(non_block = false, timeout: nil)
|
69
|
+
if non_block && timeout
|
70
|
+
raise ArgumentError, "can't set a timeout if non_block is enabled"
|
71
|
+
end
|
72
|
+
|
73
|
+
if !timeout.nil? && !timeout.is_a?(Numeric)
|
74
|
+
raise TypeError, "no implicit conversion to float from #{timeout.class.name.downcase}"
|
75
|
+
end
|
76
|
+
|
77
|
+
@mutex.synchronize do
|
78
|
+
# The data is there.
|
79
|
+
return @data.shift if !@data.empty?
|
80
|
+
|
81
|
+
# Non block raises on empty queue
|
82
|
+
raise ThreadError, "queue empty" if non_block
|
83
|
+
|
84
|
+
# 0 means immediate timeout. Closed empty queue also immediately returns a nil
|
85
|
+
return nil if timeout == 0 || @closed
|
86
|
+
|
87
|
+
# Blocking and open. Let's wait.
|
88
|
+
timeout_at = timeout.nil? ? nil : now + timeout.to_f
|
89
|
+
|
90
|
+
begin
|
91
|
+
# We could keep the threads in an array, but a counter should do as well.
|
92
|
+
@num_waiting += 1
|
93
|
+
|
94
|
+
while @data.empty? && !@closed
|
95
|
+
if timeout_at.nil?
|
96
|
+
# Wait indefinitely.
|
97
|
+
@cv.wait(@mutex)
|
98
|
+
else
|
99
|
+
# Wait for what's left of the deadline
|
100
|
+
break if (left = timeout_at - now) <= 0.0
|
101
|
+
@cv.wait(@mutex, left)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
ensure
|
105
|
+
@num_waiting -= 1
|
106
|
+
end
|
107
|
+
|
108
|
+
# Return whatever is there now, or nil (if timed out)
|
109
|
+
@data.shift
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
alias_method :deq, :pop
|
114
|
+
alias_method :shift, :pop
|
115
|
+
|
116
|
+
private
|
117
|
+
|
118
|
+
def now
|
119
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
data/lib/plain_apm/transport.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require "net/http"
|
4
4
|
require "json"
|
5
|
+
require "zlib"
|
5
6
|
|
6
7
|
module PlainApm
|
7
8
|
class Transport
|
@@ -16,7 +17,7 @@ module PlainApm
|
|
16
17
|
HTTP_TIMEOUTS = [
|
17
18
|
Net::OpenTimeout,
|
18
19
|
Net::ReadTimeout,
|
19
|
-
|
20
|
+
Net::WriteTimeout
|
20
21
|
].compact.freeze
|
21
22
|
|
22
23
|
ERRNO_ERRORS = [
|
@@ -47,10 +48,7 @@ module PlainApm
|
|
47
48
|
|
48
49
|
http.open_timeout = HTTP_OPEN_TIMEOUT_SECONDS
|
49
50
|
http.read_timeout = HTTP_READ_TIMEOUT_SECONDS
|
50
|
-
|
51
|
-
if RUBY_VERSION >= "2.6.0"
|
52
|
-
http.write_timeout = HTTP_WRITE_TIMEOUT_SECONDS
|
53
|
-
end
|
51
|
+
http.write_timeout = HTTP_WRITE_TIMEOUT_SECONDS
|
54
52
|
|
55
53
|
at_exit { shutdown }
|
56
54
|
end
|
@@ -60,9 +58,9 @@ module PlainApm
|
|
60
58
|
#
|
61
59
|
# @param data [String] serialized payload to POST
|
62
60
|
# @return [Array] [response, error, retriable]
|
63
|
-
def deliver(data)
|
61
|
+
def deliver(data, meta = {})
|
64
62
|
http_response do
|
65
|
-
http_request(http, uri.path, data)
|
63
|
+
http_request(http, uri.path, data, meta)
|
66
64
|
end
|
67
65
|
end
|
68
66
|
|
@@ -82,16 +80,21 @@ module PlainApm
|
|
82
80
|
http.finish if http.started?
|
83
81
|
end
|
84
82
|
|
85
|
-
def http_request(http, path, body)
|
86
|
-
request = Net::HTTP::Post.new(path, http_headers)
|
87
|
-
http.request(request, body)
|
83
|
+
def http_request(http, path, body, meta)
|
84
|
+
request = Net::HTTP::Post.new(path, http_headers(meta))
|
85
|
+
http.request(request, Zlib::Deflate.deflate(JSON.generate(body)))
|
88
86
|
end
|
89
87
|
|
90
|
-
def http_headers
|
88
|
+
def http_headers(meta)
|
89
|
+
meta_headers = meta.map do |k, v|
|
90
|
+
["X-PlainApm-#{k.to_s.split("_").map(&:capitalize).join("-")}", v.to_s]
|
91
|
+
end.to_h
|
92
|
+
|
91
93
|
{
|
92
94
|
"Content-Type" => "application/json, charset=UTF-8",
|
95
|
+
"Content-Encoding" => "gzip",
|
93
96
|
"X-PlainApm-Key" => app_key
|
94
|
-
}
|
97
|
+
}.merge(meta_headers)
|
95
98
|
end
|
96
99
|
|
97
100
|
def http_response
|
data/lib/plain_apm/version.rb
CHANGED
data/lib/plain_apm.rb
CHANGED
@@ -1,13 +1,31 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# Rails deps
|
4
|
+
begin
|
5
|
+
require "active_support"
|
6
|
+
require "active_support/notifications"
|
7
|
+
require "rails/railtie"
|
8
|
+
rescue LoadError
|
9
|
+
nil
|
10
|
+
end
|
11
|
+
|
3
12
|
require_relative "plain_apm/version"
|
4
13
|
require_relative "plain_apm/transport"
|
14
|
+
require_relative "plain_apm/queue"
|
5
15
|
require_relative "plain_apm/config"
|
6
16
|
require_relative "plain_apm/agent"
|
7
17
|
require_relative "plain_apm/deploy_tracking"
|
8
18
|
require_relative "plain_apm/event_attributes"
|
19
|
+
require_relative "plain_apm/helpers"
|
20
|
+
|
21
|
+
# Per thread context for request IDs / job IDs.
|
22
|
+
require_relative "plain_apm/extensions/context"
|
9
23
|
|
10
|
-
|
24
|
+
# Rack exceptions. Activate the middleware if in Rails.
|
25
|
+
require_relative "plain_apm/extensions/exceptions"
|
26
|
+
|
27
|
+
# Per thread allocations in ASN events
|
28
|
+
require_relative "plain_apm/extensions/thread_allocations"
|
11
29
|
|
12
30
|
# Rails instrumentation. The hooks won't install unless
|
13
31
|
# ActiveSupport::Notifications is loaded.
|
@@ -21,23 +39,6 @@ require_relative "plain_apm/hooks/active_support"
|
|
21
39
|
require_relative "plain_apm/hooks/manual"
|
22
40
|
require_relative "plain_apm/hooks/error_reporter"
|
23
41
|
|
24
|
-
# Per thread context for request IDs / job IDs.
|
25
|
-
require_relative "plain_apm/extensions/context"
|
26
|
-
require_relative "plain_apm/extensions/context/rack"
|
27
|
-
require_relative "plain_apm/extensions/context/active_job"
|
28
|
-
require_relative "plain_apm/extensions/context/railtie"
|
29
|
-
|
30
|
-
# Per thread allocations in ASN events
|
31
|
-
require_relative "plain_apm/extensions/thread_allocations/active_support_event"
|
32
|
-
require_relative "plain_apm/extensions/thread_allocations/railtie"
|
33
|
-
|
34
|
-
# Helpers du jour.
|
35
|
-
require_relative "plain_apm/helpers"
|
36
|
-
|
37
|
-
# Rack exceptions. Activate the middleware if in Rails.
|
38
|
-
require_relative "plain_apm/extensions/exceptions/rack"
|
39
|
-
require_relative "plain_apm/extensions/exceptions/railtie"
|
40
|
-
|
41
42
|
module PlainApm
|
42
43
|
# Allow swapping out the Agent for a synchronous, in-memory implementation in
|
43
44
|
# the tests.
|
@@ -49,16 +50,12 @@ module PlainApm
|
|
49
50
|
@@agent ||= Agent.instance
|
50
51
|
end
|
51
52
|
|
52
|
-
begin
|
53
|
-
require "rails/railtie"
|
54
|
-
rescue LoadError
|
55
|
-
nil
|
56
|
-
end
|
57
|
-
|
58
|
-
# after_initialize allows reading settings from ENV on app start.
|
59
53
|
if defined?(Rails::Railtie)
|
60
54
|
class Railtie < Rails::Railtie
|
61
|
-
|
55
|
+
# allows reading settings from ENV vars set in config/initializers.
|
56
|
+
initializer(:plain_apm_agent_start, after: :load_config_initializers) do
|
57
|
+
PlainApm.agent.start
|
58
|
+
end
|
62
59
|
end
|
63
60
|
else
|
64
61
|
PlainApm.agent.start
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: plain_apm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- PlainAPM Team
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-03-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|
@@ -107,9 +107,11 @@ files:
|
|
107
107
|
- lib/plain_apm/extensions/context/middleware.rb
|
108
108
|
- lib/plain_apm/extensions/context/rack.rb
|
109
109
|
- lib/plain_apm/extensions/context/railtie.rb
|
110
|
+
- lib/plain_apm/extensions/exceptions.rb
|
110
111
|
- lib/plain_apm/extensions/exceptions/active_job.rb
|
111
112
|
- lib/plain_apm/extensions/exceptions/rack.rb
|
112
113
|
- lib/plain_apm/extensions/exceptions/railtie.rb
|
114
|
+
- lib/plain_apm/extensions/thread_allocations.rb
|
113
115
|
- lib/plain_apm/extensions/thread_allocations/active_support_event.rb
|
114
116
|
- lib/plain_apm/extensions/thread_allocations/railtie.rb
|
115
117
|
- lib/plain_apm/helpers.rb
|
@@ -122,6 +124,7 @@ files:
|
|
122
124
|
- lib/plain_apm/hooks/active_support_subscriber.rb
|
123
125
|
- lib/plain_apm/hooks/error_reporter.rb
|
124
126
|
- lib/plain_apm/hooks/manual.rb
|
127
|
+
- lib/plain_apm/queue.rb
|
125
128
|
- lib/plain_apm/transport.rb
|
126
129
|
- lib/plain_apm/version.rb
|
127
130
|
homepage: https://plainapm.com
|