appsignal 4.10.1-java → 5.0.0.rc.1-java

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.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +19 -0
  3. data/Rakefile +87 -0
  4. data/appsignal.gemspec +8 -0
  5. data/build_matrix.yml +14 -1
  6. data/ext/appsignal_extension.c +14 -0
  7. data/lib/appsignal/backends.rb +55 -0
  8. data/lib/appsignal/config.rb +140 -1
  9. data/lib/appsignal/demo.rb +1 -1
  10. data/lib/appsignal/event_formatter/action_view/render_formatter.rb +34 -22
  11. data/lib/appsignal/event_formatter/active_job/perform_formatter.rb +35 -0
  12. data/lib/appsignal/event_formatter/active_record/sql_formatter.rb +19 -0
  13. data/lib/appsignal/event_formatter/elastic_search/search_formatter.rb +27 -0
  14. data/lib/appsignal/event_formatter/recorded_elsewhere.rb +17 -0
  15. data/lib/appsignal/event_formatter/rom/sql_formatter.rb +24 -0
  16. data/lib/appsignal/event_formatter/sequel/sql_formatter.rb +5 -0
  17. data/lib/appsignal/event_formatter/view_component/render_formatter.rb +21 -10
  18. data/lib/appsignal/event_formatter.rb +78 -0
  19. data/lib/appsignal/extension.rb +4 -0
  20. data/lib/appsignal/helpers/instrumentation.rb +236 -20
  21. data/lib/appsignal/helpers/metrics.rb +3 -24
  22. data/lib/appsignal/hooks/action_cable.rb +18 -6
  23. data/lib/appsignal/hooks/active_job.rb +128 -39
  24. data/lib/appsignal/hooks/at_exit.rb +4 -1
  25. data/lib/appsignal/hooks/excon.rb +20 -0
  26. data/lib/appsignal/hooks/faraday.rb +16 -0
  27. data/lib/appsignal/hooks/http.rb +5 -0
  28. data/lib/appsignal/hooks/resque.rb +1 -1
  29. data/lib/appsignal/hooks/sequel.rb +32 -2
  30. data/lib/appsignal/hooks/shoryuken.rb +3 -3
  31. data/lib/appsignal/hooks/sidekiq.rb +1 -1
  32. data/lib/appsignal/integrations/action_cable.rb +5 -2
  33. data/lib/appsignal/integrations/active_support_notifications.rb +59 -14
  34. data/lib/appsignal/integrations/data_mapper.rb +14 -2
  35. data/lib/appsignal/integrations/delayed_job_plugin.rb +45 -5
  36. data/lib/appsignal/integrations/dry_monitor.rb +39 -15
  37. data/lib/appsignal/integrations/excon/appsignal_middleware.rb +21 -0
  38. data/lib/appsignal/integrations/excon.rb +52 -15
  39. data/lib/appsignal/integrations/faraday.rb +47 -12
  40. data/lib/appsignal/integrations/http.rb +43 -1
  41. data/lib/appsignal/integrations/mongo_ruby_driver.rb +73 -4
  42. data/lib/appsignal/integrations/net_http.rb +31 -2
  43. data/lib/appsignal/integrations/puma.rb +4 -1
  44. data/lib/appsignal/integrations/que.rb +224 -37
  45. data/lib/appsignal/integrations/railtie.rb +4 -1
  46. data/lib/appsignal/integrations/rake.rb +9 -3
  47. data/lib/appsignal/integrations/redis.rb +22 -1
  48. data/lib/appsignal/integrations/redis_client.rb +22 -1
  49. data/lib/appsignal/integrations/resque.rb +57 -10
  50. data/lib/appsignal/integrations/shoryuken.rb +140 -12
  51. data/lib/appsignal/integrations/sidekiq.rb +73 -16
  52. data/lib/appsignal/integrations/webmachine.rb +47 -4
  53. data/lib/appsignal/loaders/padrino.rb +2 -1
  54. data/lib/appsignal/logger/extension_backend.rb +24 -0
  55. data/lib/appsignal/logger/opentelemetry_backend.rb +66 -0
  56. data/lib/appsignal/logger.rb +13 -9
  57. data/lib/appsignal/metrics/extension_backend.rb +47 -0
  58. data/lib/appsignal/metrics/opentelemetry_backend.rb +89 -0
  59. data/lib/appsignal/opentelemetry/attributes.rb +31 -0
  60. data/lib/appsignal/opentelemetry/dependencies.rb +35 -0
  61. data/lib/appsignal/opentelemetry/error_type.rb +37 -0
  62. data/lib/appsignal/opentelemetry/http_client_request.rb +83 -0
  63. data/lib/appsignal/opentelemetry/http_method.rb +59 -0
  64. data/lib/appsignal/opentelemetry/http_response.rb +30 -0
  65. data/lib/appsignal/opentelemetry/http_server_request.rb +45 -0
  66. data/lib/appsignal/opentelemetry/messaging.rb +82 -0
  67. data/lib/appsignal/opentelemetry/rendering.rb +29 -0
  68. data/lib/appsignal/opentelemetry/sql_db_system.rb +89 -0
  69. data/lib/appsignal/opentelemetry.rb +337 -0
  70. data/lib/appsignal/rack/abstract_middleware.rb +63 -4
  71. data/lib/appsignal/rack/body_wrapper.rb +18 -5
  72. data/lib/appsignal/rack/event_handler.rb +36 -3
  73. data/lib/appsignal/rack/grape_middleware.rb +1 -0
  74. data/lib/appsignal/rack/hanami_middleware.rb +2 -1
  75. data/lib/appsignal/rack/instrumentation_middleware.rb +1 -0
  76. data/lib/appsignal/rack/rails_instrumentation.rb +1 -0
  77. data/lib/appsignal/rack/sinatra_instrumentation.rb +1 -0
  78. data/lib/appsignal/rack.rb +39 -11
  79. data/lib/appsignal/sample_data.rb +4 -0
  80. data/lib/appsignal/transaction/base_backend.rb +107 -0
  81. data/lib/appsignal/transaction/extension_backend.rb +203 -0
  82. data/lib/appsignal/transaction/opentelemetry_backend.rb +796 -0
  83. data/lib/appsignal/transaction.rb +537 -144
  84. data/lib/appsignal/utils/stdout_and_logger_message.rb +9 -0
  85. data/lib/appsignal/version.rb +1 -1
  86. data/lib/appsignal.rb +9 -0
  87. data/sig/appsignal.rbi +426 -37
  88. data/sig/appsignal.rbs +386 -27
  89. metadata +23 -1
@@ -5,6 +5,25 @@ module Appsignal
5
5
  # @!visibility private
6
6
  module ActiveRecord
7
7
  class SqlFormatter < Appsignal::EventFormatter
8
+ # A query is an outgoing call to a datastore.
9
+ def opentelemetry_kind
10
+ :client
11
+ end
12
+
13
+ # The payload carries the connection the query ran on (Rails 6.0+),
14
+ # whose `adapter_name` is each adapter's own name for itself, such as
15
+ # `"PostgreSQL"` or `"Mysql2"`. A name the mapping does not recognise
16
+ # is left to the SQL sentinel, same as an adapter this gem has never
17
+ # heard of.
18
+ def opentelemetry_attributes(payload)
19
+ name = Appsignal::OpenTelemetry::SqlDbSystem.name_for_active_record(
20
+ payload[:connection]&.adapter_name
21
+ )
22
+ return unless name
23
+
24
+ { "db.system.name" => name }
25
+ end
26
+
8
27
  def format(payload)
9
28
  [payload[:name], payload[:sql], SQL_BODY_FORMAT]
10
29
  end
@@ -5,6 +5,21 @@ module Appsignal
5
5
  # @!visibility private
6
6
  module ElasticSearch
7
7
  class SearchFormatter < Appsignal::EventFormatter
8
+ # A search is an outgoing call to an Elasticsearch cluster.
9
+ def opentelemetry_kind
10
+ :client
11
+ end
12
+
13
+ def opentelemetry_attributes(payload)
14
+ {
15
+ "db.system.name" => "elasticsearch",
16
+ # This notification is only emitted for a search, so that is the
17
+ # operation every one of these spans describes.
18
+ "db.operation.name" => "search",
19
+ "db.collection.name" => search_index(payload)
20
+ }.compact
21
+ end
22
+
8
23
  def format(payload)
9
24
  [
10
25
  "#{payload[:name]}: #{payload[:klass]}",
@@ -12,6 +27,18 @@ module Appsignal
12
27
  ]
13
28
  end
14
29
 
30
+ # The index a search ran against, which the notification carries in the
31
+ # search it describes. A search that names more than one index, or none
32
+ # at all, is left without this attribute rather than described with a
33
+ # value that is not an index name.
34
+ def search_index(payload)
35
+ search = payload[:search]
36
+ return unless search.respond_to?(:[])
37
+
38
+ index = search[:index]
39
+ index if index.is_a?(String)
40
+ end
41
+
15
42
  def sanitized_search(search)
16
43
  return unless search.is_a?(Hash)
17
44
 
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Appsignal
4
+ class EventFormatter
5
+ # Registered for an event that a dedicated AppSignal integration already
6
+ # records with richer semantics. The generic instrumentation paths ask the
7
+ # registry whether to record an event, so registering this for an event
8
+ # name is how that integration claims it.
9
+ #
10
+ # @!visibility private
11
+ class RecordedElsewhere < Appsignal::EventFormatter
12
+ def record?
13
+ false
14
+ end
15
+ end
16
+ end
17
+ end
@@ -5,6 +5,18 @@ module Appsignal
5
5
  # @!visibility private
6
6
  module Rom
7
7
  class SqlFormatter < Appsignal::EventFormatter
8
+ # These events arrive over dry-monitor, which is a notification bus
9
+ # rather than a library that queries a database. ROM is what emits
10
+ # them, so that is what the scope names.
11
+ def opentelemetry_scope
12
+ ["appsignal-ruby/rom", Appsignal::VERSION]
13
+ end
14
+
15
+ # A query is an outgoing call to a datastore.
16
+ def opentelemetry_kind
17
+ :client
18
+ end
19
+
8
20
  # dry-monitor reports an event under an id rather than a name, so the
9
21
  # first value here names the event. Naming it after ROM keeps every ROM
10
22
  # query in one group.
@@ -17,6 +29,18 @@ module Appsignal
17
29
  def format(payload)
18
30
  ["query.rom", payload[:query], SQL_BODY_FORMAT]
19
31
  end
32
+
33
+ # The payload's `name` is Sequel's `database_type` symbol for the
34
+ # database ROM is talking to, so this uses Sequel's own lookup
35
+ # rather than a coincidentally similar one. A symbol the mapping does
36
+ # not recognise is left to the SQL sentinel, same as an engine this
37
+ # gem has never heard of.
38
+ def opentelemetry_attributes(payload)
39
+ name = Appsignal::OpenTelemetry::SqlDbSystem.name_for_sequel(payload[:name])
40
+ return unless name
41
+
42
+ { "db.system.name" => name }
43
+ end
20
44
  end
21
45
  end
22
46
  end
@@ -10,6 +10,11 @@ module Appsignal
10
10
  # formatter the sequel-rails events are recorded without the SQL query
11
11
  # that's being executed.
12
12
  class SqlFormatter < Appsignal::EventFormatter
13
+ # A query is an outgoing call to a datastore.
14
+ def opentelemetry_kind
15
+ :client
16
+ end
17
+
13
18
  def format(payload)
14
19
  [payload[:name].to_s, payload[:sql], SQL_BODY_FORMAT]
15
20
  end
@@ -7,11 +7,28 @@ module Appsignal
7
7
  class RenderFormatter < Appsignal::EventFormatter
8
8
  BLANK = ""
9
9
 
10
+ def opentelemetry_attributes(_payload)
11
+ Appsignal::OpenTelemetry::Rendering.attributes
12
+ end
13
+
10
14
  def format(payload)
15
+ # The body is the component's path made relative to the application's
16
+ # root, so a component rendered outside an application gets no title
17
+ # and no body.
18
+ return unless root_path
19
+
11
20
  [payload[:name], payload[:identifier].sub(root_path, BLANK)]
12
21
  end
13
22
 
23
+ # The application's root, which a component's path is made relative to.
24
+ #
25
+ # Whether there is an application is decided here, when the event is
26
+ # formatted, rather than when this file is loaded. AppSignal can be
27
+ # required before Rails is, and deciding it at load time would leave
28
+ # every component render in the application without a title.
14
29
  def root_path
30
+ return unless defined?(Rails)
31
+
15
32
  @root_path ||= "#{Rails.root}/"
16
33
  end
17
34
  end
@@ -19,13 +36,7 @@ module Appsignal
19
36
  end
20
37
  end
21
38
 
22
- if defined?(Rails)
23
- Appsignal::EventFormatter.register(
24
- "render.view_component",
25
- Appsignal::EventFormatter::ViewComponent::RenderFormatter
26
- )
27
- Appsignal::EventFormatter.register(
28
- "!render.view_component",
29
- Appsignal::EventFormatter::ViewComponent::RenderFormatter
30
- )
31
- end
39
+ Appsignal::EventFormatter.register(
40
+ "render.view_component",
41
+ Appsignal::EventFormatter::ViewComponent::RenderFormatter
42
+ )
@@ -102,8 +102,77 @@ module Appsignal
102
102
  formatter&.format(payload)
103
103
  end
104
104
 
105
+ # The OpenTelemetry span kind for an event, which its formatter can
106
+ # declare. An event with no formatter, or whose formatter declares
107
+ # nothing, has no kind of its own and falls back to the default.
108
+ #
109
+ # A formatter written against the documented interface only implements
110
+ # `format`, so ask whether this one answers to the method at all rather
111
+ # than assuming every formatter does.
112
+ #
113
+ # @!visibility private
114
+ def opentelemetry_kind(name)
115
+ formatter = formatter_for(name)
116
+ return unless formatter.respond_to?(:opentelemetry_kind)
117
+
118
+ formatter.opentelemetry_kind
119
+ end
120
+
121
+ # The OpenTelemetry attributes describing an event, which its formatter
122
+ # can build from the event's payload. An event with no formatter, or
123
+ # whose formatter describes nothing, gets no attributes of its own.
124
+ #
125
+ # @!visibility private
126
+ def opentelemetry_attributes(name, payload)
127
+ formatter = formatter_for(name)
128
+ return unless formatter.respond_to?(:opentelemetry_attributes)
129
+
130
+ formatter.opentelemetry_attributes(payload)
131
+ end
132
+
133
+ # The OpenTelemetry instrumentation scope for an event, which its
134
+ # formatter can declare. It names the library the instrumentation is for,
135
+ # which is not always the library the event arrived through.
136
+ #
137
+ # An event with no formatter, or whose formatter declares nothing, is
138
+ # left to the scope the recording path derives for it.
139
+ #
140
+ # @!visibility private
141
+ def opentelemetry_scope(name)
142
+ formatter = formatter_for(name)
143
+ return unless formatter.respond_to?(:opentelemetry_scope)
144
+
145
+ formatter.opentelemetry_scope
146
+ end
147
+
148
+ # Whether the generic instrumentation paths should record an event, which
149
+ # its formatter can answer. An event a dedicated integration already
150
+ # records says no, so that it is not recorded a second time. An event
151
+ # with no formatter, or whose formatter says nothing, is recorded.
152
+ #
153
+ # @!visibility private
154
+ def record?(name)
155
+ formatter = formatter_for(name)
156
+ return true unless formatter.respond_to?(:record?)
157
+
158
+ formatter.record?
159
+ end
160
+
105
161
  private
106
162
 
163
+ # The formatter registered for an event name.
164
+ #
165
+ # A formatter is registered under whatever key was given to `register`,
166
+ # which is a String for every formatter in this gem. An event can be
167
+ # instrumented under a Symbol name, so fall back to the String form of it.
168
+ #
169
+ # `format` does not do this, on purpose. It has always looked a name up
170
+ # exactly as given, so making it match a Symbol name would start giving a
171
+ # title to events that have never had one.
172
+ def formatter_for(name)
173
+ formatters[name] || formatters[name.to_s]
174
+ end
175
+
107
176
  def initialize_formatter(name, formatter)
108
177
  format_method = formatter.instance_method(:format)
109
178
  if !format_method || format_method.arity != 1
@@ -123,6 +192,15 @@ module Appsignal
123
192
  end
124
193
  end
125
194
 
195
+ # The title and the body to show for an event, as an array. A formatter
196
+ # that is registered to describe an event in some other way, rather than to
197
+ # name it, does not have to implement this.
198
+ #
199
+ # @!visibility private
200
+ def format(_payload)
201
+ nil
202
+ end
203
+
126
204
  # @return [Integer]
127
205
  # @api public
128
206
  DEFAULT = 0
@@ -46,6 +46,10 @@ module Appsignal
46
46
  def data_array_new
47
47
  Appsignal::Extension::MockData.new
48
48
  end
49
+
50
+ def allocation_count
51
+ 0
52
+ end
49
53
  end
50
54
  end
51
55
 
@@ -102,6 +102,18 @@ module Appsignal
102
102
  # within the block with {#set_action}.
103
103
  # This will not update the active transaction's action if
104
104
  # {.monitor} is called when another transaction is already active.
105
+ # @param opentelemetry_kind [Symbol] In collector mode, the OpenTelemetry
106
+ # span kind: one of `:server`, `:consumer`, `:producer` or `:internal`.
107
+ # Defaults to `:server`.
108
+ # @param opentelemetry_relationship [Symbol] In collector mode, how an
109
+ # incoming `opentelemetry_context` relates to this transaction's span:
110
+ # one of `:parent`, `:link`, `:both` or `:none`. Defaults to `:parent`.
111
+ # @param opentelemetry_context In collector mode, an incoming OpenTelemetry
112
+ # trace context to relate this transaction's span to.
113
+ # @param opentelemetry_scope [Array(String, String)] In collector mode, the
114
+ # OpenTelemetry instrumentation scope to record this transaction's spans
115
+ # under, given as a `[name, version]` pair. Defaults to the AppSignal
116
+ # scope.
105
117
  # @yield [] The block to monitor.
106
118
  # @yieldreturn [Object] The return value of the block
107
119
  # @raise [Exception] Any exception that occurs within the given block is
@@ -112,7 +124,14 @@ module Appsignal
112
124
  #
113
125
  # @see https://docs.appsignal.com/ruby/instrumentation/background-jobs.html
114
126
  # Monitor guide
115
- def monitor(action:, namespace: nil)
127
+ def monitor( # rubocop:disable Metrics/ParameterLists
128
+ action:,
129
+ namespace: nil,
130
+ opentelemetry_context: nil,
131
+ opentelemetry_scope: nil,
132
+ opentelemetry_kind: nil,
133
+ opentelemetry_relationship: nil
134
+ )
116
135
  return yield unless Appsignal.active?
117
136
 
118
137
  has_parent_transaction = Appsignal::Transaction.current?
@@ -133,7 +152,13 @@ module Appsignal
133
152
  if has_parent_transaction
134
153
  Appsignal::Transaction.current
135
154
  else
136
- Appsignal::Transaction.create(namespace || Appsignal::Transaction::HTTP_REQUEST)
155
+ Appsignal::Transaction.create(
156
+ namespace || Appsignal::Transaction::HTTP_REQUEST,
157
+ :opentelemetry_context => opentelemetry_context,
158
+ :opentelemetry_scope => opentelemetry_scope,
159
+ :opentelemetry_kind => opentelemetry_kind,
160
+ :opentelemetry_relationship => opentelemetry_relationship
161
+ )
137
162
  end
138
163
 
139
164
  begin
@@ -168,6 +193,18 @@ module Appsignal
168
193
  # within the block with {#set_action}.
169
194
  # This will not update the active transaction's action if
170
195
  # {.monitor} is called when another transaction is already active.
196
+ # @param opentelemetry_kind [Symbol] In collector mode, the OpenTelemetry
197
+ # span kind: one of `:server`, `:consumer`, `:producer` or `:internal`.
198
+ # Defaults to `:server`.
199
+ # @param opentelemetry_relationship [Symbol] In collector mode, how an
200
+ # incoming `opentelemetry_context` relates to this transaction's span:
201
+ # one of `:parent`, `:link`, `:both` or `:none`. Defaults to `:parent`.
202
+ # @param opentelemetry_context In collector mode, an incoming OpenTelemetry
203
+ # trace context to relate this transaction's span to.
204
+ # @param opentelemetry_scope [Array(String, String)] In collector mode, the
205
+ # OpenTelemetry instrumentation scope to record this transaction's spans
206
+ # under, given as a `[name, version]` pair. Defaults to the AppSignal
207
+ # scope.
171
208
  # @yield [] The block to monitor.
172
209
  # @yieldreturn [Object] The return value of the block
173
210
  # @raise [Exception] Any exception that occurs within the given block is
@@ -175,13 +212,29 @@ module Appsignal
175
212
  # @return [Object, nil] The value of the given block is returned.
176
213
  #
177
214
  # @see monitor
178
- def monitor_and_stop(action:, namespace: nil, &block)
215
+ def monitor_and_stop( # rubocop:disable Metrics/ParameterLists
216
+ action:,
217
+ namespace: nil,
218
+ opentelemetry_context: nil,
219
+ opentelemetry_scope: nil,
220
+ opentelemetry_kind: nil,
221
+ opentelemetry_relationship: nil,
222
+ &block
223
+ )
179
224
  Appsignal::Utils::StdoutAndLoggerMessage.warning \
180
225
  "The `Appsignal.monitor_and_stop` helper is deprecated. " \
181
226
  "Use the `Appsignal.monitor` along with our `enable_at_exit_hook` " \
182
227
  "option instead."
183
228
 
184
- monitor(:namespace => namespace, :action => action, &block)
229
+ monitor(
230
+ :namespace => namespace,
231
+ :action => action,
232
+ :opentelemetry_context => opentelemetry_context,
233
+ :opentelemetry_scope => opentelemetry_scope,
234
+ :opentelemetry_kind => opentelemetry_kind,
235
+ :opentelemetry_relationship => opentelemetry_relationship,
236
+ &block
237
+ )
185
238
  ensure
186
239
  Appsignal.stop("monitor_and_stop")
187
240
  end
@@ -218,6 +271,18 @@ module Appsignal
218
271
  #
219
272
  # @since 0.6.0
220
273
  # @param error [Exception] The error to send to AppSignal.
274
+ # @param opentelemetry_kind [Symbol] In collector mode, the OpenTelemetry
275
+ # span kind: one of `:server`, `:consumer`, `:producer` or `:internal`.
276
+ # Defaults to `:server`.
277
+ # @param opentelemetry_relationship [Symbol] In collector mode, how an
278
+ # incoming `opentelemetry_context` relates to this transaction's span:
279
+ # one of `:parent`, `:link`, `:both` or `:none`. Defaults to `:parent`.
280
+ # @param opentelemetry_context In collector mode, an incoming OpenTelemetry
281
+ # trace context to relate this transaction's span to.
282
+ # @param opentelemetry_scope [Array(String, String)] In collector mode, the
283
+ # OpenTelemetry instrumentation scope to record this transaction's spans
284
+ # under, given as a `[name, version]` pair. Defaults to the AppSignal
285
+ # scope.
221
286
  # @yield [transaction] yields block to allow modification of the
222
287
  # transaction before it's send.
223
288
  # @yieldparam transaction [Transaction] yields the AppSignal transaction
@@ -226,7 +291,14 @@ module Appsignal
226
291
  #
227
292
  # @see https://docs.appsignal.com/ruby/instrumentation/exception-handling.html
228
293
  # Exception handling guide
229
- def send_error(error, &block)
294
+ def send_error(
295
+ error,
296
+ opentelemetry_context: nil,
297
+ opentelemetry_scope: nil,
298
+ opentelemetry_kind: nil,
299
+ opentelemetry_relationship: nil,
300
+ &block
301
+ )
230
302
  return unless Appsignal.active?
231
303
 
232
304
  unless error.is_a?(Exception)
@@ -237,8 +309,14 @@ module Appsignal
237
309
  end
238
310
 
239
311
  transaction =
240
- Appsignal::Transaction.new(Appsignal::Transaction::HTTP_REQUEST)
241
- transaction.set_error(error, &block)
312
+ Appsignal::Transaction.new(
313
+ Appsignal::Transaction::HTTP_REQUEST,
314
+ :opentelemetry_context => opentelemetry_context,
315
+ :opentelemetry_scope => opentelemetry_scope,
316
+ :opentelemetry_kind => opentelemetry_kind,
317
+ :opentelemetry_relationship => opentelemetry_relationship
318
+ )
319
+ transaction.set_error(error, :source => "Appsignal.send_error", &block)
242
320
 
243
321
  transaction.complete
244
322
  end
@@ -348,6 +426,20 @@ module Appsignal
348
426
  # @since 4.0.0
349
427
  # @param exception [Exception] The error to add to the current
350
428
  # transaction.
429
+ # @param opentelemetry_kind [Symbol] In collector mode, the OpenTelemetry
430
+ # span kind: one of `:server`, `:consumer`, `:producer` or `:internal`.
431
+ # Defaults to `:server`. Only used when a new transaction is created.
432
+ # @param opentelemetry_relationship [Symbol] In collector mode, how an
433
+ # incoming `opentelemetry_context` relates to this transaction's span:
434
+ # one of `:parent`, `:link`, `:both` or `:none`. Defaults to `:parent`.
435
+ # Only used when a new transaction is created.
436
+ # @param opentelemetry_context In collector mode, an incoming OpenTelemetry
437
+ # trace context to relate this transaction's span to. Only used when a
438
+ # new transaction is created.
439
+ # @param opentelemetry_scope [Array(String, String)] In collector mode, the
440
+ # OpenTelemetry instrumentation scope to record this transaction's spans
441
+ # under, given as a `[name, version]` pair. Defaults to the AppSignal
442
+ # scope.
351
443
  # @yield [transaction] yields block to allow modification of the
352
444
  # transaction.
353
445
  # @yieldparam transaction [Transaction] yields the AppSignal transaction
@@ -356,7 +448,14 @@ module Appsignal
356
448
  #
357
449
  # @see https://docs.appsignal.com/ruby/instrumentation/exception-handling.html
358
450
  # Exception handling guide
359
- def report_error(exception, &block)
451
+ def report_error(
452
+ exception,
453
+ opentelemetry_context: nil,
454
+ opentelemetry_scope: nil,
455
+ opentelemetry_kind: nil,
456
+ opentelemetry_relationship: nil,
457
+ &block
458
+ )
360
459
  unless exception.is_a?(Exception)
361
460
  Appsignal.internal_logger.error "Appsignal.report_error: " \
362
461
  "Cannot add error. " \
@@ -370,10 +469,16 @@ module Appsignal
370
469
  if has_parent_transaction
371
470
  Appsignal::Transaction.current
372
471
  else
373
- Appsignal::Transaction.new(Appsignal::Transaction::HTTP_REQUEST)
472
+ Appsignal::Transaction.new(
473
+ Appsignal::Transaction::HTTP_REQUEST,
474
+ :opentelemetry_context => opentelemetry_context,
475
+ :opentelemetry_scope => opentelemetry_scope,
476
+ :opentelemetry_kind => opentelemetry_kind,
477
+ :opentelemetry_relationship => opentelemetry_relationship
478
+ )
374
479
  end
375
480
 
376
- transaction.add_error(exception, &block)
481
+ transaction.add_error(exception, :source => "Appsignal.report_error", &block)
377
482
 
378
483
  transaction.complete unless has_parent_transaction
379
484
  end
@@ -602,16 +707,95 @@ module Appsignal
602
707
  end
603
708
  alias set_params add_params
604
709
 
710
+ # Add the request payload to the current transaction.
711
+ #
712
+ # The request payload is the parameters of an incoming request, such as
713
+ # the query string and the request body. In collector mode it maps to its
714
+ # own attribute, separate from the function parameters.
715
+ #
716
+ # Behaves like {#add_params}: merges when called multiple times, and a
717
+ # block takes precedence over the argument.
718
+ #
719
+ # @param params [Hash<String, Object>, Array<Object>] The request payload to add to the
720
+ # transaction.
721
+ # @yield This block is called when the transaction is sampled. The block's
722
+ # return value will become the new request payload.
723
+ # @yieldreturn [Hash<String, Object>, Array<Object>]
724
+ # @return [void]
725
+ #
726
+ # @see #add_function_parameters
727
+ def add_request_payload(params = nil, &block)
728
+ return unless Appsignal.active?
729
+ return unless Appsignal::Transaction.current?
730
+
731
+ transaction = Appsignal::Transaction.current
732
+ transaction.add_request_payload(params, &block)
733
+ end
734
+
735
+ # Add the function parameters to the current transaction.
736
+ #
737
+ # The function parameters are the arguments a background job or function
738
+ # was called with. In collector mode they map to their own attribute,
739
+ # separate from the request payload.
740
+ #
741
+ # Behaves like {#add_params}: merges when called multiple times, and a
742
+ # block takes precedence over the argument.
743
+ #
744
+ # @param params [Hash<String, Object>, Array<Object>] The function parameters to add to
745
+ # the transaction.
746
+ # @yield This block is called when the transaction is sampled. The block's
747
+ # return value will become the new function parameters.
748
+ # @yieldreturn [Hash<String, Object>, Array<Object>]
749
+ # @return [void]
750
+ #
751
+ # @see #add_request_payload
752
+ def add_function_parameters(params = nil, &block)
753
+ return unless Appsignal.active?
754
+ return unless Appsignal::Transaction.current?
755
+
756
+ transaction = Appsignal::Transaction.current
757
+ transaction.add_function_parameters(params, &block)
758
+ end
759
+
760
+ # Add the query parameters to the current transaction.
761
+ #
762
+ # The query parameters are the parameters parsed from an incoming
763
+ # request's query string. In collector mode they map to their own
764
+ # attribute, separate from the request payload and the function
765
+ # parameters.
766
+ #
767
+ # Behaves like {#add_params}: merges when called multiple times, and a
768
+ # block takes precedence over the argument.
769
+ #
770
+ # @param params [Hash<String, Object>, Array<Object>] The query parameters to add to the
771
+ # transaction.
772
+ # @yield This block is called when the transaction is sampled. The block's
773
+ # return value will become the new query parameters.
774
+ # @yieldreturn [Hash<String, Object>, Array<Object>]
775
+ # @return [void]
776
+ #
777
+ # @see #add_request_payload
778
+ def add_query_parameters(params = nil, &block)
779
+ return unless Appsignal.active?
780
+ return unless Appsignal::Transaction.current?
781
+
782
+ transaction = Appsignal::Transaction.current
783
+ transaction.add_query_parameters(params, &block)
784
+ end
785
+
605
786
  # Mark the parameters sample data to be set as an empty value.
606
787
  #
607
- # Use this helper to unset request parameters / background job arguments
608
- # and not report any for this transaction.
788
+ # Use this helper to report no parameters for this transaction, whatever
789
+ # their source.
609
790
  #
610
- # If parameters would normally be added by AppSignal instrumentations of
611
- # libraries, these parameters will not be added to the Transaction.
791
+ # This suppresses every params channel. In collector mode, where the
792
+ # request payload and the function parameters (a background job's
793
+ # arguments) are tracked as separate attributes, it suppresses both, not
794
+ # only the request payload. Parameters that an AppSignal integration would
795
+ # otherwise add are not added.
612
796
  #
613
- # Calling {#add_params} after this helper will add new parameters to the
614
- # transaction.
797
+ # Calling {#add_params}, {#add_request_payload} or
798
+ # {#add_function_parameters} after this helper adds parameters again.
615
799
  #
616
800
  # @since 4.2.0
617
801
  # @return [void]
@@ -715,7 +899,7 @@ module Appsignal
715
899
  # Breadcrumbs can be used to trace what path a user has taken
716
900
  # before encountering an error.
717
901
  #
718
- # Only the last 20 added breadcrumbs will be saved.
902
+ # At most 20 of the added breadcrumbs will be saved.
719
903
  #
720
904
  # @example
721
905
  # Appsignal.add_breadcrumb(
@@ -786,6 +970,12 @@ module Appsignal
786
970
  # instrumented. Accepted values are {EventFormatter::DEFAULT} and
787
971
  # {EventFormatter::SQL_BODY_FORMAT}, but we recommend you use
788
972
  # {.instrument_sql} instead of {EventFormatter::SQL_BODY_FORMAT}.
973
+ # @param opentelemetry_kind [Symbol] In collector mode, the OpenTelemetry
974
+ # span kind for the event's span, such as `:client` for an outgoing HTTP
975
+ # request. Defaults to the OpenTelemetry default of `:internal`.
976
+ # @param opentelemetry_scope [Array(String, String)] In collector mode, the
977
+ # OpenTelemetry instrumentation scope to record the event's span under,
978
+ # given as a `[name, version]` pair. Defaults to the AppSignal scope.
789
979
  # @yield [] yields the given block of code instrumented in an AppSignal
790
980
  # event.
791
981
  # @return [Object] Returns the block's return value.
@@ -795,15 +985,25 @@ module Appsignal
795
985
  # AppSignal custom instrumentation guide
796
986
  # @see https://docs.appsignal.com/api/event-names.html
797
987
  # AppSignal event naming guide
798
- def instrument(
988
+ def instrument( # rubocop:disable Metrics/ParameterLists
799
989
  name,
800
990
  title = nil,
801
991
  body = nil,
802
992
  body_format = Appsignal::EventFormatter::DEFAULT,
993
+ opentelemetry_kind: nil,
994
+ opentelemetry_scope: nil,
803
995
  &block
804
996
  )
805
997
  Appsignal::Transaction.current
806
- .instrument(name, title, body, body_format, &block)
998
+ .instrument(
999
+ name,
1000
+ title,
1001
+ body,
1002
+ body_format,
1003
+ :opentelemetry_kind => opentelemetry_kind,
1004
+ :opentelemetry_scope => opentelemetry_scope,
1005
+ &block
1006
+ )
807
1007
  end
808
1008
 
809
1009
  # Instrumentation helper for SQL queries.
@@ -827,6 +1027,13 @@ module Appsignal
827
1027
  # naming guide listed under "See also".
828
1028
  # @param title [String, nil] Human readable name of the event.
829
1029
  # @param body [String, nil] SQL query that's being executed.
1030
+ # @param opentelemetry_kind [Symbol] In collector mode, the OpenTelemetry
1031
+ # span kind for the event's span. Defaults to `:client`, because a query
1032
+ # is an outgoing call to a datastore. Pass `:internal` for a query that
1033
+ # is not an outgoing call.
1034
+ # @param opentelemetry_scope [Array(String, String)] In collector mode, the
1035
+ # OpenTelemetry instrumentation scope to record the event's span under,
1036
+ # given as a `[name, version]` pair. Defaults to the AppSignal scope.
830
1037
  # @yield [] yields the given block of code instrumented in an AppSignal
831
1038
  # event.
832
1039
  # @return [Object] Returns the block's return value.
@@ -836,12 +1043,21 @@ module Appsignal
836
1043
  # AppSignal custom instrumentation guide
837
1044
  # @see https://docs.appsignal.com/api/event-names.html
838
1045
  # AppSignal event naming guide
839
- def instrument_sql(name, title = nil, body = nil, &block)
1046
+ def instrument_sql(
1047
+ name,
1048
+ title = nil,
1049
+ body = nil,
1050
+ opentelemetry_kind: :client,
1051
+ opentelemetry_scope: nil,
1052
+ &block
1053
+ )
840
1054
  instrument(
841
1055
  name,
842
1056
  title,
843
1057
  body,
844
1058
  Appsignal::EventFormatter::SQL_BODY_FORMAT,
1059
+ :opentelemetry_kind => opentelemetry_kind,
1060
+ :opentelemetry_scope => opentelemetry_scope,
845
1061
  &block
846
1062
  )
847
1063
  end