elastic-apm 1.1.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of elastic-apm might be problematic. Click here for more details.

Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rspec +1 -0
  4. data/.rubocop.yml +7 -1
  5. data/CHANGELOG.md +45 -0
  6. data/Gemfile +17 -12
  7. data/bench/app.rb +1 -2
  8. data/bench/benchmark.rb +1 -1
  9. data/bench/stackprof.rb +1 -1
  10. data/docs/api.asciidoc +115 -76
  11. data/docs/configuration.asciidoc +232 -167
  12. data/docs/context.asciidoc +7 -3
  13. data/docs/custom-instrumentation.asciidoc +17 -28
  14. data/docs/index.asciidoc +13 -7
  15. data/docs/supported-technologies.asciidoc +65 -0
  16. data/elastic-apm.gemspec +3 -2
  17. data/lib/elastic_apm.rb +272 -121
  18. data/lib/elastic_apm/agent.rb +56 -107
  19. data/lib/elastic_apm/config.rb +130 -106
  20. data/lib/elastic_apm/config/duration.rb +25 -0
  21. data/lib/elastic_apm/config/size.rb +28 -0
  22. data/lib/elastic_apm/context_builder.rb +1 -0
  23. data/lib/elastic_apm/deprecations.rb +19 -0
  24. data/lib/elastic_apm/error.rb +5 -2
  25. data/lib/elastic_apm/error/exception.rb +1 -1
  26. data/lib/elastic_apm/error_builder.rb +5 -0
  27. data/lib/elastic_apm/instrumenter.rb +121 -53
  28. data/lib/elastic_apm/internal_error.rb +1 -0
  29. data/lib/elastic_apm/{log.rb → logging.rb} +16 -11
  30. data/lib/elastic_apm/metadata.rb +20 -0
  31. data/lib/elastic_apm/metadata/process_info.rb +26 -0
  32. data/lib/elastic_apm/metadata/service_info.rb +56 -0
  33. data/lib/elastic_apm/metadata/system_info.rb +30 -0
  34. data/lib/elastic_apm/middleware.rb +31 -15
  35. data/lib/elastic_apm/normalizers/action_controller.rb +1 -1
  36. data/lib/elastic_apm/normalizers/action_mailer.rb +1 -1
  37. data/lib/elastic_apm/normalizers/action_view.rb +3 -3
  38. data/lib/elastic_apm/normalizers/active_record.rb +2 -1
  39. data/lib/elastic_apm/railtie.rb +1 -1
  40. data/lib/elastic_apm/span.rb +59 -29
  41. data/lib/elastic_apm/span/context.rb +30 -4
  42. data/lib/elastic_apm/span_helpers.rb +1 -1
  43. data/lib/elastic_apm/spies/delayed_job.rb +7 -7
  44. data/lib/elastic_apm/spies/elasticsearch.rb +4 -4
  45. data/lib/elastic_apm/spies/http.rb +38 -0
  46. data/lib/elastic_apm/spies/mongo.rb +22 -11
  47. data/lib/elastic_apm/spies/net_http.rb +7 -4
  48. data/lib/elastic_apm/spies/rake.rb +5 -6
  49. data/lib/elastic_apm/spies/redis.rb +1 -1
  50. data/lib/elastic_apm/spies/sequel.rb +9 -7
  51. data/lib/elastic_apm/spies/sidekiq.rb +5 -5
  52. data/lib/elastic_apm/spies/tilt.rb +2 -2
  53. data/lib/elastic_apm/sql_summarizer.rb +3 -3
  54. data/lib/elastic_apm/stacktrace_builder.rb +6 -6
  55. data/lib/elastic_apm/subscriber.rb +3 -3
  56. data/lib/elastic_apm/traceparent.rb +62 -0
  57. data/lib/elastic_apm/transaction.rb +62 -93
  58. data/lib/elastic_apm/transport/base.rb +98 -0
  59. data/lib/elastic_apm/transport/connection.rb +175 -0
  60. data/lib/elastic_apm/transport/filters.rb +45 -0
  61. data/lib/elastic_apm/transport/filters/request_body_filter.rb +31 -0
  62. data/lib/elastic_apm/transport/filters/secrets_filter.rb +59 -0
  63. data/lib/elastic_apm/transport/serializers.rb +58 -0
  64. data/lib/elastic_apm/transport/serializers/error_serializer.rb +59 -0
  65. data/lib/elastic_apm/transport/serializers/span_serializer.rb +30 -0
  66. data/lib/elastic_apm/transport/serializers/transaction_serializer.rb +33 -0
  67. data/lib/elastic_apm/transport/worker.rb +73 -0
  68. data/lib/elastic_apm/util.rb +11 -8
  69. data/lib/elastic_apm/version.rb +1 -1
  70. metadata +40 -21
  71. data/.travis.yml +0 -5
  72. data/docs/troubleshooting.asciidoc +0 -28
  73. data/lib/elastic_apm/filters.rb +0 -46
  74. data/lib/elastic_apm/filters/request_body_filter.rb +0 -33
  75. data/lib/elastic_apm/filters/secrets_filter.rb +0 -59
  76. data/lib/elastic_apm/http.rb +0 -139
  77. data/lib/elastic_apm/process_info.rb +0 -24
  78. data/lib/elastic_apm/serializers.rb +0 -28
  79. data/lib/elastic_apm/serializers/errors.rb +0 -61
  80. data/lib/elastic_apm/serializers/transactions.rb +0 -51
  81. data/lib/elastic_apm/service_info.rb +0 -54
  82. data/lib/elastic_apm/system_info.rb +0 -28
  83. data/lib/elastic_apm/util/dig.rb +0 -31
  84. data/lib/elastic_apm/util/inspector.rb +0 -61
  85. data/lib/elastic_apm/worker.rb +0 -106
@@ -5,13 +5,14 @@
5
5
  [float]
6
6
  ==== Adding custom context
7
7
 
8
- You can add your own custom, nested JSON-compatible data to the current transaction using `ElasticAPM.add_custom_context(hash)` eg.:
8
+ You can add your own custom, nested JSON-compatible data to the current
9
+ transaction using `ElasticAPM.set_custom_context(hash)` eg.:
9
10
 
10
11
  [source,ruby]
11
12
  ----
12
13
  class ThingsController < ApplicationController
13
14
  before_action do
14
- ElasticAPM.add_custom_context(company: current_user.company)
15
+ ElasticAPM.set_custom_context(company: current_user.company)
15
16
  end
16
17
 
17
18
  # ...
@@ -21,13 +22,16 @@ end
21
22
  [float]
22
23
  ==== Adding tags
23
24
 
24
- Tags are special in that they are indexed in your Elasticsearch database and therefore searchable.
25
+ Tags are special in that they are indexed in your Elasticsearch database and
26
+ therefore searchable.
25
27
 
26
28
  [source,ruby]
27
29
  ----
28
30
  ElasticAPM.set_tag(:company_name, 'Acme, Inc.')
29
31
  ----
30
32
 
33
+ Note that `.`, `*` and `"` in keys are converted to `_`.
34
+
31
35
  [float]
32
36
  ==== Providing info about the user
33
37
 
@@ -1,19 +1,22 @@
1
1
  [[custom-instrumentation]]
2
2
  === Custom instrumentation
3
3
 
4
- When <<introduction,installed>> and <<configuration,properly configured>> ElasticAPM will automatically wrap your app's request/responses in
5
- transactions and report its errors.
4
+ When <<introduction,installed>> and <<configuration,properly configured>>
5
+ ElasticAPM will automatically wrap your app's request/responses in transactions
6
+ and report its errors.
6
7
  It also wraps each background job if you use Sidekiq or DelayedJob.
7
8
 
8
- But it is possible to create your own transactions as well as provide spans for any
9
- automatic or custom transaction.
9
+ But it is possible to create your own transactions as well as provide spans for
10
+ any automatic or custom transaction.
10
11
 
11
- See <<api-transaction,`ElasticAPM.transaction`>> and <<api-agent-span,`ElasticAPM.span`>>.
12
+ See <<api-agent-start_transaction,`ElasticAPM.start_transaction`>> and
13
+ <<api-agent-start_span,`ElasticAPM.start_span`>>.
12
14
 
13
15
  [float]
14
16
  ==== Helpers
15
17
 
16
- ElasticAPM includes some nifty helpers if you just want to instrument a regular method.
18
+ ElasticAPM includes some nifty helpers if you just want to instrument a regular
19
+ method.
17
20
 
18
21
  [source,ruby]
19
22
  ----
@@ -35,14 +38,14 @@ end
35
38
  [float]
36
39
  ==== Custom span example
37
40
 
38
- If you are already inside a Transaction (most likely) and you want to intrument
41
+ If you are already inside a Transaction (most likely) and you want to instrument
39
42
  some work inside it, add a custom span:
40
43
 
41
44
  [source,ruby]
42
45
  ----
43
46
  class ThingsController < ApplicationController
44
47
  def index
45
- @result_of_work = ElasticAPM.span "Heavy work" do
48
+ @result_of_work = ElasticAPM.with_span "Heavy work" do
46
49
  do_the_heavy_work
47
50
  end
48
51
  end
@@ -52,40 +55,26 @@ end
52
55
  [float]
53
56
  ==== Custom transaction example
54
57
 
55
- If you are **not** inside a Transaction already (eg. outside of your common web application)
56
- start and manage your own transactions like so:
58
+ If you are **not** inside a Transaction already (eg. outside of your common web
59
+ application) start and manage your own transactions like so:
57
60
 
58
61
  [source,ruby]
59
62
  ----
60
63
  class Something
61
64
  def do_work
62
- transaction = ElasticAPM.transaction 'Something#do_work'
65
+ transaction = ElasticAPM.start_transaction 'Something#do_work'
63
66
 
64
67
  begin
65
68
  Sequel[:users] # many third party libs will be automatically instrumented
66
- transaction.submit('success') if transaction
67
69
  rescue Exception => e
68
70
  ElasticAPM.report(e)
69
- transaction.submit('error') if transaction
70
71
  raise
71
72
  ensure
72
- transaction.release
73
+ ElasticAPM.end_transaction('result')
73
74
  end
74
75
  end
75
76
  end
76
77
  ----
77
78
 
78
- **Note:** If the agent isn't started beforehand this will do nothing. See <<api-agent-start,ElasticAPM.start>>.
79
-
80
- [[spies]]
81
- === Spies
82
-
83
- [float]
84
- ==== Automatic integrations with third-party libraries
85
-
86
- ElasticAPM has built-in integrations for some popular libraries.
87
- Use `config.disabled_spies` to disable specific integrations.
88
-
89
- For a list of available spies, see
90
- https://github.com/elastic/apm-agent-ruby/blob/1.x/lib/elastic_apm/config.rb#L174-L188[config.rb].
91
-
79
+ **Note:** If the agent isn't started beforehand this will do nothing.
80
+ See <<api-agent-start,ElasticAPM.start>>.
@@ -2,7 +2,8 @@
2
2
  include::{asciidoc-dir}/../../shared/attributes.asciidoc[]
3
3
 
4
4
  ifdef::env-github[]
5
- NOTE: For the best reading experience, please view this documentation at https://www.elastic.co/guide/en/apm/agent/ruby[elastic.co]
5
+ NOTE: For the best reading experience, please view this documentation at
6
+ https://www.elastic.co/guide/en/apm/agent/ruby[elastic.co]
6
7
  endif::[]
7
8
 
8
9
  = APM Ruby Agent Reference
@@ -10,18 +11,23 @@ endif::[]
10
11
  [[introduction]]
11
12
  == Introduction
12
13
 
13
- The Elastic APM Ruby Agent sends performance metrics and error logs to an Elastic APM Server.
14
+ The Elastic APM Ruby Agent sends performance metrics and error logs to an
15
+ Elastic APM Server.
14
16
 
15
- It has built-in support for <<getting-started-rails,Ruby on Rails>> and other <<getting-started-rack,Rack-compatible>> applications.
17
+ It has built-in support for <<getting-started-rails,Ruby on Rails>> and other
18
+ <<getting-started-rack,Rack-compatible>> applications.
16
19
 
17
- This agent is one of several components you need to get started collecting APM data. See also:
20
+ This agent is one of several components you need to get started collecting APM
21
+ data. See also:
18
22
 
19
23
  * {apm-server-ref}[APM Server]
20
24
 
21
25
  [[framework-support]]
22
- The Elastic APM Ruby Agent officially supports <<getting-started-rails,Ruby on Rails>> versions 4.x on onwards.
26
+ The Elastic APM Ruby Agent officially supports Ruby on Rails versions 4.x on
27
+ onwards, see <<getting-started-rails,Getting started with Ruby on Rails>>.
23
28
 
24
- For Sinatra and other Rack compatible frameworks, see <<getting-started-rack,Getting started with Rack>>.
29
+ For Sinatra and other Rack compatible frameworks, see
30
+ <<getting-started-rack,Getting started with Rack>>.
25
31
 
26
32
  include::./getting-started-rails.asciidoc[]
27
33
  include::./getting-started-rack.asciidoc[]
@@ -31,7 +37,7 @@ include::./configuration.asciidoc[]
31
37
  == Advanced Topics
32
38
  include::./context.asciidoc[]
33
39
  include::./custom-instrumentation.asciidoc[]
34
- include::./troubleshooting.asciidoc[]
35
40
 
41
+ include::./supported-technologies.asciidoc[]
36
42
  include::./api.asciidoc[]
37
43
 
@@ -0,0 +1,65 @@
1
+ [[supported-technologies]]
2
+ == Supported technologies
3
+
4
+ The Elastic APM Ruby Agent has built-in support for many frameworks and
5
+ libraries.
6
+
7
+ Generally we want to support all the most popular libraries, so if your favorite
8
+ is missing feel free so request it in an issue or better yet supply a pull
9
+ request.
10
+
11
+ [float]
12
+ [[supported-technologies-ruby]]
13
+ === Ruby
14
+
15
+ We follow Ruby's own maintenance policy and officially support all currently
16
+ maintained versions per
17
+ https://www.ruby-lang.org/en/downloads/branches/[Ruby Maintenance Branches].
18
+
19
+ [float]
20
+ [[supported-technologies-web]]
21
+ === Web Frameworks and Libraries
22
+
23
+ We have automatic support for Ruby on Rails and all Rack compatible web
24
+ frameworks.
25
+
26
+ We test against all supported minor versions of Rails and Sinatra.
27
+
28
+ [float]
29
+ [[supported-technologies-rails]]
30
+ ==== Ruby on Rails
31
+
32
+ We currently support all versions of Rails since 4.2.
33
+ This follows Rails' own https://rubyonrails.org/security/[Security policy].
34
+
35
+ See <<getting-started-rails>>.
36
+
37
+ [float]
38
+ [[supported-technologies-sinatra]]
39
+ ==== Sinatra
40
+
41
+ We currently support all versions of Sinatra since 1.0.
42
+
43
+ See <<getting-started-rack>>.
44
+
45
+ [float]
46
+ [[supported-technologies-databases]]
47
+ === Databases
48
+
49
+ We automatically instrument database actions using:
50
+
51
+ - ActiveRecord
52
+ - Elasticsearch
53
+ - Mongo
54
+ - Redis
55
+ - Sequel
56
+
57
+ [float]
58
+ [[supported-technologies-http]]
59
+ === External HTTP requests
60
+
61
+ We automatically instrument and add support for distributed tracing to external
62
+ requests using these libraries:
63
+
64
+ - `net/http`
65
+ - Http.rb
@@ -12,13 +12,14 @@ Gem::Specification.new do |spec|
12
12
  spec.homepage = 'https://github.com/elastic/apm-agent-ruby'
13
13
  spec.metadata = { 'source_code_uri' => 'https://github.com/elastic/apm-agent-ruby' }
14
14
  spec.license = 'Apache-2.0'
15
- spec.required_ruby_version = ">= 2.2.0"
15
+ spec.required_ruby_version = ">= 2.3.0"
16
16
 
17
17
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
18
  f.match(%r{^(test|spec|features)/})
19
19
  end
20
20
 
21
- spec.add_dependency('concurrent-ruby', '~> 1.0.0')
21
+ spec.add_dependency('concurrent-ruby', '~> 1.0')
22
+ spec.add_dependency('http', '>= 3.0')
22
23
 
23
24
  spec.require_paths = ['lib']
24
25
  end
@@ -1,16 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'elastic_apm/version'
4
- require 'elastic_apm/log'
5
- require 'elastic_apm/util/dig'
4
+ require 'elastic_apm/internal_error'
5
+ require 'elastic_apm/logging'
6
+ require 'elastic_apm/deprecations'
6
7
 
7
8
  # Core
8
9
  require 'elastic_apm/agent'
9
10
  require 'elastic_apm/config'
10
11
  require 'elastic_apm/context'
11
12
  require 'elastic_apm/instrumenter'
12
- require 'elastic_apm/internal_error'
13
- require 'elastic_apm/span_helpers'
14
13
  require 'elastic_apm/util'
15
14
 
16
15
  require 'elastic_apm/middleware'
@@ -18,142 +17,294 @@ require 'elastic_apm/middleware'
18
17
  require 'elastic_apm/railtie' if defined?(::Rails::Railtie)
19
18
 
20
19
  # ElasticAPM
21
- module ElasticAPM
22
- ### Life cycle
23
-
24
- # Starts the ElasticAPM Agent
25
- #
26
- # @param config [Config] An instance of Config
27
- # @return [Agent] The resulting [Agent]
28
- def self.start(config = {})
29
- Agent.start config
30
- end
20
+ module ElasticAPM # rubocop:disable Metrics/ModuleLength
21
+ class << self
22
+ extend ElasticAPM::Deprecations
31
23
 
32
- # Stops the ElasticAPM Agent
33
- def self.stop
34
- Agent.stop
35
- end
24
+ ### Life cycle
36
25
 
37
- # @return [Boolean] Whether there's an [Agent] running
38
- def self.running?
39
- Agent.running?
40
- end
26
+ # Starts the ElasticAPM Agent
27
+ #
28
+ # @param config [Config] An instance of Config
29
+ # @return [Agent] The resulting [Agent]
30
+ def start(config = {})
31
+ Agent.start config
32
+ end
41
33
 
42
- # @return [Agent] Currently running [Agent] if any
43
- def self.agent
44
- Agent.instance
45
- end
34
+ # Stops the ElasticAPM Agent
35
+ def stop
36
+ Agent.stop
37
+ end
46
38
 
47
- ### Metrics
39
+ # @return [Boolean] Whether there's an [Agent] running
40
+ def running?
41
+ Agent.running?
42
+ end
48
43
 
49
- # Returns the currently active transaction (if any)
50
- #
51
- # @return [Transaction] if any
52
- def self.current_transaction
53
- agent && agent.current_transaction
54
- end
44
+ # @return [Agent] Currently running [Agent] if any
45
+ def agent
46
+ Agent.instance
47
+ end
55
48
 
56
- # Start a new transaction or return the currently running
57
- #
58
- # @param name [String] A description of the transaction, eg
59
- # `ExamplesController#index`
60
- # @param type [String] The kind of the transaction, eg `app.request.get` or
61
- # `db.mysql2.query`
62
- # @param context [Context] An optional [Context]
63
- # @yield [Transaction] Optional block encapsulating transaction
64
- # @return [Transaction] Unless block given
65
- def self.transaction(name = nil, type = nil, context: nil, &block)
66
- return (block_given? ? yield : nil) unless agent
67
-
68
- agent.transaction(name, type, context: context, &block)
69
- end
49
+ ### Metrics
50
+
51
+ # Returns the currently active transaction (if any)
52
+ #
53
+ # @return [Transaction] or `nil`
54
+ def current_transaction
55
+ agent&.current_transaction
56
+ end
57
+
58
+ # Returns the currently active span (if any)
59
+ #
60
+ # @return [Span] or `nil`
61
+ def current_span
62
+ agent&.current_span
63
+ end
64
+
65
+ # Start a new transaction or return the currently running
66
+ #
67
+ # @param name [String] A description of the transaction, eg
68
+ # `ExamplesController#index`
69
+ # @param type [String] The kind of the transaction, eg `app.request.get` or
70
+ # `db.mysql2.query`
71
+ # @param context [Context] An optional [Context]
72
+ # @yield [Transaction] Optional block encapsulating transaction
73
+ # @return [Transaction] Unless block given
74
+ # @deprecated See `with_transaction` or `start_transaction`
75
+ def transaction(name = nil, type = nil, context: nil, &block)
76
+ return (block_given? ? yield : nil) unless agent
77
+
78
+ if block_given?
79
+ with_transaction(name, type, context: context, &block)
80
+ else
81
+ start_transaction(name, type, context: context)
82
+ end
83
+ end
84
+
85
+ deprecate :transaction, :with_transaction
86
+
87
+ # Start a new transaction
88
+ #
89
+ # @param name [String] A description of the transaction, eg
90
+ # `ExamplesController#index`
91
+ # @param type [String] The kind of the transaction, eg `app.request.get` or
92
+ # `db.mysql2.query`
93
+ # @param context [Context] An optional [Context]
94
+ # @return [Transaction]
95
+ def start_transaction(
96
+ name = nil,
97
+ type = nil,
98
+ context: nil,
99
+ traceparent: nil
100
+ )
101
+ agent&.start_transaction(
102
+ name,
103
+ type,
104
+ context: context,
105
+ traceparent: traceparent
106
+ )
107
+ end
108
+
109
+ # Ends the current transaction with `result`
110
+ #
111
+ # @param result [String] The result of the transaction
112
+ # @return [Transaction]
113
+ def end_transaction(result = nil)
114
+ agent&.end_transaction(result)
115
+ end
116
+
117
+ # rubocop:disable Metrics/MethodLength
118
+ # Wrap a block in a Transaction, ending it after the block
119
+ #
120
+ # @param name [String] A description of the transaction, eg
121
+ # `ExamplesController#index`
122
+ # @param type [String] The kind of the transaction, eg `app.request.get` or
123
+ # `db.mysql2.query`
124
+ # @param context [Context] An optional [Context]
125
+ # @yield [Transaction]
126
+ # @return result of block
127
+ def with_transaction(name = nil, type = nil, context: nil, traceparent: nil)
128
+ unless block_given?
129
+ raise ArgumentError,
130
+ 'expected a block. Do you want `start_transaction\' instead?'
131
+ end
132
+
133
+ return yield(nil) unless agent
70
134
 
71
- # Starts a new span under the current Transaction
72
- #
73
- # @param name [String] A description of the span, eq `SELECT FROM "users"`
74
- # @param type [String] The kind of span, eq `db.mysql2.query`
75
- # @param context [Span::Context] Context information about the span
76
- # @yield [Span] Optional block encapsulating span
77
- # @return [Span] Unless block given
78
- def self.span(name, type = nil, context: nil, include_stacktrace: true,
79
- &block)
80
- return (block_given? ? yield : nil) unless agent
81
-
82
- agent.span(
135
+ begin
136
+ transaction =
137
+ start_transaction(
138
+ name,
139
+ type,
140
+ context: context,
141
+ traceparent: traceparent
142
+ )
143
+ yield transaction
144
+ ensure
145
+ end_transaction
146
+ end
147
+ end
148
+ # rubocop:enable Metrics/MethodLength
149
+
150
+ # rubocop:disable Metrics/MethodLength
151
+ # Start a new span
152
+ #
153
+ # @param name [String] A description of the span, eq `SELECT FROM "users"`
154
+ # @param type [String] The kind of span, eq `db.mysql2.query`
155
+ # @param context [Span::Context] Context information about the span
156
+ # @yield [Span] Optional block encapsulating span
157
+ # @return [Span] Unless block given
158
+ # @deprecated See `with_span` or `start_span`
159
+ def span(name, type = nil, context: nil, include_stacktrace: true, &block)
160
+ return (block_given? ? yield : nil) unless agent
161
+
162
+ if block_given?
163
+ with_span(
164
+ name,
165
+ type,
166
+ context:
167
+ context,
168
+ include_stacktrace: include_stacktrace,
169
+ &block
170
+ )
171
+ else
172
+ start_span(
173
+ name,
174
+ type,
175
+ context: context,
176
+ include_stacktrace: include_stacktrace
177
+ )
178
+ end
179
+ end
180
+ # rubocop:enable Metrics/MethodLength
181
+
182
+ deprecate :span, :with_span
183
+
184
+ # Start a new span
185
+ #
186
+ # @param name [String] A description of the span, eq `SELECT FROM "users"`
187
+ # @param type [String] The kind of span, eq `db.mysql2.query`
188
+ # @param context [Span::Context] Context information about the span
189
+ # @param include_stacktrace [Boolean] Whether or not to capture a stacktrace
190
+ # @return [Span]
191
+ def start_span(name, type = nil, context: nil, include_stacktrace: true)
192
+ agent&.start_span(
193
+ name,
194
+ type,
195
+ context: context,
196
+ backtrace: include_stacktrace ? caller : nil
197
+ )
198
+ end
199
+
200
+ # Ends the current span
201
+ #
202
+ # @return [Span]
203
+ def end_span
204
+ agent&.end_span
205
+ end
206
+
207
+ # rubocop:disable Metrics/MethodLength
208
+ # Wrap a block in a Span, ending it after the block
209
+ #
210
+ # @param name [String] A description of the span, eq `SELECT FROM "users"`
211
+ # @param type [String] The kind of span, eq `db.mysql2.query`
212
+ # @param context [Span::Context] Context information about the span
213
+ # @param include_stacktrace [Boolean] Whether or not to capture a stacktrace
214
+ # @yield [Span]
215
+ # @return Result of block
216
+ def with_span(
83
217
  name,
84
- type,
85
- context: context,
86
- backtrace: include_stacktrace ? caller : nil,
87
- &block
218
+ type = nil,
219
+ context: nil,
220
+ include_stacktrace: true
88
221
  )
89
- end
222
+ unless block_given?
223
+ raise ArgumentError,
224
+ 'expected a block. Do you want `start_span\' instead?'
225
+ end
90
226
 
91
- # Build a [Context] from a Rack `env`. The context may include information
92
- # about the request, response, current user and more
93
- #
94
- # @param rack_env [Rack::Env] A Rack env
95
- # @return [Context] The built context
96
- def self.build_context(rack_env)
97
- agent && agent.build_context(rack_env)
98
- end
227
+ return yield nil unless agent
228
+
229
+ begin
230
+ span =
231
+ start_span(
232
+ name, type, context: context, include_stacktrace: include_stacktrace
233
+ )
234
+ yield span
235
+ ensure
236
+ end_span
237
+ end
238
+ end
239
+ # rubocop:enable Metrics/MethodLength
99
240
 
100
- ### Errors
241
+ # Build a [Context] from a Rack `env`. The context may include information
242
+ # about the request, response, current user and more
243
+ #
244
+ # @param rack_env [Rack::Env] A Rack env
245
+ # @return [Context] The built context
246
+ def build_context(rack_env)
247
+ agent&.build_context(rack_env)
248
+ end
101
249
 
102
- # Report and exception to APM
103
- #
104
- # @param exception [Exception] The exception
105
- # @param handled [Boolean] Whether the exception was rescued
106
- # @return [Error] The generated [Error]
107
- def self.report(exception, handled: true)
108
- agent && agent.report(exception, handled: handled)
109
- end
250
+ ### Errors
110
251
 
111
- # Report a custom string error message to APM
112
- #
113
- # @param message [String] The message
114
- # @return [Error] The generated [Error]
115
- def self.report_message(message, **attrs)
116
- agent && agent.report_message(message, backtrace: caller, **attrs)
117
- end
252
+ # Report and exception to APM
253
+ #
254
+ # @param exception [Exception] The exception
255
+ # @param handled [Boolean] Whether the exception was rescued
256
+ # @return [Error] The generated [Error]
257
+ def report(exception, handled: true)
258
+ agent&.report(exception, handled: handled)
259
+ end
118
260
 
119
- ### Context
261
+ # Report a custom string error message to APM
262
+ #
263
+ # @param message [String] The message
264
+ # @return [Error] The generated [Error]
265
+ def report_message(message, **attrs)
266
+ agent&.report_message(message, backtrace: caller, **attrs)
267
+ end
120
268
 
121
- # Set a _tag_ value for the current transaction
122
- #
123
- # @param key [String,Symbol] A key
124
- # @param value [Object] A value (will be converted to string)
125
- # @return [Object] The given value
126
- def self.set_tag(key, value)
127
- agent && agent.set_tag(key, value)
128
- end
269
+ ### Context
129
270
 
130
- # Provide further context for the current transaction
131
- #
132
- # @param custom [Hash] A hash with custom information. Can be nested.
133
- # @return [Hash] The current custom context
134
- def self.set_custom_context(custom)
135
- agent && agent.set_custom_context(custom)
136
- end
271
+ # Set a _tag_ value for the current transaction
272
+ #
273
+ # @param key [String,Symbol] A key
274
+ # @param value [Object] A value (will be converted to string)
275
+ # @return [Object] The given value
276
+ def set_tag(key, value)
277
+ agent&.set_tag(key, value)
278
+ end
137
279
 
138
- # Provide a user to the current transaction
139
- #
140
- # @param user [Object] An object representing a user
141
- # @return [Object] Given user
142
- def self.set_user(user)
143
- agent && agent.set_user(user)
144
- end
280
+ # Provide further context for the current transaction
281
+ #
282
+ # @param custom [Hash] A hash with custom information. Can be nested.
283
+ # @return [Hash] The current custom context
284
+ def set_custom_context(custom)
285
+ agent&.set_custom_context(custom)
286
+ end
145
287
 
146
- # Provide a filter to transform payloads before sending them off
147
- #
148
- # @param key [Symbol] Unique filter key
149
- # @param callback [Object, Proc] A filter that responds to #call(payload)
150
- # @yield [Hash] A filter. Will be used if provided. Otherwise using `callback`
151
- # @return [Bool] true
152
- def self.add_filter(key, callback = nil, &block)
153
- if callback.nil? && !block_given?
154
- raise ArgumentError, '#add_filter needs either `callback\' or a block'
288
+ # Provide a user to the current transaction
289
+ #
290
+ # @param user [Object] An object representing a user
291
+ # @return [Object] Given user
292
+ def set_user(user)
293
+ agent&.set_user(user)
155
294
  end
156
295
 
157
- agent && agent.add_filter(key, block || callback)
296
+ # Provide a filter to transform payloads before sending them off
297
+ #
298
+ # @param key [Symbol] Unique filter key
299
+ # @param callback [Object, Proc] A filter that responds to #call(payload)
300
+ # @yield [Hash] A filter. Used if provided. Otherwise using `callback`
301
+ # @return [Bool] true
302
+ def add_filter(key, callback = nil, &block)
303
+ if callback.nil? && !block_given?
304
+ raise ArgumentError, '#add_filter needs either `callback\' or a block'
305
+ end
306
+
307
+ agent&.add_filter(key, block || callback)
308
+ end
158
309
  end
159
310
  end