appsignal 0.11.18 → 0.12.beta.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -0
- data/CHANGELOG.md +4 -38
- data/Rakefile +14 -6
- data/appsignal.gemspec +3 -1
- data/benchmark.rake +12 -16
- data/ext/appsignal_extension.c +183 -0
- data/ext/extconf.rb +39 -0
- data/gemfiles/capistrano2.gemfile +0 -1
- data/gemfiles/capistrano3.gemfile +0 -1
- data/gemfiles/rails-4.2.gemfile +1 -1
- data/lib/appsignal.rb +23 -61
- data/lib/appsignal/capistrano.rb +1 -2
- data/lib/appsignal/config.rb +13 -1
- data/lib/appsignal/event_formatter.rb +67 -0
- data/lib/appsignal/event_formatter/action_view/render_formatter.rb +23 -0
- data/lib/appsignal/event_formatter/active_record/sql_formatter.rb +74 -0
- data/lib/appsignal/event_formatter/moped/query_formatter.rb +80 -0
- data/lib/appsignal/event_formatter/net_http/request_formatter.rb +13 -0
- data/lib/appsignal/instrumentations/net_http.rb +6 -4
- data/lib/appsignal/integrations/resque.rb +2 -10
- data/lib/appsignal/integrations/sidekiq.rb +2 -2
- data/lib/appsignal/integrations/sinatra.rb +1 -0
- data/lib/appsignal/js_exception_transaction.rb +44 -28
- data/lib/appsignal/marker.rb +11 -13
- data/lib/appsignal/params_sanitizer.rb +5 -8
- data/lib/appsignal/rack/instrumentation.rb +2 -0
- data/lib/appsignal/rack/js_exception_catcher.rb +1 -0
- data/lib/appsignal/rack/listener.rb +1 -1
- data/lib/appsignal/rack/sinatra_instrumentation.rb +2 -12
- data/lib/appsignal/subscriber.rb +59 -0
- data/lib/appsignal/transaction.rb +117 -174
- data/lib/appsignal/transmitter.rb +8 -37
- data/lib/appsignal/version.rb +2 -1
- data/spec/lib/appsignal/config_spec.rb +25 -4
- data/spec/lib/appsignal/event_formatter/action_view/render_formatter_spec.rb +42 -0
- data/spec/lib/appsignal/{aggregator/middleware/active_record_sanitizer_spec.rb → event_formatter/active_record/sql_formatter_spec.rb} +61 -61
- data/spec/lib/appsignal/{event/moped_event_spec.rb → event_formatter/moped/query_formatter_spec.rb} +32 -78
- data/spec/lib/appsignal/event_formatter/net_http/request_formatter_spec.rb +26 -0
- data/spec/lib/appsignal/event_formatter_spec.rb +102 -0
- data/spec/lib/appsignal/extension_spec.rb +75 -0
- data/spec/lib/appsignal/instrumentations/net_http_spec.rb +20 -4
- data/spec/lib/appsignal/integrations/delayed_job_spec.rb +3 -2
- data/spec/lib/appsignal/integrations/rails_spec.rb +0 -7
- data/spec/lib/appsignal/integrations/resque_spec.rb +51 -55
- data/spec/lib/appsignal/integrations/sequel_spec.rb +8 -3
- data/spec/lib/appsignal/integrations/sidekiq_spec.rb +4 -21
- data/spec/lib/appsignal/integrations/sinatra_spec.rb +0 -6
- data/spec/lib/appsignal/js_exception_transaction_spec.rb +57 -60
- data/spec/lib/appsignal/params_sanitizer_spec.rb +11 -27
- data/spec/lib/appsignal/rack/listener_spec.rb +6 -6
- data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +2 -43
- data/spec/lib/appsignal/subscriber_spec.rb +162 -0
- data/spec/lib/appsignal/transaction_spec.rb +283 -615
- data/spec/lib/appsignal/transmitter_spec.rb +3 -32
- data/spec/lib/appsignal_spec.rb +41 -90
- data/spec/lib/generators/appsignal/appsignal_generator_spec.rb +0 -17
- data/spec/spec_helper.rb +18 -22
- data/spec/support/helpers/notification_helpers.rb +1 -1
- data/spec/support/helpers/time_helpers.rb +11 -0
- data/spec/support/helpers/transaction_helpers.rb +6 -18
- data/spec/support/project_fixture/config/appsignal.yml +1 -2
- metadata +68 -78
- checksums.yaml +0 -7
- data/gemfiles/padrino-0.13.gemfile +0 -7
- data/gemfiles/resque.gemfile +0 -5
- data/lib/appsignal/agent.rb +0 -217
- data/lib/appsignal/aggregator.rb +0 -67
- data/lib/appsignal/aggregator/middleware.rb +0 -4
- data/lib/appsignal/aggregator/middleware/action_view_sanitizer.rb +0 -23
- data/lib/appsignal/aggregator/middleware/active_record_sanitizer.rb +0 -65
- data/lib/appsignal/aggregator/middleware/chain.rb +0 -101
- data/lib/appsignal/aggregator/middleware/delete_blanks.rb +0 -16
- data/lib/appsignal/aggregator/post_processor.rb +0 -32
- data/lib/appsignal/event.rb +0 -20
- data/lib/appsignal/event/moped_event.rb +0 -90
- data/lib/appsignal/integrations/padrino.rb +0 -64
- data/lib/appsignal/integrations/passenger.rb +0 -13
- data/lib/appsignal/integrations/rake.rb +0 -29
- data/lib/appsignal/integrations/unicorn.rb +0 -25
- data/lib/appsignal/ipc.rb +0 -68
- data/lib/appsignal/transaction/formatter.rb +0 -85
- data/lib/appsignal/transaction/params_sanitizer.rb +0 -4
- data/lib/appsignal/zipped_payload.rb +0 -37
- data/spec/lib/appsignal/agent_spec.rb +0 -592
- data/spec/lib/appsignal/aggregator/middleware/action_view_sanitizer_spec.rb +0 -44
- data/spec/lib/appsignal/aggregator/middleware/chain_spec.rb +0 -168
- data/spec/lib/appsignal/aggregator/middleware/delete_blanks_spec.rb +0 -37
- data/spec/lib/appsignal/aggregator/post_processor_spec.rb +0 -99
- data/spec/lib/appsignal/aggregator_spec.rb +0 -186
- data/spec/lib/appsignal/event_spec.rb +0 -48
- data/spec/lib/appsignal/integrations/padrino_spec.rb +0 -171
- data/spec/lib/appsignal/integrations/passenger_spec.rb +0 -22
- data/spec/lib/appsignal/integrations/rake_spec.rb +0 -92
- data/spec/lib/appsignal/integrations/unicorn_spec.rb +0 -48
- data/spec/lib/appsignal/ipc_spec.rb +0 -128
- data/spec/lib/appsignal/transaction/formatter_spec.rb +0 -247
- data/spec/lib/appsignal/zipped_payload_spec.rb +0 -42
@@ -0,0 +1,13 @@
|
|
1
|
+
module Appsignal
|
2
|
+
class EventFormatter
|
3
|
+
module NetHttp
|
4
|
+
class RequestFormatter < Appsignal::EventFormatter
|
5
|
+
register 'request.net_http'
|
6
|
+
|
7
|
+
def format(payload)
|
8
|
+
["#{payload[:method]} #{payload[:protocol]}://#{payload[:domain]}", nil]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -1,13 +1,15 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
1
3
|
Net::HTTP.class_eval do
|
2
4
|
alias request_without_appsignal request
|
3
5
|
|
4
6
|
def request(request, body=nil, &block)
|
5
7
|
ActiveSupport::Notifications.instrument(
|
6
8
|
'request.net_http',
|
7
|
-
:
|
8
|
-
:
|
9
|
-
:path
|
10
|
-
:method
|
9
|
+
:protocol => use_ssl? ? 'https' : 'http',
|
10
|
+
:domain => request['host'] || self.address,
|
11
|
+
:path => request.path,
|
12
|
+
:method => request.method
|
11
13
|
) do
|
12
14
|
request_without_appsignal(request, body, &block)
|
13
15
|
end
|
@@ -17,14 +17,6 @@ if defined?(::Resque)
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
#
|
21
|
-
Resque.
|
22
|
-
Appsignal::IPC::Server.start if Appsignal.active?
|
23
|
-
end
|
24
|
-
|
25
|
-
# In the fork, stop the normal agent startup
|
26
|
-
# and stop listening to the server
|
27
|
-
Resque.after_fork do |job|
|
28
|
-
Appsignal::IPC.forked! if Appsignal.active?
|
29
|
-
end
|
20
|
+
# Extend the default job class with AppSignal instrumentation
|
21
|
+
Resque::Job.send(:extend, Appsignal::Integrations::ResquePlugin)
|
30
22
|
end
|
@@ -15,7 +15,7 @@ if defined?(::Sidekiq)
|
|
15
15
|
def call(worker, item, queue)
|
16
16
|
Appsignal.monitor_transaction(
|
17
17
|
'perform_job.sidekiq',
|
18
|
-
:class => item['
|
18
|
+
:class => item['class'],
|
19
19
|
:method => 'perform',
|
20
20
|
:metadata => formatted_metadata(item),
|
21
21
|
:params => format_args(item['args']),
|
@@ -48,7 +48,7 @@ if defined?(::Sidekiq)
|
|
48
48
|
end
|
49
49
|
|
50
50
|
def truncate(text)
|
51
|
-
text.size >
|
51
|
+
text.size > 100 ? "#{text[0...97]}..." : text
|
52
52
|
end
|
53
53
|
end
|
54
54
|
end
|
@@ -3,45 +3,61 @@ module Appsignal
|
|
3
3
|
|
4
4
|
def initialize(data)
|
5
5
|
@data = data
|
6
|
-
@
|
6
|
+
@uuid = SecureRandom.uuid
|
7
|
+
|
8
|
+
Appsignal::Extension.start_transaction(@uuid)
|
9
|
+
|
10
|
+
set_base_data
|
11
|
+
set_metadata
|
12
|
+
set_error
|
13
|
+
set_error_data
|
7
14
|
end
|
8
15
|
|
9
|
-
def
|
10
|
-
|
16
|
+
def set_base_data
|
17
|
+
Appsignal::Extension.set_transaction_basedata(
|
18
|
+
@uuid,
|
19
|
+
'frontend',
|
20
|
+
@data['action'],
|
21
|
+
0
|
22
|
+
)
|
11
23
|
end
|
12
24
|
|
13
|
-
def
|
14
|
-
|
25
|
+
def set_metadata
|
26
|
+
Appsignal::Extension.set_transaction_metadata(
|
27
|
+
@uuid, 'path', @data['path']
|
28
|
+
) if @data['path']
|
15
29
|
end
|
16
30
|
|
17
|
-
def
|
18
|
-
|
19
|
-
|
31
|
+
def set_error
|
32
|
+
Appsignal::Extension.set_transaction_error(
|
33
|
+
@uuid,
|
34
|
+
@data['name'],
|
35
|
+
@data['message']
|
36
|
+
)
|
37
|
+
end
|
20
38
|
|
21
|
-
def
|
39
|
+
def set_error_data
|
22
40
|
{
|
23
|
-
:
|
24
|
-
:
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
}
|
41
|
+
:params => @data['params'],
|
42
|
+
:environment => @data['environment'],
|
43
|
+
:backtrace => @data['backtrace'],
|
44
|
+
:tags => @data['tags']
|
45
|
+
}.each do |key, data|
|
46
|
+
next unless data.is_a?(Array) || data.is_a?(Hash)
|
47
|
+
begin
|
48
|
+
Appsignal::Extension.set_transaction_error_data(
|
49
|
+
@uuid,
|
50
|
+
key.to_s,
|
51
|
+
JSON.generate(data)
|
52
|
+
)
|
53
|
+
rescue JSON::GeneratorError=>e
|
54
|
+
Appsignal.logger.error("JSON generate error (#{e.message}) for '#{data.inspect}'")
|
55
|
+
end
|
56
|
+
end
|
40
57
|
end
|
41
58
|
|
42
59
|
def complete!
|
43
|
-
Appsignal.
|
60
|
+
Appsignal::Extension.finish_transaction(@uuid)
|
44
61
|
end
|
45
|
-
|
46
62
|
end
|
47
63
|
end
|
data/lib/appsignal/marker.rb
CHANGED
@@ -14,20 +14,18 @@ module Appsignal
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def transmit
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
raise "#{result} at #{transmitter.uri}"
|
25
|
-
end
|
26
|
-
rescue Exception => e
|
27
|
-
carefully_log_error(
|
28
|
-
"Something went wrong while trying to notify Appsignal: #{e}"
|
29
|
-
)
|
17
|
+
transmitter = Transmitter.new(ACTION, config)
|
18
|
+
logger.info("Notifying Appsignal of deploy with: revision: #{marker_data[:revision]}, user: #{marker_data[:user]}")
|
19
|
+
result = transmitter.transmit(marker_data)
|
20
|
+
if result == '200'
|
21
|
+
logger.info('Appsignal has been notified of this deploy!')
|
22
|
+
else
|
23
|
+
raise "#{result} at #{transmitter.uri}"
|
30
24
|
end
|
25
|
+
rescue Exception => e
|
26
|
+
carefully_log_error(
|
27
|
+
"Something went wrong while trying to notify Appsignal: #{e}"
|
28
|
+
)
|
31
29
|
end
|
32
30
|
end
|
33
31
|
end
|
@@ -25,10 +25,8 @@ module Appsignal
|
|
25
25
|
sanitize_hash(value)
|
26
26
|
when Array
|
27
27
|
sanitize_array(value)
|
28
|
-
when Fixnum, String, Symbol
|
28
|
+
when Fixnum, String, Symbol
|
29
29
|
unmodified(value)
|
30
|
-
when TrueClass, FalseClass
|
31
|
-
stringified(value)
|
32
30
|
else
|
33
31
|
inspected(value)
|
34
32
|
end
|
@@ -48,16 +46,15 @@ module Appsignal
|
|
48
46
|
target_array
|
49
47
|
end
|
50
48
|
|
51
|
-
def stringified(value)
|
52
|
-
value.to_s
|
53
|
-
end
|
54
|
-
|
55
49
|
def unmodified(value)
|
56
50
|
value
|
57
51
|
end
|
58
52
|
|
59
53
|
def inspected(value)
|
60
|
-
|
54
|
+
value.inspect
|
55
|
+
rescue
|
56
|
+
# It turns out that sometimes inspect can fail
|
57
|
+
"#<#{value.class.to_s}/>"
|
61
58
|
end
|
62
59
|
end
|
63
60
|
end
|
@@ -18,7 +18,7 @@ module Appsignal
|
|
18
18
|
Appsignal::Transaction.create(request_id(env), env)
|
19
19
|
@app.call(env)
|
20
20
|
rescue Exception => exception
|
21
|
-
Appsignal.
|
21
|
+
Appsignal.set_exception(exception)
|
22
22
|
raise exception
|
23
23
|
ensure
|
24
24
|
Appsignal::Transaction.complete_current!
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'rack'
|
2
|
+
|
1
3
|
module Appsignal
|
2
4
|
module Rack
|
3
5
|
class SinatraInstrumentation
|
@@ -7,14 +9,6 @@ module Appsignal
|
|
7
9
|
end
|
8
10
|
|
9
11
|
def call(env)
|
10
|
-
if Appsignal.active?
|
11
|
-
call_with_appsignal_monitoring(env)
|
12
|
-
else
|
13
|
-
@app.call(env)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
def call_with_appsignal_monitoring(env)
|
18
12
|
ActiveSupport::Notifications.instrument(
|
19
13
|
'process_action.sinatra',
|
20
14
|
raw_payload(env)
|
@@ -27,10 +21,6 @@ module Appsignal
|
|
27
21
|
payload[:action] = env['sinatra.route']
|
28
22
|
end
|
29
23
|
end
|
30
|
-
ensure
|
31
|
-
# In production newer versions of Sinatra don't raise errors, but store
|
32
|
-
# them in the sinatra.error env var.
|
33
|
-
Appsignal.add_exception(env['sinatra.error']) if env['sinatra.error']
|
34
24
|
end
|
35
25
|
|
36
26
|
def raw_payload(env)
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Appsignal
|
2
|
+
class Subscriber
|
3
|
+
PROCESS_ACTION_PREFIX = 'process_action'.freeze
|
4
|
+
PERFORM_JOB_PREFIX = 'perform_job'.freeze
|
5
|
+
BLANK = ''.freeze
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
subscribe
|
9
|
+
end
|
10
|
+
|
11
|
+
def subscribe
|
12
|
+
Appsignal.logger.debug('Subscribing to notifications')
|
13
|
+
# Subscribe to notifications that don't start with a !
|
14
|
+
ActiveSupport::Notifications.subscribe(/^[^!]/, self)
|
15
|
+
end
|
16
|
+
|
17
|
+
def unsubscribe
|
18
|
+
Appsignal.logger.debug('Unsubscribing from notifications')
|
19
|
+
ActiveSupport::Notifications.unsubscribe(self)
|
20
|
+
end
|
21
|
+
|
22
|
+
def resubscribe
|
23
|
+
Appsignal.logger.debug('Resubscribing to notifications')
|
24
|
+
unsubscribe
|
25
|
+
subscribe
|
26
|
+
end
|
27
|
+
|
28
|
+
def publish(name, *args)
|
29
|
+
# Not used, it's part of AS notifications but is not used in Rails
|
30
|
+
# and it seems to be unclear what it's function is. See:
|
31
|
+
# https://github.com/rails/rails/blob/master/activesupport/lib/active_support/notifications/fanout.rb#L49
|
32
|
+
end
|
33
|
+
|
34
|
+
def start(name, id, payload)
|
35
|
+
return unless transaction = Appsignal::Transaction.current
|
36
|
+
|
37
|
+
return if transaction.paused?
|
38
|
+
Appsignal::Extension.start_event(transaction.request_id)
|
39
|
+
end
|
40
|
+
|
41
|
+
def finish(name, id, payload)
|
42
|
+
return unless transaction = Appsignal::Transaction.current
|
43
|
+
|
44
|
+
if name.start_with?(PROCESS_ACTION_PREFIX, PERFORM_JOB_PREFIX)
|
45
|
+
transaction.set_root_event(name, payload)
|
46
|
+
end
|
47
|
+
|
48
|
+
return if transaction.paused?
|
49
|
+
|
50
|
+
title, body = Appsignal::EventFormatter.format(name, payload)
|
51
|
+
Appsignal::Extension.finish_event(
|
52
|
+
transaction.request_id,
|
53
|
+
name,
|
54
|
+
title || BLANK,
|
55
|
+
body || BLANK
|
56
|
+
)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -1,5 +1,8 @@
|
|
1
1
|
module Appsignal
|
2
2
|
class Transaction
|
3
|
+
HTTP_REQUEST = 'http_request'.freeze
|
4
|
+
BACKGROUND_JOB = 'background_job'.freeze
|
5
|
+
|
3
6
|
# Based on what Rails uses + some variables we'd like to show
|
4
7
|
ENV_METHODS = %w(CONTENT_LENGTH AUTH_TYPE GATEWAY_INTERFACE
|
5
8
|
PATH_TRANSLATED REMOTE_HOST REMOTE_IDENT REMOTE_USER REMOTE_ADDR
|
@@ -11,40 +14,39 @@ module Appsignal
|
|
11
14
|
HTTP_CACHE_CONTROL HTTP_CONNECTION HTTP_USER_AGENT HTTP_FROM HTTP_NEGOTIATE
|
12
15
|
HTTP_PRAGMA HTTP_REFERER HTTP_X_FORWARDED_FOR HTTP_CLIENT_IP).freeze
|
13
16
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
17
|
+
class << self
|
18
|
+
def create(request_id, env)
|
19
|
+
Appsignal.logger.debug("Creating transaction: #{request_id}")
|
20
|
+
Appsignal::Extension.start_transaction(request_id)
|
21
|
+
Thread.current[:appsignal_transaction] = Appsignal::Transaction.new(request_id, env)
|
22
|
+
end
|
19
23
|
|
20
|
-
|
21
|
-
|
22
|
-
|
24
|
+
def current
|
25
|
+
Thread.current[:appsignal_transaction]
|
26
|
+
end
|
23
27
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
28
|
+
def complete_current!
|
29
|
+
if current
|
30
|
+
Appsignal::Extension.finish_transaction(current.request_id)
|
31
|
+
Thread.current[:appsignal_transaction] = nil
|
32
|
+
else
|
33
|
+
Appsignal.logger.error('Trying to complete current, but no transaction present')
|
34
|
+
end
|
30
35
|
end
|
31
36
|
end
|
32
37
|
|
33
|
-
attr_reader :request_id, :
|
34
|
-
:env, :fullpath, :time, :tags, :kind, :queue_start, :paused, :
|
38
|
+
attr_reader :request_id, :process_action_event, :action, :exception,
|
39
|
+
:env, :fullpath, :time, :tags, :kind, :queue_start, :paused, :root_event_payload
|
35
40
|
|
36
|
-
def initialize(request_id, env
|
37
|
-
|
38
|
-
@request_id
|
39
|
-
@events = []
|
41
|
+
def initialize(request_id, env)
|
42
|
+
@root_event_payload = nil
|
43
|
+
@request_id = request_id
|
40
44
|
@process_action_event = nil
|
41
|
-
@exception
|
42
|
-
@env
|
43
|
-
@
|
44
|
-
@
|
45
|
-
@
|
46
|
-
@action = defaults[:action]
|
47
|
-
@paused = false
|
45
|
+
@exception = nil
|
46
|
+
@env = env
|
47
|
+
@tags = {}
|
48
|
+
@paused = false
|
49
|
+
@queue_start = -1
|
48
50
|
end
|
49
51
|
|
50
52
|
def sanitized_environment
|
@@ -55,148 +57,96 @@ module Appsignal
|
|
55
57
|
@sanitized_session_data ||= {}
|
56
58
|
end
|
57
59
|
|
58
|
-
def sanitized_params
|
59
|
-
@sanitized_params ||= {}
|
60
|
-
end
|
61
|
-
|
62
60
|
def request
|
63
|
-
::Rack::Request.new(
|
61
|
+
@request ||= ::Rack::Request.new(env)
|
64
62
|
end
|
65
63
|
|
66
64
|
def set_tags(given_tags={})
|
67
65
|
@tags.merge!(given_tags)
|
68
66
|
end
|
69
67
|
|
70
|
-
def
|
71
|
-
@
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
@
|
83
|
-
|
84
|
-
@action = @process_action_event.payload[:action]
|
68
|
+
def set_root_event(name, payload)
|
69
|
+
@root_event_payload = payload
|
70
|
+
if name.start_with?(Subscriber::PROCESS_ACTION_PREFIX)
|
71
|
+
@action = "#{@root_event_payload[:controller]}##{@root_event_payload[:action]}"
|
72
|
+
@kind = HTTP_REQUEST
|
73
|
+
set_http_queue_start
|
74
|
+
set_metadata('path', payload[:path])
|
75
|
+
set_metadata('request_format', payload[:request_format])
|
76
|
+
set_metadata('request_method', payload[:request_method])
|
77
|
+
set_metadata('status', payload[:status].to_s)
|
78
|
+
elsif name.start_with?(Subscriber::PERFORM_JOB_PREFIX)
|
79
|
+
@action = "#{@root_event_payload[:class]}##{@root_event_payload[:method]}"
|
80
|
+
@kind = BACKGROUND_JOB
|
81
|
+
set_background_queue_start
|
85
82
|
end
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
:
|
109
|
-
:
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
83
|
+
Appsignal::Extension.set_transaction_basedata(
|
84
|
+
request_id,
|
85
|
+
kind,
|
86
|
+
action,
|
87
|
+
queue_start
|
88
|
+
)
|
89
|
+
end
|
90
|
+
|
91
|
+
def set_metadata(key, value)
|
92
|
+
return unless value
|
93
|
+
Appsignal::Extension.set_transaction_metadata(request_id, key, value)
|
94
|
+
end
|
95
|
+
|
96
|
+
def set_error(error)
|
97
|
+
return unless error
|
98
|
+
Appsignal::Extension.set_transaction_error(
|
99
|
+
request_id,
|
100
|
+
error.class.name,
|
101
|
+
error.message
|
102
|
+
)
|
103
|
+
|
104
|
+
{
|
105
|
+
:params => sanitized_params,
|
106
|
+
:environment => sanitized_environment,
|
107
|
+
:session_data => sanitized_session_data,
|
108
|
+
:backtrace => cleaned_backtrace(error.backtrace),
|
109
|
+
:tags => sanitized_tags
|
110
|
+
}.each do |key, data|
|
111
|
+
next unless data.is_a?(Array) || data.is_a?(Hash)
|
112
|
+
begin
|
113
|
+
Appsignal::Extension.set_transaction_error_data(
|
114
|
+
request_id,
|
115
|
+
key.to_s,
|
116
|
+
JSON.generate(data)
|
117
|
+
)
|
118
|
+
rescue JSON::GeneratorError=>e
|
119
|
+
Appsignal.logger.error("JSON generate error (#{e.message}) for '#{data.inspect}'")
|
120
|
+
end
|
123
121
|
end
|
124
122
|
end
|
123
|
+
alias_method :add_exception, :set_error
|
125
124
|
|
126
|
-
def
|
127
|
-
|
128
|
-
Appsignal.config[:slow_request_threshold] <= process_action_event.duration
|
129
|
-
end
|
130
|
-
|
131
|
-
def slower?(transaction)
|
132
|
-
process_action_event.duration > transaction.process_action_event.duration
|
133
|
-
end
|
134
|
-
|
135
|
-
def clear_events!
|
136
|
-
events.clear
|
137
|
-
end
|
138
|
-
|
139
|
-
def truncate!
|
140
|
-
return if truncated?
|
141
|
-
process_action_event.truncate!
|
142
|
-
events.clear
|
143
|
-
tags.clear
|
144
|
-
sanitized_environment.clear
|
145
|
-
sanitized_session_data.clear
|
146
|
-
sanitized_params.clear
|
147
|
-
@env = nil
|
148
|
-
@truncated = true
|
149
|
-
end
|
150
|
-
|
151
|
-
def truncated?
|
152
|
-
!! @truncated
|
153
|
-
end
|
154
|
-
|
155
|
-
def convert_values_to_primitives!
|
156
|
-
return if have_values_been_converted_to_primitives?
|
157
|
-
@process_action_event.sanitize! if @process_action_event
|
158
|
-
@events.each { |event| event.sanitize! }
|
159
|
-
add_sanitized_context!
|
160
|
-
@have_values_been_converted_to_primitives = true
|
161
|
-
end
|
162
|
-
|
163
|
-
def have_values_been_converted_to_primitives?
|
164
|
-
!! @have_values_been_converted_to_primitives
|
125
|
+
def pause!
|
126
|
+
@paused = true
|
165
127
|
end
|
166
128
|
|
167
|
-
def
|
168
|
-
|
169
|
-
return :slow_request if slow_request?
|
170
|
-
:regular_request
|
129
|
+
def resume!
|
130
|
+
@paused = false
|
171
131
|
end
|
172
132
|
|
173
|
-
def
|
174
|
-
|
133
|
+
def paused?
|
134
|
+
@paused == true
|
175
135
|
end
|
176
136
|
|
177
|
-
|
178
|
-
Thread.current[:appsignal_transaction_id] = nil
|
179
|
-
Appsignal.transactions.delete(@request_id)
|
180
|
-
if process_action_event || exception?
|
181
|
-
if Appsignal::IPC::Client.active?
|
182
|
-
convert_values_to_primitives!
|
183
|
-
Appsignal::IPC::Client.enqueue(self)
|
184
|
-
else
|
185
|
-
Appsignal.logger.debug("Enqueueing transaction: #{@request_id}")
|
186
|
-
Appsignal.enqueue(self)
|
187
|
-
end
|
188
|
-
else
|
189
|
-
Appsignal.logger.debug("Not processing transaction: #{@request_id} (#{events.length} events recorded)")
|
190
|
-
end
|
191
|
-
ensure
|
192
|
-
Appsignal.transactions.delete(@request_id)
|
193
|
-
end
|
137
|
+
protected
|
194
138
|
|
195
139
|
def set_background_queue_start
|
196
|
-
|
140
|
+
return unless root_event_payload
|
141
|
+
queue_start = root_event_payload[:queue_start]
|
197
142
|
return unless queue_start
|
198
143
|
Appsignal.logger.debug("Setting background queue start: #{queue_start}")
|
199
|
-
@queue_start = queue_start.to_f
|
144
|
+
@queue_start = (queue_start.to_f * 1000.0).to_i
|
145
|
+
end
|
146
|
+
|
147
|
+
def sanitized_params
|
148
|
+
return unless root_event_payload
|
149
|
+
Appsignal::ParamsSanitizer.sanitize(root_event_payload[:params])
|
200
150
|
end
|
201
151
|
|
202
152
|
def set_http_queue_start
|
@@ -208,52 +158,45 @@ module Appsignal
|
|
208
158
|
unless cleaned_value.empty?
|
209
159
|
value = cleaned_value.to_i
|
210
160
|
[1_000_000.0, 1_000.0].each do |factor|
|
211
|
-
@queue_start = value / factor
|
161
|
+
@queue_start = (value / factor).to_i
|
212
162
|
break if @queue_start > 946_681_200.0 # Ok if it's later than 2000
|
213
163
|
end
|
214
164
|
end
|
215
165
|
end
|
216
166
|
end
|
217
167
|
|
218
|
-
|
168
|
+
def sanitized_environment
|
169
|
+
return unless env
|
170
|
+
{}.tap do |out|
|
171
|
+
ENV_METHODS.each do |key|
|
172
|
+
out[key] = env[key] if env[key]
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
219
176
|
|
220
|
-
def
|
221
|
-
|
222
|
-
|
223
|
-
sanitize_tags!
|
224
|
-
sanitize_params!
|
225
|
-
@env = nil
|
177
|
+
def sanitized_session_data
|
178
|
+
return if Appsignal.config[:skip_session_data] || !env
|
179
|
+
Appsignal::ParamsSanitizer.sanitize(request.session.to_hash)
|
226
180
|
end
|
227
181
|
|
228
182
|
# Only keep tags if they meet the following criteria:
|
229
183
|
# * Key is a symbol or string with less then 100 chars
|
230
184
|
# * Value is a symbol or string with less then 100 chars
|
231
185
|
# * Value is an integer
|
232
|
-
def
|
233
|
-
@tags.
|
186
|
+
def sanitized_tags
|
187
|
+
@tags.select do |k, v|
|
234
188
|
(k.is_a?(Symbol) || k.is_a?(String) && k.length <= 100) &&
|
235
189
|
(((v.is_a?(Symbol) || v.is_a?(String)) && v.length <= 100) || (v.is_a?(Integer)))
|
236
190
|
end
|
237
191
|
end
|
238
192
|
|
239
|
-
def
|
240
|
-
|
241
|
-
|
242
|
-
|
193
|
+
def cleaned_backtrace(backtrace)
|
194
|
+
if defined?(::Rails)
|
195
|
+
::Rails.backtrace_cleaner.clean(backtrace, nil)
|
196
|
+
else
|
197
|
+
backtrace
|
243
198
|
end
|
244
199
|
end
|
245
200
|
|
246
|
-
def sanitize_session_data!
|
247
|
-
return unless request
|
248
|
-
@sanitized_session_data = Appsignal::ParamsSanitizer.sanitize(
|
249
|
-
request.session.to_hash
|
250
|
-
) if Appsignal.config[:skip_session_data] == false
|
251
|
-
@fullpath = request.fullpath
|
252
|
-
end
|
253
|
-
|
254
|
-
def sanitize_params!
|
255
|
-
return unless Appsignal.config[:send_params]
|
256
|
-
@sanitized_params = Appsignal::ParamsSanitizer.sanitize(@params)
|
257
|
-
end
|
258
201
|
end
|
259
202
|
end
|