atatus 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|