plain_apm 0.6.7 → 0.7.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: da1f9aa5f6ef59cc4dfafb04888453d4bb1b498f4a741812ff3da2024b948980
4
- data.tar.gz: 8e103d3aadd8ccca146f6783739ea2b3d7303b3bec82f433567af73a447074f5
3
+ metadata.gz: 2b4d2bddabd031b2b17d2edcf27e32f323c217b2331c469072e95d0afeb58ec7
4
+ data.tar.gz: a892bbd62da4a10b074046c39326576355d591bf02982f9d336a97d887f99bc6
5
5
  SHA512:
6
- metadata.gz: 440081dc334c342649b6375b857c129d4e47c8bbd47fb2d60b199c58f1156dcc2539593305e509de5a9bbe6ad48d9a07bb645b61cc8ad7a8380fc4e1f4181dad
7
- data.tar.gz: 9569d0b13c04e3c1630bd00f1af3f68d0573a798c82a2d6643585da7baf9a69c8b5376d6e72f34750c07cda4ebb2607fe955ff4873d8264c080454447d6e8795
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,7 +12,7 @@ module PlainApm
12
12
  end
13
13
 
14
14
  def payload(event)
15
- name, base = common_attributes(event)
15
+ name, base = attributes_from_notification(event)
16
16
  payload = event.payload
17
17
 
18
18
  case name
@@ -12,7 +12,7 @@ module PlainApm
12
12
  end
13
13
 
14
14
  def payload(event)
15
- name, base = common_attributes(event)
15
+ name, base = attributes_from_notification(event)
16
16
  payload = event.payload
17
17
 
18
18
  case name
@@ -12,7 +12,7 @@ module PlainApm
12
12
  end
13
13
 
14
14
  def payload(event)
15
- name, base = common_attributes(event)
15
+ name, base = attributes_from_notification(event)
16
16
  payload = event.payload
17
17
 
18
18
  case name
@@ -12,7 +12,7 @@ module PlainApm
12
12
  end
13
13
 
14
14
  def payload(event)
15
- name, base = common_attributes(event)
15
+ name, base = attributes_from_notification(event)
16
16
  payload = event.payload
17
17
  job = payload[:job]
18
18
 
@@ -6,7 +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
+ IGNORED_SQL_NAMES = %w[SCHEMA CACHE].freeze
10
10
 
11
11
  private
12
12
 
@@ -15,14 +15,14 @@ module PlainApm
15
15
  end
16
16
 
17
17
  def payload(event)
18
- name, base = common_attributes(event)
18
+ name, base = attributes_from_notification(event)
19
19
  payload = event.payload
20
20
 
21
21
  return if IGNORED_SQL_NAMES.include?(payload[:name])
22
22
 
23
23
  case name
24
24
  when "sql"
25
- base.merge({ "sql" => payload[:sql] })
25
+ base.merge({"sql" => payload[:sql]})
26
26
  end
27
27
  end
28
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,17 +12,17 @@ module PlainApm
12
12
  end
13
13
 
14
14
  def payload(event)
15
- name, base = common_attributes(event)
15
+ name, base = attributes_from_notification(event)
16
16
  payload = event.payload
17
17
 
18
- base.merge!({ "store" => payload[:store] })
18
+ base["store"] = payload[:store]
19
19
 
20
20
  case name
21
21
  when "cache_read"
22
22
  base.merge({
23
23
  "key" => payload[:key],
24
24
  "hit" => payload[:hit],
25
- "trigger" => payload[:super_operation],
25
+ "trigger" => payload[:super_operation]
26
26
  })
27
27
  when "cache_read_multi"
28
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,31 +40,6 @@ module PlainApm
38
40
  def payload(event)
39
41
  raise "Not implemented"
40
42
  end
41
-
42
- def common_attributes(event)
43
- name, source = *event.name.split(".")
44
- bt = filtered_backtrace
45
-
46
- attrs = {
47
- "source" => source,
48
- "name" => name,
49
- "allocations" => event.allocations,
50
- "thread_allocations" => event.thread_allocations,
51
- "started_at" => event.time,
52
- "finished_at" => event.end
53
- }
54
-
55
- attrs.merge!("backtrace" => bt) if bt && !bt.empty?
56
-
57
- [name, attrs]
58
- end
59
-
60
- def filtered_backtrace
61
- if defined?(Rails) && defined?(Rails::BacktraceCleaner)
62
- @cleaner ||= Rails::BacktraceCleaner.new
63
- @cleaner.clean(caller)
64
- end
65
- end
66
43
  end
67
44
  end
68
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,7 +12,7 @@ module PlainApm
12
12
  end
13
13
 
14
14
  def payload(event)
15
- name, base = common_attributes(event)
15
+ name, base = attributes_from_notification(event)
16
16
 
17
17
  base.merge({
18
18
  "source" => "user",
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PlainApm
4
- VERSION = "0.6.7"
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.7
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: 2023-01-01 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