Class: Rollbar::Item

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/rollbar/item.rb,
lib/rollbar/item/frame.rb,
lib/rollbar/item/locals.rb,
lib/rollbar/item/backtrace.rb

Overview

This class represents the payload to be sent to the API. It contains the logic to build the payload, trucante it and dump the JSON.

Defined Under Namespace

Classes: Backtrace, Frame, Locals

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options) ⇒ Item

Returns a new instance of Item.



39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/rollbar/item.rb', line 39

def initialize(options)
  @level = options[:level]
  @message = options[:message]
  @exception = options[:exception]
  @extra = options[:extra]
  @configuration = options[:configuration]
  @logger = options[:logger]
  @scope = options[:scope]
  @payload = nil
  @notifier = options[:notifier]
  @context = options[:context]
end

Instance Attribute Details

#configurationObject (readonly)

Returns the value of attribute configuration.



26
27
28
# File 'lib/rollbar/item.rb', line 26

def configuration
  @configuration
end

#contextObject (readonly)

Returns the value of attribute context.



26
27
28
# File 'lib/rollbar/item.rb', line 26

def context
  @context
end

#exceptionObject (readonly)

Returns the value of attribute exception.



26
27
28
# File 'lib/rollbar/item.rb', line 26

def exception
  @exception
end

#extraObject (readonly)

Returns the value of attribute extra.



26
27
28
# File 'lib/rollbar/item.rb', line 26

def extra
  @extra
end

#levelObject (readonly)

Returns the value of attribute level.



26
27
28
# File 'lib/rollbar/item.rb', line 26

def level
  @level
end

#loggerObject (readonly)

Returns the value of attribute logger.



26
27
28
# File 'lib/rollbar/item.rb', line 26

def logger
  @logger
end

#messageObject (readonly)

Returns the value of attribute message.



26
27
28
# File 'lib/rollbar/item.rb', line 26

def message
  @message
end

#notifierObject (readonly)

Returns the value of attribute notifier.



26
27
28
# File 'lib/rollbar/item.rb', line 26

def notifier
  @notifier
end

#payloadObject



52
53
54
# File 'lib/rollbar/item.rb', line 52

def payload
  @payload ||= build
end

#scopeObject (readonly)

Returns the value of attribute scope.



26
27
28
# File 'lib/rollbar/item.rb', line 26

def scope
  @scope
end

Class Method Details

.build_with(payload, options = {}) ⇒ Object



32
33
34
35
36
# File 'lib/rollbar/item.rb', line 32

def build_with(payload, options = {})
  new(options).tap do |item|
    item.payload = item.add_access_token_to_payload(payload)
  end
end

Instance Method Details

#add_access_token_to_payload(payload) ⇒ Object



174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/rollbar/item.rb', line 174

def add_access_token_to_payload(payload)
  # Some use cases remain where the token is needed in the payload. For example:
  #
  # When using async senders, if the access token is changed dynamically in
  # the main process config, the sender process won't see that change.
  #
  # Until the delayed sender interface is changed to allow passing dynamic
  # config options, this workaround allows the main process to set the token
  # by adding it to the payload.
  if configuration && configuration.use_payload_access_token
    payload['access_token'] ||= configuration.access_token
  end

  payload
end

#buildObject



56
57
58
59
60
61
62
63
# File 'lib/rollbar/item.rb', line 56

def build
  data = build_data
  self.payload = add_access_token_to_payload({ 'data' => data })

  enforce_valid_utf8
  transform
  payload
end

#build_dataObject



65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/rollbar/item.rb', line 65

def build_data
  data = initial_data

  build_optional_data(data)

  Util.deep_merge(data, configuration.payload_options)
  Util.deep_merge(data, scope)

  # Our API doesn't allow null context values, so just delete
  # the key if value is nil.
  data.delete(:context) unless data[:context]

  data
end

#build_optional_data(data) ⇒ Object



97
98
99
100
101
102
103
104
105
106
107
# File 'lib/rollbar/item.rb', line 97

def build_optional_data(data)
  if configuration.project_gem_paths.any?
    data[:project_package_paths] = configuration.project_gem_paths
  end

  data[:code_version] = configuration.code_version if configuration.code_version

  return unless defined?(SecureRandom) && SecureRandom.respond_to?(:uuid)

  data[:uuid] = SecureRandom.uuid
end

#configured_optionsObject



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/rollbar/item.rb', line 109

def configured_options
  if Gem.loaded_specs['activesupport'] &&
     Gem.loaded_specs['activesupport'].version < Gem::Version.new('4.1')
    # There are too many types that crash ActiveSupport JSON serialization,
    # and not worth the risk just to send this diagnostic object.
    # In versions < 4.1, ActiveSupport hooks Ruby's JSON.generate so deeply
    # that there's no workaround.
    'not serialized in ActiveSupport < 4.1'
  elsif configuration.use_async && !configuration.async_json_payload
    # The setting allows serialization to be performed by each handler,
    # and this usually means it is actually performed by ActiveSupport,
    # which cannot safely serialize this key.
    'not serialized when async_json_payload is not set'
  else
    scrub(configuration.configured_options.configured)
  end
end

#dumpObject



127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/rollbar/item.rb', line 127

def dump
  # Ensure all keys are strings since we can receive the payload inline or
  # from an async handler job, which can be serialized.
  stringified_payload = Util::Hash.deep_stringify_keys(payload)
  attempts = []
  result = Truncation.truncate(stringified_payload, attempts)

  return result unless Truncation.truncate?(result)

  handle_too_large_payload(stringified_payload, result, attempts)

  nil
end

#handle_too_large_payload(stringified_payload, _final_payload, attempts) ⇒ Object



141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/rollbar/item.rb', line 141

def handle_too_large_payload(stringified_payload, _final_payload, attempts)
  uuid = stringified_payload['data']['uuid']
  host = stringified_payload['data'].fetch('server', {})['host']

  original_error = {
    :message => message,
    :exception => exception,
    :configuration => configuration,
    :uuid => uuid,
    :host => host
  }

  notifier.send_failsafe(too_large_payload_string(attempts), nil, original_error)

  logger.error('[Rollbar] Payload too large to be sent for UUID ' \
    "#{uuid}: #{Rollbar::JSON.dump(payload)}")
end

#ignored?Boolean

Returns:

  • (Boolean)


165
166
167
168
169
170
171
172
# File 'lib/rollbar/item.rb', line 165

def ignored?
  data = payload['data']

  return unless data[:person]

  person_id = data[:person][configuration.person_id_method.to_sym]
  configuration.ignored_person_ids.include?(person_id)
end

#initial_dataObject



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/rollbar/item.rb', line 80

def initial_data
  {
    :timestamp => Time.now.to_i,
    :environment => build_environment,
    :level => level,
    :language => 'ruby',
    :framework => configuration.framework,
    :server => server_data,
    :notifier => {
      :name => 'rollbar-gem',
      :version => VERSION,
      :configured_options => configured_options
    },
    :body => build_body
  }
end

#too_large_payload_string(attempts) ⇒ Object



159
160
161
162
163
# File 'lib/rollbar/item.rb', line 159

def too_large_payload_string(attempts)
  'Could not send payload due to it being too large after truncating attempts. ' \
    "Original size: #{attempts.first} Attempts: #{attempts.join(', ')} " \
    "Final size: #{attempts.last}"
end