plain_apm 0.6.7 → 0.7.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: da1f9aa5f6ef59cc4dfafb04888453d4bb1b498f4a741812ff3da2024b948980
4
- data.tar.gz: 8e103d3aadd8ccca146f6783739ea2b3d7303b3bec82f433567af73a447074f5
3
+ metadata.gz: 41e2fd7c72868351a09c83a13a22df9e9718e00cbb1950c27e7ce129cf24a826
4
+ data.tar.gz: 2f658463e3ee8f8195142a2b456b6f5c535efac868ada116f766ef92db5ab714
5
5
  SHA512:
6
- metadata.gz: 440081dc334c342649b6375b857c129d4e47c8bbd47fb2d60b199c58f1156dcc2539593305e509de5a9bbe6ad48d9a07bb645b61cc8ad7a8380fc4e1f4181dad
7
- data.tar.gz: 9569d0b13c04e3c1630bd00f1af3f68d0573a798c82a2d6643585da7baf9a69c8b5376d6e72f34750c07cda4ebb2607fe955ff4873d8264c080454447d6e8795
6
+ metadata.gz: 139c55ba03f6982640310ba59122fab53c6fb9c871e409c304b5d5ebd50e44c34af8db691195acb4dd7b4b43087092e7b9f1fe052f8d7aa299b863d4b4301c8e
7
+ data.tar.gz: da0cd391b91b3660ef48fc8587e26562d1caf908526b2af86e9c42e2cff945940c779b6b115763bacf8f105e33e7422e4a27d403c788b8d44be9d33d909e1460
@@ -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,141 @@
1
+ module PlainApm
2
+ module EventAttributes
3
+ SOURCES_WITH_EXTRA_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!(trace_attributes(source))
27
+
28
+ [tool, attrs]
29
+ end
30
+
31
+ def attributes_from_exception(e, context)
32
+ source = "exception"
33
+
34
+ return [source, nil] if IGNORED_EXCEPTIONS.include?(e.class.name)
35
+
36
+ attrs = {
37
+ "class" => e.class.name,
38
+ "message" => e.message,
39
+ "backtrace" => e.backtrace
40
+ }
41
+
42
+ if context[:env]
43
+ attrs["params"] = context[:env]["action_dispatch.request.parameters"]
44
+ end
45
+
46
+ if context[:job]&.is_a?(ActiveJob::Base)
47
+ attrs["job_class"] = context[:job].class.name
48
+ attrs["queue_name"] = context[:job].queue_name
49
+ end
50
+
51
+ if e.cause
52
+ attrs.merge!({
53
+ "cause_class" => e.cause.class.name,
54
+ "cause_message" => e.cause.message,
55
+ "cause_backtrace" => e.cause.backtrace
56
+ })
57
+ end
58
+
59
+ attrs.merge!(trace_attributes(source))
60
+
61
+ [source, attrs]
62
+ end
63
+
64
+ def attributes_from_notification(event)
65
+ name, source = *event.name.split(".")
66
+ loc = source_location
67
+
68
+ attrs = {
69
+ "source" => source,
70
+ "name" => name,
71
+ "allocations" => event.allocations,
72
+ "thread_allocations" => event.thread_allocations,
73
+ "event_time" => event.time,
74
+ "duration" => event.duration
75
+ }
76
+
77
+ attrs["source_location"] = loc if !loc.nil?
78
+
79
+ attrs.merge!(trace_attributes(source))
80
+
81
+ [name, attrs]
82
+ end
83
+
84
+ private
85
+
86
+ def trace_attributes(source)
87
+ attrs = agent_attributes
88
+
89
+ if add_extra_attributes?(source)
90
+ attrs.merge!(process_attributes, context_attributes)
91
+ else
92
+ attrs.merge!(context_attributes.slice(:trace_id))
93
+ end
94
+
95
+ attrs
96
+ end
97
+
98
+ def add_extra_attributes?(source)
99
+ SOURCES_WITH_EXTRA_ATTRIBUTES.include?(source)
100
+ end
101
+
102
+ def agent_attributes
103
+ {
104
+ "version" => PlainApm::VERSION
105
+ }
106
+ end
107
+
108
+ def process_attributes
109
+ {
110
+ "collected_at" => Time.now.iso8601(9),
111
+ "hostname" => Socket.gethostname,
112
+ "pid" => Process.pid,
113
+ "thread_id" => Thread.current.object_id
114
+ }
115
+ end
116
+
117
+ def context_attributes
118
+ ##
119
+ # Context contains the trace ID (which comes from either
120
+ # HTTP_X_REQUEST_ID header, the deserialized job,
121
+ # or is generated by the trace_id middleware).
122
+ # It can also carry user inserted app data.
123
+ if defined?(PlainApm::Extensions::Context)
124
+ PlainApm::Extensions::Context.current
125
+ else
126
+ {}
127
+ end
128
+ end
129
+
130
+ def source_location
131
+ filtered_backtrace&.first
132
+ end
133
+
134
+ def filtered_backtrace
135
+ if defined?(Rails) && defined?(Rails::BacktraceCleaner)
136
+ @cleaner ||= Rails::BacktraceCleaner.new
137
+ @cleaner.clean(caller)
138
+ end
139
+ end
140
+ end
141
+ 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.1"
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.1
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