appsignal 0.12.rc.9 → 0.12.rc.10
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Gem Version](https://badge.fury.io/rb/appsignal.svg)](http://badge.fury.io/rb/appsignal)
|
9
9
|
[![Code Climate](https://codeclimate.com/github/appsignal/appsignal.png)](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
|