opbeat 2.0.0 → 3.0.0
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/.gitignore +4 -3
- data/.travis.yml +19 -28
- data/.yardopts +3 -0
- data/Gemfile +4 -2
- data/HISTORY.md +3 -0
- data/LICENSE +7 -196
- data/README.md +96 -177
- data/Rakefile +19 -13
- data/gemfiles/Gemfile.base +28 -0
- data/gemfiles/Gemfile.rails-3.2.x +3 -0
- data/gemfiles/Gemfile.rails-4.0.x +3 -0
- data/gemfiles/Gemfile.rails-4.1.x +3 -0
- data/gemfiles/Gemfile.rails-4.2.x +3 -0
- data/lib/opbeat.rb +113 -93
- data/lib/opbeat/capistrano.rb +3 -4
- data/lib/opbeat/client.rb +243 -82
- data/lib/opbeat/configuration.rb +51 -64
- data/lib/opbeat/data_builders.rb +16 -0
- data/lib/opbeat/data_builders/error.rb +27 -0
- data/lib/opbeat/data_builders/transactions.rb +85 -0
- data/lib/opbeat/error.rb +1 -2
- data/lib/opbeat/error_message.rb +71 -0
- data/lib/opbeat/error_message/exception.rb +12 -0
- data/lib/opbeat/error_message/http.rb +62 -0
- data/lib/opbeat/error_message/stacktrace.rb +75 -0
- data/lib/opbeat/error_message/user.rb +23 -0
- data/lib/opbeat/filter.rb +53 -43
- data/lib/opbeat/http_client.rb +141 -0
- data/lib/opbeat/injections.rb +83 -0
- data/lib/opbeat/injections/json.rb +19 -0
- data/lib/opbeat/injections/net_http.rb +43 -0
- data/lib/opbeat/injections/redis.rb +23 -0
- data/lib/opbeat/injections/sequel.rb +32 -0
- data/lib/opbeat/injections/sinatra.rb +56 -0
- data/lib/opbeat/{capistrano → integration}/capistrano2.rb +6 -6
- data/lib/opbeat/{capistrano → integration}/capistrano3.rb +3 -3
- data/lib/opbeat/{integrations → integration}/delayed_job.rb +6 -11
- data/lib/opbeat/integration/rails/inject_exceptions_catcher.rb +23 -0
- data/lib/opbeat/integration/railtie.rb +53 -0
- data/lib/opbeat/integration/resque.rb +16 -0
- data/lib/opbeat/integration/sidekiq.rb +38 -0
- data/lib/opbeat/line_cache.rb +21 -0
- data/lib/opbeat/logging.rb +37 -0
- data/lib/opbeat/middleware.rb +59 -0
- data/lib/opbeat/normalizers.rb +65 -0
- data/lib/opbeat/normalizers/action_controller.rb +21 -0
- data/lib/opbeat/normalizers/action_view.rb +71 -0
- data/lib/opbeat/normalizers/active_record.rb +41 -0
- data/lib/opbeat/sql_summarizer.rb +27 -0
- data/lib/opbeat/subscriber.rb +80 -0
- data/lib/opbeat/tasks.rb +20 -18
- data/lib/opbeat/trace.rb +47 -0
- data/lib/opbeat/trace_helpers.rb +29 -0
- data/lib/opbeat/transaction.rb +99 -0
- data/lib/opbeat/util.rb +26 -0
- data/lib/opbeat/util/constantize.rb +54 -0
- data/lib/opbeat/util/inspector.rb +75 -0
- data/lib/opbeat/version.rb +1 -1
- data/lib/opbeat/worker.rb +55 -0
- data/opbeat.gemspec +6 -14
- data/spec/opbeat/client_spec.rb +216 -29
- data/spec/opbeat/configuration_spec.rb +34 -38
- data/spec/opbeat/data_builders/error_spec.rb +43 -0
- data/spec/opbeat/data_builders/transactions_spec.rb +51 -0
- data/spec/opbeat/error_message/exception_spec.rb +22 -0
- data/spec/opbeat/error_message/http_spec.rb +65 -0
- data/spec/opbeat/error_message/stacktrace_spec.rb +56 -0
- data/spec/opbeat/error_message/user_spec.rb +28 -0
- data/spec/opbeat/error_message_spec.rb +78 -0
- data/spec/opbeat/filter_spec.rb +21 -99
- data/spec/opbeat/http_client_spec.rb +64 -0
- data/spec/opbeat/injections/net_http_spec.rb +37 -0
- data/spec/opbeat/injections/sequel_spec.rb +33 -0
- data/spec/opbeat/injections/sinatra_spec.rb +13 -0
- data/spec/opbeat/injections_spec.rb +49 -0
- data/spec/opbeat/integration/delayed_job_spec.rb +35 -0
- data/spec/opbeat/integration/json_spec.rb +41 -0
- data/spec/opbeat/integration/rails_spec.rb +88 -0
- data/spec/opbeat/integration/redis_spec.rb +20 -0
- data/spec/opbeat/integration/resque_spec.rb +42 -0
- data/spec/opbeat/integration/sidekiq_spec.rb +40 -0
- data/spec/opbeat/integration/sinatra_spec.rb +66 -0
- data/spec/opbeat/line_cache_spec.rb +38 -0
- data/spec/opbeat/logging_spec.rb +47 -0
- data/spec/opbeat/middleware_spec.rb +32 -0
- data/spec/opbeat/normalizers/action_controller_spec.rb +32 -0
- data/spec/opbeat/normalizers/action_view_spec.rb +77 -0
- data/spec/opbeat/normalizers/active_record_spec.rb +70 -0
- data/spec/opbeat/normalizers_spec.rb +16 -0
- data/spec/opbeat/sql_summarizer_spec.rb +6 -0
- data/spec/opbeat/subscriber_spec.rb +83 -0
- data/spec/opbeat/trace_spec.rb +43 -0
- data/spec/opbeat/transaction_spec.rb +98 -0
- data/spec/opbeat/util/inspector_spec.rb +40 -0
- data/spec/opbeat/util_spec.rb +20 -0
- data/spec/opbeat/worker_spec.rb +54 -0
- data/spec/opbeat_spec.rb +49 -0
- data/spec/spec_helper.rb +79 -6
- metadata +89 -149
- data/Makefile +0 -3
- data/gemfiles/rails30.gemfile +0 -9
- data/gemfiles/rails31.gemfile +0 -9
- data/gemfiles/rails32.gemfile +0 -9
- data/gemfiles/rails40.gemfile +0 -9
- data/gemfiles/rails41.gemfile +0 -9
- data/gemfiles/rails42.gemfile +0 -9
- data/gemfiles/ruby192_rails31.gemfile +0 -10
- data/gemfiles/ruby192_rails32.gemfile +0 -10
- data/gemfiles/sidekiq31.gemfile +0 -11
- data/lib/opbeat/better_attr_accessor.rb +0 -44
- data/lib/opbeat/event.rb +0 -223
- data/lib/opbeat/integrations/resque.rb +0 -22
- data/lib/opbeat/integrations/sidekiq.rb +0 -32
- data/lib/opbeat/interfaces.rb +0 -35
- data/lib/opbeat/interfaces/exception.rb +0 -16
- data/lib/opbeat/interfaces/http.rb +0 -57
- data/lib/opbeat/interfaces/message.rb +0 -19
- data/lib/opbeat/interfaces/stack_trace.rb +0 -50
- data/lib/opbeat/linecache.rb +0 -25
- data/lib/opbeat/logger.rb +0 -21
- data/lib/opbeat/rack.rb +0 -46
- data/lib/opbeat/rails/middleware/debug_exceptions_catcher.rb +0 -22
- data/lib/opbeat/railtie.rb +0 -26
- data/spec/opbeat/better_attr_accessor_spec.rb +0 -99
- data/spec/opbeat/event_spec.rb +0 -138
- data/spec/opbeat/integrations/delayed_job_spec.rb +0 -38
- data/spec/opbeat/logger_spec.rb +0 -55
- data/spec/opbeat/opbeat_spec.rb +0 -64
- data/spec/opbeat/rack_spec.rb +0 -117
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
module Opbeat
|
|
2
|
+
# @api private
|
|
3
|
+
module Normalizers
|
|
4
|
+
|
|
5
|
+
class Normalizer
|
|
6
|
+
def self.register name
|
|
7
|
+
Normalizers.register name, self
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def initialize config
|
|
11
|
+
@config = config
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
attr_reader :config
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
class Default < Normalizer
|
|
18
|
+
def normalize transaction, name, payload
|
|
19
|
+
:skip
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
DEFAULT = Default.new nil
|
|
24
|
+
|
|
25
|
+
def self.register name, cls
|
|
26
|
+
(@registered ||= {})[name] = cls
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def self.build config
|
|
30
|
+
normalizers = @registered.reduce({}) do |coll, kv|
|
|
31
|
+
name, cls = kv
|
|
32
|
+
coll[name] = cls.new config
|
|
33
|
+
coll
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
Container.new(normalizers)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
class Container
|
|
40
|
+
def initialize normalizers
|
|
41
|
+
@normalizers = normalizers
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def keys
|
|
45
|
+
@normalizers.keys
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def normalizer_for name
|
|
49
|
+
@normalizers[name] || DEFAULT
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def normalize transaction, name, payload
|
|
53
|
+
normalizer_for(name).normalize transaction, name, payload
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
%w{
|
|
58
|
+
action_controller
|
|
59
|
+
active_record
|
|
60
|
+
action_view
|
|
61
|
+
}.each do |f|
|
|
62
|
+
require "opbeat/normalizers/#{f}"
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Opbeat
|
|
2
|
+
module Normalizers
|
|
3
|
+
module ActionController
|
|
4
|
+
class ProcessAction < Normalizer
|
|
5
|
+
register 'process_action.action_controller'
|
|
6
|
+
KIND = 'app.controller.action'.freeze
|
|
7
|
+
|
|
8
|
+
def normalize transaction, name, payload
|
|
9
|
+
transaction.endpoint = endpoint(payload)
|
|
10
|
+
[transaction.endpoint, KIND, nil]
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
def endpoint payload
|
|
16
|
+
"#{payload[:controller]}##{payload[:action]}"
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
module Opbeat
|
|
2
|
+
module Normalizers
|
|
3
|
+
module ActionView
|
|
4
|
+
|
|
5
|
+
class RenderNormalizer < Normalizer
|
|
6
|
+
def normalize_render payload, kind
|
|
7
|
+
signature = path_for(payload[:identifier])
|
|
8
|
+
|
|
9
|
+
[signature, kind, nil]
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
def path_for identifier
|
|
15
|
+
return "Unknown template".freeze unless path = identifier
|
|
16
|
+
return path unless path.start_with?("/")
|
|
17
|
+
|
|
18
|
+
path && relative_path(path)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def relative_path path
|
|
22
|
+
root = config.view_paths.find { |p| path.start_with? p }
|
|
23
|
+
type = :app
|
|
24
|
+
|
|
25
|
+
unless root
|
|
26
|
+
root = Gem.path.find { |p| path.start_with? p }
|
|
27
|
+
type = :gem
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
return "Absolute path".freeze unless root
|
|
31
|
+
|
|
32
|
+
start = root.length
|
|
33
|
+
start += 1 if path[root.length] == "/".freeze
|
|
34
|
+
|
|
35
|
+
if type == :gem
|
|
36
|
+
"$GEM_PATH/#{path[start, path.length]}"
|
|
37
|
+
else
|
|
38
|
+
path[start, path.length]
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
class RenderTemplate < RenderNormalizer
|
|
44
|
+
register 'render_template.action_view'
|
|
45
|
+
KIND = 'template.view'.freeze
|
|
46
|
+
|
|
47
|
+
def normalize transaction, name, payload
|
|
48
|
+
normalize_render(payload, KIND)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
class RenderPartial < RenderNormalizer
|
|
53
|
+
register 'render_partial.action_view'
|
|
54
|
+
KIND = 'template.view.partial'.freeze
|
|
55
|
+
|
|
56
|
+
def normalize transaction, name, payload
|
|
57
|
+
normalize_render(payload, KIND)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
class RenderCollection < RenderNormalizer
|
|
62
|
+
register 'render_collection.action_view'
|
|
63
|
+
KIND = 'template.view.collection'.freeze
|
|
64
|
+
|
|
65
|
+
def normalize transaction, name, payload
|
|
66
|
+
normalize_render(payload, KIND)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
require 'opbeat/sql_summarizer'
|
|
2
|
+
|
|
3
|
+
module Opbeat
|
|
4
|
+
module Normalizers
|
|
5
|
+
module ActiveRecord
|
|
6
|
+
class SQL < Normalizer
|
|
7
|
+
register 'sql.active_record'
|
|
8
|
+
|
|
9
|
+
def initialize *args
|
|
10
|
+
super(*args)
|
|
11
|
+
adapter = ::ActiveRecord::Base.connection.adapter_name.downcase rescue nil
|
|
12
|
+
@kind = "db.#{adapter || 'unknown'}.sql".freeze
|
|
13
|
+
@sql_parser = SqlSummarizer.new config
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def normalize transaction, name, payload
|
|
17
|
+
if %w{SCHEMA CACHE}.include? payload[:name]
|
|
18
|
+
return :skip
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
signature =
|
|
22
|
+
signature_for(payload[:sql]) || # SELECT FROM "users"
|
|
23
|
+
payload[:name] || # Users load
|
|
24
|
+
"SQL".freeze
|
|
25
|
+
|
|
26
|
+
if signature == 'SELECT FROM "schema_migrations"'
|
|
27
|
+
return :skip
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
[signature, @kind, { sql: payload[:sql] }]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def signature_for sql
|
|
36
|
+
@sql_parser.signature_for(sql)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Opbeat
|
|
2
|
+
# @api private
|
|
3
|
+
class SqlSummarizer
|
|
4
|
+
CACHE = {}
|
|
5
|
+
TBL = "[^ ]+".freeze
|
|
6
|
+
REGEXES = {
|
|
7
|
+
/^SELECT .* FROM (#{TBL})/i => "SELECT FROM ".freeze,
|
|
8
|
+
/^INSERT INTO (#{TBL})/i => "INSERT INTO ".freeze,
|
|
9
|
+
/^UPDATE (#{TBL})/i => "UPDATE ".freeze,
|
|
10
|
+
/^DELETE FROM (#{TBL})/i => "DELETE FROM ".freeze
|
|
11
|
+
}.freeze
|
|
12
|
+
|
|
13
|
+
def initialize config
|
|
14
|
+
@config = config
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def signature_for sql
|
|
18
|
+
return CACHE[sql] if CACHE[sql]
|
|
19
|
+
|
|
20
|
+
REGEXES.find do |regex, sig|
|
|
21
|
+
if match = sql.match(regex)
|
|
22
|
+
break sig + match[1]
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
require 'active_support/notifications'
|
|
2
|
+
require 'opbeat/normalizers'
|
|
3
|
+
|
|
4
|
+
module Opbeat
|
|
5
|
+
# @api private
|
|
6
|
+
class Subscriber
|
|
7
|
+
include Logging
|
|
8
|
+
|
|
9
|
+
def initialize config, client
|
|
10
|
+
@config = config
|
|
11
|
+
@client = client
|
|
12
|
+
@normalizers = Normalizers.build config
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
attr_reader :config
|
|
16
|
+
|
|
17
|
+
def register!
|
|
18
|
+
unregister! if @subscription
|
|
19
|
+
@subscription = ActiveSupport::Notifications.subscribe actions_regex, self
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def unregister!
|
|
23
|
+
ActiveSupport::Notifications.unsubscribe @subscription
|
|
24
|
+
@subscription = nil
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# AS::Notifications API
|
|
28
|
+
|
|
29
|
+
class Notification
|
|
30
|
+
def initialize id, trace
|
|
31
|
+
@id = id
|
|
32
|
+
@trace = trace
|
|
33
|
+
end
|
|
34
|
+
attr_reader :id, :trace
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def start name, id, payload
|
|
38
|
+
return unless transaction = @client.current_transaction
|
|
39
|
+
|
|
40
|
+
normalized = @normalizers.normalize(transaction, name, payload)
|
|
41
|
+
|
|
42
|
+
trace = nil
|
|
43
|
+
|
|
44
|
+
unless normalized == :skip
|
|
45
|
+
sig, kind, extra = normalized
|
|
46
|
+
|
|
47
|
+
trace = Trace.new(transaction, sig, kind, transaction.running_traces, extra)
|
|
48
|
+
offset = transaction.current_offset
|
|
49
|
+
|
|
50
|
+
transaction.traces << trace
|
|
51
|
+
|
|
52
|
+
trace.start offset
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
transaction.notifications << Notification.new(id, trace)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def finish name, id, payload
|
|
59
|
+
return unless transaction = @client.current_transaction
|
|
60
|
+
|
|
61
|
+
while notification = transaction.notifications.pop
|
|
62
|
+
if notification.id == id
|
|
63
|
+
if trace = notification.trace
|
|
64
|
+
trace.done
|
|
65
|
+
end
|
|
66
|
+
return
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
private
|
|
72
|
+
|
|
73
|
+
def actions_regex
|
|
74
|
+
@actions_regex ||= Regexp.new(
|
|
75
|
+
"(".freeze + @normalizers.keys.join("|".freeze) + ")".freeze
|
|
76
|
+
)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
end
|
|
80
|
+
end
|
data/lib/opbeat/tasks.rb
CHANGED
|
@@ -1,24 +1,26 @@
|
|
|
1
|
-
# Capistrano tasks for notifying Opbeat of deploys
|
|
2
1
|
namespace :opbeat do
|
|
3
|
-
desc "Notify Opbeat of a
|
|
4
|
-
task :
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
load initializer_file
|
|
10
|
-
else
|
|
11
|
-
Rake::Task[:environment].invoke
|
|
12
|
-
end
|
|
2
|
+
desc "Notify Opbeat of a release"
|
|
3
|
+
task :release => :environment do
|
|
4
|
+
unless rev = ENV["REV"]
|
|
5
|
+
puts "Please specify a revision in an env variable\n" +
|
|
6
|
+
"eg. REV=abc123 rake opbeat:release"
|
|
7
|
+
exit 1
|
|
13
8
|
end
|
|
14
|
-
rev = ENV['REV']
|
|
15
9
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
10
|
+
# empty env means dev
|
|
11
|
+
ENV["RAILS_ENV"] ||= 'development'
|
|
12
|
+
|
|
13
|
+
# log to STDOUT
|
|
14
|
+
Opbeat::Client.inst.config.logger = Logger.new STDOUT
|
|
15
|
+
|
|
16
|
+
unless Opbeat.release({
|
|
17
|
+
rev: rev,
|
|
18
|
+
branch: ENV['BRANCH'],
|
|
19
|
+
status: 'completed'
|
|
20
|
+
}, inline: true)
|
|
21
|
+
exit 1 # release returned nil
|
|
21
22
|
end
|
|
22
23
|
end
|
|
23
|
-
end
|
|
24
24
|
|
|
25
|
+
task :deployment => :release
|
|
26
|
+
end
|
data/lib/opbeat/trace.rb
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
require 'opbeat/util'
|
|
2
|
+
|
|
3
|
+
module Opbeat
|
|
4
|
+
class Trace
|
|
5
|
+
|
|
6
|
+
DEFAULT_KIND = 'code.custom'.freeze
|
|
7
|
+
|
|
8
|
+
def initialize transaction, signature, kind = nil, parents = [], extra = nil
|
|
9
|
+
@transaction = transaction
|
|
10
|
+
@signature = signature
|
|
11
|
+
@kind = kind || DEFAULT_KIND
|
|
12
|
+
@parents = parents || []
|
|
13
|
+
@extra = extra
|
|
14
|
+
|
|
15
|
+
@timestamp = Util.nearest_minute.to_i
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
attr_accessor :signature, :kind, :parents, :extra
|
|
19
|
+
attr_reader :transaction, :timestamp, :duration, :relative_start, :start_time
|
|
20
|
+
|
|
21
|
+
def start relative_to
|
|
22
|
+
@start_time = Util.nanos
|
|
23
|
+
@relative_start = start_time - relative_to
|
|
24
|
+
|
|
25
|
+
self
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def done ms = Util.nanos
|
|
29
|
+
@duration = ms - start_time
|
|
30
|
+
|
|
31
|
+
self
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def done?
|
|
35
|
+
!!duration
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def running?
|
|
39
|
+
!done?
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def inspect
|
|
43
|
+
info = %w{signature kind parents extra timestamp duration relative_start}
|
|
44
|
+
"<Trace #{info.map { |m| "#{m}:#{send(m).inspect}" }.join(' ')}>"
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module Opbeat
|
|
2
|
+
module TraceHelpers
|
|
3
|
+
module ClassMethods
|
|
4
|
+
def trace_class_method method, signature, kind
|
|
5
|
+
__trace_method_on(singleton_class, method, signature, kind)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
private
|
|
9
|
+
|
|
10
|
+
def __trace_method_on(klass, method, signature, kind)
|
|
11
|
+
klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
12
|
+
alias :"__without_opb_#{method}" :"#{method}"
|
|
13
|
+
|
|
14
|
+
def #{method}(*args, &block)
|
|
15
|
+
Opbeat.trace "#{signature}", "#{kind}" do
|
|
16
|
+
__without_opb_#{method}(*args, &block)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
RUBY
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def self.included(kls)
|
|
24
|
+
kls.class_eval do
|
|
25
|
+
extend ClassMethods
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
require 'opbeat/util'
|
|
2
|
+
|
|
3
|
+
module Opbeat
|
|
4
|
+
class Transaction
|
|
5
|
+
|
|
6
|
+
ROOT_TRACE_NAME = 'transaction'.freeze
|
|
7
|
+
|
|
8
|
+
def initialize client, endpoint, kind = 'code.custom', result = nil
|
|
9
|
+
@client = client
|
|
10
|
+
@endpoint = endpoint
|
|
11
|
+
@kind = kind
|
|
12
|
+
@result = result
|
|
13
|
+
|
|
14
|
+
@timestamp = Util.nearest_minute.to_i
|
|
15
|
+
|
|
16
|
+
@root_trace = Trace.new(self, ROOT_TRACE_NAME, ROOT_TRACE_NAME)
|
|
17
|
+
@traces = [@root_trace]
|
|
18
|
+
@notifications = []
|
|
19
|
+
|
|
20
|
+
@start_time = Util.nanos
|
|
21
|
+
@root_trace.start @start_time
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
attr_accessor :endpoint, :kind, :result, :duration
|
|
25
|
+
attr_reader :timestamp, :start_time, :traces, :notifications, :root_trace
|
|
26
|
+
|
|
27
|
+
def release
|
|
28
|
+
@client.current_transaction = nil
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def done result = nil
|
|
32
|
+
@result = result
|
|
33
|
+
|
|
34
|
+
@root_trace.done Util.nanos
|
|
35
|
+
@duration = @root_trace.duration
|
|
36
|
+
|
|
37
|
+
self
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def done?
|
|
41
|
+
@root_trace.done?
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def submit result = nil
|
|
45
|
+
done result
|
|
46
|
+
|
|
47
|
+
release
|
|
48
|
+
|
|
49
|
+
@client.submit_transaction self
|
|
50
|
+
|
|
51
|
+
self
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def trace signature, kind = nil, extra = nil, &block
|
|
55
|
+
trace = Trace.new(self, signature, kind, running_traces, extra)
|
|
56
|
+
|
|
57
|
+
rel_time = current_offset
|
|
58
|
+
|
|
59
|
+
traces << trace
|
|
60
|
+
|
|
61
|
+
trace.start rel_time
|
|
62
|
+
|
|
63
|
+
return trace unless block_given?
|
|
64
|
+
|
|
65
|
+
begin
|
|
66
|
+
result = yield trace
|
|
67
|
+
ensure
|
|
68
|
+
trace.done
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
result
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def running_traces
|
|
75
|
+
traces.select(&:running?)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def current_trace
|
|
79
|
+
traces.reverse.find(&:running?)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def current_offset
|
|
83
|
+
if curr = current_trace
|
|
84
|
+
return curr.start_time
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
start_time
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def inspect
|
|
91
|
+
info = %w{endpoint kind result duration timestamp start_time}
|
|
92
|
+
<<-TEXT
|
|
93
|
+
<Transaction #{info.map { |m| "#{m}:#{send(m).inspect}" }.join(' ')}>
|
|
94
|
+
#{traces.map(&:inspect).join("\n ")}"
|
|
95
|
+
TEXT
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
end
|
|
99
|
+
end
|