appsignal 0.12.rc.9 → 0.12.rc.10
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 +4 -4
- data/README.md +3 -62
- data/Rakefile +3 -2
- data/ext/agent.yml +7 -7
- data/ext/appsignal_extension.c +17 -7
- data/lib/appsignal.rb +1 -1
- data/lib/appsignal/config.rb +8 -5
- data/lib/appsignal/hooks.rb +38 -0
- data/lib/appsignal/hooks/sidekiq.rb +2 -12
- data/lib/appsignal/integrations/delayed_job_plugin.rb +9 -0
- data/lib/appsignal/js_exception_transaction.rb +5 -5
- data/lib/appsignal/transaction.rb +35 -22
- data/lib/appsignal/version.rb +1 -1
- data/spec/lib/appsignal/config_spec.rb +9 -1
- data/spec/lib/appsignal/extension_spec.rb +3 -3
- data/spec/lib/appsignal/hooks/delayed_job_spec.rb +11 -8
- data/spec/lib/appsignal/hooks/sidekiq_spec.rb +0 -32
- data/spec/lib/appsignal/hooks_spec.rb +76 -0
- data/spec/lib/appsignal/js_exception_transaction_spec.rb +11 -7
- data/spec/lib/appsignal/transaction_spec.rb +76 -47
- data/spec/lib/appsignal_spec.rb +6 -12
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 693aa4f235ee31447feb2a8b1f33a70df69fee2c
|
4
|
+
data.tar.gz: d52a48f030ed7a0b816b315365e0a71a26a77436
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 20ba8304f8ac2b8969b34f869e7cd0f9ea43c9ba007112dd6d1195e2bcbcfc9d1b0210acba9ceb529b4b7cc576ce4b34c3c5f5fd3737023ff8d8b086cd1ca74c
|
7
|
+
data.tar.gz: 8909aa17bfec6253d49c4ad7bdff01d57f8cc66c4c8b4a905ced96e5be942f918e8681788f209fbe8073d806288bc342954013eb89980eeb02cc46caa515f877
|
data/README.md
CHANGED
@@ -8,81 +8,22 @@ applications and sends it to [AppSignal](https://appsignal.com)
|
|
8
8
|
[](http://badge.fury.io/rb/appsignal)
|
9
9
|
[](https://codeclimate.com/github/appsignal/appsignal)
|
10
10
|
|
11
|
-
## Pull requests / issues
|
12
|
-
|
13
|
-
New features should be made in an issue or pullrequest. Title format is as follows:
|
14
|
-
|
15
|
-
name [request_count]
|
16
|
-
|
17
|
-
example
|
18
|
-
|
19
|
-
tagging [2]
|
20
|
-
|
21
|
-
## Postprocessing middleware
|
22
|
-
|
23
|
-
Appsignal sends Rails
|
24
|
-
[ActiveSupport::Notification](http://api.rubyonrails.org/classes/ActiveSupport/Notifications.html)-events
|
25
|
-
to AppSignal over SSL. These events contain basic metadata such as a name
|
26
|
-
and timestamps, and additional 'payload' log data. Appsignal uses a postprocessing
|
27
|
-
middleware stack to clean up events before they get sent to appsignal.com. You
|
28
|
-
can add your own middleware to this stack in `config/environment/my_env.rb`.
|
29
|
-
|
30
|
-
### Examples
|
31
|
-
|
32
|
-
#### Minimal template
|
33
|
-
|
34
|
-
```ruby
|
35
|
-
class MiddlewareTemplate
|
36
|
-
def call(event)
|
37
|
-
# modify the event in place
|
38
|
-
yield # pass control to the next middleware
|
39
|
-
# modify the event some more
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
Appsignal.post_processing_middleware.add MiddlewareTemplate
|
44
|
-
```
|
45
|
-
|
46
|
-
#### Remove boring payloads
|
47
|
-
|
48
|
-
```ruby
|
49
|
-
class RemoveBoringPayload
|
50
|
-
def call(event)
|
51
|
-
event.payload.clear unless event.name == 'interesting'
|
52
|
-
yield
|
53
|
-
end
|
54
|
-
end
|
55
|
-
```
|
56
|
-
|
57
11
|
## Development
|
58
12
|
|
59
|
-
Run rake
|
60
|
-
|
61
|
-
```
|
62
|
-
bundle --gemfile gemfiles/capistrano2.gemfile
|
63
|
-
bundle --gemfile gemfiles/capistrano3.gemfile
|
64
|
-
bundle --gemfile gemfiles/no_dependencies.gemfile
|
65
|
-
bundle --gemfile gemfiles/rails-3.0.gemfile
|
66
|
-
bundle --gemfile gemfiles/rails-3.1.gemfile
|
67
|
-
bundle --gemfile gemfiles/rails-3.2.gemfile
|
68
|
-
bundle --gemfile gemfiles/rails-4.0.gemfile
|
69
|
-
bundle --gemfile gemfiles/rails-4.1.gemfile
|
70
|
-
bundle --gemfile gemfiles/rails-4.2.gemfile
|
71
|
-
bundle --gemfile gemfiles/sinatra.gemfile
|
72
|
-
```
|
73
|
-
|
74
|
-
To run the spec suite with a specific Gemfile:
|
13
|
+
Run `rake install`, then run the spec suite with a specific Gemfile:
|
75
14
|
|
76
15
|
```
|
77
16
|
BUNDLE_GEMFILE=gemfiles/capistrano2.gemfile bundle exec rspec
|
78
17
|
BUNDLE_GEMFILE=gemfiles/capistrano3.gemfile bundle exec rspec
|
79
18
|
BUNDLE_GEMFILE=gemfiles/no_dependencies.gemfile bundle exec rspec
|
19
|
+
BUNDLE_GEMFILE=gemfiles/padrino.gemfile bundle exec rspec
|
80
20
|
BUNDLE_GEMFILE=gemfiles/rails-3.0.gemfile bundle exec rspec
|
81
21
|
BUNDLE_GEMFILE=gemfiles/rails-3.1.gemfile bundle exec rspec
|
82
22
|
BUNDLE_GEMFILE=gemfiles/rails-3.2.gemfile bundle exec rspec
|
83
23
|
BUNDLE_GEMFILE=gemfiles/rails-4.0.gemfile bundle exec rspec
|
84
24
|
BUNDLE_GEMFILE=gemfiles/rails-4.1.gemfile bundle exec rspec
|
85
25
|
BUNDLE_GEMFILE=gemfiles/rails-4.2.gemfile bundle exec rspec
|
26
|
+
BUNDLE_GEMFILE=gemfiles/sequel.gemfile bundle exec rspec
|
86
27
|
BUNDLE_GEMFILE=gemfiles/sinatra.gemfile bundle exec rspec
|
87
28
|
```
|
88
29
|
|
data/Rakefile
CHANGED
@@ -93,7 +93,8 @@ task :publish do
|
|
93
93
|
end
|
94
94
|
end
|
95
95
|
|
96
|
-
task :
|
96
|
+
task :install do
|
97
|
+
system 'cd ext && rm -f libappsignal.a && ruby extconf.rb && make clean && make && cd ..'
|
97
98
|
GEMFILES.each do |gemfile|
|
98
99
|
system "bundle --gemfile gemfiles/#{gemfile}.gemfile"
|
99
100
|
end
|
@@ -119,7 +120,7 @@ task :generate_bundle_and_spec_all do
|
|
119
120
|
RUBY_VERSIONS.each do |version|
|
120
121
|
out << "echo 'Switching to #{version}'"
|
121
122
|
out << "#{switch_command} #{version} || { echo 'Switching Ruby failed'; exit 1; }"
|
122
|
-
out << 'cd ext && ruby extconf.rb && make clean && make && cd ..'
|
123
|
+
out << 'cd ext && rm -f libappsignal.a && ruby extconf.rb && make clean && make && cd ..'
|
123
124
|
GEMFILES.each do |gemfile|
|
124
125
|
out << "echo 'Bundling #{gemfile} in #{version}'"
|
125
126
|
out << "bundle --quiet --gemfile gemfiles/#{gemfile}.gemfile || { echo 'Bundling failed'; exit 1; }"
|
data/ext/agent.yml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
|
-
:version:
|
2
|
+
:version: ae85df1
|
3
3
|
:triples:
|
4
4
|
x86_64-linux:
|
5
|
-
:checksum:
|
6
|
-
:download_url: https://appsignal-agent-releases.global.ssl.fastly.net/
|
5
|
+
:checksum: f5b31b2e487a9865bf660ef244142e38f18d90b7ff91d538fff9d3d9b386c044
|
6
|
+
:download_url: https://appsignal-agent-releases.global.ssl.fastly.net/ae85df1/appsignal-agent-x86_64-linux-static.tar.gz
|
7
7
|
:lib_filename: libappsignal.a
|
8
8
|
i686-linux:
|
9
|
-
:checksum:
|
10
|
-
:download_url: https://appsignal-agent-releases.global.ssl.fastly.net/
|
9
|
+
:checksum: 6a053ed939a6f9c36271ac4b421674d01e2ea4d6b962914cec5fbb36f64675bd
|
10
|
+
:download_url: https://appsignal-agent-releases.global.ssl.fastly.net/ae85df1/appsignal-agent-i686-linux-static.tar.gz
|
11
11
|
:lib_filename: libappsignal.a
|
12
12
|
x86_64-darwin:
|
13
|
-
:checksum:
|
14
|
-
:download_url: https://appsignal-agent-releases.global.ssl.fastly.net/
|
13
|
+
:checksum: 91fe3a509541a9d18c1cc41821df21d3b09bf6e0bbcbd52e30b49674c348cd32
|
14
|
+
:download_url: https://appsignal-agent-releases.global.ssl.fastly.net/ae85df1/appsignal-agent-x86_64-darwin-static.tar.gz
|
15
15
|
:lib_filename: libappsignal.a
|
data/ext/appsignal_extension.c
CHANGED
@@ -41,25 +41,27 @@ static VALUE finish_event(VALUE self, VALUE transaction_index, VALUE name, VALUE
|
|
41
41
|
return Qnil;
|
42
42
|
}
|
43
43
|
|
44
|
-
static VALUE set_transaction_error(VALUE self, VALUE transaction_index, VALUE name, VALUE message) {
|
44
|
+
static VALUE set_transaction_error(VALUE self, VALUE transaction_index, VALUE name, VALUE message, VALUE backtrace) {
|
45
45
|
Check_Type(transaction_index, T_FIXNUM);
|
46
46
|
Check_Type(name, T_STRING);
|
47
47
|
Check_Type(message, T_STRING);
|
48
|
+
Check_Type(backtrace, T_STRING);
|
48
49
|
|
49
50
|
appsignal_set_transaction_error(
|
50
51
|
FIX2INT(transaction_index),
|
51
52
|
StringValueCStr(name),
|
52
|
-
StringValueCStr(message)
|
53
|
+
StringValueCStr(message),
|
54
|
+
StringValueCStr(backtrace)
|
53
55
|
);
|
54
56
|
return Qnil;
|
55
57
|
}
|
56
58
|
|
57
|
-
static VALUE
|
59
|
+
static VALUE set_transaction_sample_data(VALUE self, VALUE transaction_index, VALUE key, VALUE payload) {
|
58
60
|
Check_Type(transaction_index, T_FIXNUM);
|
59
61
|
Check_Type(key, T_STRING);
|
60
62
|
Check_Type(payload, T_STRING);
|
61
63
|
|
62
|
-
|
64
|
+
appsignal_set_transaction_sample_data(
|
63
65
|
FIX2INT(transaction_index),
|
64
66
|
StringValueCStr(key),
|
65
67
|
StringValueCStr(payload)
|
@@ -105,7 +107,14 @@ static VALUE set_transaction_metadata(VALUE self, VALUE transaction_index, VALUE
|
|
105
107
|
static VALUE finish_transaction(VALUE self, VALUE transaction_index) {
|
106
108
|
Check_Type(transaction_index, T_FIXNUM);
|
107
109
|
|
108
|
-
appsignal_finish_transaction(FIX2INT(transaction_index));
|
110
|
+
int sample = appsignal_finish_transaction(FIX2INT(transaction_index));
|
111
|
+
return sample == 1 ? Qtrue : Qfalse;
|
112
|
+
}
|
113
|
+
|
114
|
+
static VALUE complete_transaction(VALUE self, VALUE transaction_index) {
|
115
|
+
Check_Type(transaction_index, T_FIXNUM);
|
116
|
+
|
117
|
+
appsignal_complete_transaction(FIX2INT(transaction_index));
|
109
118
|
return Qnil;
|
110
119
|
}
|
111
120
|
|
@@ -228,12 +237,13 @@ void Init_appsignal_extension(void) {
|
|
228
237
|
rb_define_singleton_method(Extension, "start_transaction", start_transaction, 2);
|
229
238
|
rb_define_singleton_method(Extension, "start_event", start_event, 1);
|
230
239
|
rb_define_singleton_method(Extension, "finish_event", finish_event, 4);
|
231
|
-
rb_define_singleton_method(Extension, "set_transaction_error", set_transaction_error,
|
232
|
-
rb_define_singleton_method(Extension, "
|
240
|
+
rb_define_singleton_method(Extension, "set_transaction_error", set_transaction_error, 4);
|
241
|
+
rb_define_singleton_method(Extension, "set_transaction_sample_data", set_transaction_sample_data, 3);
|
233
242
|
rb_define_singleton_method(Extension, "set_transaction_action", set_transaction_action, 2);
|
234
243
|
rb_define_singleton_method(Extension, "set_transaction_queue_start", set_transaction_queue_start, 2);
|
235
244
|
rb_define_singleton_method(Extension, "set_transaction_metadata", set_transaction_metadata, 3);
|
236
245
|
rb_define_singleton_method(Extension, "finish_transaction", finish_transaction, 1);
|
246
|
+
rb_define_singleton_method(Extension, "complete_transaction", complete_transaction, 1);
|
237
247
|
|
238
248
|
// Event hook installation
|
239
249
|
rb_define_singleton_method(Extension, "install_allocation_event_hook", install_allocation_event_hook, 0);
|
data/lib/appsignal.rb
CHANGED
data/lib/appsignal/config.rb
CHANGED
@@ -20,7 +20,8 @@ module Appsignal
|
|
20
20
|
:enable_frontend_error_catching => false,
|
21
21
|
:frontend_error_catching_path => '/appsignal_error_catcher',
|
22
22
|
:enable_allocation_tracking => true,
|
23
|
-
:enable_gc_instrumentation => true
|
23
|
+
:enable_gc_instrumentation => true,
|
24
|
+
:running_in_container => false
|
24
25
|
}.freeze
|
25
26
|
|
26
27
|
ENV_TO_KEY_MAPPING = {
|
@@ -40,7 +41,8 @@ module Appsignal
|
|
40
41
|
'APPSIGNAL_IGNORE_ACTIONS' => :ignore_actions,
|
41
42
|
'APPSIGNAL_HTTP_PROXY' => :http_proxy,
|
42
43
|
'APPSIGNAL_ENABLE_ALLOCATION_TRACKING' => :enable_allocation_tracking,
|
43
|
-
'APPSIGNAL_ENABLE_GC_INSTRUMENTATION' => :enable_gc_instrumentation
|
44
|
+
'APPSIGNAL_ENABLE_GC_INSTRUMENTATION' => :enable_gc_instrumentation,
|
45
|
+
'APPSIGNAL_RUNNING_IN_CONTAINER' => :running_in_container
|
44
46
|
}.freeze
|
45
47
|
|
46
48
|
attr_reader :root_path, :env, :initial_config, :config_hash
|
@@ -75,8 +77,7 @@ module Appsignal
|
|
75
77
|
path = config_hash[:log_path] || root_path
|
76
78
|
File.join(File.realpath(path), 'appsignal.log')
|
77
79
|
rescue Errno::ENOENT
|
78
|
-
|
79
|
-
nil
|
80
|
+
'/tmp/appsignal.log'
|
80
81
|
end
|
81
82
|
|
82
83
|
def valid?
|
@@ -101,6 +102,7 @@ module Appsignal
|
|
101
102
|
ENV['APPSIGNAL_APP_NAME'] = config_hash[:name]
|
102
103
|
ENV['APPSIGNAL_HTTP_PROXY'] = config_hash[:http_proxy]
|
103
104
|
ENV['APPSIGNAL_IGNORE_ACTIONS'] = config_hash[:ignore_actions].join(',')
|
105
|
+
ENV['APPSIGNAL_RUNNING_IN_CONTAINER'] = config_hash[:running_in_container].to_s
|
104
106
|
end
|
105
107
|
|
106
108
|
protected
|
@@ -151,7 +153,8 @@ module Appsignal
|
|
151
153
|
# Configuration with boolean type
|
152
154
|
%w(APPSIGNAL_ACTIVE APPSIGNAL_DEBUG APPSIGNAL_INSTRUMENT_NET_HTTP
|
153
155
|
APPSIGNAL_SKIP_SESSION_DATA APPSIGNAL_ENABLE_FRONTEND_ERROR_CATCHING
|
154
|
-
APPSIGNAL_ENABLE_ALLOCATION_TRACKING APPSIGNAL_ENABLE_GC_INSTRUMENTATION
|
156
|
+
APPSIGNAL_ENABLE_ALLOCATION_TRACKING APPSIGNAL_ENABLE_GC_INSTRUMENTATION
|
157
|
+
APPSIGNAL_RUNNING_IN_CONTAINER).each do |var|
|
155
158
|
if env_var = ENV[var]
|
156
159
|
config[ENV_TO_KEY_MAPPING[var]] = env_var == 'true'
|
157
160
|
end
|
data/lib/appsignal/hooks.rb
CHANGED
@@ -45,6 +45,44 @@ module Appsignal
|
|
45
45
|
raise NotImplementedError
|
46
46
|
end
|
47
47
|
end
|
48
|
+
|
49
|
+
module Helpers
|
50
|
+
|
51
|
+
def self.included(base)
|
52
|
+
base.extend(ClassMethods)
|
53
|
+
end
|
54
|
+
|
55
|
+
module ClassMethods
|
56
|
+
def truncate(text)
|
57
|
+
Appsignal::Hooks::Helpers.truncate(text)
|
58
|
+
end
|
59
|
+
|
60
|
+
def string_or_inspect(string_or_other)
|
61
|
+
Appsignal::Hooks::Helpers.string_or_inspect(string_or_other)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def string_or_inspect(string_or_other)
|
66
|
+
Appsignal::Hooks::Helpers.string_or_inspect(string_or_other)
|
67
|
+
end
|
68
|
+
|
69
|
+
def truncate(text)
|
70
|
+
Appsignal::Hooks::Helpers.truncate(text)
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.string_or_inspect(string_or_other)
|
74
|
+
if string_or_other.is_a?(String)
|
75
|
+
string_or_other
|
76
|
+
else
|
77
|
+
string_or_other.inspect
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.truncate(text)
|
82
|
+
text.size > 200 ? "#{text[0...197]}..." : text
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
48
86
|
end
|
49
87
|
end
|
50
88
|
|
@@ -1,6 +1,8 @@
|
|
1
1
|
module Appsignal
|
2
2
|
class Hooks
|
3
3
|
class SidekiqPlugin
|
4
|
+
include Appsignal::Hooks::Helpers
|
5
|
+
|
4
6
|
def job_keys
|
5
7
|
@job_keys ||= Set.new(%w(
|
6
8
|
class args retried_at failed_at
|
@@ -30,23 +32,11 @@ module Appsignal
|
|
30
32
|
end
|
31
33
|
end
|
32
34
|
|
33
|
-
def string_or_inspect(string_or_other)
|
34
|
-
if string_or_other.is_a?(String)
|
35
|
-
string_or_other
|
36
|
-
else
|
37
|
-
string_or_other.inspect
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
35
|
def format_args(args)
|
42
36
|
args.map do |arg|
|
43
37
|
truncate(string_or_inspect(arg))
|
44
38
|
end
|
45
39
|
end
|
46
|
-
|
47
|
-
def truncate(text)
|
48
|
-
text.size > 200 ? "#{text[0...197]}..." : text
|
49
|
-
end
|
50
40
|
end
|
51
41
|
|
52
42
|
class SidekiqHook < Appsignal::Hooks::Hook
|
@@ -1,6 +1,8 @@
|
|
1
1
|
module Appsignal
|
2
2
|
class Hooks
|
3
3
|
class DelayedJobPlugin < ::Delayed::Plugin
|
4
|
+
include Appsignal::Hooks::Helpers
|
5
|
+
|
4
6
|
callbacks do |lifecycle|
|
5
7
|
lifecycle.around(:invoke_job) do |job, &block|
|
6
8
|
invoke_with_instrumentation(job, block)
|
@@ -29,11 +31,18 @@ module Appsignal
|
|
29
31
|
:priority => job.priority || 0,
|
30
32
|
:attempts => job.attempts || 0
|
31
33
|
},
|
34
|
+
:params => format_args(job.payload_object.args),
|
32
35
|
:queue_start => job.created_at
|
33
36
|
) do
|
34
37
|
block.call(job)
|
35
38
|
end
|
36
39
|
end
|
40
|
+
|
41
|
+
def self.format_args(args)
|
42
|
+
args.map do |arg|
|
43
|
+
self.truncate(self.string_or_inspect(arg))
|
44
|
+
end
|
45
|
+
end
|
37
46
|
end
|
38
47
|
end
|
39
48
|
end
|
@@ -10,7 +10,7 @@ module Appsignal
|
|
10
10
|
set_action
|
11
11
|
set_metadata
|
12
12
|
set_error
|
13
|
-
|
13
|
+
set_sample_data
|
14
14
|
end
|
15
15
|
|
16
16
|
def set_action
|
@@ -27,20 +27,20 @@ module Appsignal
|
|
27
27
|
Appsignal::Extension.set_transaction_error(
|
28
28
|
@transaction_index,
|
29
29
|
@data['name'],
|
30
|
-
@data['message']
|
30
|
+
@data['message'],
|
31
|
+
JSON.generate(@data['backtrace'])
|
31
32
|
)
|
32
33
|
end
|
33
34
|
|
34
|
-
def
|
35
|
+
def set_sample_data
|
35
36
|
{
|
36
37
|
:params => @data['params'],
|
37
38
|
:environment => @data['environment'],
|
38
|
-
:backtrace => @data['backtrace'],
|
39
39
|
:tags => @data['tags']
|
40
40
|
}.each do |key, data|
|
41
41
|
next unless data.is_a?(Array) || data.is_a?(Hash)
|
42
42
|
begin
|
43
|
-
Appsignal::Extension.
|
43
|
+
Appsignal::Extension.set_transaction_sample_data(
|
44
44
|
@transaction_index,
|
45
45
|
key.to_s,
|
46
46
|
JSON.generate(data)
|
@@ -26,7 +26,7 @@ module Appsignal
|
|
26
26
|
|
27
27
|
def complete_current!
|
28
28
|
if current
|
29
|
-
|
29
|
+
current.complete
|
30
30
|
Thread.current[:appsignal_transaction] = nil
|
31
31
|
else
|
32
32
|
Appsignal.logger.error('Trying to complete current, but no transaction present')
|
@@ -49,6 +49,13 @@ module Appsignal
|
|
49
49
|
@transaction_index = Appsignal::Extension.start_transaction(@transaction_id, @namespace)
|
50
50
|
end
|
51
51
|
|
52
|
+
def complete
|
53
|
+
if Appsignal::Extension.finish_transaction(transaction_index)
|
54
|
+
sample_data
|
55
|
+
end
|
56
|
+
Appsignal::Extension.complete_transaction(transaction_index)
|
57
|
+
end
|
58
|
+
|
52
59
|
def pause!
|
53
60
|
@paused = true
|
54
61
|
end
|
@@ -97,36 +104,43 @@ module Appsignal
|
|
97
104
|
Appsignal::Extension.set_transaction_metadata(transaction_index, key, value)
|
98
105
|
end
|
99
106
|
|
100
|
-
def
|
101
|
-
return unless
|
102
|
-
|
103
|
-
|
104
|
-
Appsignal.logger.debug("Adding #{error.class.name} to transaction: #{transaction_id}")
|
105
|
-
Appsignal::Extension.set_transaction_error(
|
107
|
+
def set_sample_data(key, data)
|
108
|
+
return unless key && data && (data.is_a?(Array) || data.is_a?(Hash))
|
109
|
+
Appsignal::Extension.set_transaction_sample_data(
|
106
110
|
transaction_index,
|
107
|
-
|
108
|
-
|
111
|
+
key.to_s,
|
112
|
+
JSON.generate(data)
|
109
113
|
)
|
114
|
+
rescue JSON::GeneratorError=>e
|
115
|
+
Appsignal.logger.error("JSON generate error (#{e.message}) for '#{data.inspect}'")
|
116
|
+
end
|
110
117
|
|
118
|
+
def sample_data
|
111
119
|
{
|
112
120
|
:params => sanitized_params,
|
113
121
|
:environment => sanitized_environment,
|
114
122
|
:session_data => sanitized_session_data,
|
115
|
-
:backtrace => cleaned_backtrace(error.backtrace),
|
116
123
|
:tags => sanitized_tags
|
117
124
|
}.each do |key, data|
|
118
|
-
|
119
|
-
begin
|
120
|
-
Appsignal::Extension.set_transaction_error_data(
|
121
|
-
transaction_index,
|
122
|
-
key.to_s,
|
123
|
-
JSON.generate(data)
|
124
|
-
)
|
125
|
-
rescue JSON::GeneratorError=>e
|
126
|
-
Appsignal.logger.error("JSON generate error (#{e.message}) for '#{data.inspect}'")
|
127
|
-
end
|
125
|
+
set_sample_data(key, data)
|
128
126
|
end
|
129
127
|
end
|
128
|
+
|
129
|
+
def set_error(error)
|
130
|
+
return unless error
|
131
|
+
return if Appsignal.is_ignored_error?(error)
|
132
|
+
|
133
|
+
Appsignal.logger.debug("Adding #{error.class.name} to transaction: #{transaction_id}")
|
134
|
+
backtrace = cleaned_backtrace(error.backtrace)
|
135
|
+
Appsignal::Extension.set_transaction_error(
|
136
|
+
transaction_index,
|
137
|
+
error.class.name,
|
138
|
+
error.message,
|
139
|
+
backtrace ? JSON.generate(backtrace) : ''
|
140
|
+
)
|
141
|
+
rescue JSON::GeneratorError=>e
|
142
|
+
Appsignal.logger.error("JSON generate error (#{e.message}) for '#{backtrace.inspect}'")
|
143
|
+
end
|
130
144
|
alias_method :add_exception, :set_error
|
131
145
|
|
132
146
|
class GenericRequest
|
@@ -145,8 +159,7 @@ module Appsignal
|
|
145
159
|
|
146
160
|
def background_queue_start
|
147
161
|
return unless request.env
|
148
|
-
queue_start = request.env[:queue_start]
|
149
|
-
return unless queue_start
|
162
|
+
return unless queue_start = request.env[:queue_start]
|
150
163
|
(queue_start.to_f * 1000.0).to_i
|
151
164
|
end
|
152
165
|
|
data/lib/appsignal/version.rb
CHANGED
@@ -32,7 +32,8 @@ describe Appsignal::Config do
|
|
32
32
|
:enable_frontend_error_catching => false,
|
33
33
|
:frontend_error_catching_path => '/appsignal_error_catcher',
|
34
34
|
:enable_allocation_tracking => true,
|
35
|
-
:enable_gc_instrumentation => true
|
35
|
+
:enable_gc_instrumentation => true,
|
36
|
+
:running_in_container => false
|
36
37
|
}
|
37
38
|
end
|
38
39
|
|
@@ -40,6 +41,12 @@ describe Appsignal::Config do
|
|
40
41
|
let(:config) { project_fixture_config('production', :log_path => '/tmp') }
|
41
42
|
|
42
43
|
its(:log_file_path) { should end_with('/tmp/appsignal.log') }
|
44
|
+
|
45
|
+
context "if it is not writable" do
|
46
|
+
let(:config) { project_fixture_config('production', :log_path => '/root') }
|
47
|
+
|
48
|
+
its(:log_file_path) { should == '/tmp/appsignal.log' }
|
49
|
+
end
|
43
50
|
end
|
44
51
|
|
45
52
|
context "when there is a pre 0.12 style endpoint" do
|
@@ -90,6 +97,7 @@ describe Appsignal::Config do
|
|
90
97
|
ENV['APPSIGNAL_LANGUAGE_INTEGRATION_VERSION'].should == Appsignal::VERSION
|
91
98
|
ENV['APPSIGNAL_HTTP_PROXY'].should == 'http://localhost'
|
92
99
|
ENV['APPSIGNAL_IGNORE_ACTIONS'].should == 'action1,action2'
|
100
|
+
ENV['APPSIGNAL_RUNNING_IN_CONTAINER'].should == 'false'
|
93
101
|
end
|
94
102
|
end
|
95
103
|
|
@@ -50,11 +50,11 @@ describe "extension loading and operation" do
|
|
50
50
|
end
|
51
51
|
|
52
52
|
it "should have a set_transaction_error method" do
|
53
|
-
subject.set_transaction_error(1, 'name', 'message')
|
53
|
+
subject.set_transaction_error(1, 'name', 'message', '[backtrace]')
|
54
54
|
end
|
55
55
|
|
56
|
-
it "should have a
|
57
|
-
subject.
|
56
|
+
it "should have a set_transaction_sample_data method" do
|
57
|
+
subject.set_transaction_sample_data(1, 'params', '{}')
|
58
58
|
end
|
59
59
|
|
60
60
|
it "should have a set_transaction_action method" do
|
@@ -36,7 +36,7 @@ describe Appsignal::Hooks::DelayedJobHook do
|
|
36
36
|
:attempts => 1,
|
37
37
|
:queue => 'default',
|
38
38
|
:created_at => time - 60_000,
|
39
|
-
:payload_object => double
|
39
|
+
:payload_object => double(:args => ['argument']),
|
40
40
|
)
|
41
41
|
end
|
42
42
|
let(:invoked_block) { Proc.new { } }
|
@@ -54,6 +54,7 @@ describe Appsignal::Hooks::DelayedJobHook do
|
|
54
54
|
:queue => 'default',
|
55
55
|
:id => 123
|
56
56
|
},
|
57
|
+
:params => ['argument'],
|
57
58
|
:queue_start => time - 60_000,
|
58
59
|
)
|
59
60
|
|
@@ -66,14 +67,15 @@ describe Appsignal::Hooks::DelayedJobHook do
|
|
66
67
|
let(:job) do
|
67
68
|
double(
|
68
69
|
:payload_object => double(
|
69
|
-
:appsignal_name => 'CustomClass#perform'
|
70
|
+
:appsignal_name => 'CustomClass#perform',
|
71
|
+
:args => ['argument']
|
70
72
|
),
|
71
|
-
:id
|
72
|
-
:name
|
73
|
-
:priority
|
74
|
-
:attempts
|
75
|
-
:queue
|
76
|
-
:created_at
|
73
|
+
:id => 123,
|
74
|
+
:name => 'TestClass#perform',
|
75
|
+
:priority => 1,
|
76
|
+
:attempts => 1,
|
77
|
+
:queue => 'default',
|
78
|
+
:created_at => time - 60_000
|
77
79
|
)
|
78
80
|
end
|
79
81
|
it "should wrap in a transaction with the correct params" do
|
@@ -87,6 +89,7 @@ describe Appsignal::Hooks::DelayedJobHook do
|
|
87
89
|
:queue => 'default',
|
88
90
|
:id => 123
|
89
91
|
},
|
92
|
+
:params => ['argument'],
|
90
93
|
:queue_start => time - 60_000
|
91
94
|
)
|
92
95
|
|
@@ -107,38 +107,6 @@ describe Appsignal::Hooks::SidekiqPlugin do
|
|
107
107
|
plugin.format_args(args).should == ['Model', '1', object.inspect]
|
108
108
|
end
|
109
109
|
end
|
110
|
-
|
111
|
-
describe "#truncate" do
|
112
|
-
let(:very_long_text) do
|
113
|
-
"a" * 400
|
114
|
-
end
|
115
|
-
|
116
|
-
it "should truncate the text to 200 chars max" do
|
117
|
-
plugin.truncate(very_long_text).should == "#{'a' * 197}..."
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
describe "#string_or_inspect" do
|
122
|
-
context "when string" do
|
123
|
-
it "should return the string" do
|
124
|
-
plugin.string_or_inspect('foo').should == 'foo'
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
context "when integer" do
|
129
|
-
it "should return the string" do
|
130
|
-
plugin.string_or_inspect(1).should == '1'
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
context "when object" do
|
135
|
-
let(:object) { Object.new }
|
136
|
-
|
137
|
-
it "should return the string" do
|
138
|
-
plugin.string_or_inspect(object).should == object.inspect
|
139
|
-
end
|
140
|
-
end
|
141
|
-
end
|
142
110
|
end
|
143
111
|
|
144
112
|
describe Appsignal::Hooks::SidekiqHook do
|
@@ -74,3 +74,79 @@ describe Appsignal::Hooks do
|
|
74
74
|
Appsignal::Hooks.hooks[:mock_error_hook].installed?.should be_false
|
75
75
|
end
|
76
76
|
end
|
77
|
+
|
78
|
+
describe Appsignal::Hooks::Helpers do
|
79
|
+
class ClassWithHelpers
|
80
|
+
include Appsignal::Hooks::Helpers
|
81
|
+
end
|
82
|
+
|
83
|
+
let(:class_with_helpers) { ClassWithHelpers.new }
|
84
|
+
|
85
|
+
describe "#truncate" do
|
86
|
+
it "should call the class method helper" do
|
87
|
+
expect( Appsignal::Hooks::Helpers ).to receive(:truncate).with('text')
|
88
|
+
|
89
|
+
class_with_helpers.truncate('text')
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "#string_or_inspect" do
|
94
|
+
it "should call the class method helper" do
|
95
|
+
expect( Appsignal::Hooks::Helpers ).to receive(:string_or_inspect)
|
96
|
+
.with('string')
|
97
|
+
|
98
|
+
class_with_helpers.string_or_inspect('string')
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe Appsignal::Hooks::Helpers::ClassMethods do
|
103
|
+
describe "#truncate" do
|
104
|
+
it "should call the class method helper" do
|
105
|
+
expect( Appsignal::Hooks::Helpers ).to receive(:truncate).with('text')
|
106
|
+
|
107
|
+
ClassWithHelpers.truncate('text')
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe "#string_or_inspect" do
|
112
|
+
it "should call the class method helper" do
|
113
|
+
expect( Appsignal::Hooks::Helpers ).to receive(:string_or_inspect)
|
114
|
+
.with('string')
|
115
|
+
|
116
|
+
ClassWithHelpers.string_or_inspect('string')
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
describe ".truncate" do
|
122
|
+
let(:very_long_text) do
|
123
|
+
"a" * 400
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should truncate the text to 200 chars max" do
|
127
|
+
Appsignal::Hooks::Helpers.truncate(very_long_text).should == "#{'a' * 197}..."
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
describe ".string_or_inspect" do
|
132
|
+
context "when string" do
|
133
|
+
it "should return the string" do
|
134
|
+
Appsignal::Hooks::Helpers.string_or_inspect('foo').should == 'foo'
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
context "when integer" do
|
139
|
+
it "should return the string" do
|
140
|
+
Appsignal::Hooks::Helpers.string_or_inspect(1).should == '1'
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
context "when object" do
|
145
|
+
let(:object) { Object.new }
|
146
|
+
|
147
|
+
it "should return the string" do
|
148
|
+
Appsignal::Hooks::Helpers.string_or_inspect(object).should == object.inspect
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
@@ -14,6 +14,9 @@ describe Appsignal::JSExceptionTransaction do
|
|
14
14
|
'backtrace' => [
|
15
15
|
'foo.bar/js:11:1',
|
16
16
|
'foo.bar/js:22:2',
|
17
|
+
],
|
18
|
+
'tags' => [
|
19
|
+
'tag1'
|
17
20
|
]
|
18
21
|
}
|
19
22
|
end
|
@@ -25,7 +28,7 @@ describe Appsignal::JSExceptionTransaction do
|
|
25
28
|
expect( transaction ).to receive(:set_action)
|
26
29
|
expect( transaction ).to receive(:set_metadata)
|
27
30
|
expect( transaction ).to receive(:set_error)
|
28
|
-
expect( transaction ).to receive(:
|
31
|
+
expect( transaction ).to receive(:set_sample_data)
|
29
32
|
|
30
33
|
transaction.send :initialize, data
|
31
34
|
|
@@ -61,22 +64,23 @@ describe Appsignal::JSExceptionTransaction do
|
|
61
64
|
expect( Appsignal::Extension ).to receive(:set_transaction_error).with(
|
62
65
|
kind_of(Integer),
|
63
66
|
'TypeError',
|
64
|
-
'foo is not a valid method'
|
67
|
+
'foo is not a valid method',
|
68
|
+
"[\"foo.bar/js:11:1\",\"foo.bar/js:22:2\"]"
|
65
69
|
)
|
66
70
|
|
67
71
|
transaction.set_error
|
68
72
|
end
|
69
73
|
end
|
70
74
|
|
71
|
-
describe "#
|
75
|
+
describe "#set_sample_data" do
|
72
76
|
it "should call `Appsignal::Extension.set_transaction_error_data`" do
|
73
|
-
expect( Appsignal::Extension ).to receive(:
|
77
|
+
expect( Appsignal::Extension ).to receive(:set_transaction_sample_data).with(
|
74
78
|
kind_of(Integer),
|
75
|
-
'
|
76
|
-
'["
|
79
|
+
'tags',
|
80
|
+
'["tag1"]'
|
77
81
|
)
|
78
82
|
|
79
|
-
transaction.
|
83
|
+
transaction.set_sample_data
|
80
84
|
end
|
81
85
|
end
|
82
86
|
|
@@ -71,6 +71,24 @@ describe Appsignal::Transaction do
|
|
71
71
|
end
|
72
72
|
end
|
73
73
|
|
74
|
+
describe "#complete" do
|
75
|
+
it "should sample data if it needs to be sampled" do
|
76
|
+
Appsignal::Extension.should_receive(:finish_transaction).and_return(true)
|
77
|
+
Appsignal::Extension.should_receive(:complete_transaction)
|
78
|
+
transaction.should_receive(:sample_data)
|
79
|
+
|
80
|
+
transaction.complete
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should not sample data if it does not need to be sampled" do
|
84
|
+
Appsignal::Extension.should_receive(:finish_transaction).and_return(false)
|
85
|
+
Appsignal::Extension.should_receive(:complete_transaction)
|
86
|
+
transaction.should_not_receive(:sample_data)
|
87
|
+
|
88
|
+
transaction.complete
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
74
92
|
context "pausing" do
|
75
93
|
describe "#pause!" do
|
76
94
|
it "should change the pause flag to true" do
|
@@ -243,6 +261,62 @@ describe Appsignal::Transaction do
|
|
243
261
|
end
|
244
262
|
end
|
245
263
|
|
264
|
+
describe "set_sample_data" do
|
265
|
+
it "should generate json and set the data" do
|
266
|
+
Appsignal::Extension.should_receive(:set_transaction_sample_data).with(
|
267
|
+
kind_of(Integer),
|
268
|
+
'params',
|
269
|
+
'{"controller":"blog_posts","action":"show","id":"1"}'
|
270
|
+
).once
|
271
|
+
|
272
|
+
transaction.set_sample_data(
|
273
|
+
'params',
|
274
|
+
{
|
275
|
+
:controller => 'blog_posts',
|
276
|
+
:action => 'show',
|
277
|
+
:id => '1'
|
278
|
+
}
|
279
|
+
)
|
280
|
+
end
|
281
|
+
|
282
|
+
it "should do nothing if the data cannot be converted to json" do
|
283
|
+
Appsignal::Extension.should_not_receive(:set_transaction_sample_data).with(
|
284
|
+
kind_of(Integer),
|
285
|
+
'params',
|
286
|
+
kind_of(String)
|
287
|
+
)
|
288
|
+
|
289
|
+
transaction.set_sample_data('params', 'string')
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
describe "#sample_data" do
|
294
|
+
it "should sample data" do
|
295
|
+
Appsignal::Extension.should_receive(:set_transaction_sample_data).with(
|
296
|
+
kind_of(Integer),
|
297
|
+
'environment',
|
298
|
+
"{\"CONTENT_LENGTH\":\"0\",\"REQUEST_METHOD\":\"GET\",\"SERVER_NAME\":\"example.org\",\"SERVER_PORT\":\"80\",\"PATH_INFO\":\"/blog\"}"
|
299
|
+
).once
|
300
|
+
Appsignal::Extension.should_receive(:set_transaction_sample_data).with(
|
301
|
+
kind_of(Integer),
|
302
|
+
'session_data',
|
303
|
+
"{}"
|
304
|
+
).once
|
305
|
+
Appsignal::Extension.should_receive(:set_transaction_sample_data).with(
|
306
|
+
kind_of(Integer),
|
307
|
+
'params',
|
308
|
+
'{"controller":"blog_posts","action":"show","id":"1"}'
|
309
|
+
).once
|
310
|
+
Appsignal::Extension.should_receive(:set_transaction_sample_data).with(
|
311
|
+
kind_of(Integer),
|
312
|
+
'tags',
|
313
|
+
"{}"
|
314
|
+
).once
|
315
|
+
|
316
|
+
transaction.sample_data
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
246
320
|
describe '#set_error' do
|
247
321
|
let(:env) { http_request_env_with_data }
|
248
322
|
let(:error) { double(:error, :message => 'test message', :backtrace => ['line 1']) }
|
@@ -259,58 +333,13 @@ describe Appsignal::Transaction do
|
|
259
333
|
end
|
260
334
|
|
261
335
|
context "for a http request" do
|
262
|
-
it "should set an error
|
336
|
+
it "should set an error in the extension" do
|
263
337
|
Appsignal::Extension.should_receive(:set_transaction_error).with(
|
264
338
|
kind_of(Integer),
|
265
339
|
'RSpec::Mocks::Mock',
|
266
|
-
'test message'
|
267
|
-
)
|
268
|
-
Appsignal::Extension.should_receive(:set_transaction_error_data).with(
|
269
|
-
kind_of(Integer),
|
270
|
-
'environment',
|
271
|
-
"{\"CONTENT_LENGTH\":\"0\",\"REQUEST_METHOD\":\"GET\",\"SERVER_NAME\":\"example.org\",\"SERVER_PORT\":\"80\",\"PATH_INFO\":\"/blog\"}"
|
272
|
-
).once
|
273
|
-
Appsignal::Extension.should_receive(:set_transaction_error_data).with(
|
274
|
-
kind_of(Integer),
|
275
|
-
'session_data',
|
276
|
-
"{}"
|
277
|
-
).once
|
278
|
-
Appsignal::Extension.should_receive(:set_transaction_error_data).with(
|
279
|
-
kind_of(Integer),
|
280
|
-
'backtrace',
|
340
|
+
'test message',
|
281
341
|
"[\"line 1\"]"
|
282
|
-
).once
|
283
|
-
Appsignal::Extension.should_receive(:set_transaction_error_data).with(
|
284
|
-
kind_of(Integer),
|
285
|
-
'params',
|
286
|
-
'{"controller":"blog_posts","action":"show","id":"1"}'
|
287
|
-
).once
|
288
|
-
Appsignal::Extension.should_receive(:set_transaction_error_data).with(
|
289
|
-
kind_of(Integer),
|
290
|
-
'tags',
|
291
|
-
"{}"
|
292
|
-
).once
|
293
|
-
|
294
|
-
transaction.set_error(error)
|
295
|
-
end
|
296
|
-
end
|
297
|
-
|
298
|
-
context "with a non-json convertable type" do
|
299
|
-
before do
|
300
|
-
transaction.stub(:sanitized_params => 'a string')
|
301
|
-
end
|
302
|
-
|
303
|
-
it "should skip the field" do
|
304
|
-
Appsignal::Extension.should_not_receive(:set_transaction_error_data).with(
|
305
|
-
kind_of(Integer),
|
306
|
-
'params',
|
307
|
-
kind_of(String)
|
308
342
|
)
|
309
|
-
Appsignal::Extension.should_receive(:set_transaction_error_data).with(
|
310
|
-
kind_of(Integer),
|
311
|
-
kind_of(String),
|
312
|
-
kind_of(String)
|
313
|
-
).exactly(4).times
|
314
343
|
|
315
344
|
transaction.set_error(error)
|
316
345
|
end
|
data/spec/lib/appsignal_spec.rb
CHANGED
@@ -401,7 +401,12 @@ describe Appsignal do
|
|
401
401
|
describe ".increment_counter" do
|
402
402
|
it "should call increment_counter on the extension" do
|
403
403
|
Appsignal::Extension.should_receive(:increment_counter).with('key', 1)
|
404
|
-
Appsignal.increment_counter('key'
|
404
|
+
Appsignal.increment_counter('key')
|
405
|
+
end
|
406
|
+
|
407
|
+
it "should call increment_counter on the extension with a count" do
|
408
|
+
Appsignal::Extension.should_receive(:increment_counter).with('key', 5)
|
409
|
+
Appsignal.increment_counter('key', 5)
|
405
410
|
end
|
406
411
|
end
|
407
412
|
|
@@ -453,17 +458,6 @@ describe Appsignal do
|
|
453
458
|
end
|
454
459
|
end
|
455
460
|
|
456
|
-
context "when the log path is not writable" do
|
457
|
-
let(:log_path) { '/nonsense/log' }
|
458
|
-
|
459
|
-
it "should log to stdout" do
|
460
|
-
Appsignal.start_logger
|
461
|
-
Appsignal.logger.error('Log to stdout')
|
462
|
-
out_stream.string.should include 'appsignal: Log to stdout'
|
463
|
-
out_stream.string.should include 'Log something'
|
464
|
-
end
|
465
|
-
end
|
466
|
-
|
467
461
|
context "when we're on Heroku" do
|
468
462
|
before do
|
469
463
|
ENV['DYNO'] = 'dyno1'
|
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: 0.12.rc.
|
4
|
+
version: 0.12.rc.10
|
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: 2015-
|
12
|
+
date: 2015-12-14 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rack
|