plain_apm 0.6.6 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e97786261500cb8d3f51d59adcf10e16fae25ec9d75abb892f9f484e6a8f301e
4
- data.tar.gz: 81d5e828c98ab00c203d429e963c6ad54c39a81e5ac21c21f84400e0daed0287
3
+ metadata.gz: 2b4d2bddabd031b2b17d2edcf27e32f323c217b2331c469072e95d0afeb58ec7
4
+ data.tar.gz: a892bbd62da4a10b074046c39326576355d591bf02982f9d336a97d887f99bc6
5
5
  SHA512:
6
- metadata.gz: 0b967abf825f2a5e11c7318a207cfe7d254142999e80d255cd991802a85527fd89957c6819c0ef42a6e6887cb83c2084193c8cad760f906b8981b4514cae1b72
7
- data.tar.gz: 7db71b4417c755e4146ea5a9824f926dcc548b6a0de9952eaa752917fd85078af651f357acbd78c2900c89c4bf30df4183ef5ab67b5c7028f2591dc5e19a847a
6
+ metadata.gz: b523dbaea426bbb9f2e4c2808efb4937ebf5c842361d07c9a0ae6a23bef03fe8bef0a71815710b4c55a7f8a1eeaea01e8b0fbe01bb3ed9af58743a31aa09c0aa
7
+ data.tar.gz: 93c110b5e728cd6e934cbb25e56bd5345e3cc45dc1776922ca39a5de902e19a996fcc2aa7de0c749b231e8faf137b16be49f1d9389bec1735986223f18bc6798
@@ -1,6 +1,6 @@
1
- require 'mkmf'
1
+ require "mkmf"
2
2
 
3
- have_header('ruby/ruby.h') or missing('ruby/ruby.h')
4
- have_header('ruby/debug.h') or missing('ruby/debug.h')
3
+ have_header("ruby/ruby.h") or missing("ruby/ruby.h")
4
+ have_header("ruby/debug.h") or missing("ruby/debug.h")
5
5
 
6
- create_makefile('object_tracing')
6
+ create_makefile("object_tracing")
@@ -19,23 +19,6 @@ module PlainApm
19
19
  def collect(event)
20
20
  return unless @config.enabled
21
21
 
22
- ##
23
- # Context contains the trace ID (which comes from either
24
- # HTTP_X_REQUEST_ID header, the deserialized job,
25
- # or is generated by the trace_id middleware).
26
- # It can also carry user inserted app data.
27
- if defined?(PlainApm::Extensions::Context)
28
- event.merge!(PlainApm::Extensions::Context.current)
29
- end
30
-
31
- event.merge!(
32
- "version" => PlainApm::VERSION,
33
- "collected_at" => Time.now.utc.to_f,
34
- "hostname" => Socket.gethostname,
35
- "pid" => Process.pid,
36
- "thread_id" => Thread.current.object_id.to_s,
37
- )
38
-
39
22
  @events << event
40
23
  end
41
24
 
@@ -0,0 +1,131 @@
1
+ module PlainApm
2
+ module EventAttributes
3
+ SOURCES_WITH_HOST_ATTRIBUTES = %w[
4
+ action_controller
5
+ action_mailer
6
+ active_job
7
+ deploy
8
+ exception
9
+ ].freeze
10
+
11
+ # FIXME: This is duplicated for ErrorReporter
12
+ IGNORED_EXCEPTIONS = [
13
+ "Sidekiq::JobRetry::Skip", # Sidekiq uses exceptions for control flow.
14
+ "ActionController::RoutingError" # Rails unmapped route, raised before the request hits the app.
15
+ ].freeze
16
+
17
+ def attributes_from_deploy(tool, revision)
18
+ source = "deploy"
19
+
20
+ attrs = {
21
+ "source" => source,
22
+ "revision" => revision,
23
+ "name" => tool
24
+ }
25
+
26
+ attrs.merge!(agent_attributes)
27
+ attrs.merge!(host_attributes) if add_host_attributes?(source)
28
+
29
+ [tool, attrs]
30
+ end
31
+
32
+ def attributes_from_exception(e, context)
33
+ source = "exception"
34
+
35
+ return [source, nil] if IGNORED_EXCEPTIONS.include?(e.class.name)
36
+
37
+ attrs = {
38
+ "class" => e.class.name,
39
+ "message" => e.message,
40
+ "backtrace" => e.backtrace
41
+ }
42
+
43
+ if context[:env]
44
+ attrs["params"] = env["action_dispatch.request.parameters"]
45
+ end
46
+
47
+ if context[:job]&.is_a?(ActiveJob::Base)
48
+ attrs["job_class"] = context[:job].class.name
49
+ attrs["queue_name"] = context[:job].queue_name
50
+ end
51
+
52
+ if e.cause
53
+ attrs.merge!({
54
+ "cause_class" => e.cause.class.name,
55
+ "cause_message" => e.cause.message,
56
+ "cause_backtrace" => e.cause.backtrace
57
+ })
58
+ end
59
+
60
+ attrs.merge!(context_attributes, agent_attributes)
61
+ attrs.merge!(host_attributes) if add_host_attributes?(source)
62
+
63
+ [source, attrs]
64
+ end
65
+
66
+ def attributes_from_notification(event)
67
+ name, source = *event.name.split(".")
68
+ loc = source_location
69
+
70
+ attrs = {
71
+ "source" => source,
72
+ "name" => name,
73
+ "allocations" => event.allocations,
74
+ "thread_allocations" => event.thread_allocations,
75
+ "started_at" => event.time,
76
+ "finished_at" => event.end
77
+ }
78
+
79
+ attrs["source_location"] = loc if !loc.nil?
80
+ attrs.merge!(context_attributes, agent_attributes)
81
+ attrs.merge!(host_attributes) if add_host_attributes?(source)
82
+
83
+ [name, attrs]
84
+ end
85
+
86
+ private
87
+
88
+ def context_attributes
89
+ ##
90
+ # Context contains the trace ID (which comes from either
91
+ # HTTP_X_REQUEST_ID header, the deserialized job,
92
+ # or is generated by the trace_id middleware).
93
+ # It can also carry user inserted app data.
94
+ if defined?(PlainApm::Extensions::Context)
95
+ PlainApm::Extensions::Context.current
96
+ else
97
+ {}
98
+ end
99
+ end
100
+
101
+ def agent_attributes
102
+ {
103
+ "version" => PlainApm::VERSION
104
+ }
105
+ end
106
+
107
+ def host_attributes
108
+ {
109
+ "collected_at" => Time.now.iso8601(9),
110
+ "hostname" => Socket.gethostname,
111
+ "pid" => Process.pid,
112
+ "thread_id" => Thread.current.object_id
113
+ }
114
+ end
115
+
116
+ def add_host_attributes?(source)
117
+ SOURCES_WITH_HOST_ATTRIBUTES.include?(source)
118
+ end
119
+
120
+ def source_location
121
+ filtered_backtrace&.first
122
+ end
123
+
124
+ def filtered_backtrace
125
+ if defined?(Rails) && defined?(Rails::BacktraceCleaner)
126
+ @cleaner ||= Rails::BacktraceCleaner.new
127
+ @cleaner.clean(caller)
128
+ end
129
+ end
130
+ end
131
+ end
@@ -4,11 +4,7 @@ module PlainApm
4
4
  module Extensions
5
5
  module Exceptions
6
6
  class Rack
7
- # FIXME: This is duplicated for ErrorReporter
8
- IGNORED_EXCEPTIONS = [
9
- "Sidekiq::JobRetry::Skip", # Sidekiq uses exceptions for control flow.
10
- "ActionController::RoutingError" # Rails unmapped route, raised before the request hits the app.
11
- ].freeze
7
+ include EventAttributes
12
8
 
13
9
  def initialize(app)
14
10
  @app = app
@@ -29,24 +25,12 @@ module PlainApm
29
25
  private
30
26
 
31
27
  def report_exception(e, env)
32
- return if IGNORED_EXCEPTIONS.include?(e.class.name)
33
-
34
- event = {
35
- "source" => "exception",
36
- "name" => "rack_middleware",
37
- "class" => e.class.name,
38
- "message" => e.message,
39
- "backtrace" => e.backtrace,
40
- "params" => env["action_dispatch.request.parameters"]
41
- }
42
-
43
- if e.cause
44
- event.merge!({
45
- "cause_class" => e.cause.class.name,
46
- "cause_message" => e.cause.message,
47
- "cause_backtrace" => e.cause.backtrace
48
- })
49
- end
28
+ source, event = attributes_from_exception(e, {env: env})
29
+
30
+ return if event.nil?
31
+
32
+ event["source"] = source
33
+ event["name"] = "rack_middleware"
50
34
 
51
35
  PlainApm::Agent.collect(event)
52
36
  end
@@ -5,7 +5,7 @@ module PlainApm
5
5
  end
6
6
 
7
7
  def plain_apm_instrument(name, context = {}, &block)
8
- sanitized_name = name.gsub(/\W/, "_").gsub(/(?!^)([A-Z])/) { |m| "_#{m}" }.gsub(/_+/, "_").downcase
8
+ sanitized_name = name.gsub(/\W/, "_").gsub(/(?!^)([A-Z])/) { |m| "_#{m}" }.squeeze("_").downcase
9
9
  ActiveSupport::Notifications.instrument("#{sanitized_name}.manual_plain_apm", **context, &block)
10
10
  end
11
11
  end
@@ -12,19 +12,9 @@ module PlainApm
12
12
  end
13
13
 
14
14
  def payload(event)
15
- name, source = *event.name.split(".")
15
+ name, base = attributes_from_notification(event)
16
16
  payload = event.payload
17
17
 
18
- base = {
19
- "source" => source,
20
- "name" => name,
21
- "backtrace" => filtered_backtrace,
22
- "allocations" => event.allocations,
23
- "thread_allocations" => event.thread_allocations,
24
- "started_at" => event.time,
25
- "finished_at" => event.end
26
- }
27
-
28
18
  case name
29
19
  when "deliver"
30
20
  base.merge({
@@ -12,19 +12,9 @@ module PlainApm
12
12
  end
13
13
 
14
14
  def payload(event)
15
- name, source = *event.name.split(".")
15
+ name, base = attributes_from_notification(event)
16
16
  payload = event.payload
17
17
 
18
- base = {
19
- "source" => source,
20
- "name" => name,
21
- "backtrace" => filtered_backtrace,
22
- "allocations" => event.allocations,
23
- "thread_allocations" => event.thread_allocations,
24
- "started_at" => event.time,
25
- "finished_at" => event.end
26
- }
27
-
28
18
  case name
29
19
  when "process_action"
30
20
  base.merge({
@@ -12,19 +12,9 @@ module PlainApm
12
12
  end
13
13
 
14
14
  def payload(event)
15
- name, source = *event.name.split(".")
15
+ name, base = attributes_from_notification(event)
16
16
  payload = event.payload
17
17
 
18
- base = {
19
- "source" => source,
20
- "name" => name,
21
- "backtrace" => filtered_backtrace,
22
- "started_at" => event.time,
23
- "finished_at" => event.end,
24
- "allocations" => event.allocations,
25
- "thread_allocations" => event.thread_allocations
26
- }
27
-
28
18
  case name
29
19
  when "render_collection"
30
20
  base.merge({
@@ -12,18 +12,11 @@ module PlainApm
12
12
  end
13
13
 
14
14
  def payload(event)
15
- name, source = *event.name.split(".")
15
+ name, base = attributes_from_notification(event)
16
16
  payload = event.payload
17
17
  job = payload[:job]
18
18
 
19
- base = {
20
- "source" => source,
21
- "name" => name,
22
- "backtrace" => filtered_backtrace,
23
- "started_at" => event.time,
24
- "finished_at" => event.end,
25
- "allocations" => event.allocations,
26
- "thread_allocations" => event.thread_allocations,
19
+ base.merge!({
27
20
  "queue_name" => job.queue_name,
28
21
  "job_id" => job.job_id,
29
22
  "job_class" => job.class.name,
@@ -34,7 +27,7 @@ module PlainApm
34
27
  "scheduled_at" => job.scheduled_at,
35
28
  "adapter" => payload[:adapter].class.name,
36
29
  "aborted" => payload[:aborted]
37
- }
30
+ })
38
31
 
39
32
  case name
40
33
  when "enqueue", "enqueue_at", "perform"
@@ -6,6 +6,7 @@ module PlainApm
6
6
  module Hooks
7
7
  class ActiveRecord < ActiveSupportSubscriber
8
8
  NOTIFICATION_PATTERN = /\A[^!]\w+\.active_record\Z/.freeze
9
+ IGNORED_SQL_NAMES = %w[SCHEMA CACHE].freeze
9
10
 
10
11
  private
11
12
 
@@ -14,25 +15,14 @@ module PlainApm
14
15
  end
15
16
 
16
17
  def payload(event)
17
- name, source = *event.name.split(".")
18
+ name, base = attributes_from_notification(event)
18
19
  payload = event.payload
19
20
 
20
- base = {
21
- "source" => source,
22
- "name" => name,
23
- "backtrace" => filtered_backtrace,
24
- "started_at" => event.time,
25
- "finished_at" => event.end,
26
- "allocations" => event.allocations,
27
- "thread_allocations" => event.thread_allocations
28
- }
21
+ return if IGNORED_SQL_NAMES.include?(payload[:name])
29
22
 
30
23
  case name
31
24
  when "sql"
32
- base.merge({
33
- "sql_name" => payload[:name],
34
- "sql" => payload[:sql]
35
- })
25
+ base.merge({"sql" => payload[:sql]})
36
26
  end
37
27
  end
38
28
  end
@@ -3,7 +3,7 @@
3
3
  module PlainApm
4
4
  module Hooks
5
5
  class ActiveSupport < ActiveSupportSubscriber
6
- NOTIFICATION_PATTERN = /\Acache_[\w\?]+\.active_support\Z/.freeze
6
+ NOTIFICATION_PATTERN = /\Acache_[\w?]+\.active_support\Z/.freeze
7
7
 
8
8
  private
9
9
 
@@ -12,26 +12,17 @@ module PlainApm
12
12
  end
13
13
 
14
14
  def payload(event)
15
- name, source = *event.name.split(".")
15
+ name, base = attributes_from_notification(event)
16
16
  payload = event.payload
17
17
 
18
- base = {
19
- "source" => source,
20
- "name" => name,
21
- "backtrace" => filtered_backtrace,
22
- "started_at" => event.time,
23
- "finished_at" => event.end,
24
- "allocations" => event.allocations,
25
- "thread_allocations" => event.thread_allocations,
26
- "store" => payload[:store]
27
- }
18
+ base["store"] = payload[:store]
28
19
 
29
20
  case name
30
21
  when "cache_read"
31
22
  base.merge({
32
23
  "key" => payload[:key],
33
24
  "hit" => payload[:hit],
34
- "trigger" => payload[:super_operation],
25
+ "trigger" => payload[:super_operation]
35
26
  })
36
27
  when "cache_read_multi"
37
28
  base.merge({
@@ -3,6 +3,8 @@
3
3
  module PlainApm
4
4
  module Hooks
5
5
  class ActiveSupportSubscriber
6
+ include EventAttributes
7
+
6
8
  def install
7
9
  begin
8
10
  require "active_support/notifications"
@@ -26,7 +28,7 @@ module PlainApm
26
28
 
27
29
  return if payload.nil?
28
30
 
29
- Agent.instance.collect(payload)
31
+ Agent.collect(payload)
30
32
  end
31
33
 
32
34
  private
@@ -38,13 +40,6 @@ module PlainApm
38
40
  def payload(event)
39
41
  raise "Not implemented"
40
42
  end
41
-
42
- def filtered_backtrace
43
- if defined?(Rails) && defined?(Rails::BacktraceCleaner)
44
- @cleaner ||= Rails::BacktraceCleaner.new
45
- @cleaner.clean(caller)
46
- end
47
- end
48
43
  end
49
44
  end
50
45
  end
@@ -6,6 +6,8 @@ module PlainApm
6
6
  # for performance regressions.
7
7
  module Hooks
8
8
  class Deploy
9
+ include EventAttributes
10
+
9
11
  ##
10
12
  # Collect once, immediately on install.
11
13
  def install
@@ -15,17 +17,9 @@ module PlainApm
15
17
  def collect
16
18
  result = git_revision || hg_revision || return
17
19
 
18
- tool, revision = *result
19
-
20
- Agent.instance.collect(
21
- {
22
- "source" => "deploy",
23
- "revision" => revision,
24
- "name" => tool,
25
- "started_at" => Time.now.to_f,
26
- "finished_at" => Time.now.to_f
27
- }
28
- )
20
+ _, attrs = attributes_from_deploy(*result)
21
+
22
+ Agent.collect(attrs)
29
23
  end
30
24
 
31
25
  private
@@ -2,10 +2,7 @@ module PlainApm
2
2
  module Hooks
3
3
  # Rails 7 error notification mechanism
4
4
  class ErrorReporter
5
- IGNORED_EXCEPTIONS = [
6
- "Sidekiq::JobRetry::Skip", # Sidekiq uses exceptions for control flow.
7
- "ActionController::RoutingError" # Rails unmapped route, raised before the request hits the app.
8
- ].freeze
5
+ include EventAttributes
9
6
 
10
7
  def install
11
8
  begin
@@ -23,33 +20,12 @@ module PlainApm
23
20
  end
24
21
 
25
22
  def collect(e, handled:, severity:, context: {})
26
- return if IGNORED_EXCEPTIONS.include?(e.class.name)
23
+ source, event = attributes_from_exception(e, context)
27
24
 
28
- event = {
29
- "source" => "exception",
30
- "name" => "error_reporter",
31
- "class" => e.class.name,
32
- "message" => e.message,
33
- "backtrace" => e.backtrace,
34
- "handled" => handled,
35
- "severity" => severity,
36
- "context" => context
37
- }
25
+ return if event.nil?
38
26
 
39
- if context[:job] && context[:job].is_a?(ActiveJob::Base)
40
- event.merge!({
41
- "job_class" => context[:job].class.name,
42
- "queue_name" => context[:job].queue_name
43
- })
44
- end
45
-
46
- if e.cause
47
- event.merge!({
48
- "cause_class" => e.cause.class.name,
49
- "cause_message" => e.cause.message,
50
- "cause_backtrace" => e.cause.backtrace
51
- })
52
- end
27
+ event["source"] = source
28
+ event["name"] = "error_reporter"
53
29
 
54
30
  PlainApm::Agent.collect(event)
55
31
  end
@@ -12,19 +12,14 @@ module PlainApm
12
12
  end
13
13
 
14
14
  def payload(event)
15
- name, source = *event.name.split(".")
15
+ name, base = attributes_from_notification(event)
16
16
 
17
- {
17
+ base.merge({
18
18
  "source" => "user",
19
19
  "name" => "manual",
20
- "backtrace" => filtered_backtrace,
21
- "started_at" => event.time,
22
- "finished_at" => event.end,
23
- "allocations" => event.allocations,
24
- "thread_allocations" => event.thread_allocations,
25
20
  "payload_name" => name,
26
21
  "payload" => event.payload
27
- }
22
+ })
28
23
  end
29
24
  end
30
25
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PlainApm
4
- VERSION = "0.6.6"
4
+ VERSION = "0.7.0"
5
5
  end
data/lib/plain_apm.rb CHANGED
@@ -4,6 +4,7 @@ require_relative "plain_apm/version"
4
4
  require_relative "plain_apm/transport"
5
5
  require_relative "plain_apm/config"
6
6
  require_relative "plain_apm/agent"
7
+ require_relative "plain_apm/event_attributes"
7
8
 
8
9
  require "object_tracing"
9
10
 
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.6.6
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - PlainAPM Team
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-12-28 00:00:00.000000000 Z
11
+ date: 2023-01-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -99,6 +99,7 @@ files:
99
99
  - lib/plain_apm/agent.rb
100
100
  - lib/plain_apm/backoff.rb
101
101
  - lib/plain_apm/config.rb
102
+ - lib/plain_apm/event_attributes.rb
102
103
  - lib/plain_apm/extensions/context.rb
103
104
  - lib/plain_apm/extensions/context/LICENSE.txt
104
105
  - lib/plain_apm/extensions/context/active_job.rb