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:



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/appsignal/transaction.rb', line 117

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
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.



101
102
103
# File 'lib/appsignal/transaction.rb', line 101

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.



110
111
112
# File 'lib/appsignal/transaction.rb', line 110

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.



110
111
112
# File 'lib/appsignal/transaction.rb', line 110

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.



110
111
112
# File 'lib/appsignal/transaction.rb', line 110

def transaction_id
  @transaction_id
end

Class Method Details

.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.



96
97
98
# File 'lib/appsignal/transaction.rb', line 96

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.



84
85
86
87
88
89
90
91
92
# File 'lib/appsignal/transaction.rb', line 84

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:



69
70
71
# File 'lib/appsignal/transaction.rb', line 69

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:



78
79
80
# File 'lib/appsignal/transaction.rb', line 78

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.



48
49
50
# File 'lib/appsignal/transaction.rb', line 48

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.



56
57
58
59
60
61
62
# File 'lib/appsignal/transaction.rb', line 56

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:



405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
# File 'lib/appsignal/transaction.rb', line 405

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



386
387
388
# File 'lib/appsignal/transaction.rb', line 386

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.



513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
# File 'lib/appsignal/transaction.rb', line 513

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



352
353
354
# File 'lib/appsignal/transaction.rb', line 352

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



372
373
374
# File 'lib/appsignal/transaction.rb', line 372

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



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

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



274
275
276
# File 'lib/appsignal/transaction.rb', line 274

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



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

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



336
337
338
# File 'lib/appsignal/transaction.rb', line 336

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



294
295
296
# File 'lib/appsignal/transaction.rb', line 294

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.



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/appsignal/transaction.rb', line 153

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
  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.



215
216
217
# File 'lib/appsignal/transaction.rb', line 215

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)


225
226
227
# File 'lib/appsignal/transaction.rb', line 225

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)


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

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.



548
549
550
551
552
553
554
555
556
557
558
# File 'lib/appsignal/transaction.rb', line 548

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.



577
578
579
580
581
582
# File 'lib/appsignal/transaction.rb', line 577

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)


148
149
150
# File 'lib/appsignal/transaction.rb', line 148

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.



200
201
202
# File 'lib/appsignal/transaction.rb', line 200

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)


210
211
212
# File 'lib/appsignal/transaction.rb', line 210

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.



562
563
564
565
566
567
568
569
570
571
572
573
# File 'lib/appsignal/transaction.rb', line 562

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.



220
221
222
# File 'lib/appsignal/transaction.rb', line 220

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.



205
206
207
# File 'lib/appsignal/transaction.rb', line 205

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



432
433
434
435
436
437
# File 'lib/appsignal/transaction.rb', line 432

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



455
456
457
458
459
# File 'lib/appsignal/transaction.rb', line 455

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.



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

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.



504
505
506
507
508
509
# File 'lib/appsignal/transaction.rb', line 504

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



480
481
482
483
484
485
# File 'lib/appsignal/transaction.rb', line 480

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.



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

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.



540
541
542
543
544
# File 'lib/appsignal/transaction.rb', line 540

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.



230
231
232
# File 'lib/appsignal/transaction.rb', line 230

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.



585
586
587
# File 'lib/appsignal/transaction.rb', line 585

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