lib/syslog-sd/notifier.rb in syslog-sd-1.3.2 vs lib/syslog-sd/notifier.rb in syslog-sd-1.4.0.beta1
- old
+ new
@@ -118,97 +118,133 @@
exception
end
def notify_with_level!(message_level, *args)
return unless @enabled
- extract_hash(*args)
- @hash['level'] = message_level unless message_level.nil?
- if @hash['level'] >= level
- str = serialize_hash
+ hash = extract_hash(*args)
+ hash['level'] = message_level unless message_level.nil?
+ if hash['level'] >= level
+ str = serialize_hash(hash)
@sender.send_datagram(str)
str
end
end
def extract_hash(object = nil, args = {})
+ args = self.class.stringify_keys(args)
+
primary_data = if object.respond_to?(:to_hash)
object.to_hash
elsif object.is_a?(Exception)
args['level'] ||= SyslogSD::ERROR
self.class.extract_hash_from_exception(object)
else
args['level'] ||= SyslogSD::INFO
{ 'short_message' => object.to_s }
end
- @hash = default_options.merge(self.class.stringify_keys(args.merge(primary_data)))
- convert_hoptoad_keys_to_graylog2
- set_file_and_line if @collect_file_and_line
- set_timestamp
- check_presence_of_mandatory_attributes
- @hash
+ hash = self.class.stringify_keys(primary_data)
+ hash = default_options.merge(args.merge(hash))
+ hash = convert_airbrake_keys_to_graylog2(hash)
+ hash = set_file_and_line(hash)
+ hash = set_timestamp(hash)
+ check_presence_of_mandatory_attributes(hash)
+ hash
end
+ CALLER_REGEXP = /^(.*):(\d+).*/
+
def self.extract_hash_from_exception(exception)
- bt = exception.backtrace || ["Backtrace is not available."]
- { 'short_message' => "#{exception.class}: #{exception.message}", 'full_message' => "Backtrace:\n" + bt.join("\n") }
+ error_class = exception.class.name
+ error_message = exception.message
+
+ # always collect file and line there (ignore @collect_file_and_line)
+ # since we already know them, no need to call `caller`
+ file, line = nil, nil
+ bt = exception.backtrace
+ if bt
+ match = CALLER_REGEXP.match(bt[0])
+ if match
+ file = match[1]
+ line = match[2].to_i
+ end
+ else
+ bt = ["Backtrace is not available."]
+ end
+
+ { 'short_message' => "#{error_class}: #{error_message}", 'full_message' => "Backtrace:\n" + bt.join("\n"),
+ 'error_class' => error_class, 'error_message' => error_message,
+ 'file' => file, 'line' => line }
end
- # Converts Hoptoad-specific keys in +@hash+ to Graylog2-specific.
- def convert_hoptoad_keys_to_graylog2
- if @hash['short_message'].to_s.empty?
- if @hash.has_key?('error_class') && @hash.has_key?('error_message')
- @hash['short_message'] = @hash.delete('error_class') + ': ' + @hash.delete('error_message')
+ # Converts Airbrake-specific keys in +hash+ to Graylog2-specific.
+ def convert_airbrake_keys_to_graylog2(hash)
+ if hash['short_message'].to_s.empty?
+ if hash.has_key?('error_class') && hash.has_key?('error_message')
+ hash['short_message'] = hash['error_class'] + ': ' + hash['error_message']
end
end
+ hash
end
- CALLER_REGEXP = /^(.*):(\d+).*/
LIB_PATTERN = File.join('lib', 'syslog-sd')
- def set_file_and_line
- stack = caller
- begin
- frame = stack.shift
- end while frame.include?(LIB_PATTERN)
- match = CALLER_REGEXP.match(frame)
- @hash['file'] = match[1]
- @hash['line'] = match[2].to_i
+ def set_file_and_line(hash)
+ return hash unless hash['file'].nil? || hash['line'].nil?
+
+ if @collect_file_and_line
+ stack = caller
+ begin
+ frame = stack.shift
+ end while frame.include?(LIB_PATTERN)
+
+ match = CALLER_REGEXP.match(frame)
+ if match
+ hash['file'] = match[1]
+ hash['line'] = match[2].to_i
+ else
+ hash['file'] = 'unknown'
+ hash['line'] = -1
+ end
+ end
+
+ hash
end
- def set_timestamp
- @hash['timestamp'] = Time.now.utc.to_f if @hash['timestamp'].nil?
+ def set_timestamp(hash)
+ hash['timestamp'] ||= Time.now.utc.to_f
+ hash
end
- def check_presence_of_mandatory_attributes
+ def check_presence_of_mandatory_attributes(hash)
%w(short_message host).each do |attribute|
- if @hash[attribute].to_s.empty?
+ if hash[attribute].to_s.empty?
raise ArgumentError.new("#{attribute} is missing. Options short_message and host must be set.")
end
end
end
- def serialize_hash
- raise ArgumentError.new("Hash is empty.") if @hash.nil? || @hash.empty?
+ def serialize_hash(hash)
+ raise ArgumentError.new("Hash is empty.") if hash.nil? || hash.empty?
- @hash['level'] = @level_mapping[@hash['level']]
+ hash['level'] = @level_mapping[hash['level']]
- prival = 128 + @hash.delete('level') # 128 = 16(local0) * 8
+ prival = 128 + hash.delete('level') # 128 = 16(local0) * 8
t = Time.now.utc
timestamp = timestamp_as_float ? t.to_f : t.strftime("%Y-%m-%dT%H:%M:%S.#{t.usec.to_s[0,3]}Z")
- host = @hash.delete('host')
- facility = @hash.delete('facility') || '-'
- procid = @hash.delete('procid')
- msgid = @hash.delete('msgid') || '-'
- short_message = @hash.delete('short_message')
- "<#{prival}>1 #{timestamp} #{host} #{facility} #{procid} #{msgid} #{serialize_sd} #{short_message}"
+ host = hash.delete('host')
+ facility = hash.delete('facility') || '-'
+ procid = hash.delete('procid')
+ msgid = hash.delete('msgid') || '-'
+ short_message = hash.delete('short_message')
+ "<#{prival}>1 #{timestamp} #{host} #{facility} #{procid} #{msgid} #{serialize_sd(hash)} #{short_message}"
end
- def serialize_sd
- return '-' if @hash.empty?
+ def serialize_sd(hash)
+ return '-' if hash.empty?
res = @sd_id
- @hash.each_pair do |key, value|
+ hash.each_pair do |key, value|
value = value.to_s.gsub(/([\\\]\"])/) { "\\#{$1}" }
res += " #{key}=\"#{value}\""
end
'[' + res + ']'
end