appsignal 3.0.12-java → 3.0.16-java

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.
@@ -0,0 +1,92 @@
1
+ module Appsignal
2
+ class Span
3
+ def initialize(namespace = nil, ext = nil)
4
+ @ext = if ext
5
+ ext
6
+ else
7
+ Appsignal::Extension::Span.root(namespace || "")
8
+ end
9
+ end
10
+
11
+ def child
12
+ Span.new(nil, @ext.child)
13
+ end
14
+
15
+ def name=(value)
16
+ @ext.set_name(value)
17
+ end
18
+
19
+ def add_error(error)
20
+ unless error.is_a?(Exception)
21
+ Appsignal.logger.error "Appsignal::Span#add_error: Cannot add error. " \
22
+ "The given value is not an exception: #{error.inspect}"
23
+ return
24
+ end
25
+ return unless error
26
+
27
+ backtrace = cleaned_backtrace(error.backtrace)
28
+ @ext.add_error(
29
+ error.class.name,
30
+ error.message.to_s,
31
+ backtrace ? Appsignal::Utils::Data.generate(backtrace) : Appsignal::Extension.data_array_new
32
+ )
33
+ end
34
+
35
+ def set_sample_data(key, data)
36
+ return unless key && data && (data.is_a?(Array) || data.is_a?(Hash))
37
+ @ext.set_sample_data(
38
+ key.to_s,
39
+ Appsignal::Utils::Data.generate(data)
40
+ )
41
+ end
42
+
43
+ def []=(key, value)
44
+ case value
45
+ when String
46
+ @ext.set_attribute_string(key.to_s, value)
47
+ when Integer
48
+ begin
49
+ @ext.set_attribute_int(key.to_s, value)
50
+ rescue RangeError
51
+ @ext.set_attribute_string(key.to_s, "bigint:#{value}")
52
+ end
53
+ when TrueClass, FalseClass
54
+ @ext.set_attribute_bool(key.to_s, value)
55
+ when Float
56
+ @ext.set_attribute_double(key.to_s, value)
57
+ else
58
+ raise TypeError, "value needs to be a string, int, bool or float"
59
+ end
60
+ end
61
+
62
+ def to_h
63
+ json = @ext.to_json
64
+ return unless json
65
+ JSON.parse(json)
66
+ end
67
+
68
+ def instrument
69
+ yield self
70
+ ensure
71
+ close
72
+ end
73
+
74
+ def close
75
+ @ext.close
76
+ end
77
+
78
+ def closed?
79
+ to_h.nil?
80
+ end
81
+
82
+ private
83
+
84
+ def cleaned_backtrace(backtrace)
85
+ if defined?(::Rails) && backtrace
86
+ ::Rails.backtrace_cleaner.clean(backtrace, nil)
87
+ else
88
+ backtrace
89
+ end
90
+ end
91
+ end
92
+ end
@@ -333,7 +333,7 @@ module Appsignal
333
333
  backtrace = cleaned_backtrace(error.backtrace)
334
334
  @ext.set_error(
335
335
  error.class.name,
336
- error.message.to_s,
336
+ cleaned_error_message(error),
337
337
  backtrace ? Appsignal::Utils::Data.generate(backtrace) : Appsignal::Extension.data_array_new
338
338
  )
339
339
  end
@@ -533,6 +533,17 @@ module Appsignal
533
533
  end
534
534
  end
535
535
 
536
+ # Clean error messages that are known to potentially contain user data.
537
+ # Returns an unchanged message otherwise.
538
+ def cleaned_error_message(error)
539
+ case error.class.to_s
540
+ when "PG::UniqueViolation"
541
+ error.message.to_s.gsub(/\)=\(.*\)/, ")=(?)")
542
+ else
543
+ error.message.to_s
544
+ end
545
+ end
546
+
536
547
  # Stub that is returned by {Transaction.current} if there is no current
537
548
  # transaction, so that it's still safe to call methods on it if there is no
538
549
  # current transaction.
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Appsignal
4
- VERSION = "3.0.12".freeze
4
+ VERSION = "3.0.16".freeze
5
5
  end
@@ -2,6 +2,8 @@
2
2
 
3
3
  set -eu
4
4
 
5
+ LINTJE_VERSION="0.6.1"
6
+
5
7
  mkdir -p $HOME/bin
6
8
  cache_key=v1-lintje-$LINTJE_VERSION
7
9
  cache restore $cache_key
@@ -16,3 +18,5 @@ else
16
18
  tar -xz --directory $HOME/bin
17
19
  cache store $cache_key $HOME/bin/lintje
18
20
  fi
21
+
22
+ $HOME/bin/lintje $SEMAPHORE_GIT_COMMIT_RANGE
@@ -115,7 +115,6 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :send_report => :yes_cli_i
115
115
  it "logs to the log file" do
116
116
  run
117
117
  log_contents = File.read(config.log_file_path)
118
- p log_contents
119
118
  expect(log_contents).to contains_log :info, "Starting AppSignal diagnose"
120
119
  end
121
120
 
@@ -192,8 +191,8 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :send_report => :yes_cli_i
192
191
 
193
192
  it "outputs version numbers" do
194
193
  expect(output).to include \
195
- "Gem version: #{Appsignal::VERSION}",
196
- "Agent version: #{Appsignal::Extension.agent_version}"
194
+ "Gem version: \"#{Appsignal::VERSION}\"",
195
+ "Agent version: \"#{Appsignal::Extension.agent_version}\""
197
196
  end
198
197
 
199
198
  it "transmits version numbers in report" do
@@ -295,18 +294,18 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :send_report => :yes_cli_i
295
294
  "Installation result",
296
295
  " Status: success",
297
296
  "Language details",
298
- " Implementation: #{jruby ? "jruby" : "ruby"}",
299
- " Ruby version: #{"#{rbconfig["ruby_version"]}-p#{rbconfig["PATCHLEVEL"]}"}",
297
+ " Implementation: \"#{jruby ? "jruby" : "ruby"}\"",
298
+ " Ruby version: \"#{"#{rbconfig["ruby_version"]}-p#{rbconfig["PATCHLEVEL"]}"}\"",
300
299
  "Download details",
301
- " Download URL: https://",
302
- " Checksum: verified",
300
+ " Download URL: \"https://",
301
+ " Checksum: \"verified\"",
303
302
  "Build details",
304
- " Install time: 20",
305
- " Architecture: #{Appsignal::System.agent_architecture}",
306
- " Target: #{Appsignal::System.agent_platform}",
303
+ " Install time: \"20",
304
+ " Architecture: \"#{Appsignal::System.agent_architecture}\"",
305
+ " Target: \"#{Appsignal::System.agent_platform}\"",
307
306
  " Musl override: false",
308
307
  " Linux ARM override: false",
309
- " Library type: #{jruby ? "dynamic" : "static"}",
308
+ " Library type: \"#{jruby ? "dynamic" : "static"}\"",
310
309
  " Dependencies: {",
311
310
  " Flags: {",
312
311
  "Host details",
@@ -611,9 +610,9 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :send_report => :yes_cli_i
611
610
  run
612
611
  expect(output).to include \
613
612
  "Host information",
614
- "Architecture: #{rbconfig["host_cpu"]}",
615
- "Operating System: #{rbconfig["host_os"]}",
616
- "Ruby version: #{language_version}"
613
+ "Architecture: \"#{rbconfig["host_cpu"]}\"",
614
+ "Operating System: \"#{rbconfig["host_os"]}\"",
615
+ "Ruby version: \"#{language_version}\""
617
616
  end
618
617
 
619
618
  context "when on Microsoft Windows" do
@@ -751,13 +750,13 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :send_report => :yes_cli_i
751
750
  end
752
751
 
753
752
  it "outputs a warning that no config is loaded" do
754
- expect(output).to include "Environment: \"\"\n#{warning_message}"
753
+ expect(output).to include "environment: \"\"\n#{warning_message}"
755
754
  expect(output).to_not have_color_markers
756
755
  end
757
756
 
758
757
  context "with color", :color => true do
759
758
  it "outputs a warning that no config is loaded in color" do
760
- expect(output).to include "Environment: \"\"\n"
759
+ expect(output).to include "environment: \"\"\n"
761
760
  expect(output).to have_colorized_text :red, warning_message
762
761
  end
763
762
  end
@@ -786,7 +785,7 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :send_report => :yes_cli_i
786
785
  describe "environment" do
787
786
  it "outputs environment" do
788
787
  run
789
- expect(output).to include(%(Environment: "production"))
788
+ expect(output).to include(%(environment: "production"))
790
789
  end
791
790
 
792
791
  context "when the source is a single source" do
@@ -794,7 +793,7 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :send_report => :yes_cli_i
794
793
 
795
794
  it "outputs the label source after the value" do
796
795
  expect(output).to include(
797
- %(Environment: "#{Appsignal.config.env}" (Loaded from: initial)\n)
796
+ %(environment: "#{Appsignal.config.env}" (Loaded from: initial)\n)
798
797
  )
799
798
  end
800
799
  end
@@ -811,7 +810,7 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :send_report => :yes_cli_i
811
810
 
812
811
  it "outputs a list of sources with their values" do
813
812
  expect(output).to include(
814
- %( Environment: "production"\n) +
813
+ %( environment: "production"\n) +
815
814
  %( Sources:\n) +
816
815
  %( initial: "development"\n) +
817
816
  %( env: "production"\n)
@@ -905,7 +904,7 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :send_report => :yes_cli_i
905
904
  before { run_within_dir tmp_dir }
906
905
 
907
906
  it "outputs environment" do
908
- expect(output).to include(%(Environment: "foobar"))
907
+ expect(output).to include(%(environment: "foobar"))
909
908
  end
910
909
 
911
910
  it "outputs config defaults" do
@@ -1008,7 +1007,7 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :send_report => :yes_cli_i
1008
1007
 
1009
1008
  it "outputs failure with status code" do
1010
1009
  expect(output).to include "Validation",
1011
- "Validating Push API key: Failed with status 500\n" +
1010
+ "Validating Push API key: Failed to validate: status 500\n" +
1012
1011
  %("Could not confirm authorization: 500")
1013
1012
  end
1014
1013
 
@@ -1016,14 +1015,19 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :send_report => :yes_cli_i
1016
1015
  it "outputs error in color" do
1017
1016
  expect(output).to include "Validation",
1018
1017
  "Validating Push API key: " +
1019
- colorize(%(Failed with status 500\n"Could not confirm authorization: 500"), :red)
1018
+ colorize(
1019
+ "Failed to validate: status 500\n" +
1020
+ %("Could not confirm authorization: 500"),
1021
+ :red
1022
+ )
1020
1023
  end
1021
1024
  end
1022
1025
 
1023
1026
  it "transmits validation in report" do
1024
1027
  expect(received_report).to include(
1025
1028
  "validation" => {
1026
- "push_api_key" => %(Failed with status 500\n\"Could not confirm authorization: 500")
1029
+ "push_api_key" => "Failed to validate: status 500\n" +
1030
+ %("Could not confirm authorization: 500")
1027
1031
  }
1028
1032
  )
1029
1033
  end
@@ -151,33 +151,35 @@ describe Appsignal::Config do
151
151
 
152
152
  it "merges with the default config" do
153
153
  expect(config.config_hash).to eq(
154
+ :active => true,
155
+ :ca_file_path => File.join(resources_dir, "cacert.pem"),
154
156
  :debug => false,
155
- :log => "file",
157
+ :dns_servers => [],
158
+ :enable_allocation_tracking => true,
159
+ :enable_gc_instrumentation => false,
160
+ :enable_host_metrics => true,
161
+ :enable_minutely_probes => true,
162
+ :enable_statsd => true,
163
+ :endpoint => "https://push.appsignal.com",
164
+ :files_world_accessible => true,
165
+ :filter_parameters => [],
166
+ :filter_session_data => [],
156
167
  :ignore_actions => [],
157
168
  :ignore_errors => [],
158
169
  :ignore_namespaces => [],
159
- :filter_parameters => [],
160
- :filter_session_data => [],
161
170
  :instrument_net_http => true,
162
171
  :instrument_redis => true,
163
172
  :instrument_sequel => true,
164
- :skip_session_data => false,
165
- :send_environment_metadata => true,
166
- :send_params => true,
167
- :endpoint => "https://push.appsignal.com",
168
- :push_api_key => "abc",
173
+ :log => "file",
174
+ :log_level => "info",
169
175
  :name => "TestApp",
170
- :active => true,
171
- :enable_allocation_tracking => true,
172
- :enable_gc_instrumentation => false,
173
- :enable_host_metrics => true,
174
- :enable_minutely_probes => true,
175
- :ca_file_path => File.join(resources_dir, "cacert.pem"),
176
- :dns_servers => [],
177
- :files_world_accessible => true,
178
- :transaction_debug_mode => false,
176
+ :push_api_key => "abc",
177
+ :request_headers => [],
179
178
  :revision => "v2.5.1",
180
- :request_headers => []
179
+ :send_environment_metadata => true,
180
+ :send_params => true,
181
+ :skip_session_data => false,
182
+ :transaction_debug_mode => false
181
183
  )
182
184
  end
183
185
 
@@ -318,13 +320,15 @@ describe Appsignal::Config do
318
320
  "non-existing-path",
319
321
  "production",
320
322
  :running_in_container => true,
321
- :debug => true
323
+ :debug => true,
324
+ :log_level => "debug"
322
325
  )
323
326
  end
324
327
 
325
328
  it "overrides system detected and defaults config" do
326
329
  expect(config[:running_in_container]).to be_truthy
327
330
  expect(config[:debug]).to be_truthy
331
+ expect(config[:log_level]).to eq("debug")
328
332
  end
329
333
  end
330
334
 
@@ -501,6 +505,7 @@ describe Appsignal::Config do
501
505
  config[:log] = "stdout"
502
506
  config[:log_path] = "/tmp"
503
507
  config[:filter_parameters] = %w[password confirm_password]
508
+ config[:filter_session_data] = %w[key1 key2]
504
509
  config[:running_in_container] = false
505
510
  config[:dns_servers] = ["8.8.8.8", "8.8.4.4"]
506
511
  config[:transaction_debug_mode] = true
@@ -534,6 +539,8 @@ describe Appsignal::Config do
534
539
  expect(ENV["_APPSIGNAL_FILES_WORLD_ACCESSIBLE"]).to eq "true"
535
540
  expect(ENV["_APPSIGNAL_TRANSACTION_DEBUG_MODE"]).to eq "true"
536
541
  expect(ENV["_APPSIGNAL_SEND_ENVIRONMENT_METADATA"]).to eq "false"
542
+ expect(ENV["_APPSIGNAL_FILTER_PARAMETERS"]).to eq "password,confirm_password"
543
+ expect(ENV["_APPSIGNAL_FILTER_SESSION_DATA"]).to eq "key1,key2"
537
544
  expect(ENV["_APP_REVISION"]).to eq "v2.5.1"
538
545
  expect(ENV).to_not have_key("_APPSIGNAL_WORKING_DIR_PATH")
539
546
  expect(ENV).to_not have_key("_APPSIGNAL_WORKING_DIRECTORY_PATH")
@@ -0,0 +1,23 @@
1
+ describe Appsignal::Hooks::MriHook do
2
+ describe "#dependencies_present?" do
3
+ subject { described_class.new.dependencies_present? }
4
+
5
+ if DependencyHelper.running_jruby?
6
+ it { is_expected.to be_falsy }
7
+ else
8
+ it { is_expected.to be_truthy }
9
+ end
10
+ end
11
+
12
+ unless DependencyHelper.running_jruby?
13
+ context "install" do
14
+ before do
15
+ Appsignal::Hooks.load_hooks
16
+ end
17
+
18
+ it "should be added to minutely probes" do
19
+ expect(Appsignal::Minutely.probes[:mri]).to be Appsignal::Probes::MriProbe
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,33 @@
1
+ describe Appsignal::Probes::MriProbe do
2
+ let(:probe) { described_class.new }
3
+
4
+ describe ".dependencies_present?" do
5
+ if DependencyHelper.running_jruby? || DependencyHelper.running_ruby_2_0?
6
+ it "should not be present" do
7
+ expect(described_class.dependencies_present?).to be_falsy
8
+ end
9
+ else
10
+ it "should be present" do
11
+ expect(described_class.dependencies_present?).to be_truthy
12
+ end
13
+ end
14
+ end
15
+
16
+ unless DependencyHelper.running_jruby? || DependencyHelper.running_ruby_2_0?
17
+ describe "#call" do
18
+ it "should track vm metrics" do
19
+ expect_distribution_value(:class_serial)
20
+ expect_distribution_value(:global_constant_state)
21
+
22
+ probe.call
23
+ end
24
+ end
25
+
26
+ def expect_distribution_value(metric)
27
+ expect(Appsignal).to receive(:add_distribution_value)
28
+ .with("ruby_vm", kind_of(Numeric), :metric => metric)
29
+ .and_call_original
30
+ .once
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,141 @@
1
+ require "appsignal/span"
2
+
3
+ describe Appsignal::Span do
4
+ before :context do
5
+ start_agent
6
+ end
7
+
8
+ let(:namespace) { "web" }
9
+ let(:root) { Appsignal::Span.new(namespace) }
10
+
11
+ describe "creating a span" do
12
+ it "creates an empty span" do
13
+ expect(root.to_h["namespace"]).to eq "web"
14
+ expect(root.to_h["trace_id"].length).to eq 16
15
+ expect(root.to_h["span_id"].length).to eq 8
16
+ expect(root.to_h["parent_span_id"]).to be_empty
17
+ expect(root.to_h["name"]).to be_empty
18
+ expect(root.to_h["start_time"]).to be > 1_600_000_000
19
+ expect(root.to_h["closed"]).to be false
20
+ end
21
+ end
22
+
23
+ describe "#child" do
24
+ let(:child) { root.child }
25
+
26
+ it "creates a child span" do
27
+ expect(child.to_h["namespace"]).to be_empty
28
+ expect(child.to_h["trace_id"].length).to eq 16
29
+ expect(child.to_h["span_id"].length).to eq 8
30
+ expect(child.to_h["parent_span_id"]).to eq root.to_h["span_id"]
31
+ expect(child.to_h["name"]).to be_empty
32
+ expect(child.to_h["start_time"]).to be > 1_600_000_000
33
+ expect(child.to_h["closed"]).to be false
34
+ end
35
+ end
36
+
37
+ describe "#add_error" do
38
+ it "adds an error" do
39
+ begin
40
+ raise "Error"
41
+ rescue => error
42
+ root.add_error(error)
43
+ end
44
+
45
+ error = root.to_h["error"]
46
+ expect(error["name"]).to eq "RuntimeError"
47
+ expect(error["message"]).to eq "Error"
48
+ expect(error["backtrace"]).not_to be_empty
49
+ end
50
+ end
51
+
52
+ describe "set_sample_data" do
53
+ it "sets sample data" do
54
+ root.set_sample_data(:params, "key" => "value")
55
+
56
+ sample_data = root.to_h["sample_data"]
57
+ expect(sample_data["params"]).to eq "{\"key\":\"value\"}"
58
+ end
59
+ end
60
+
61
+ describe "#name=" do
62
+ it "sets the name" do
63
+ root.name = "Span name"
64
+
65
+ expect(root.to_h["name"]).to eq "Span name"
66
+ end
67
+ end
68
+
69
+ describe "#[]=" do
70
+ let(:attributes) { root.to_h["attributes"] }
71
+
72
+ it "sets a string attribute" do
73
+ root["string"] = "attribute"
74
+
75
+ expect(attributes["string"]).to eq "attribute"
76
+ end
77
+
78
+ it "sets an integer attribute" do
79
+ root["integer"] = 1001
80
+
81
+ expect(attributes["integer"]).to eq 1001
82
+ end
83
+
84
+ it "sets a bigint attribute" do
85
+ root["bigint"] = 1 << 64
86
+
87
+ expect(attributes["bigint"]).to eq "bigint:#{1 << 64}"
88
+ end
89
+
90
+ it "sets a boolean attribute" do
91
+ root["true"] = true
92
+ root["false"] = false
93
+
94
+ expect(attributes["true"]).to eq true
95
+ expect(attributes["false"]).to eq false
96
+ end
97
+
98
+ it "sets a float attribute" do
99
+ root["float"] = 10.01
100
+
101
+ expect(attributes["float"]).to eq 10.01
102
+ end
103
+
104
+ it "raises an error for other types" do
105
+ expect do
106
+ root["something"] = Object.new
107
+ end.to raise_error TypeError
108
+ end
109
+ end
110
+
111
+ describe "#instrument" do
112
+ it "closes the span after yielding" do
113
+ root.instrument do
114
+ # Nothing happening
115
+ end
116
+ expect(root.closed?).to eq true
117
+ end
118
+
119
+ context "with an error raised in the passed block" do
120
+ it "closes the span after yielding" do
121
+ expect do
122
+ root.instrument do
123
+ raise ExampleException, "foo"
124
+ end
125
+ end.to raise_error(ExampleException, "foo")
126
+ expect(root.closed?).to eq true
127
+ end
128
+ end
129
+ end
130
+
131
+ describe "#close" do
132
+ it "closes a span" do
133
+ expect(root.closed?).to eq false
134
+
135
+ root.close
136
+
137
+ expect(root.to_h).to be_nil
138
+ expect(root.closed?).to eq true
139
+ end
140
+ end
141
+ end
@@ -1341,6 +1341,31 @@ describe Appsignal::Transaction do
1341
1341
  end
1342
1342
  end
1343
1343
 
1344
+ describe "#cleaned_error_message" do
1345
+ let(:error) { StandardError.new("Error message") }
1346
+ subject { transaction.send(:cleaned_error_message, error) }
1347
+
1348
+ it "returns the error message" do
1349
+ expect(subject).to eq "Error message"
1350
+ end
1351
+
1352
+ context "with a PG::UniqueViolation" do
1353
+ module PG
1354
+ class UniqueViolation < StandardError; end
1355
+ end
1356
+
1357
+ let(:error) do
1358
+ PG::UniqueViolation.new(
1359
+ "ERROR: duplicate key value violates unique constraint \"index_users_on_email\" DETAIL: Key (email)=(test@test.com) already exists."
1360
+ )
1361
+ end
1362
+
1363
+ it "returns a sanizited error message" do
1364
+ expect(subject).to eq "ERROR: duplicate key value violates unique constraint \"index_users_on_email\" DETAIL: Key (email)=(?) already exists."
1365
+ end
1366
+ end
1367
+ end
1368
+
1344
1369
  describe ".to_hash / .to_h" do
1345
1370
  subject { transaction.to_hash }
1346
1371
 
@@ -5,6 +5,10 @@ module DependencyHelper
5
5
  Gem::Version.new(RUBY_VERSION)
6
6
  end
7
7
 
8
+ def running_ruby_2_0?
9
+ ruby_version.segments.take(2) == [2, 0]
10
+ end
11
+
8
12
  def running_jruby?
9
13
  defined?(RUBY_ENGINE) && RUBY_ENGINE == "jruby"
10
14
  end