Class: Opbeat::Event

Inherits:
Object
  • Object
show all
Defined in:
lib/opbeat/event.rb

Constant Summary collapse

LOG_LEVELS =
{
  "debug" => "debug",
  "info" => "info",
  "warn" => "warn",
  "warning" => "warn",
  "error" => "error",
}
BACKTRACE_RE =
/^(.+?):(\d+)(?::in `(.+?)')?$/

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}, configuration = nil, &block) ⇒ Event

Returns a new instance of Event.

Raises:



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/opbeat/event.rb', line 27

def initialize(options={}, configuration=nil, &block)
  @configuration = configuration || Opbeat.configuration
  @interfaces = {}

  @id = options[:id] || UUIDTools::UUID.random_create.hexdigest
  @message = options[:message]
  @timestamp = options[:timestamp] || Time.now.utc
  @level = options[:level] || :error
  @logger = options[:logger] || 'root'
  @culprit = options[:culprit]
  @environment = @configuration[:current_environment]
  @extra = options[:extra]
  @user = options[:user]

  # Try to resolve the hostname to an FQDN, but fall back to whatever the load name is
  hostname = Socket.gethostname
  hostname = Socket.gethostbyname(hostname).first rescue hostname
  @hostname = options[:hostname] || hostname

  block.call(self) if block

  # Some type coercion
  @timestamp = @timestamp.strftime('%Y-%m-%dT%H:%M:%S') if @timestamp.is_a?(Time)
  @level = LOG_LEVELS[@level.to_s.downcase] if @level.is_a?(String) || @level.is_a?(Symbol)

  # Basic sanity checking
  raise Error.new('A message is required for all events') unless @message && !@message.empty?
  raise Error.new('A timestamp is required for all events') unless @timestamp
end

Instance Attribute Details

#appObject

Returns the value of attribute app.



23
24
25
# File 'lib/opbeat/event.rb', line 23

def app
  @app
end

#culpritObject

Returns the value of attribute culprit.



24
25
26
# File 'lib/opbeat/event.rb', line 24

def culprit
  @culprit
end

#environmentObject

Returns the value of attribute environment.



25
26
27
# File 'lib/opbeat/event.rb', line 25

def environment
  @environment
end

#extraObject

Returns the value of attribute extra.



24
25
26
# File 'lib/opbeat/event.rb', line 24

def extra
  @extra
end

#hostnameObject

Returns the value of attribute hostname.



24
25
26
# File 'lib/opbeat/event.rb', line 24

def hostname
  @hostname
end

#idObject (readonly)

Returns the value of attribute id.



22
23
24
# File 'lib/opbeat/event.rb', line 22

def id
  @id
end

#levelObject

Returns the value of attribute level.



23
24
25
# File 'lib/opbeat/event.rb', line 23

def level
  @level
end

#loggerObject

Returns the value of attribute logger.



24
25
26
# File 'lib/opbeat/event.rb', line 24

def logger
  @logger
end

#messageObject

Returns the value of attribute message.



23
24
25
# File 'lib/opbeat/event.rb', line 23

def message
  @message
end

#modulesObject

Returns the value of attribute modules.



24
25
26
# File 'lib/opbeat/event.rb', line 24

def modules
  @modules
end

#organizationObject

Returns the value of attribute organization.



23
24
25
# File 'lib/opbeat/event.rb', line 23

def organization
  @organization
end

#timestampObject

Returns the value of attribute timestamp.



23
24
25
# File 'lib/opbeat/event.rb', line 23

def timestamp
  @timestamp
end

#userObject

Returns the value of attribute user.



24
25
26
# File 'lib/opbeat/event.rb', line 24

def user
  @user
end

Class Method Details

.capture_exception(exc, options = {}, &block) ⇒ Object Also known as: captionException



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/opbeat/event.rb', line 97

def self.capture_exception(exc, options={}, &block)
  configuration = Opbeat.configuration
  if exc.is_a?(Opbeat::Error)
    # Try to prevent error reporting loops
    Opbeat.logger.info "Refusing to capture Opbeat error: #{exc.inspect}"
    return nil
  end
  if configuration[:excluded_exceptions].include? exc.class.name
    Opbeat.logger.info "User excluded error: #{exc.inspect}"
    return nil
  end
  options = self.merge_context(options)
  self.new(options, configuration) do |evt|
    evt.message = "#{exc.class.to_s}: #{exc.message}"
    evt.level = :error
    evt.parse_exception(exc)
    if (exc.backtrace)
      evt.interface :stack_trace do |int|
        int.frames = exc.backtrace.reverse.map do |trace_line|
          int.frame {|frame| evt.parse_backtrace_line(trace_line, frame) }
        end
        evt.culprit = evt.get_culprit(int.frames)
      end
    end
    block.call(evt) if block
  end
end

.capture_message(message, options = {}) ⇒ Object Also known as: captureMessage



144
145
146
147
148
149
150
151
152
153
154
# File 'lib/opbeat/event.rb', line 144

def self.capture_message(message, options={})
  configuration ||= Opbeat.configuration
  options = self.merge_context(options)
  self.new(options, configuration) do |evt|
    evt.message = message
    evt.level = :error
    evt.interface :message do |int|
      int.message = message
    end
  end
end

.capture_rack_exception(exc, rack_env, options = {}, &block) ⇒ Object



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/opbeat/event.rb', line 125

def self.capture_rack_exception(exc, rack_env, options={}, &block)
  capture_exception(exc, options) do |evt|
    evt.interface :http do |int|
      int.from_rack(rack_env)
    end

    if not evt.user
      controller = rack_env["action_controller.instance"]
      user_method_name = Opbeat.configuration.user_controller_method
      if controller and controller.respond_to? user_method_name
        user_obj = controller.send user_method_name
        evt.from_user_object(user_obj)
      end
    end        

    block.call(evt) if block
  end
end

.set_context(options = {}) ⇒ Object



156
157
158
# File 'lib/opbeat/event.rb', line 156

def self.set_context(options={})
  Thread.current["_opbeat_context"] = options
end

Instance Method Details

#[](key) ⇒ Object



65
66
67
# File 'lib/opbeat/event.rb', line 65

def [](key)
  interface(key)
end

#[]=(key, value) ⇒ Object



69
70
71
# File 'lib/opbeat/event.rb', line 69

def []=(key, value)
  interface(key, value)
end

#from_user_object(user_obj) ⇒ Object



187
188
189
190
191
192
# File 'lib/opbeat/event.rb', line 187

def from_user_object(user_obj)
  @user = {} if not @user
  @user[:id] = user_obj.send(:id) rescue nil
  @user[:email] = user_obj.send(:email) rescue nil
  @user[:username] = user_obj.send(:username) rescue nil
end

#get_culprit(frames) ⇒ Object



160
161
162
163
# File 'lib/opbeat/event.rb', line 160

def get_culprit(frames)
    lastframe = frames[-2]
    "#{lastframe.filename} in #{lastframe.function}" if lastframe
end

#interface(name, value = nil, &block) ⇒ Object

Raises:



57
58
59
60
61
62
63
# File 'lib/opbeat/event.rb', line 57

def interface(name, value=nil, &block)
  int = Opbeat::find_interface(name)
  Opbeat.logger.info "Unknown interface: #{name}" unless int
  raise Error.new("Unknown interface: #{name}") unless int
  @interfaces[int.name] = int.new(value, &block) if value || block
  @interfaces[int.name]
end

#parse_backtrace_line(line, frame) ⇒ Object

Raises:



173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/opbeat/event.rb', line 173

def parse_backtrace_line(line, frame)
  md = BACKTRACE_RE.match(line)
  raise Error.new("Unable to parse backtrace line: #{line.inspect}") unless md
  frame.abs_path = md[1]
  frame.lineno = md[2].to_i
  frame.function = md[3] if md[3]
  frame.filename = strip_load_path_from(frame.abs_path)
  if context_lines = @configuration[:context_lines]
    frame.pre_context, frame.context_line, frame.post_context = \
      get_contextlines(frame.abs_path, frame.lineno, context_lines)
  end
  frame
end

#parse_exception(exception) ⇒ Object



165
166
167
168
169
170
171
# File 'lib/opbeat/event.rb', line 165

def parse_exception(exception)
  interface(:exception) do |int|
    int.type = exception.class.to_s
    int.value = exception.message
    int.module = exception.class.to_s.split('::')[0...-1].join('::')
  end
end

#to_hashObject



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/opbeat/event.rb', line 73

def to_hash
  data = {
    'client_supplied_id' => self.id,
    'message' => self.message,
    'timestamp' => self.timestamp,
    'level' => self.level,
    'logger' => self.logger,
  }
  data['culprit'] = self.culprit if self.culprit
  data['machine'] = {'hostname' => self.hostname } if self.hostname
  data['environment'] = self.environment if self.environment
  data['extra'] = self.extra if self.extra
  if self.user
    data['user'] = self.user
    if self.user[:id] or self.user[:email] or self.user[:username]
      data['user'][:is_authenticated] = true
    end
  end
  @interfaces.each_pair do |name, int_data|
    data[name] = int_data.to_hash
  end
  data
end