mirror of
https://github.com/meineerde/rackstash.git
synced 2025-10-17 14:01:01 +00:00
Add Rackstash::Logger#add_exception to easily add details about exceptions as buffer fields
This commit is contained in:
parent
d9ea199d4f
commit
25dfa87de7
@ -73,6 +73,10 @@ module Rackstash
|
|||||||
FIELD_TIMESTAMP = '@timestamp'.freeze
|
FIELD_TIMESTAMP = '@timestamp'.freeze
|
||||||
FIELD_VERSION = '@version'.freeze
|
FIELD_VERSION = '@version'.freeze
|
||||||
|
|
||||||
|
FIELD_ERROR = 'error'.freeze
|
||||||
|
FIELD_ERROR_MESSAGE = 'error_message'.freeze
|
||||||
|
FIELD_ERROR_TRACE = 'error_trace'.freeze
|
||||||
|
|
||||||
def self.severity_label(severity)
|
def self.severity_label(severity)
|
||||||
if severity.is_a?(Integer)
|
if severity.is_a?(Integer)
|
||||||
return SEVERITY_LABELS.last if severity < 0
|
return SEVERITY_LABELS.last if severity < 0
|
||||||
|
|||||||
@ -272,6 +272,37 @@ module Rackstash
|
|||||||
end
|
end
|
||||||
alias log add
|
alias log add
|
||||||
|
|
||||||
|
# Extract useful data from an exception and add it to fields of the buffer
|
||||||
|
# for structured logging. The following fields will be set:
|
||||||
|
#
|
||||||
|
# * `error` - The class name of the exception
|
||||||
|
# * `error_message` - The exception's message
|
||||||
|
# * `error_trace` - The backtrace of the exception, one frame per line
|
||||||
|
#
|
||||||
|
# The exception will not be added to the buffer's `message` field.
|
||||||
|
# Log it manually with {#add} if desired.
|
||||||
|
#
|
||||||
|
# By default, the details of subsequent exceptions will overwrite those of
|
||||||
|
# older exceptions in the current buffer. Only by the `force` argument to
|
||||||
|
# `false`, we will preserve existing exceptions.
|
||||||
|
#
|
||||||
|
# @param exception [Exception] an Exception object as catched by `rescue`
|
||||||
|
# @param force [Boolean] set to `false` to preserve the details of an
|
||||||
|
# existing exception in the current buffer's fields, set to `true` to
|
||||||
|
# overwrite them.
|
||||||
|
# @return [Exception] the passed `exception`
|
||||||
|
def add_exception(exception, force: true)
|
||||||
|
return exception if !force && buffer.fields[FIELD_ERROR]
|
||||||
|
|
||||||
|
exception_fields = {
|
||||||
|
FIELD_ERROR => exception.class.name,
|
||||||
|
FIELD_ERROR_MESSAGE => exception.message,
|
||||||
|
FIELD_ERROR_TRACE => (exception.backtrace || []).join("\n")
|
||||||
|
}
|
||||||
|
buffer.fields.merge!(exception_fields)
|
||||||
|
exception
|
||||||
|
end
|
||||||
|
|
||||||
# Create a new buffering {Buffer} and puts in on the {BufferStack} for the
|
# Create a new buffering {Buffer} and puts in on the {BufferStack} for the
|
||||||
# current Thread. For the duration of the block, all new logged messages
|
# current Thread. For the duration of the block, all new logged messages
|
||||||
# and any access to fields and tags will be sent to this new buffer.
|
# and any access to fields and tags will be sent to this new buffer.
|
||||||
|
|||||||
@ -401,6 +401,72 @@ describe Rackstash::Logger do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#add_exception' do
|
||||||
|
let(:fields) { Rackstash::Fields::Hash.new }
|
||||||
|
|
||||||
|
before(:each) do
|
||||||
|
buffer = instance_double('Rackstash::Buffer')
|
||||||
|
allow(buffer).to receive(:fields).and_return(fields)
|
||||||
|
allow(logger).to receive(:buffer).and_return(buffer)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'adds the exception fields' do
|
||||||
|
begin
|
||||||
|
raise 'My Error'
|
||||||
|
rescue => e
|
||||||
|
logger.add_exception(e)
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(fields['error']).to eql 'RuntimeError'
|
||||||
|
expect(fields['error_message']).to eql 'My Error'
|
||||||
|
expect(fields['error_trace']).to match %r{\A#{__FILE__}:#{__LINE__ - 7}:in}
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not require a backtrace' do
|
||||||
|
logger.add_exception(StandardError.new('Error'))
|
||||||
|
|
||||||
|
expect(fields['error']).to eql 'StandardError'
|
||||||
|
expect(fields['error_message']).to eql 'Error'
|
||||||
|
expect(fields['error_trace']).to eql ''
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with force: true' do
|
||||||
|
it 'overwrites exceptions' do
|
||||||
|
begin
|
||||||
|
raise 'Error'
|
||||||
|
rescue => first
|
||||||
|
logger.add_exception(first, force: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
begin
|
||||||
|
raise TypeError, 'Another Error'
|
||||||
|
rescue => second
|
||||||
|
logger.add_exception(second, force: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(fields['error']).to eql 'TypeError'
|
||||||
|
expect(fields['error_message']).to eql 'Another Error'
|
||||||
|
expect(fields['error_trace']).to match %r{\A#{__FILE__}:#{__LINE__ - 7}:in}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with force: false' do
|
||||||
|
it 'does not overwrite exceptions' do
|
||||||
|
fields['error'] = 'Something is wrong'
|
||||||
|
|
||||||
|
begin
|
||||||
|
raise TypeError, 'Error'
|
||||||
|
rescue => second
|
||||||
|
logger.add_exception(second, force: false)
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(fields['error']).to eql 'Something is wrong'
|
||||||
|
expect(fields['error_message']).to be_nil
|
||||||
|
expect(fields['error_trace']).to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe '#with_buffer' do
|
describe '#with_buffer' do
|
||||||
it 'requires a block' do
|
it 'requires a block' do
|
||||||
expect { logger.with_buffer }.to raise_error ArgumentError
|
expect { logger.with_buffer }.to raise_error ArgumentError
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user