Class: Appsignal::Transaction

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

Defined Under Namespace

Classes: GenericRequest, NilTransaction

Constant Summary collapse

HTTP_REQUEST =
"http_request".freeze
BACKGROUND_JOB =
"background_job".freeze
ACTION_CABLE =
"action_cable".freeze
FRONTEND =
"frontend".freeze
BLANK =
"".freeze
ALLOWED_TAG_KEY_TYPES =
[Symbol, String].freeze
ALLOWED_TAG_VALUE_TYPES =
[Symbol, String, Integer].freeze
20

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(transaction_id, namespace, request, options = {}) ⇒ Transaction

Returns a new instance of Transaction.



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/appsignal/transaction.rb', line 85

def initialize(transaction_id, namespace, request, options = {})
  @transaction_id = transaction_id
  @action = nil
  @namespace = namespace
  @request = request
  @paused = false
  @discarded = false
  @tags = {}
  @breadcrumbs = []
  @store = Hash.new({})
  @options = options
  @options[:params_method] ||= :params

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

Instance Attribute Details

#actionObject (readonly)

Returns the value of attribute action.



71
72
73
# File 'lib/appsignal/transaction.rb', line 71

def action
  @action
end

Returns the value of attribute breadcrumbs.



71
72
73
# File 'lib/appsignal/transaction.rb', line 71

def breadcrumbs
  @breadcrumbs
end

#discardedObject (readonly)

Returns the value of attribute discarded.



71
72
73
# File 'lib/appsignal/transaction.rb', line 71

def discarded
  @discarded
end

#extObject (readonly)

Returns the value of attribute ext.



71
72
73
# File 'lib/appsignal/transaction.rb', line 71

def ext
  @ext
end

#namespaceObject (readonly)

Returns the value of attribute namespace.



71
72
73
# File 'lib/appsignal/transaction.rb', line 71

def namespace
  @namespace
end

#optionsObject (readonly)

Returns the value of attribute options.



71
72
73
# File 'lib/appsignal/transaction.rb', line 71

def options
  @options
end

#paramsHash

Attribute for parameters of the transaction.

When no parameters are set with #params= the parameters it will look for parameters on the #request environment.

The parameters set using #params= are leading over those extracted from a request's environment.

Returns:

  • (Hash)


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

attr_writer :params

#pausedObject (readonly)

Returns the value of attribute paused.



71
72
73
# File 'lib/appsignal/transaction.rb', line 71

def paused
  @paused
end

#requestObject (readonly)

Returns the value of attribute request.



71
72
73
# File 'lib/appsignal/transaction.rb', line 71

def request
  @request
end

#tagsObject (readonly)

Returns the value of attribute tags.



71
72
73
# File 'lib/appsignal/transaction.rb', line 71

def tags
  @tags
end

#transaction_idObject (readonly)

Returns the value of attribute transaction_id.



71
72
73
# File 'lib/appsignal/transaction.rb', line 71

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.



66
67
68
# File 'lib/appsignal/transaction.rb', line 66

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

.complete_current!Object



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

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

.create(id, namespace, request, options = {}) ⇒ Object



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/appsignal/transaction.rb', line 17

def create(id, namespace, request, options = {})
  # Allow middleware to force a new transaction
  if options.include?(:force) && options[:force]
    Thread.current[:appsignal_transaction] = nil
  end

  # Check if we already have a running transaction
  if Thread.current[:appsignal_transaction].nil?
    # If not, start a new transaction
    Thread.current[:appsignal_transaction] = Appsignal::Transaction.new(id, namespace, request, options)
  else
    # Otherwise, log the issue about trying to start another transaction
    Appsignal.logger.warn_once_then_debug :transaction_id, "Trying to start new transaction with id " \
      "'#{id}', 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:



43
44
45
# File 'lib/appsignal/transaction.rb', line 43

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:



52
53
54
# File 'lib/appsignal/transaction.rb', line 52

def current?
  current && !current.nil_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 http://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 format

Options Hash (time):

  • time (Time)

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

See Also:



182
183
184
185
186
187
188
189
190
191
# File 'lib/appsignal/transaction.rb', line 182

def add_breadcrumb(category, action, message = "",  = {}, time = Time.now.utc)
  @breadcrumbs.push(
    :time => time.to_i,
    :category => category,
    :action => action,
    :message => message,
    :metadata => 
  )
  @breadcrumbs = @breadcrumbs.last(BREADCRUMB_LIMIT)
end

#completeObject



109
110
111
112
113
114
115
116
117
# File 'lib/appsignal/transaction.rb', line 109

def complete
  if discarded?
    Appsignal.logger.debug "Skipping transaction '#{transaction_id}' " \
      "because it was manually discarded."
    return
  end
  sample_data if @ext.finish(0)
  @ext.complete
end

#discard!Object



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

def discard!
  @discarded = true
end

#discarded?Boolean

Returns:

  • (Boolean)


139
140
141
# File 'lib/appsignal/transaction.rb', line 139

def discarded?
  @discarded == true
end

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



354
355
356
357
358
359
360
361
362
363
# File 'lib/appsignal/transaction.rb', line 354

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



377
378
379
380
381
382
# File 'lib/appsignal/transaction.rb', line 377

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

Returns:

  • (Boolean)


105
106
107
# File 'lib/appsignal/transaction.rb', line 105

def nil_transaction?
  false
end

#pause!Object



119
120
121
# File 'lib/appsignal/transaction.rb', line 119

def pause!
  @paused = true
end

#paused?Boolean

Returns:

  • (Boolean)


127
128
129
# File 'lib/appsignal/transaction.rb', line 127

def paused?
  @paused == true
end

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



365
366
367
368
369
370
371
372
373
374
375
# File 'lib/appsignal/transaction.rb', line 365

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



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

def restore!
  @discarded = false
end

#resume!Object



123
124
125
# File 'lib/appsignal/transaction.rb', line 123

def resume!
  @paused = false
end

#sample_dataObject



318
319
320
321
322
323
324
325
326
327
328
329
# File 'lib/appsignal/transaction.rb', line 318

def sample_data
  {
    :params       => sanitized_params,
    :environment  => sanitized_environment,
    :session_data => sanitized_session_data,
    :metadata     => ,
    :tags         => sanitized_tags,
    :breadcrumbs  => breadcrumbs
  }.each do |key, data|
    set_sample_data(key, data)
  end
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



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

def set_action(action)
  return unless action
  @action = action
  @ext.set_action(action)
end

#set_action_if_nil(action) ⇒ void

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



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

def set_action_if_nil(action)
  return if @action
  set_action(action)
end

#set_error(error) ⇒ Object Also known as: add_exception



331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
# File 'lib/appsignal/transaction.rb', line 331

def set_error(error)
  unless error.is_a?(Exception)
    Appsignal.logger.error "Appsignal::Transaction#set_error: Cannot set error. " \
      "The given value is not an exception: #{error.inspect}"
    return
  end
  return unless error
  return unless Appsignal.active?

  backtrace = cleaned_backtrace(error.backtrace)
  @ext.set_error(
    error.class.name,
    cleaned_error_message(error),
    backtrace ? Appsignal::Utils::Data.generate(backtrace) : Appsignal::Extension.data_array_new
  )
end

#set_http_or_background_action(from = request.params) ⇒ Object



249
250
251
252
253
254
255
256
# File 'lib/appsignal/transaction.rb', line 249

def set_http_or_background_action(from = request.params)
  return unless from
  group_and_action = [
    from[:controller] || from[:class],
    from[:action] || from[:method]
  ]
  set_action_if_nil(group_and_action.compact.join("#"))
end

#set_http_or_background_queue_startvoid

This method returns an undefined value.

Set the queue time based on the HTTP header or :queue_start env key value.

This method will first try to read the queue time from the HTTP headers X-Request-Start or X-Queue-Start. Which are parsed by Rack as HTTP_X_QUEUE_START and HTTP_X_REQUEST_START. The header value is parsed by AppSignal as either milliseconds or microseconds.

If no headers are found, or the value could not be parsed, it falls back on the :queue_start env key on this Transaction's #request environment (called like request.env[:queue_start]). This value is parsed by AppSignal as seconds.



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

def set_http_or_background_queue_start
  start = http_queue_start || background_queue_start
  return unless start

  set_queue_start(start)
end

#set_metadata(key, value) ⇒ Object



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

def (key, value)
  return unless key && value
  @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.

Since:

  • 2.2.0



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

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.

Most commononly called by #set_http_or_background_queue_start.

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.



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

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

#set_sample_data(key, data) ⇒ Object



303
304
305
306
307
308
309
310
311
312
313
314
315
316
# File 'lib/appsignal/transaction.rb', line 303

def set_sample_data(key, data)
  return unless key && data && (data.is_a?(Array) || data.is_a?(Hash))
  @ext.set_sample_data(
    key.to_s,
    Appsignal::Utils::Data.generate(data)
  )
rescue RuntimeError => e
  begin
    inspected_data = data.inspect
    Appsignal.logger.error("Error generating data (#{e.class}: #{e.message}) for '#{inspected_data}'")
  rescue => e
    Appsignal.logger.error("Error generating data (#{e.class}: #{e.message}). Can't inspect data.")
  end
end

#set_tags(given_tags = {}) ⇒ void

This method returns an undefined value.

Set tags on the transaction.

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:



164
165
166
# File 'lib/appsignal/transaction.rb', line 164

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

#start_eventObject



349
350
351
352
# File 'lib/appsignal/transaction.rb', line 349

def start_event
  return if paused?
  @ext.start_event(0)
end

#store(key) ⇒ Object



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

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.



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

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