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

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.



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/appsignal/transaction.rb', line 75

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

  @ext = Appsignal::Extension.start_transaction(
    @transaction_id,
    @namespace,
    self.class.garbage_collection_profiler.total_time
  )
end

Instance Attribute Details

#actionObject (readonly)

Returns the value of attribute action.



61
62
63
# File 'lib/appsignal/transaction.rb', line 61

def action
  @action
end

#discardedObject (readonly)

Returns the value of attribute discarded.



61
62
63
# File 'lib/appsignal/transaction.rb', line 61

def discarded
  @discarded
end

#extObject (readonly)

Returns the value of attribute ext.



61
62
63
# File 'lib/appsignal/transaction.rb', line 61

def ext
  @ext
end

#namespaceObject (readonly)

Returns the value of attribute namespace.



61
62
63
# File 'lib/appsignal/transaction.rb', line 61

def namespace
  @namespace
end

#optionsObject (readonly)

Returns the value of attribute options.



61
62
63
# File 'lib/appsignal/transaction.rb', line 61

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)


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

attr_writer :params

#pausedObject (readonly)

Returns the value of attribute paused.



61
62
63
# File 'lib/appsignal/transaction.rb', line 61

def paused
  @paused
end

#requestObject (readonly)

Returns the value of attribute request.



61
62
63
# File 'lib/appsignal/transaction.rb', line 61

def request
  @request
end

#tagsObject (readonly)

Returns the value of attribute tags.



61
62
63
# File 'lib/appsignal/transaction.rb', line 61

def tags
  @tags
end

#transaction_idObject (readonly)

Returns the value of attribute transaction_id.



61
62
63
# File 'lib/appsignal/transaction.rb', line 61

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.



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

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

.complete_current!Object



41
42
43
44
45
46
47
# File 'lib/appsignal/transaction.rb', line 41

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



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

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

.currentObject



37
38
39
# File 'lib/appsignal/transaction.rb', line 37

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

.garbage_collection_profilerObject



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

def garbage_collection_profiler
  @garbage_collection_profiler ||=
    Appsignal.config[:enable_gc_instrumentation] ? Appsignal::GarbageCollectionProfiler.new : NilGarbageCollectionProfiler.new
end

Instance Method Details

#completeObject



98
99
100
101
102
103
104
105
106
107
108
# File 'lib/appsignal/transaction.rb', line 98

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

#discard!Object



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

def discard!
  @discarded = true
end

#discarded?Boolean

Returns:

  • (Boolean)


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

def discarded?
  @discarded == true
end

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



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

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,
    self.class.garbage_collection_profiler.total_time
  )
end

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



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

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)


94
95
96
# File 'lib/appsignal/transaction.rb', line 94

def nil_transaction?
  false
end

#pause!Object



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

def pause!
  @paused = true
end

#paused?Boolean

Returns:

  • (Boolean)


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

def paused?
  @paused == true
end

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



300
301
302
303
304
305
306
307
308
309
310
# File 'lib/appsignal/transaction.rb', line 300

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,
    self.class.garbage_collection_profiler.total_time
  )
end

#restore!Object



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

def restore!
  @discarded = false
end

#resume!Object



114
115
116
# File 'lib/appsignal/transaction.rb', line 114

def resume!
  @paused = false
end

#sample_dataObject



254
255
256
257
258
259
260
261
262
263
264
# File 'lib/appsignal/transaction.rb', line 254

def sample_data
  {
    :params       => sanitized_params,
    :environment  => sanitized_environment,
    :session_data => sanitized_session_data,
    :metadata     => ,
    :tags         => sanitized_tags
  }.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



169
170
171
172
173
# File 'lib/appsignal/transaction.rb', line 169

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



189
190
191
192
# File 'lib/appsignal/transaction.rb', line 189

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

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



266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/appsignal/transaction.rb', line 266

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,
    error.message.to_s,
    backtrace ? Appsignal::Utils::Data.generate(backtrace) : Appsignal::Extension.data_array_new
  )
end

#set_http_or_background_action(from = request.params) ⇒ Object



215
216
217
218
219
220
221
222
# File 'lib/appsignal/transaction.rb', line 215

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(group_and_action.compact.join("#"))
end

#set_http_or_background_queue_startObject



231
232
233
234
235
236
237
# File 'lib/appsignal/transaction.rb', line 231

def set_http_or_background_queue_start
  if namespace == HTTP_REQUEST
    set_queue_start(http_queue_start)
  elsif namespace == BACKGROUND_JOB
    set_queue_start(background_queue_start)
  end
end

#set_metadata(key, value) ⇒ Object



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

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_action("admin")

Parameters:

  • namespace (String)

    namespace name to use for this transaction.

Since:

  • 2.2.0



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

def set_namespace(namespace)
  return unless namespace
  @namespace = namespace
  @ext.set_namespace(namespace)
end

#set_queue_start(start) ⇒ Object



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

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



244
245
246
247
248
249
250
251
252
# File 'lib/appsignal/transaction.rb', line 244

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
  Appsignal.logger.error("Error generating data (#{e.class}: #{e.message}) for '#{data.inspect}'")
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:



155
156
157
# File 'lib/appsignal/transaction.rb', line 155

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

#start_eventObject



284
285
286
287
# File 'lib/appsignal/transaction.rb', line 284

def start_event
  return if paused?
  @ext.start_event(self.class.garbage_collection_profiler.total_time)
end

#store(key) ⇒ Object



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

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.



320
321
322
# File 'lib/appsignal/transaction.rb', line 320

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