atatus 1.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 +7 -0
- data/.gitignore +16 -0
- data/CHANGELOG.md +11 -0
- data/Gemfile +57 -0
- data/LICENSE +65 -0
- data/LICENSE-THIRD-PARTY +205 -0
- data/README.md +13 -0
- data/Rakefile +19 -0
- data/atatus.gemspec +36 -0
- data/atatus.yml +2 -0
- data/bench/.gitignore +2 -0
- data/bench/app.rb +53 -0
- data/bench/benchmark.rb +36 -0
- data/bench/report.rb +55 -0
- data/bench/rubyprof.rb +39 -0
- data/bench/stackprof.rb +23 -0
- data/bin/build_docs +5 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/bin/with_framework +7 -0
- data/lib/atatus.rb +325 -0
- data/lib/atatus/agent.rb +260 -0
- data/lib/atatus/central_config.rb +141 -0
- data/lib/atatus/central_config/cache_control.rb +34 -0
- data/lib/atatus/collector/base.rb +329 -0
- data/lib/atatus/collector/builder.rb +317 -0
- data/lib/atatus/collector/transport.rb +72 -0
- data/lib/atatus/config.rb +248 -0
- data/lib/atatus/config/bytes.rb +25 -0
- data/lib/atatus/config/duration.rb +23 -0
- data/lib/atatus/config/options.rb +134 -0
- data/lib/atatus/config/regexp_list.rb +13 -0
- data/lib/atatus/context.rb +33 -0
- data/lib/atatus/context/request.rb +11 -0
- data/lib/atatus/context/request/socket.rb +19 -0
- data/lib/atatus/context/request/url.rb +42 -0
- data/lib/atatus/context/response.rb +22 -0
- data/lib/atatus/context/user.rb +42 -0
- data/lib/atatus/context_builder.rb +97 -0
- data/lib/atatus/deprecations.rb +22 -0
- data/lib/atatus/error.rb +22 -0
- data/lib/atatus/error/exception.rb +46 -0
- data/lib/atatus/error/log.rb +24 -0
- data/lib/atatus/error_builder.rb +76 -0
- data/lib/atatus/instrumenter.rb +224 -0
- data/lib/atatus/internal_error.rb +6 -0
- data/lib/atatus/logging.rb +55 -0
- data/lib/atatus/metadata.rb +19 -0
- data/lib/atatus/metadata/process_info.rb +18 -0
- data/lib/atatus/metadata/service_info.rb +61 -0
- data/lib/atatus/metadata/system_info.rb +35 -0
- data/lib/atatus/metadata/system_info/container_info.rb +121 -0
- data/lib/atatus/metadata/system_info/hw_info.rb +118 -0
- data/lib/atatus/metadata/system_info/os_info.rb +31 -0
- data/lib/atatus/metrics.rb +98 -0
- data/lib/atatus/metrics/cpu_mem.rb +240 -0
- data/lib/atatus/metrics/vm.rb +60 -0
- data/lib/atatus/metricset.rb +19 -0
- data/lib/atatus/middleware.rb +76 -0
- data/lib/atatus/naively_hashable.rb +21 -0
- data/lib/atatus/normalizers.rb +68 -0
- data/lib/atatus/normalizers/action_controller.rb +27 -0
- data/lib/atatus/normalizers/action_mailer.rb +26 -0
- data/lib/atatus/normalizers/action_view.rb +77 -0
- data/lib/atatus/normalizers/active_record.rb +45 -0
- data/lib/atatus/opentracing.rb +346 -0
- data/lib/atatus/rails.rb +61 -0
- data/lib/atatus/railtie.rb +30 -0
- data/lib/atatus/span.rb +125 -0
- data/lib/atatus/span/context.rb +40 -0
- data/lib/atatus/span_helpers.rb +44 -0
- data/lib/atatus/spies.rb +86 -0
- data/lib/atatus/spies/action_dispatch.rb +28 -0
- data/lib/atatus/spies/delayed_job.rb +68 -0
- data/lib/atatus/spies/elasticsearch.rb +36 -0
- data/lib/atatus/spies/faraday.rb +70 -0
- data/lib/atatus/spies/http.rb +44 -0
- data/lib/atatus/spies/json.rb +22 -0
- data/lib/atatus/spies/mongo.rb +87 -0
- data/lib/atatus/spies/net_http.rb +70 -0
- data/lib/atatus/spies/rake.rb +45 -0
- data/lib/atatus/spies/redis.rb +27 -0
- data/lib/atatus/spies/sequel.rb +47 -0
- data/lib/atatus/spies/sidekiq.rb +89 -0
- data/lib/atatus/spies/sinatra.rb +41 -0
- data/lib/atatus/spies/tilt.rb +27 -0
- data/lib/atatus/sql_summarizer.rb +35 -0
- data/lib/atatus/stacktrace.rb +16 -0
- data/lib/atatus/stacktrace/frame.rb +52 -0
- data/lib/atatus/stacktrace_builder.rb +104 -0
- data/lib/atatus/subscriber.rb +77 -0
- data/lib/atatus/trace_context.rb +85 -0
- data/lib/atatus/transaction.rb +100 -0
- data/lib/atatus/transport/base.rb +174 -0
- data/lib/atatus/transport/connection.rb +156 -0
- data/lib/atatus/transport/connection/http.rb +116 -0
- data/lib/atatus/transport/connection/proxy_pipe.rb +75 -0
- data/lib/atatus/transport/filters.rb +43 -0
- data/lib/atatus/transport/filters/secrets_filter.rb +74 -0
- data/lib/atatus/transport/serializers.rb +93 -0
- data/lib/atatus/transport/serializers/context_serializer.rb +85 -0
- data/lib/atatus/transport/serializers/error_serializer.rb +77 -0
- data/lib/atatus/transport/serializers/metadata_serializer.rb +70 -0
- data/lib/atatus/transport/serializers/metricset_serializer.rb +28 -0
- data/lib/atatus/transport/serializers/span_serializer.rb +80 -0
- data/lib/atatus/transport/serializers/transaction_serializer.rb +37 -0
- data/lib/atatus/transport/worker.rb +73 -0
- data/lib/atatus/util.rb +42 -0
- data/lib/atatus/util/inflector.rb +93 -0
- data/lib/atatus/util/lru_cache.rb +48 -0
- data/lib/atatus/util/prefixed_logger.rb +18 -0
- data/lib/atatus/util/throttle.rb +35 -0
- data/lib/atatus/version.rb +5 -0
- data/vendor/.gitkeep +0 -0
- metadata +190 -0
data/bench/app.rb
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
$LOAD_PATH.unshift(File.expand_path('../lib', __dir__))
|
|
5
|
+
require 'active_record'
|
|
6
|
+
require 'action_controller/railtie'
|
|
7
|
+
require 'atatus'
|
|
8
|
+
require 'atatus/railtie'
|
|
9
|
+
|
|
10
|
+
$log = Logger.new('/tmp/bench.log')
|
|
11
|
+
|
|
12
|
+
ActiveRecord::Base.logger = $log
|
|
13
|
+
|
|
14
|
+
ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: '/tmp/bench.sqlite3')
|
|
15
|
+
|
|
16
|
+
ActiveRecord::Schema.define do
|
|
17
|
+
create_table :posts, force: true do |t|
|
|
18
|
+
t.string :title
|
|
19
|
+
t.timestamps
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
class Post < ActiveRecord::Base
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
10.times { |i| Post.create! title: "Post #{i}" }
|
|
27
|
+
|
|
28
|
+
class ApplicationController < ActionController::Base
|
|
29
|
+
def index
|
|
30
|
+
render inline: '<%= Post.pluck(:title).join(", ") %>'
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def favicon
|
|
34
|
+
render nothing: true
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
class App < Rails::Application
|
|
39
|
+
config.secret_key_base = '__secret'
|
|
40
|
+
config.logger = $log
|
|
41
|
+
config.eager_load = false
|
|
42
|
+
|
|
43
|
+
config.atatus.disable_send = true
|
|
44
|
+
config.atatus.logger = $log
|
|
45
|
+
config.atatus.log_level = Logger::DEBUG
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
App.initialize!
|
|
49
|
+
|
|
50
|
+
App.routes.draw do
|
|
51
|
+
get '/favicon.ico', to: 'application#favicon'
|
|
52
|
+
root to: 'application#index'
|
|
53
|
+
end
|
data/bench/benchmark.rb
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
ENV['RAILS_ENV'] = 'production'
|
|
5
|
+
|
|
6
|
+
require 'bundler'
|
|
7
|
+
require 'bundler/setup'
|
|
8
|
+
|
|
9
|
+
require 'benchmark'
|
|
10
|
+
include Benchmark
|
|
11
|
+
require 'rack/test'
|
|
12
|
+
|
|
13
|
+
require './bench/app'
|
|
14
|
+
|
|
15
|
+
def app
|
|
16
|
+
App
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
include Rack::Test::Methods
|
|
20
|
+
|
|
21
|
+
def perform
|
|
22
|
+
10_000.times do
|
|
23
|
+
get '/'
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
bench = Benchmark.benchmark(CAPTION, 15, FORMAT) do |b|
|
|
28
|
+
perform # warm up
|
|
29
|
+
|
|
30
|
+
b.report('with agent:') { perform }
|
|
31
|
+
|
|
32
|
+
Atatus.stop
|
|
33
|
+
perform # warm up
|
|
34
|
+
|
|
35
|
+
b.report('without agent:') { perform }
|
|
36
|
+
end
|
data/bench/report.rb
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require 'time'
|
|
5
|
+
require 'json'
|
|
6
|
+
|
|
7
|
+
input = STDIN.read.split("\n")
|
|
8
|
+
|
|
9
|
+
git_sha, git_msg = `git log -n 1 --pretty="format:%H|||%s"`.split('|||')
|
|
10
|
+
git_date = `git log -n 1 --pretty="format:%ai"`
|
|
11
|
+
platform = Gem::Platform.local
|
|
12
|
+
|
|
13
|
+
def doc(payload)
|
|
14
|
+
puts({ index: { _index: "benchmark-ruby", _type: "_doc" } }.to_json)
|
|
15
|
+
puts(payload.to_json)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
meta = {
|
|
19
|
+
executed_at: Time.new.iso8601,
|
|
20
|
+
'git.commit' => git_sha,
|
|
21
|
+
'git.date' => String(git_date).strip != '' && Time.parse(git_date).iso8601,
|
|
22
|
+
'git.subject' => git_msg,
|
|
23
|
+
hostname: `hostname`.chomp,
|
|
24
|
+
engine: RUBY_ENGINE,
|
|
25
|
+
arch: platform.cpu,
|
|
26
|
+
os: platform.os,
|
|
27
|
+
ruby_version: "#{RUBY_ENGINE == 'jruby' ? 'j' : ''}#{RUBY_VERSION}"
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
results =
|
|
31
|
+
input
|
|
32
|
+
.grep(/^with/)
|
|
33
|
+
.map do |line|
|
|
34
|
+
title = line.match(/^(.*):/) { |m| m[1] }
|
|
35
|
+
user, system, total, real = line.scan(/[0-9\.]+/).map(&:to_f)
|
|
36
|
+
meta.merge(
|
|
37
|
+
title: title,
|
|
38
|
+
user: user,
|
|
39
|
+
system: system,
|
|
40
|
+
total: total,
|
|
41
|
+
real: real,
|
|
42
|
+
)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
results.each { |result| doc result }
|
|
46
|
+
|
|
47
|
+
overhead =
|
|
48
|
+
(results[0][:total] - results[1][:total]) *
|
|
49
|
+
1000 / # milliseconds
|
|
50
|
+
10_000 # transactions
|
|
51
|
+
|
|
52
|
+
doc meta.merge(
|
|
53
|
+
title: 'overhead',
|
|
54
|
+
overhead: overhead
|
|
55
|
+
)
|
data/bench/rubyprof.rb
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'ruby-prof'
|
|
4
|
+
require 'rack/test'
|
|
5
|
+
|
|
6
|
+
$LOAD_PATH.unshift(File.expand_path('../lib', __dir__))
|
|
7
|
+
require 'atatus'
|
|
8
|
+
|
|
9
|
+
require './bench/app'
|
|
10
|
+
include App::Helpers
|
|
11
|
+
|
|
12
|
+
def perform(app, count: 1000)
|
|
13
|
+
app.start
|
|
14
|
+
|
|
15
|
+
transactions = count.times.map do |i|
|
|
16
|
+
Atatus.transaction "Transaction##{i}",
|
|
17
|
+
context: Atatus.build_context(app.mock_env) do
|
|
18
|
+
Atatus.span('Number one') { 'ok 1' }
|
|
19
|
+
Atatus.span('Number two') { 'ok 2' }
|
|
20
|
+
Atatus.span('Number three') { 'ok 3' }
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
app.stop
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def do_bench(transaction_count: 1000, **config)
|
|
28
|
+
with_app(config) do |app|
|
|
29
|
+
profile = RubyProf::Profile.new
|
|
30
|
+
profile.exclude_common_methods!
|
|
31
|
+
profile.start
|
|
32
|
+
perform(app, count: transaction_count)
|
|
33
|
+
profile.stop
|
|
34
|
+
printer = RubyProf::GraphHtmlPrinter.new(profile)
|
|
35
|
+
printer.print(File.open('bench/tmp/out.html', 'w'))
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
do_bench(transaction_count: 10_000)
|
data/bench/stackprof.rb
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require 'stackprof'
|
|
5
|
+
require 'rack/test'
|
|
6
|
+
|
|
7
|
+
require './bench/app'
|
|
8
|
+
|
|
9
|
+
def app
|
|
10
|
+
App
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
include Rack::Test::Methods
|
|
14
|
+
|
|
15
|
+
puts 'Running '
|
|
16
|
+
profile = StackProf.run(mode: :cpu) do
|
|
17
|
+
10_000.times do
|
|
18
|
+
get '/'
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
puts ''
|
|
22
|
+
|
|
23
|
+
StackProf::Report.new(profile).print_text
|
data/bin/build_docs
ADDED
data/bin/console
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require 'bundler/setup'
|
|
5
|
+
require 'atatus'
|
|
6
|
+
|
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
|
9
|
+
|
|
10
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
|
11
|
+
# require "pry"
|
|
12
|
+
# Pry.start
|
|
13
|
+
|
|
14
|
+
require 'irb'
|
|
15
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/bin/with_framework
ADDED
data/lib/atatus.rb
ADDED
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'atatus/version'
|
|
4
|
+
require 'atatus/internal_error'
|
|
5
|
+
require 'atatus/logging'
|
|
6
|
+
|
|
7
|
+
# Core
|
|
8
|
+
require 'atatus/agent'
|
|
9
|
+
require 'atatus/config'
|
|
10
|
+
require 'atatus/context'
|
|
11
|
+
require 'atatus/instrumenter'
|
|
12
|
+
require 'atatus/util'
|
|
13
|
+
|
|
14
|
+
require 'atatus/middleware'
|
|
15
|
+
|
|
16
|
+
require 'atatus/railtie' if defined?(::Rails::Railtie)
|
|
17
|
+
|
|
18
|
+
# Atatus
|
|
19
|
+
module Atatus # rubocop:disable Metrics/ModuleLength
|
|
20
|
+
class << self
|
|
21
|
+
### Life cycle
|
|
22
|
+
|
|
23
|
+
# Starts the Atatus Agent
|
|
24
|
+
#
|
|
25
|
+
# @param config [Config] An instance of Config
|
|
26
|
+
# @return [Agent] The resulting [Agent]
|
|
27
|
+
def start(config = {})
|
|
28
|
+
Agent.start config
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Stops the Atatus Agent
|
|
32
|
+
def stop
|
|
33
|
+
Agent.stop
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# @return [Boolean] Whether there's an [Agent] running
|
|
37
|
+
def running?
|
|
38
|
+
Agent.running?
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# @return [Agent] Currently running [Agent] if any
|
|
42
|
+
def agent
|
|
43
|
+
Agent.instance
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
### Metrics
|
|
47
|
+
|
|
48
|
+
# Returns the currently active transaction (if any)
|
|
49
|
+
#
|
|
50
|
+
# @return [Transaction] or `nil`
|
|
51
|
+
def current_transaction
|
|
52
|
+
agent&.current_transaction
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Returns the currently active span (if any)
|
|
56
|
+
#
|
|
57
|
+
# @return [Span] or `nil`
|
|
58
|
+
def current_span
|
|
59
|
+
agent&.current_span
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# rubocop:disable Metrics/AbcSize
|
|
63
|
+
# Get a formatted string containing transaction, span, and trace ids.
|
|
64
|
+
# If a block is provided, the ids are yielded.
|
|
65
|
+
#
|
|
66
|
+
# @yield [String|nil, String|nil, String|nil] The transaction, span,
|
|
67
|
+
# and trace ids.
|
|
68
|
+
# @return [String] Unless block given
|
|
69
|
+
def log_ids
|
|
70
|
+
trace_id = (current_transaction || current_span)&.trace_id
|
|
71
|
+
if block_given?
|
|
72
|
+
return yield(current_transaction&.id, current_span&.id, trace_id)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
ids = []
|
|
76
|
+
ids << "transaction.id=#{current_transaction.id}" if current_transaction
|
|
77
|
+
ids << "span.id=#{current_span.id}" if current_span
|
|
78
|
+
ids << "trace.id=#{trace_id}" if trace_id
|
|
79
|
+
ids.join(' ')
|
|
80
|
+
end
|
|
81
|
+
# rubocop:enable Metrics/AbcSize
|
|
82
|
+
|
|
83
|
+
# rubocop:disable Metrics/MethodLength
|
|
84
|
+
# Start a new transaction
|
|
85
|
+
#
|
|
86
|
+
# @param name [String] A description of the transaction, eg
|
|
87
|
+
# `ExamplesController#index`
|
|
88
|
+
# @param type [String] The kind of the transaction, eg `app.request.get` or
|
|
89
|
+
# `db.mysql2.query`
|
|
90
|
+
# @param context [Context] An optional [Context]
|
|
91
|
+
# @return [Transaction]
|
|
92
|
+
def start_transaction(
|
|
93
|
+
name = nil,
|
|
94
|
+
type = nil,
|
|
95
|
+
context: nil,
|
|
96
|
+
trace_context: nil
|
|
97
|
+
)
|
|
98
|
+
agent&.start_transaction(
|
|
99
|
+
name,
|
|
100
|
+
type,
|
|
101
|
+
context: context,
|
|
102
|
+
trace_context: trace_context
|
|
103
|
+
)
|
|
104
|
+
end
|
|
105
|
+
# rubocop:enable Metrics/MethodLength
|
|
106
|
+
|
|
107
|
+
# Ends the current transaction with `result`
|
|
108
|
+
#
|
|
109
|
+
# @param result [String] The result of the transaction
|
|
110
|
+
# @return [Transaction]
|
|
111
|
+
def end_transaction(result = nil)
|
|
112
|
+
agent&.end_transaction(result)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# rubocop:disable Metrics/MethodLength
|
|
116
|
+
# Wrap a block in a Transaction, ending it after the block
|
|
117
|
+
#
|
|
118
|
+
# @param name [String] A description of the transaction, eg
|
|
119
|
+
# `ExamplesController#index`
|
|
120
|
+
# @param type [String] The kind of the transaction, eg `app.request.get` or
|
|
121
|
+
# `db.mysql2.query`
|
|
122
|
+
# @param context [Context] An optional [Context]
|
|
123
|
+
# @yield [Transaction]
|
|
124
|
+
# @return result of block
|
|
125
|
+
def with_transaction(
|
|
126
|
+
name = nil,
|
|
127
|
+
type = nil,
|
|
128
|
+
context: nil,
|
|
129
|
+
trace_context: nil
|
|
130
|
+
)
|
|
131
|
+
unless block_given?
|
|
132
|
+
raise ArgumentError,
|
|
133
|
+
'expected a block. Do you want `start_transaction\' instead?'
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
return yield(nil) unless agent
|
|
137
|
+
|
|
138
|
+
begin
|
|
139
|
+
transaction =
|
|
140
|
+
start_transaction(
|
|
141
|
+
name,
|
|
142
|
+
type,
|
|
143
|
+
context: context,
|
|
144
|
+
trace_context: trace_context
|
|
145
|
+
)
|
|
146
|
+
yield transaction
|
|
147
|
+
ensure
|
|
148
|
+
end_transaction
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
# rubocop:enable Metrics/MethodLength
|
|
152
|
+
|
|
153
|
+
# Start a new span
|
|
154
|
+
#
|
|
155
|
+
# @param name [String] A description of the span, eq `SELECT FROM "users"`
|
|
156
|
+
# @param type [String] The span type, eq `db`
|
|
157
|
+
# @param subtype [String] The span subtype, eq `postgresql`
|
|
158
|
+
# @param action [String] The span action type, eq `connect` or `query`
|
|
159
|
+
# @param context [Span::Context] Context information about the span
|
|
160
|
+
# @param include_stacktrace [Boolean] Whether or not to capture a stacktrace
|
|
161
|
+
# @return [Span]
|
|
162
|
+
def start_span(
|
|
163
|
+
name,
|
|
164
|
+
type = nil,
|
|
165
|
+
subtype: nil,
|
|
166
|
+
action: nil,
|
|
167
|
+
context: nil,
|
|
168
|
+
include_stacktrace: true,
|
|
169
|
+
trace_context: nil
|
|
170
|
+
)
|
|
171
|
+
agent&.start_span(
|
|
172
|
+
name,
|
|
173
|
+
type,
|
|
174
|
+
subtype: subtype,
|
|
175
|
+
action: action,
|
|
176
|
+
context: context,
|
|
177
|
+
trace_context: trace_context
|
|
178
|
+
).tap do |span|
|
|
179
|
+
break unless span && include_stacktrace
|
|
180
|
+
break unless agent.config.span_frames_min_duration?
|
|
181
|
+
|
|
182
|
+
span.original_backtrace ||= caller
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
# rubocop:enable Metrics/MethodLength, Metrics/ParameterLists
|
|
186
|
+
|
|
187
|
+
# Ends the current span
|
|
188
|
+
#
|
|
189
|
+
# @return [Span]
|
|
190
|
+
def end_span
|
|
191
|
+
agent&.end_span
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# rubocop:disable Metrics/MethodLength, Metrics/ParameterLists
|
|
195
|
+
# Wrap a block in a Span, ending it after the block
|
|
196
|
+
#
|
|
197
|
+
# @param name [String] A description of the span, eq `SELECT FROM "users"`
|
|
198
|
+
# @param type [String] The kind of span, eq `db.mysql2.query`
|
|
199
|
+
# @param context [Span::Context] Context information about the span
|
|
200
|
+
# @param include_stacktrace [Boolean] Whether or not to capture a stacktrace
|
|
201
|
+
# @yield [Span]
|
|
202
|
+
# @return Result of block
|
|
203
|
+
def with_span(
|
|
204
|
+
name,
|
|
205
|
+
type = nil,
|
|
206
|
+
subtype: nil,
|
|
207
|
+
action: nil,
|
|
208
|
+
context: nil,
|
|
209
|
+
include_stacktrace: true,
|
|
210
|
+
trace_context: nil
|
|
211
|
+
)
|
|
212
|
+
unless block_given?
|
|
213
|
+
raise ArgumentError,
|
|
214
|
+
'expected a block. Do you want `start_span\' instead?'
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
return yield nil unless agent
|
|
218
|
+
|
|
219
|
+
begin
|
|
220
|
+
span =
|
|
221
|
+
start_span(
|
|
222
|
+
name,
|
|
223
|
+
type,
|
|
224
|
+
subtype: subtype,
|
|
225
|
+
action: action,
|
|
226
|
+
context: context,
|
|
227
|
+
include_stacktrace: include_stacktrace,
|
|
228
|
+
trace_context: trace_context
|
|
229
|
+
)
|
|
230
|
+
yield span
|
|
231
|
+
ensure
|
|
232
|
+
end_span
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
# rubocop:enable Metrics/MethodLength, Metrics/ParameterLists
|
|
236
|
+
|
|
237
|
+
# Build a [Context] from a Rack `env`. The context may include information
|
|
238
|
+
# about the request, response, current user and more
|
|
239
|
+
#
|
|
240
|
+
# @param rack_env [Rack::Env] A Rack env
|
|
241
|
+
# @return [Context] The built context
|
|
242
|
+
def build_context(
|
|
243
|
+
rack_env: nil,
|
|
244
|
+
for_type: :transaction
|
|
245
|
+
)
|
|
246
|
+
agent&.build_context(rack_env: rack_env, for_type: for_type)
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
### Errors
|
|
250
|
+
|
|
251
|
+
# Report and exception to APM
|
|
252
|
+
#
|
|
253
|
+
# @param exception [Exception] The exception
|
|
254
|
+
# @param context [Context] An optional [Context]
|
|
255
|
+
# @param handled [Boolean] Whether the exception was rescued
|
|
256
|
+
# @return [String] ID of the generated [Error]
|
|
257
|
+
def report(exception, context: nil, handled: true)
|
|
258
|
+
agent&.report(exception, context: context, handled: handled)
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
# Report a custom string error message to APM
|
|
262
|
+
#
|
|
263
|
+
# @param message [String] The message
|
|
264
|
+
# @param context [Context] An optional [Context]
|
|
265
|
+
# @return [String] ID of the generated [Error]
|
|
266
|
+
def report_message(message, context: nil, **attrs)
|
|
267
|
+
agent&.report_message(
|
|
268
|
+
message,
|
|
269
|
+
context: context,
|
|
270
|
+
backtrace: caller,
|
|
271
|
+
**attrs
|
|
272
|
+
)
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
### Context
|
|
276
|
+
|
|
277
|
+
# Set a _label_ value for the current transaction
|
|
278
|
+
#
|
|
279
|
+
# @param key [String,Symbol] A key
|
|
280
|
+
# @param value [Object] A value
|
|
281
|
+
# @return [Object] The given value
|
|
282
|
+
def set_label(key, value)
|
|
283
|
+
case value
|
|
284
|
+
when TrueClass,
|
|
285
|
+
FalseClass,
|
|
286
|
+
Numeric,
|
|
287
|
+
NilClass,
|
|
288
|
+
String
|
|
289
|
+
agent&.set_label(key, value)
|
|
290
|
+
else
|
|
291
|
+
agent&.set_label(key, value.to_s)
|
|
292
|
+
end
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
# Provide further context for the current transaction
|
|
296
|
+
#
|
|
297
|
+
# @param custom [Hash] A hash with custom information. Can be nested.
|
|
298
|
+
# @return [Hash] The current custom context
|
|
299
|
+
def set_custom_context(custom)
|
|
300
|
+
agent&.set_custom_context(custom)
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
# Provide a user to the current transaction
|
|
304
|
+
#
|
|
305
|
+
# @param user [Object] An object representing a user
|
|
306
|
+
# @return [Object] Given user
|
|
307
|
+
def set_user(user)
|
|
308
|
+
agent&.set_user(user)
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
# Provide a filter to transform payloads before sending them off
|
|
312
|
+
#
|
|
313
|
+
# @param key [Symbol] Unique filter key
|
|
314
|
+
# @param callback [Object, Proc] A filter that responds to #call(payload)
|
|
315
|
+
# @yield [Hash] A filter. Used if provided. Otherwise using `callback`
|
|
316
|
+
# @return [Bool] true
|
|
317
|
+
def add_filter(key, callback = nil, &block)
|
|
318
|
+
if callback.nil? && !block_given?
|
|
319
|
+
raise ArgumentError, '#add_filter needs either `callback\' or a block'
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
agent&.add_filter(key, block || callback)
|
|
323
|
+
end
|
|
324
|
+
end
|
|
325
|
+
end
|