Class: Appsignal::Transaction

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

Defined Under Namespace

Classes: Formatter, ParamsSanitizer

Constant Summary collapse

ENV_METHODS =

Based on what Rails uses + some variables we’d like to show

%w(CONTENT_LENGTH AUTH_TYPE GATEWAY_INTERFACE
PATH_TRANSLATED REMOTE_HOST REMOTE_IDENT REMOTE_USER REMOTE_ADDR
REQUEST_METHOD SERVER_NAME SERVER_PORT SERVER_PROTOCOL REQUEST_URI PATH_INFO

HTTP_X_REQUEST_START HTTP_X_MIDDLEWARE_START HTTP_X_QUEUE_START
HTTP_X_QUEUE_TIME HTTP_X_HEROKU_QUEUE_WAIT_TIME HTTP_X_APPLICATION_START
HTTP_ACCEPT HTTP_ACCEPT_CHARSET HTTP_ACCEPT_ENCODING HTTP_ACCEPT_LANGUAGE
HTTP_CACHE_CONTROL HTTP_CONNECTION HTTP_USER_AGENT HTTP_FROM HTTP_NEGOTIATE
HTTP_PRAGMA HTTP_REFERER HTTP_X_FORWARDED_FOR HTTP_CLIENT_IP).freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(request_id, env) ⇒ Transaction

Returns a new instance of Transaction.



36
37
38
39
40
41
42
43
44
45
# File 'lib/appsignal/transaction.rb', line 36

def initialize(request_id, env)
  Appsignal.transactions[request_id] = self
  @request_id = request_id
  @events = []
  @process_action_event = nil
  @exception = nil
  @env = env
  @tags = {}
  @paused = false
end

Instance Attribute Details

#actionObject (readonly)

Returns the value of attribute action.



33
34
35
# File 'lib/appsignal/transaction.rb', line 33

def action
  @action
end

#envObject (readonly)

Returns the value of attribute env.



33
34
35
# File 'lib/appsignal/transaction.rb', line 33

def env
  @env
end

#eventsObject (readonly)

Returns the value of attribute events.



33
34
35
# File 'lib/appsignal/transaction.rb', line 33

def events
  @events
end

#exceptionObject (readonly)

Returns the value of attribute exception.



33
34
35
# File 'lib/appsignal/transaction.rb', line 33

def exception
  @exception
end

#fullpathObject (readonly)

Returns the value of attribute fullpath.



33
34
35
# File 'lib/appsignal/transaction.rb', line 33

def fullpath
  @fullpath
end

#kindObject (readonly)

Returns the value of attribute kind.



33
34
35
# File 'lib/appsignal/transaction.rb', line 33

def kind
  @kind
end

#pausedObject (readonly)

Returns the value of attribute paused.



33
34
35
# File 'lib/appsignal/transaction.rb', line 33

def paused
  @paused
end

#process_action_eventObject (readonly)

Returns the value of attribute process_action_event.



33
34
35
# File 'lib/appsignal/transaction.rb', line 33

def process_action_event
  @process_action_event
end

#queue_startObject (readonly)

Returns the value of attribute queue_start.



33
34
35
# File 'lib/appsignal/transaction.rb', line 33

def queue_start
  @queue_start
end

#request_idObject (readonly)

Returns the value of attribute request_id.



33
34
35
# File 'lib/appsignal/transaction.rb', line 33

def request_id
  @request_id
end

#tagsObject (readonly)

Returns the value of attribute tags.



33
34
35
# File 'lib/appsignal/transaction.rb', line 33

def tags
  @tags
end

#timeObject (readonly)

Returns the value of attribute time.



33
34
35
# File 'lib/appsignal/transaction.rb', line 33

def time
  @time
end

Class Method Details

.complete_current!Object



24
25
26
27
28
29
30
31
# File 'lib/appsignal/transaction.rb', line 24

def self.complete_current!
  if current
    current.complete!
    Thread.current[:appsignal_transaction_id] = nil
  else
    Appsignal.logger.error('Trying to complete current, but no transaction present')
  end
end

.create(request_id, env) ⇒ Object



14
15
16
17
18
# File 'lib/appsignal/transaction.rb', line 14

def self.create(request_id, env)
  Appsignal.logger.debug("Creating transaction: #{request_id}")
  Thread.current[:appsignal_transaction_id] = request_id
  Appsignal::Transaction.new(request_id, env)
end

.currentObject



20
21
22
# File 'lib/appsignal/transaction.rb', line 20

def self.current
  Appsignal.transactions[Thread.current[:appsignal_transaction_id]]
end

Instance Method Details

#add_event(event) ⇒ Object



87
88
89
# File 'lib/appsignal/transaction.rb', line 87

def add_event(event)
  @events << event unless @paused == true
end

#add_exception(ex) ⇒ Object



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

def add_exception(ex)
  @time = Time.now.utc.to_f
  @exception = ex
end

#clear_events!Object



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

def clear_events!
  events.clear
end

#complete!Object



150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/appsignal/transaction.rb', line 150

def complete!
  Thread.current[:appsignal_transaction_id] = nil
  Appsignal.transactions.delete(@request_id)
  if process_action_event || exception?
    if Appsignal::IPC::Client.active?
      convert_values_to_primitives!
      Appsignal::IPC::Client.enqueue(self)
    else
      Appsignal.logger.debug("Enqueueing transaction: #{@request_id}")
      Appsignal.enqueue(self)
    end
  else
    Appsignal.logger.debug("Not processing transaction: #{@request_id} (#{events.length} events recorded)")
  end
ensure
  Appsignal.transactions.delete(@request_id)
end

#convert_values_to_primitives!Object



128
129
130
131
132
133
134
# File 'lib/appsignal/transaction.rb', line 128

def convert_values_to_primitives!
  return if have_values_been_converted_to_primitives?
  @process_action_event.sanitize! if @process_action_event
  @events.each { |event| event.sanitize! }
  add_sanitized_context!
  @have_values_been_converted_to_primitives = true
end

#exception?Boolean

Returns:

  • (Boolean)


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

def exception?
  !! exception
end

#have_values_been_converted_to_primitives?Boolean

Returns:

  • (Boolean)


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

def have_values_been_converted_to_primitives?
  !! @have_values_been_converted_to_primitives
end

#pause!Object



63
64
65
# File 'lib/appsignal/transaction.rb', line 63

def pause!
  @paused = true
end

#requestObject



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

def request
  ::Rack::Request.new(@env)
end

#resume!Object



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

def resume!
  @paused = false
end

#sanitized_environmentObject



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

def sanitized_environment
  @sanitized_environment ||= {}
end

#sanitized_session_dataObject



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

def sanitized_session_data
  @sanitized_session_data ||= {}
end

#set_background_queue_startObject



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

def set_background_queue_start
  queue_start = process_action_event.payload[:queue_start]
  return unless queue_start
  Appsignal.logger.debug("Setting background queue start: #{queue_start}")
  @queue_start = queue_start.to_f
end

#set_http_queue_startObject



175
176
177
178
179
180
181
182
183
184
185
# File 'lib/appsignal/transaction.rb', line 175

def set_http_queue_start
  return unless env
  env_var = env['HTTP_X_QUEUE_START'] || env['HTTP_X_REQUEST_START']
  if env_var
    Appsignal.logger.debug("Setting http queue start: #{env_var}")
    value = env_var.tr('^0-9', '')
    unless value.empty?
      @queue_start = value.to_f / 1000.0
    end
  end
end

#set_perform_job_event(event) ⇒ Object



79
80
81
82
83
84
85
# File 'lib/appsignal/transaction.rb', line 79

def set_perform_job_event(event)
  return unless event && event.payload
  @process_action_event = event.dup
  @action = "#{@process_action_event.payload[:class]}##{@process_action_event.payload[:method]}"
  @kind = 'background_job'
  set_background_queue_start
end

#set_process_action_event(event) ⇒ Object



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

def set_process_action_event(event)
  return unless event && event.payload
  @process_action_event = event.dup
  @action = "#{@process_action_event.payload[:controller]}##{@process_action_event.payload[:action]}"
  @kind = 'http_request'
  set_http_queue_start
end

#set_tags(given_tags = {}) ⇒ Object



59
60
61
# File 'lib/appsignal/transaction.rb', line 59

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

#slow_request?Boolean

Returns:

  • (Boolean)


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

def slow_request?
  return false unless process_action_event && process_action_event.payload
  Appsignal.config[:slow_request_threshold] <= process_action_event.duration
end

#slower?(transaction) ⇒ Boolean

Returns:

  • (Boolean)


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

def slower?(transaction)
  process_action_event.duration > transaction.process_action_event.duration
end

#to_hashObject



146
147
148
# File 'lib/appsignal/transaction.rb', line 146

def to_hash
  Formatter.new(self).to_hash
end

#truncate!Object



113
114
115
116
117
118
119
120
121
122
# File 'lib/appsignal/transaction.rb', line 113

def truncate!
  return if truncated?
  process_action_event.truncate!
  events.clear
  tags.clear
  sanitized_environment.clear
  sanitized_session_data.clear
  @env = nil
  @truncated = true
end

#truncated?Boolean

Returns:

  • (Boolean)


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

def truncated?
  !! @truncated
end

#typeObject



140
141
142
143
144
# File 'lib/appsignal/transaction.rb', line 140

def type
  return :exception if exception?
  return :slow_request if slow_request?
  :regular_request
end