Class: Appsignal::Transaction

Inherits:
Object
  • Object
show all
Defined in:
lib/appsignal/transaction.rb

Defined Under Namespace

Classes: NilTransaction

Constant Summary collapse

HTTP_REQUEST =
"http_request"
BACKGROUND_JOB =
"background_job"
ACTION_CABLE =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

"action_cable"
BLANK =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

""
ALLOWED_TAG_KEY_TYPES =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

[Symbol, String].freeze
ALLOWED_TAG_VALUE_TYPES =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

[Symbol, String, Integer, TrueClass, FalseClass].freeze
20
ERROR_CAUSES_LIMIT =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

10
ERRORS_LIMIT =
10

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(namespace, id: SecureRandom.uuid, ext: nil) ⇒ Transaction

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Use create to create new transactions.

Parameters:

  • namespace (String)

    Namespace of the to be created transaction.

See Also:



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/appsignal/transaction.rb', line 151

def initialize(namespace, id: SecureRandom.uuid, ext: nil)
  @transaction_id = id
  @action = nil
  @namespace = namespace
  @paused = false
  @discarded = false
  @tags = {}
  @breadcrumbs = []
  @store = Hash.new { |hash, key| hash[key] = {} }
  @error_blocks = Hash.new { |hash, key| hash[key] = [] }
  @is_duplicate = false
  @error_set = nil

  @params = Appsignal::SampleData.new(:params)
  @session_data = Appsignal::SampleData.new(:session_data, Hash)
  @headers = Appsignal::SampleData.new(:headers, Hash)
  @custom_data = Appsignal::SampleData.new(:custom_data)

  @ext = ext || Appsignal::Extension.start_transaction(
    @transaction_id,
    @namespace,
    0
  ) || Appsignal::Extension::MockTransaction.new

  run_after_create_hooks
end

Class Attribute Details

.last_errorsObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



135
136
137
# File 'lib/appsignal/transaction.rb', line 135

def last_errors
  @last_errors ||= []
end

Instance Attribute Details

#actionObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



144
145
146
# File 'lib/appsignal/transaction.rb', line 144

def action
  @action
end

#namespaceObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



144
145
146
# File 'lib/appsignal/transaction.rb', line 144

def namespace
  @namespace
end

#transaction_idObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



144
145
146
# File 'lib/appsignal/transaction.rb', line 144

def transaction_id
  @transaction_id
end

Class Method Details

.after_create(&block) ⇒ Array<Proc>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Add a block, if given, to be executed after a transaction is created. The block will be called with the transaction as an argument. Returns the array of blocks that will be executed after a transaction is created.

Returns:

  • (Array<Proc>)


53
54
55
56
57
58
59
# File 'lib/appsignal/transaction.rb', line 53

def after_create(&block)
  @after_create ||= Set.new

  return @after_create if block.nil?

  @after_create << block
end

.before_complete(&block) ⇒ Array<Proc>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Add a block, if given, to be executed before a transaction is completed. This happens after duplicating the transaction for each error that was reported in the transaction – that is, when a transaction with several errors is completed, the block will be called once for each error, with the transaction (either the original one or a duplicate of it) that has each of the errors set. The block will be called with the transaction as the first argument, and the error reported by the transaction, if any, as the second argument. Returns the array of blocks that will be executed before a transaction is completed.

Returns:

  • (Array<Proc>)


73
74
75
76
77
78
79
# File 'lib/appsignal/transaction.rb', line 73

def before_complete(&block)
  @before_complete ||= Set.new

  return @before_complete if block.nil?

  @before_complete << block
end

.clear_current_transaction!Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Remove current transaction from current Thread.



130
131
132
# File 'lib/appsignal/transaction.rb', line 130

def clear_current_transaction!
  Thread.current[:appsignal_transaction] = nil
end

.complete_current!Object

Complete the currently active transaction and unset it as the active transaction.



118
119
120
121
122
123
124
125
126
# File 'lib/appsignal/transaction.rb', line 118

def complete_current!
  current.complete
rescue => e
  Appsignal.internal_logger.error(
    "Failed to complete transaction ##{current.transaction_id}. #{e.message}"
  )
ensure
  clear_current_transaction!
end

.create(namespace) ⇒ Transaction

Create a new transaction and set it as the currently active transaction.

Parameters:

  • namespace (String)

    Namespace of the to be created transaction.

Returns:



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/appsignal/transaction.rb', line 29

def create(namespace)
  # Check if we already have a running transaction
  if Thread.current[:appsignal_transaction].nil?
    # If not, start a new transaction
    set_current_transaction(Appsignal::Transaction.new(namespace))
  else
    # Otherwise, log the issue about trying to start another transaction
    Appsignal.internal_logger.warn(
      "Trying to start new transaction, but a transaction " \
        "with id '#{current.transaction_id}' is already running. " \
        "Using transaction '#{current.transaction_id}'."
    )

    # And return the current transaction instead
    current
  end
end

.currentBoolean

Returns currently active transaction or a NilTransaction if none is active.

Returns:

  • (Boolean)

See Also:



103
104
105
# File 'lib/appsignal/transaction.rb', line 103

def current
  Thread.current[:appsignal_transaction] || NilTransaction.new
end

.current?Boolean

Returns if any transaction is currently active or not. A NilTransaction is not considered an active transaction.

Returns:

  • (Boolean)

See Also:



112
113
114
# File 'lib/appsignal/transaction.rb', line 112

def current?
  current && !current.nil_transaction?
end

.set_current_transaction(transaction) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



82
83
84
# File 'lib/appsignal/transaction.rb', line 82

def set_current_transaction(transaction)
  Thread.current[:appsignal_transaction] = transaction
end

.with_transaction(transaction) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Set the current for the duration of the given block. It restores the original transaction (if any) when the block has executed.



90
91
92
93
94
95
96
# File 'lib/appsignal/transaction.rb', line 90

def with_transaction(transaction)
  original_transaction = current if current?
  set_current_transaction(transaction)
  yield
ensure
  set_current_transaction(original_transaction)
end

Instance Method Details

#add_breadcrumb(category, action, message = "", metadata = {}, time = Time.now.utc) ⇒ void

This method returns an undefined value.

Add breadcrumbs to the transaction.

Parameters:

  • category (String)

    category of breadcrumb e.g. “UI”, “Network”, “Navigation”, “Console”.

  • action (String)

    name of breadcrumb e.g “The user clicked a button”, “HTTP 500 from blablabla.com

  • message (Hash) (defaults to: "")

    a customizable set of options

  • metadata (Hash) (defaults to: {})

    a customizable set of options

  • time (Hash) (defaults to: Time.now.utc)

    a customizable set of options

Options Hash (message):

  • optional (String)

    message in string format

Options Hash (metadata):

  • key/value (Hash<String,String>)

    metadata in <string, string> format

Options Hash (time):

  • time (Time)

    of breadcrumb, should respond to ‘.to_i` defaults to `Time.now.utc`

See Also:



445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
# File 'lib/appsignal/transaction.rb', line 445

def add_breadcrumb(category, action, message = "",  = {}, time = Time.now.utc)
  unless .is_a? Hash
    Appsignal.internal_logger.error "add_breadcrumb: Cannot add breadcrumb. " \
      "The given metadata argument is not a Hash."
    return
  end

  @breadcrumbs.push(
    :time => time.to_i,
    :category => category,
    :action => action,
    :message => message,
    :metadata => 
  )
  @breadcrumbs = @breadcrumbs.last(BREADCRUMB_LIMIT)
end

#add_custom_data(data) ⇒ void Also known as: set_custom_data

This method returns an undefined value.

Add custom data to the transaction.

Parameters:

  • data (Hash/Array)

See Also:

Since:

  • 4.0.0



426
427
428
# File 'lib/appsignal/transaction.rb', line 426

def add_custom_data(data)
  @custom_data.add(data)
end

#add_error(error, &block) ⇒ Object Also known as: set_error, add_exception

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
# File 'lib/appsignal/transaction.rb', line 553

def add_error(error, &block)
  unless error.is_a?(Exception)
    Appsignal.internal_logger.error "Appsignal::Transaction#add_error: Cannot add error. " \
      "The given value is not an exception: #{error.inspect}"
    return
  end

  return unless error
  return unless Appsignal.active?

  _set_error(error) if @error_blocks.empty?

  if !@error_blocks.include?(error) && @error_blocks.length >= ERRORS_LIMIT
    Appsignal.internal_logger.warn "Appsignal::Transaction#add_error: Transaction has more " \
      "than #{ERRORS_LIMIT} distinct errors. Only the first " \
      "#{ERRORS_LIMIT} distinct errors will be reported."
    return
  end

  @error_blocks[error] << block
  @error_blocks[error].compact!
end

#add_headers(given_headers = nil) { ... } ⇒ void Also known as: set_headers

This method returns an undefined value.

Add headers to the transaction.

Parameters:

  • given_headers (Hash) (defaults to: nil)

    A hash containing headers.

Yields:

  • This block is called when the transaction is sampled. The block’s return value will become the new headers.

See Also:

Since:

  • 4.0.0



392
393
394
# File 'lib/appsignal/transaction.rb', line 392

def add_headers(given_headers = nil, &block)
  @headers.add(given_headers, &block)
end

#add_headers_if_nil(given_headers = nil) { ... } ⇒ void Also known as: set_headers_if_nil

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This method returns an undefined value.

Add headers to the transaction if not already set.

When both the ‘given_headers` and a block is given to this method, the block is leading and the argument will not be used.

Parameters:

  • given_headers (Hash) (defaults to: nil)

    A hash containing headers.

Yields:

  • This block is called when the transaction is sampled. The block’s return value will become the new headers.

See Also:

Since:

  • 4.0.0



412
413
414
# File 'lib/appsignal/transaction.rb', line 412

def add_headers_if_nil(given_headers = nil, &block)
  add_headers(given_headers, &block) unless @headers.value?
end

#add_params(given_params = nil) { ... } ⇒ void Also known as: set_params

This method returns an undefined value.

Add parameters to the transaction.

When this method is called multiple times, it will merge the request parameters.

When both the ‘given_params` and a block is given to this method, the block is leading and the argument will not be used.

Parameters:

  • given_params (Hash) (defaults to: nil)

    The parameters to set on the transaction.

Yields:

  • This block is called when the transaction is sampled. The block’s return value will become the new parameters.

See Also:

Since:

  • 4.0.0



290
291
292
# File 'lib/appsignal/transaction.rb', line 290

def add_params(given_params = nil, &block)
  @params.add(given_params, &block)
end

#add_params_if_nil(given_params = nil) { ... } ⇒ void Also known as: set_params_if_nil

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This method returns an undefined value.

Add parameters to the transaction if not already set.

Parameters:

  • given_params (Hash) (defaults to: nil)

    The parameters to set on the transaction if none are already set.

Yields:

  • This block is called when the transaction is sampled. The block’s return value will become the new parameters.

See Also:

Since:

  • 4.0.0



314
315
316
# File 'lib/appsignal/transaction.rb', line 314

def add_params_if_nil(given_params = nil, &block)
  add_params(given_params, &block) if !@params.value? && !@params.empty?
end

#add_session_data(given_session_data = nil) { ... } ⇒ void Also known as: set_session_data

This method returns an undefined value.

Add session data to the transaction.

When this method is called multiple times, it will merge the session data.

When both the ‘given_session_data` and a block is given to this method, the block is leading and the argument will not be used.

Parameters:

  • given_session_data (Hash) (defaults to: nil)

    A hash containing session data.

Yields:

  • This block is called when the transaction is sampled. The block’s return value will become the new session data.

See Also:

Since:

  • 4.0.0



355
356
357
# File 'lib/appsignal/transaction.rb', line 355

def add_session_data(given_session_data = nil, &block)
  @session_data.add(given_session_data, &block)
end

#add_session_data_if_nil(given_session_data = nil) { ... } ⇒ void Also known as: set_session_data_if_nil

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This method returns an undefined value.

Set session data on the transaction if not already set.

When both the ‘given_session_data` and a block is given to this method, the `given_session_data` argument is leading and the block will not be called.

Parameters:

  • given_session_data (Hash) (defaults to: nil)

    A hash containing session data.

Yields:

  • This block is called when the transaction is sampled. The block’s return value will become the new session data.

See Also:

Since:

  • 4.0.0



376
377
378
# File 'lib/appsignal/transaction.rb', line 376

def add_session_data_if_nil(given_session_data = nil, &block)
  add_session_data(given_session_data, &block) unless @session_data.value?
end

#add_tags(given_tags = {}) ⇒ void Also known as: set_tags

This method returns an undefined value.

Add tags to the transaction.

When this method is called multiple times, it will merge the tags.

Parameters:

  • given_tags (Hash) (defaults to: {})

    Collection of tags.

Options Hash (given_tags):

  • :any (String, Symbol, Integer)

    The name of the tag as a Symbol.

  • "any" (String, Symbol, Integer)

    The name of the tag as a String.

See Also:

Since:

  • 4.0.0



334
335
336
# File 'lib/appsignal/transaction.rb', line 334

def add_tags(given_tags = {})
  @tags.merge!(given_tags)
end

#completeObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# File 'lib/appsignal/transaction.rb', line 189

def complete
  if discarded?
    Appsignal.internal_logger.debug "Skipping transaction '#{transaction_id}' " \
      "because it was manually discarded."
    return
  end

  # If the transaction is a duplicate, we don't want to finish it,
  # because we want its finish time to be the finish time of the
  # original transaction.
  # Duplicate transactions should always be sampled, as we only
  # create duplicates for errors, which are always sampled.
  should_sample = true

  unless duplicate?
    self.class.last_errors = @error_blocks.keys
    should_sample = @ext.finish(0)
  end

  @error_blocks.each do |error, blocks|
    # Ignore the error that is already set in this transaction.
    next if error == @error_set

    duplicate.tap do |transaction|
      # In the duplicate transaction for each error, set an error
      # with a block that calls all the blocks set for that error
      # in the original transaction.
      transaction.set_error(error) do
        blocks.each { |block| block.call(transaction) }
      end

      transaction.complete
    end
  end

  if @error_set && @error_blocks[@error_set].any?
    self.class.with_transaction(self) do
      @error_blocks[@error_set].each do |block|
        block.call(self)
      end
    end
  end

  run_before_complete_hooks

  sample_data if should_sample

  @ext.complete
end

#discard!Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



255
256
257
# File 'lib/appsignal/transaction.rb', line 255

def discard!
  @discarded = true
end

#discarded?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)


265
266
267
# File 'lib/appsignal/transaction.rb', line 265

def discarded?
  @discarded == true
end

#duplicate?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)


179
180
181
# File 'lib/appsignal/transaction.rb', line 179

def duplicate?
  @is_duplicate
end

#finish_event(name, title, body, body_format = Appsignal::EventFormatter::DEFAULT) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



588
589
590
591
592
593
594
595
596
597
598
# File 'lib/appsignal/transaction.rb', line 588

def finish_event(name, title, body, body_format = Appsignal::EventFormatter::DEFAULT)
  return if paused?

  @ext.finish_event(
    name,
    title || BLANK,
    body || BLANK,
    body_format || Appsignal::EventFormatter::DEFAULT,
    0
  )
end

#instrument(name, title = nil, body = nil, body_format = Appsignal::EventFormatter::DEFAULT) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



617
618
619
620
621
622
# File 'lib/appsignal/transaction.rb', line 617

def instrument(name, title = nil, body = nil, body_format = Appsignal::EventFormatter::DEFAULT)
  start_event
  yield if block_given?
ensure
  finish_event(name, title, body, body_format)
end

#nil_transaction?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)


184
185
186
# File 'lib/appsignal/transaction.rb', line 184

def nil_transaction?
  false
end

#pause!Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



240
241
242
# File 'lib/appsignal/transaction.rb', line 240

def pause!
  @paused = true
end

#paused?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)


250
251
252
# File 'lib/appsignal/transaction.rb', line 250

def paused?
  @paused == true
end

#record_event(name, title, body, duration, body_format = Appsignal::EventFormatter::DEFAULT) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



602
603
604
605
606
607
608
609
610
611
612
613
# File 'lib/appsignal/transaction.rb', line 602

def record_event(name, title, body, duration, body_format = Appsignal::EventFormatter::DEFAULT)
  return if paused?

  @ext.record_event(
    name,
    title || BLANK,
    body || BLANK,
    body_format || Appsignal::EventFormatter::DEFAULT,
    duration,
    0
  )
end

#restore!Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



260
261
262
# File 'lib/appsignal/transaction.rb', line 260

def restore!
  @discarded = false
end

#resume!Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



245
246
247
# File 'lib/appsignal/transaction.rb', line 245

def resume!
  @paused = false
end

#set_action(action) ⇒ void

This method returns an undefined value.

Set an action name for the transaction.

An action name is used to identify the location of a certain sample; error and performance issues.

Parameters:

  • action (String)

    the action name to set.

See Also:

Since:

  • 2.2.0



472
473
474
475
476
477
# File 'lib/appsignal/transaction.rb', line 472

def set_action(action)
  return unless action

  @action = action
  @ext.set_action(action)
end

#set_action_if_nil(action) ⇒ void

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This method returns an undefined value.

Set an action name only if there is no current action set.

Commonly used by AppSignal integrations so that they don’t override custom action names.

Examples:

Appsignal.set_action("foo")
Appsignal.set_action_if_nil("bar")
# Transaction action will be "foo"

Parameters:

  • action (String)

See Also:

Since:

  • 2.2.0



495
496
497
498
499
# File 'lib/appsignal/transaction.rb', line 495

def set_action_if_nil(action)
  return if @action

  set_action(action)
end

#set_empty_params!void

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This method returns an undefined value.



300
301
302
# File 'lib/appsignal/transaction.rb', line 300

def set_empty_params!
  @params.set_empty_value!
end

#set_metadata(key, value) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



544
545
546
547
548
549
# File 'lib/appsignal/transaction.rb', line 544

def (key, value)
  return unless key && value
  return if Appsignal.config[:filter_metadata].include?(key.to_s)

  @ext.(key, value)
end

#set_namespace(namespace) ⇒ void

This method returns an undefined value.

Set the namespace for this transaction.

Useful to split up parts of an application into certain namespaces. For example: http requests, background jobs and administration panel controllers.

Note: The “http_request” namespace gets transformed on AppSignal.com to “Web” and “background_job” gets transformed to “Background”.

Examples:

transaction.set_namespace("background")

Parameters:

  • namespace (String)

    namespace name to use for this transaction.

See Also:

Since:

  • 2.2.0



520
521
522
523
524
525
# File 'lib/appsignal/transaction.rb', line 520

def set_namespace(namespace)
  return unless namespace

  @namespace = namespace
  @ext.set_namespace(namespace)
end

#set_queue_start(start) ⇒ void

This method returns an undefined value.

Set queue start time for transaction.

Parameters:

  • start (Integer)

    Queue start time in milliseconds.

Raises:

  • (RangeError)

    When the queue start time value is too big, this method raises a RangeError.

  • (TypeError)

    Raises a TypeError when the given ‘start` argument is not an Integer.



535
536
537
538
539
540
541
# File 'lib/appsignal/transaction.rb', line 535

def set_queue_start(start)
  return unless start

  @ext.set_queue_start(start)
rescue RangeError
  Appsignal.internal_logger.warn("Queue start value #{start} is too big")
end

#start_eventObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



580
581
582
583
584
# File 'lib/appsignal/transaction.rb', line 580

def start_event
  return if paused?

  @ext.start_event(0)
end

#store(key) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



270
271
272
# File 'lib/appsignal/transaction.rb', line 270

def store(key)
  @store[key]
end

#to_hObject Also known as: to_hash

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



625
626
627
# File 'lib/appsignal/transaction.rb', line 625

def to_h
  JSON.parse(@ext.to_json)
end