appsignal 3.0.15-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.
@@ -131,6 +131,65 @@ module Appsignal
131
131
  [:pointer],
132
132
  :appsignal_string
133
133
 
134
+ # Span methods
135
+ attach_function :appsignal_create_root_span,
136
+ [:appsignal_string],
137
+ :pointer
138
+ attach_function :appsignal_create_root_span_with_timestamp,
139
+ [:appsignal_string, :int64, :int64],
140
+ :pointer
141
+ attach_function :appsignal_create_child_span,
142
+ [:pointer],
143
+ :pointer
144
+ attach_function :appsignal_create_child_span_with_timestamp,
145
+ [:pointer, :int64, :int64],
146
+ :pointer
147
+ attach_function :appsignal_create_span_from_traceparent,
148
+ [:appsignal_string],
149
+ :pointer
150
+ attach_function :appsignal_span_id,
151
+ [:pointer],
152
+ :appsignal_string
153
+ attach_function :appsignal_span_to_json,
154
+ [:pointer],
155
+ :appsignal_string
156
+ attach_function :appsignal_set_span_name,
157
+ [:pointer, :appsignal_string],
158
+ :void
159
+ attach_function :appsignal_set_span_namespace,
160
+ [:pointer, :appsignal_string],
161
+ :void
162
+ attach_function :appsignal_add_span_error,
163
+ [:pointer, :appsignal_string, :appsignal_string, :pointer],
164
+ :void
165
+ attach_function :appsignal_set_span_sample_data,
166
+ [:pointer, :appsignal_string, :pointer],
167
+ :void
168
+ attach_function :appsignal_set_span_attribute_string,
169
+ [:pointer, :appsignal_string, :appsignal_string],
170
+ :void
171
+ attach_function :appsignal_set_span_attribute_sql_string,
172
+ [:pointer, :appsignal_string, :appsignal_string],
173
+ :void
174
+ attach_function :appsignal_set_span_attribute_int,
175
+ [:pointer, :appsignal_string, :int64],
176
+ :void
177
+ attach_function :appsignal_set_span_attribute_bool,
178
+ [:pointer, :appsignal_string, :bool],
179
+ :void
180
+ attach_function :appsignal_set_span_attribute_double,
181
+ [:pointer, :appsignal_string, :double],
182
+ :void
183
+ attach_function :appsignal_close_span,
184
+ [:pointer],
185
+ :void
186
+ attach_function :appsignal_close_span_with_timestamp,
187
+ [:pointer, :int64, :int64],
188
+ :void
189
+ attach_function :appsignal_free_span,
190
+ [:pointer],
191
+ :void
192
+
134
193
  # Data struct methods
135
194
  attach_function :appsignal_free_data, [], :void
136
195
  attach_function :appsignal_data_map_new, [], :pointer
@@ -375,6 +434,94 @@ module Appsignal
375
434
  end
376
435
  end
377
436
 
437
+ class Span
438
+ include StringHelpers
439
+ extend StringHelpers
440
+
441
+ attr_reader :pointer
442
+
443
+ def initialize(pointer)
444
+ @pointer = FFI::AutoPointer.new(
445
+ pointer,
446
+ Extension.method(:appsignal_free_span)
447
+ )
448
+ end
449
+
450
+ def self.root(namespace)
451
+ namespace = make_appsignal_string(namespace)
452
+ Span.new(Extension.appsignal_create_root_span(namespace))
453
+ end
454
+
455
+ def child
456
+ Span.new(Extension.appsignal_create_child_span(pointer))
457
+ end
458
+
459
+ def add_error(name, message, backtrace)
460
+ Extension.appsignal_add_span_error(
461
+ pointer,
462
+ make_appsignal_string(name),
463
+ make_appsignal_string(message),
464
+ backtrace.pointer
465
+ )
466
+ end
467
+
468
+ def set_sample_data(key, payload)
469
+ Extension.appsignal_set_span_sample_data(
470
+ pointer,
471
+ make_appsignal_string(key),
472
+ payload.pointer
473
+ )
474
+ end
475
+
476
+ def set_name(name) # rubocop:disable Naming/AccessorMethodName
477
+ Extension.appsignal_set_span_name(
478
+ pointer,
479
+ make_appsignal_string(name)
480
+ )
481
+ end
482
+
483
+ def set_attribute_string(key, value)
484
+ Extension.appsignal_set_span_attribute_string(
485
+ pointer,
486
+ make_appsignal_string(key),
487
+ make_appsignal_string(value)
488
+ )
489
+ end
490
+
491
+ def set_attribute_int(key, value)
492
+ Extension.appsignal_set_span_attribute_int(
493
+ pointer,
494
+ make_appsignal_string(key),
495
+ value
496
+ )
497
+ end
498
+
499
+ def set_attribute_bool(key, value)
500
+ Extension.appsignal_set_span_attribute_bool(
501
+ pointer,
502
+ make_appsignal_string(key),
503
+ value
504
+ )
505
+ end
506
+
507
+ def set_attribute_double(key, value)
508
+ Extension.appsignal_set_span_attribute_double(
509
+ pointer,
510
+ make_appsignal_string(key),
511
+ value
512
+ )
513
+ end
514
+
515
+ def to_json
516
+ json = Extension.appsignal_span_to_json(pointer)
517
+ make_ruby_string(json) if json[:len] > 0
518
+ end
519
+
520
+ def close
521
+ Extension.appsignal_close_span(pointer)
522
+ end
523
+ end
524
+
378
525
  class Data
379
526
  include StringHelpers
380
527
  attr_reader :pointer
@@ -60,6 +60,11 @@ module Appsignal
60
60
  # Makes sure the generated docs aren't always overwritten with the JRuby
61
61
  # version.
62
62
  Transaction = Jruby::Transaction
63
+ # Reassign Span class for JRuby extension usage.
64
+ #
65
+ # Makes sure the generated docs aren't always overwritten with the JRuby
66
+ # version.
67
+ Span = Jruby::Span
63
68
  # Reassign Data class for JRuby extension usage.
64
69
  #
65
70
  # Makes sure the generated docs aren't always overwritten with the JRuby
@@ -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.15".freeze
4
+ VERSION = "3.0.16".freeze
5
5
  end
data/script/lint_git CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  set -eu
4
4
 
5
- LINTJE_VERSION="0.5.0"
5
+ LINTJE_VERSION="0.6.1"
6
6
 
7
7
  mkdir -p $HOME/bin
8
8
  cache_key=v1-lintje-$LINTJE_VERSION
@@ -750,13 +750,13 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :send_report => :yes_cli_i
750
750
  end
751
751
 
752
752
  it "outputs a warning that no config is loaded" do
753
- expect(output).to include "Environment: \"\"\n#{warning_message}"
753
+ expect(output).to include "environment: \"\"\n#{warning_message}"
754
754
  expect(output).to_not have_color_markers
755
755
  end
756
756
 
757
757
  context "with color", :color => true do
758
758
  it "outputs a warning that no config is loaded in color" do
759
- expect(output).to include "Environment: \"\"\n"
759
+ expect(output).to include "environment: \"\"\n"
760
760
  expect(output).to have_colorized_text :red, warning_message
761
761
  end
762
762
  end
@@ -785,7 +785,7 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :send_report => :yes_cli_i
785
785
  describe "environment" do
786
786
  it "outputs environment" do
787
787
  run
788
- expect(output).to include(%(Environment: "production"))
788
+ expect(output).to include(%(environment: "production"))
789
789
  end
790
790
 
791
791
  context "when the source is a single source" do
@@ -793,7 +793,7 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :send_report => :yes_cli_i
793
793
 
794
794
  it "outputs the label source after the value" do
795
795
  expect(output).to include(
796
- %(Environment: "#{Appsignal.config.env}" (Loaded from: initial)\n)
796
+ %(environment: "#{Appsignal.config.env}" (Loaded from: initial)\n)
797
797
  )
798
798
  end
799
799
  end
@@ -810,7 +810,7 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :send_report => :yes_cli_i
810
810
 
811
811
  it "outputs a list of sources with their values" do
812
812
  expect(output).to include(
813
- %( Environment: "production"\n) +
813
+ %( environment: "production"\n) +
814
814
  %( Sources:\n) +
815
815
  %( initial: "development"\n) +
816
816
  %( env: "production"\n)
@@ -904,7 +904,7 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :send_report => :yes_cli_i
904
904
  before { run_within_dir tmp_dir }
905
905
 
906
906
  it "outputs environment" do
907
- expect(output).to include(%(Environment: "foobar"))
907
+ expect(output).to include(%(environment: "foobar"))
908
908
  end
909
909
 
910
910
  it "outputs config defaults" do
@@ -1007,7 +1007,7 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :send_report => :yes_cli_i
1007
1007
 
1008
1008
  it "outputs failure with status code" do
1009
1009
  expect(output).to include "Validation",
1010
- "Validating Push API key: Failed with status 500\n" +
1010
+ "Validating Push API key: Failed to validate: status 500\n" +
1011
1011
  %("Could not confirm authorization: 500")
1012
1012
  end
1013
1013
 
@@ -1015,14 +1015,19 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :send_report => :yes_cli_i
1015
1015
  it "outputs error in color" do
1016
1016
  expect(output).to include "Validation",
1017
1017
  "Validating Push API key: " +
1018
- 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
+ )
1019
1023
  end
1020
1024
  end
1021
1025
 
1022
1026
  it "transmits validation in report" do
1023
1027
  expect(received_report).to include(
1024
1028
  "validation" => {
1025
- "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")
1026
1031
  }
1027
1032
  )
1028
1033
  end
@@ -151,34 +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
- :enable_statsd => true,
176
- :ca_file_path => File.join(resources_dir, "cacert.pem"),
177
- :dns_servers => [],
178
- :files_world_accessible => true,
179
- :transaction_debug_mode => false,
176
+ :push_api_key => "abc",
177
+ :request_headers => [],
180
178
  :revision => "v2.5.1",
181
- :request_headers => []
179
+ :send_environment_metadata => true,
180
+ :send_params => true,
181
+ :skip_session_data => false,
182
+ :transaction_debug_mode => false
182
183
  )
183
184
  end
184
185
 
@@ -319,13 +320,15 @@ describe Appsignal::Config do
319
320
  "non-existing-path",
320
321
  "production",
321
322
  :running_in_container => true,
322
- :debug => true
323
+ :debug => true,
324
+ :log_level => "debug"
323
325
  )
324
326
  end
325
327
 
326
328
  it "overrides system detected and defaults config" do
327
329
  expect(config[:running_in_container]).to be_truthy
328
330
  expect(config[:debug]).to be_truthy
331
+ expect(config[:log_level]).to eq("debug")
329
332
  end
330
333
  end
331
334
 
@@ -502,6 +505,7 @@ describe Appsignal::Config do
502
505
  config[:log] = "stdout"
503
506
  config[:log_path] = "/tmp"
504
507
  config[:filter_parameters] = %w[password confirm_password]
508
+ config[:filter_session_data] = %w[key1 key2]
505
509
  config[:running_in_container] = false
506
510
  config[:dns_servers] = ["8.8.8.8", "8.8.4.4"]
507
511
  config[:transaction_debug_mode] = true
@@ -535,6 +539,8 @@ describe Appsignal::Config do
535
539
  expect(ENV["_APPSIGNAL_FILES_WORLD_ACCESSIBLE"]).to eq "true"
536
540
  expect(ENV["_APPSIGNAL_TRANSACTION_DEBUG_MODE"]).to eq "true"
537
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"
538
544
  expect(ENV["_APP_REVISION"]).to eq "v2.5.1"
539
545
  expect(ENV).to_not have_key("_APPSIGNAL_WORKING_DIR_PATH")
540
546
  expect(ENV).to_not have_key("_APPSIGNAL_WORKING_DIRECTORY_PATH")
@@ -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