Skip to content

Commit

Permalink
Merge pull request #417 from rollbar/rollbar-logger
Browse files Browse the repository at this point in the history
Rollbar logger
  • Loading branch information
jondeandres committed Apr 8, 2016
2 parents fd3ac50 + 2540019 commit 009de54
Show file tree
Hide file tree
Showing 5 changed files with 217 additions and 2 deletions.
21 changes: 20 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,7 @@ Rollbar.silenced {
}
```

# Sending backtrace without rescued exceptions
## Sending backtrace without rescued exceptions

If you use the gem in this way:

Expand Down Expand Up @@ -698,6 +698,25 @@ config.failover_handlers = [Rollbar::Delay::GirlFriday, Rollbar::Delay::Thread]

With the configuration above Resque will be your primary asynchronous handler but if it fails queueing the job Rollbar will use GirlFriday at first, and just a thread in case that GirlFriday fails too.

## Logger interface

The gem provides a class `Rollbar::Logger` that inherits from `Logger` so you can use Rollbar to log your application messages. The basic usage is:

```ruby
require 'rollbar/logger'

logger = Rollbar::Logger.new
logger.info('Purchase failed!')
```

If you are using Rails you can extend your `Rails.logger` so the log messages are sent to both outputs. You can use this snippet in one initializer:

```ruby
require 'rollbar/logger'

Rails.logger.extend(ActiveSupport::Logger.broadcast(Rollbar::Logger.new))
```

## Using with rollbar-agent

For even more asynchrony, you can configure the gem to write to a file instead of sending the payload to Rollbar servers directly. [rollbar-agent](https://github.com/rollbar/rollbar-agent) can then be hooked up to this file to actually send the payload across. To enable, add the following in ```config/initializers/rollbar.rb```:
Expand Down
2 changes: 1 addition & 1 deletion lib/rollbar/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def initialize
@before_process = []
@code_version = nil
@custom_data_method = nil
@default_logger = lambda { Logger.new(STDERR) }
@default_logger = lambda { ::Logger.new(STDERR) }
@delayed_job_enabled = true
@disable_monkey_patch = false
@disable_core_monkey_patch = false
Expand Down
81 changes: 81 additions & 0 deletions lib/rollbar/logger.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
require 'logger'
require 'rollbar'

module Rollbar
# This class provides logger interface that can be used to replace
# the application logger and send all the log messages to Rollbar
#
# Usage:
# require 'rollbar/logger'
# logger = Rollbar::Logger.new
# logger.error('Error processing purchase')
#
# If using Rails, you can extend the Rails logger so messages are logged
# normally and also to Rollbar:
#
# Rails.logger.extend(ActiveSupport::Logger.broadcast(Rollbar::Logger.new))
class Logger < ::Logger
class Error < RuntimeError; end
class DatetimeFormatNotSupported < Error; end
class FormatterNotSupported < Error; end

def initialize
@level = ERROR
end

def add(severity, message = nil, progname = nil)
return true if severity < @level

message ||= block_given? ? yield : progname

return true if message.blank?

rollbar.log(rollbar_level(severity), message)
end

def <<(message)
error(message)
end

def formatter=(_)
raise(FormatterNotSupported)
end

def formatter
raise(FormatterNotSupported)
end

def datetime_format=(_)
raise(DatetimeFormatNotSupported)
end

def datetime_format
raise(DatetimeFormatNotSupported)
end

# Returns a Rollbar::Notifier instance with the current global scope and
# with a logger writing to /dev/null so we don't have a infinite loop
# when Rollbar.configuration.logger is Rails.logger.
def rollbar
notifier = Rollbar.scope
notifier.configuration.logger = ::Logger.new('/dev/null')

notifier
end

private

# Find correct Rollbar level to use using the indexes in Logger::Severity
# DEBUG = 0
# INFO = 1
# WARN = 2
# ERROR = 3
# FATAL = 4
# UNKNOWN = 5
#
# If not found we'll use 'error' as the used level
def rollbar_level(severity)
[:debug, :info, :warning, :error, :critical, :error][severity] || :error
end
end
end
1 change: 1 addition & 0 deletions lib/rollbar/rake_tasks.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require 'rollbar'
require 'logger'

namespace :rollbar do
desc "Verify your gem installation by sending a test exception to Rollbar"
Expand Down
114 changes: 114 additions & 0 deletions spec/rollbar/logger_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
require 'spec_helper'
require 'rollbar/logger'

describe Rollbar::Logger do
describe '#add' do
context 'with severity under level' do
it 'returns true' do
result = subject.add(Logger::DEBUG, 'foo')

expect(result).to be_truthy
end
end

context 'with blank message' do
it 'returns true' do
result = subject.add(subject.level)

expect(result).to be_truthy
end
end

context 'with ERROR severity' do
let(:message) { 'foo' }

it 'calls Rollbar to send the message' do
expect_any_instance_of(Rollbar::Notifier).to receive(:log).with(:error, message)

subject.add(Logger::ERROR, message)
end
end

context 'with FATAL severity' do
let(:message) { 'foo' }

it 'calls Rollbar to send the message with critical level' do
expect_any_instance_of(Rollbar::Notifier).to receive(:log).with(:critical, message)

subject.add(Logger::FATAL, message)
end
end

context 'with UNKNOWN severity' do
let(:message) { 'foo' }

it 'calls Rollbar to send the message with error level' do
expect_any_instance_of(Rollbar::Notifier).to receive(:log).with(:error, message)

subject.add(Logger::UNKNOWN, message)
end
end

context 'with out of range severity' do
let(:message) { 'foo' }

it 'calls Rollbar to send the message with error level' do
expect_any_instance_of(Rollbar::Notifier).to receive(:log).with(:error, message)

subject.add(10, message)
end
end
end

describe '#<<' do
let(:message) { 'foo' }

it 'calls #error' do
expect(subject).to receive(:error).with(message)

subject << message
end
end

describe '#formatter=' do
it 'fails with FormatterNotSupported' do
expect do
subject.formatter = double
end.to raise_error(Rollbar::Logger::FormatterNotSupported)
end
end

describe '#formatter' do
it 'fails with FormatterNotSupported' do
expect do
subject.formatter
end.to raise_error(Rollbar::Logger::FormatterNotSupported)
end
end

describe '#datetime_format=' do
it 'fails with DatetimeFormatNotSupported' do
expect do
subject.datetime_format = double
end.to raise_error(Rollbar::Logger::DatetimeFormatNotSupported)
end
end

describe '#datetime_format' do
it 'fails with DatetimeFormatNotSupported' do
expect do
subject.datetime_format
end.to raise_error(Rollbar::Logger::DatetimeFormatNotSupported)
end
end

describe '#rollbar' do
it 'returns a Rollbar notifier with a logger pointing to /dev/null' do
notifier = subject.rollbar
logger = notifier.configuration.logger
logdev = logger.instance_eval { @logdev }

expect(logdev.filename).to be_eql('/dev/null')
end
end
end

0 comments on commit 009de54

Please sign in to comment.