plain_apm 0.6.7 → 0.7.1

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: 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