appsignal 2.5.1 → 2.5.2

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
  SHA1:
3
- metadata.gz: b2e375f2f3703066e529a51dc84a0db6fc9d1b29
4
- data.tar.gz: f44d521a76c7e897d07d47c2bfe244ebbb5b66f8
3
+ metadata.gz: 638c33adaf9394488da292c98738966981fad1d1
4
+ data.tar.gz: e0450850d9a358e78d3391050a1c43bfbb1b5705
5
5
  SHA512:
6
- metadata.gz: 742d3ddd1b0ac482a4211aa1752a87f1b017bb3958062364c8a63f39efc881bf40783db7960b790c130c70ac5c5b1b8c6abd5f424062322e8919c3663dd875ac
7
- data.tar.gz: fbda5dce446bf4e06146169e704eb0e372f5afae9c6129247e4be79b9912e2c941c3324ec2ace3a3e740f18627905dc9e6773f226faa23a3d92e73ad4b6af700
6
+ metadata.gz: 94d04b637d3f5477ea4a29f47411d385e608b85e57bd930ea3e18f85c31401288a385adc651365043df5bc6bade2870f73179b17067f706f220a8007b2efe3eb
7
+ data.tar.gz: bcdf191cb6943a854503e5504ee69c41cde23bad18ffa77374d056cb61f616af208e696674a97d72a6008a62bf80ddc513e4bbbe94ee9b631138c52b7e1da57c
@@ -1,3 +1,10 @@
1
+ # 2.5.2
2
+ - Support Sidekiq delay extension for ActiveRecord instances. If using this
3
+ feature in your app, an update is strongly recommended! PR #387
4
+ - Improve custom event formatter registration. An event formatter can now be
5
+ registered in a Rails initializer after AppSignal has been loaded/started.
6
+ PR #397
7
+
1
8
  # 2.5.1
2
9
  - Improve internal sample storage in agent.
3
10
  Commit 2c8eae26685c7a1517cf2e57b44edd1557a502f2
@@ -121,7 +121,7 @@ module Appsignal
121
121
  config.write_to_environment
122
122
  Appsignal::Extension.start
123
123
  Appsignal::Hooks.load_hooks
124
- Appsignal::EventFormatter.initialize_formatters
124
+ Appsignal::EventFormatter.initialize_deprecated_formatters
125
125
  initialize_extensions
126
126
 
127
127
  if config[:enable_allocation_tracking] && !Appsignal::System.jruby?
@@ -16,12 +16,35 @@ module Appsignal
16
16
  @@formatters ||= {}
17
17
  end
18
18
 
19
+ def deprecated_formatter_classes
20
+ @@deprecated_formatter_classes ||= {}
21
+ end
22
+
19
23
  def formatter_classes
20
24
  @@formatter_classes ||= {}
21
25
  end
22
26
 
23
- def register(name, formatter = self)
24
- formatter_classes[name] = formatter
27
+ def register(name, formatter = nil)
28
+ unless formatter
29
+ register_deprecated_formatter(name)
30
+ return
31
+ end
32
+
33
+ if registered?(name, formatter)
34
+ Appsignal.logger.warn(
35
+ "Formatter for '#{name}' already registered, not registering "\
36
+ "'#{formatter.name}'"
37
+ )
38
+ return
39
+ end
40
+
41
+ initialize_formatter name, formatter
42
+ end
43
+
44
+ def initialize_deprecated_formatters
45
+ deprecated_formatter_classes.each do |name, formatter|
46
+ register(name, formatter)
47
+ end
25
48
  end
26
49
 
27
50
  def unregister(name, formatter = self)
@@ -39,27 +62,37 @@ module Appsignal
39
62
  end
40
63
  end
41
64
 
42
- def initialize_formatters
43
- formatter_classes.each do |name, formatter|
44
- begin
45
- format_method = formatter.instance_method(:format)
46
- if format_method && format_method.arity == 1
47
- formatters[name] = formatter.new
48
- else
49
- raise "#{f} does not have a format(payload) method"
50
- end
51
- rescue => ex
52
- formatter_classes.delete(name)
53
- formatters.delete(name)
54
- Appsignal.logger.debug("'#{ex.message}' when initializing #{name} event formatter")
55
- end
56
- end
57
- end
58
-
59
65
  def format(name, payload)
60
66
  formatter = formatters[name]
61
67
  formatter.format(payload) unless formatter.nil?
62
68
  end
69
+
70
+ private
71
+
72
+ def initialize_formatter(name, formatter)
73
+ format_method = formatter.instance_method(:format)
74
+ if format_method && format_method.arity == 1
75
+ formatter_classes[name] = formatter
76
+ formatters[name] = formatter.new
77
+ else
78
+ raise "#{formatter} does not have a format(payload) method"
79
+ end
80
+ rescue => ex
81
+ formatter_classes.delete(name)
82
+ formatters.delete(name)
83
+ Appsignal.logger.warn("'#{ex.message}' when initializing #{name} event formatter")
84
+ end
85
+
86
+ def register_deprecated_formatter(name)
87
+ Appsignal.logger.warn(
88
+ "Formatter for '#{name}' is using a deprecated registration " \
89
+ "method. This event formatter will not be loaded. " \
90
+ "Please update the formatter according to the documentation at: " \
91
+ "https://docs.appsignal.com/ruby/instrumentation/event-formatters.html"
92
+ )
93
+
94
+ deprecated_formatter_classes[name] = self
95
+ end
63
96
  end
64
97
 
65
98
  # @api public
@@ -2,10 +2,7 @@ module Appsignal
2
2
  class EventFormatter
3
3
  # @api private
4
4
  module ActionView
5
- class RenderFormatter < Appsignal::EventFormatter
6
- register "render_partial.action_view"
7
- register "render_template.action_view"
8
-
5
+ class RenderFormatter
9
6
  BLANK = "".freeze
10
7
 
11
8
  attr_reader :root_path
@@ -22,3 +19,12 @@ module Appsignal
22
19
  end
23
20
  end
24
21
  end
22
+
23
+ Appsignal::EventFormatter.register(
24
+ "render_partial.action_view",
25
+ Appsignal::EventFormatter::ActionView::RenderFormatter
26
+ )
27
+ Appsignal::EventFormatter.register(
28
+ "render_template.action_view",
29
+ Appsignal::EventFormatter::ActionView::RenderFormatter
30
+ )
@@ -2,9 +2,7 @@ module Appsignal
2
2
  class EventFormatter
3
3
  # @api private
4
4
  module ActiveRecord
5
- class InstantiationFormatter < Appsignal::EventFormatter
6
- register "instantiation.active_record"
7
-
5
+ class InstantiationFormatter
8
6
  def format(payload)
9
7
  [payload[:class_name], nil]
10
8
  end
@@ -12,3 +10,8 @@ module Appsignal
12
10
  end
13
11
  end
14
12
  end
13
+
14
+ Appsignal::EventFormatter.register(
15
+ "instantiation.active_record",
16
+ Appsignal::EventFormatter::ActiveRecord::InstantiationFormatter
17
+ )
@@ -2,9 +2,7 @@ module Appsignal
2
2
  class EventFormatter
3
3
  # @api private
4
4
  module ActiveRecord
5
- class SqlFormatter < Appsignal::EventFormatter
6
- register "sql.active_record"
7
-
5
+ class SqlFormatter
8
6
  def format(payload)
9
7
  [payload[:name], payload[:sql], SQL_BODY_FORMAT]
10
8
  end
@@ -12,3 +10,8 @@ module Appsignal
12
10
  end
13
11
  end
14
12
  end
13
+
14
+ Appsignal::EventFormatter.register(
15
+ "sql.active_record",
16
+ Appsignal::EventFormatter::ActiveRecord::SqlFormatter
17
+ )
@@ -2,9 +2,7 @@ module Appsignal
2
2
  class EventFormatter
3
3
  # @api private
4
4
  module ElasticSearch
5
- class SearchFormatter < Appsignal::EventFormatter
6
- register "search.elasticsearch"
7
-
5
+ class SearchFormatter
8
6
  def format(payload)
9
7
  [
10
8
  "#{payload[:name]}: #{payload[:klass]}",
@@ -30,3 +28,8 @@ module Appsignal
30
28
  end
31
29
  end
32
30
  end
31
+
32
+ Appsignal::EventFormatter.register(
33
+ "search.elasticsearch",
34
+ Appsignal::EventFormatter::ElasticSearch::SearchFormatter
35
+ )
@@ -2,9 +2,7 @@ module Appsignal
2
2
  class EventFormatter
3
3
  # @api private
4
4
  module Faraday
5
- class RequestFormatter < Appsignal::EventFormatter
6
- register "request.faraday"
7
-
5
+ class RequestFormatter
8
6
  def format(payload)
9
7
  http_method = payload[:method].to_s.upcase
10
8
  uri = payload[:url]
@@ -17,3 +15,8 @@ module Appsignal
17
15
  end
18
16
  end
19
17
  end
18
+
19
+ Appsignal::EventFormatter.register(
20
+ "request.faraday",
21
+ Appsignal::EventFormatter::Faraday::RequestFormatter
22
+ )
@@ -2,9 +2,7 @@ module Appsignal
2
2
  class EventFormatter
3
3
  # @api private
4
4
  module Moped
5
- class QueryFormatter < Appsignal::EventFormatter
6
- register "query.moped"
7
-
5
+ class QueryFormatter
8
6
  def format(payload)
9
7
  if payload[:ops] && !payload[:ops].empty?
10
8
  op = payload[:ops].first
@@ -78,3 +76,8 @@ module Appsignal
78
76
  end
79
77
  end
80
78
  end
79
+
80
+ Appsignal::EventFormatter.register(
81
+ "query.moped",
82
+ Appsignal::EventFormatter::Moped::QueryFormatter
83
+ )
@@ -19,7 +19,7 @@ module Appsignal
19
19
  end
20
20
 
21
21
  # @api private
22
- class SidekiqPlugin
22
+ class SidekiqPlugin # rubocop:disable Metrics/ClassLength
23
23
  include Appsignal::Hooks::Helpers
24
24
 
25
25
  JOB_KEYS = %w[
@@ -84,6 +84,10 @@ module Appsignal
84
84
  def parse_action_name(job)
85
85
  args = job["args"]
86
86
  case job["class"]
87
+ when "Sidekiq::Extensions::DelayedModel"
88
+ safe_load(job["args"][0], job["class"]) do |target, method, _|
89
+ "#{target.class}##{method}"
90
+ end
87
91
  when /\ASidekiq::Extensions::Delayed/
88
92
  safe_load(job["args"][0], job["class"]) do |target, method, _|
89
93
  "#{target}.#{method}"
@@ -1,3 +1,3 @@
1
1
  module Appsignal
2
- VERSION = "2.5.1".freeze
2
+ VERSION = "2.5.2".freeze
3
3
  end
@@ -1,6 +1,4 @@
1
1
  class MockFormatter < Appsignal::EventFormatter
2
- register "mock"
3
-
4
2
  attr_reader :body
5
3
 
6
4
  def initialize
@@ -23,20 +21,30 @@ class IncorrectFormatMockFormatter < Appsignal::EventFormatter
23
21
  end
24
22
 
25
23
  class MockDependentFormatter < Appsignal::EventFormatter
26
- register "mock.dependent"
27
-
28
24
  def initialize
29
25
  NonsenseDependency.something
30
26
  end
31
27
  end
32
28
 
29
+ Appsignal::EventFormatter.register "mock", MockFormatter
30
+ Appsignal::EventFormatter.register "mock.dependent", MockDependentFormatter
31
+
33
32
  describe Appsignal::EventFormatter do
34
33
  before do
35
- Appsignal::EventFormatter.initialize_formatters
34
+ klass.register("mock", MockFormatter)
36
35
  end
37
36
 
38
37
  let(:klass) { Appsignal::EventFormatter }
39
38
 
39
+ let(:deprecated_formatter) do
40
+ Class.new(Appsignal::EventFormatter) do
41
+ register "mock.deprecated"
42
+
43
+ def format(_payload)
44
+ end
45
+ end
46
+ end
47
+
40
48
  context "registering and unregistering formatters" do
41
49
  it "should register a formatter" do
42
50
  expect(klass.formatters["mock"]).to be_instance_of(MockFormatter)
@@ -53,19 +61,8 @@ describe Appsignal::EventFormatter do
53
61
  expect(klass.registered?("mock.dependent")).to be_falsy
54
62
  end
55
63
 
56
- it "doesn't register formatters that don't have a format(payload) method" do
57
- klass.register("mock.missing_format", MissingFormatMockFormatter)
58
- klass.register("mock.incorrect_format", IncorrectFormatMockFormatter)
59
-
60
- Appsignal::EventFormatter.initialize_formatters
61
-
62
- expect(klass.registered?("mock.missing_format")).to be_falsy
63
- expect(klass.registered?("mock.incorrect_format")).to be_falsy
64
- end
65
-
66
64
  it "should register a custom formatter" do
67
65
  klass.register("mock.specific", MockFormatter)
68
- Appsignal::EventFormatter.initialize_formatters
69
66
 
70
67
  expect(klass.formatter_classes["mock.specific"]).to eq MockFormatter
71
68
  expect(klass.registered?("mock.specific")).to be_truthy
@@ -86,6 +83,32 @@ describe Appsignal::EventFormatter do
86
83
  klass.unregister("mock.unregister", MockFormatter)
87
84
  expect(klass.registered?("mock.unregister")).to be_falsy
88
85
  end
86
+
87
+ it "should not register two formatters for the same name" do
88
+ expect(Appsignal.logger).to receive(:warn)
89
+ .with("Formatter for 'mock.twice' already registered, not registering 'MockFormatter'")
90
+ klass.register("mock.twice", MockFormatter)
91
+ klass.register("mock.twice", MockFormatter)
92
+ end
93
+
94
+ it "should not register deprecated formatter" do
95
+ expect(Appsignal.logger).to receive(:warn)
96
+ .with("Formatter for 'mock.deprecated' is using a deprecated registration method. " \
97
+ "This event formatter will not be loaded. " \
98
+ "Please update the formatter according to the documentation at: " \
99
+ "https://docs.appsignal.com/ruby/instrumentation/event-formatters.html")
100
+
101
+ deprecated_formatter
102
+
103
+ expect(Appsignal::EventFormatter.deprecated_formatter_classes.keys).to include("mock.deprecated")
104
+ end
105
+
106
+ it "should initialize deprecated formatters" do
107
+ deprecated_formatter
108
+ Appsignal::EventFormatter.initialize_deprecated_formatters
109
+
110
+ expect(klass.registered?("mock.deprecated")).to be_truthy
111
+ end
89
112
  end
90
113
 
91
114
  context "calling formatters" do
@@ -151,6 +151,46 @@ describe Appsignal::Hooks::SidekiqPlugin, :with_yaml_parse_error => false do
151
151
  end
152
152
  end
153
153
 
154
+ context "when using the Sidekiq ActiveRecord instance delayed extension" do
155
+ let(:item) do
156
+ {
157
+ "jid" => "efb140489485999d32b5504c",
158
+ "class" => "Sidekiq::Extensions::DelayedModel",
159
+ "queue" => "default",
160
+ "args" => [
161
+ "---\n- !ruby/object:DelayedTestClass {}\n- :foo_method\n- - :bar: :baz\n"
162
+ ],
163
+ "retry" => true,
164
+ "created_at" => Time.parse("2001-01-01 10:00:00UTC").to_f,
165
+ "enqueued_at" => Time.parse("2001-01-01 10:00:00UTC").to_f,
166
+ "extra" => "data"
167
+ }
168
+ end
169
+
170
+ it "uses the delayed class and method name for the action" do
171
+ perform_job
172
+
173
+ transaction_hash = transaction.to_h
174
+ expect(transaction_hash["action"]).to eq("DelayedTestClass#foo_method")
175
+ expect(transaction_hash["sample_data"]).to include(
176
+ "params" => ["bar" => "baz"]
177
+ )
178
+ end
179
+
180
+ context "when job arguments is a malformed YAML object", :with_yaml_parse_error => true do
181
+ before { item["args"] = [] }
182
+
183
+ it "logs a warning and uses the default argument" do
184
+ perform_job
185
+
186
+ transaction_hash = transaction.to_h
187
+ expect(transaction_hash["action"]).to eq("Sidekiq::Extensions::DelayedModel#perform")
188
+ expect(transaction_hash["sample_data"]).to include("params" => [])
189
+ expect(log_contents(log)).to contains_log(:warn, "Unable to load YAML")
190
+ end
191
+ end
192
+ end
193
+
154
194
  context "when using ActiveJob" do
155
195
  let(:item) do
156
196
  {
@@ -61,8 +61,8 @@ describe Appsignal do
61
61
  Appsignal.start
62
62
  end
63
63
 
64
- it "should initialize formatters" do
65
- expect(Appsignal::EventFormatter).to receive(:initialize_formatters)
64
+ it "should load deprecated event formatters" do
65
+ expect(Appsignal::EventFormatter).to receive(:initialize_deprecated_formatters)
66
66
  Appsignal.start
67
67
  end
68
68
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: appsignal
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.5.1
4
+ version: 2.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Beekman
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2018-03-13 00:00:00.000000000 Z
12
+ date: 2018-04-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack