RF Logger provides a consistent API to log events of different severity levels. Severities include:

    :debug # dev-only, for exploring issues
    :info  # end users, to audit process
    :warn  # weird thing happened, but isn't really an issue
    :error # someone fix the code
    :fatal # system-wide errors

The API provides helper methods for each severity (i.e. Logger.debug). In addition to logging severity levels, the following fields are optional:

  • actor (The user or caller of the event that you are logging)
  • action (The event you are logging)
  • target_type (We use this in cases where we want to tie a log record to a particular entity or object in the database, for example User)
  • target_id (This is used in conjunction with target_type, as the unique identifier for the relevant entity)
  • metadata (Additional information such as error details and backtraces or other messages, stored as a hash)
    • Include in this Hash is the rf_logger_request_tags, which by default contains the request_id if available.

This gem includes RfLogger::SimpleLogger, RfLogger::Sequel::Logger and RfLogger::ActiveRecord::Logger loggers as options that adhere to this API. The fields above should be passed into helper methods as a hash.


Integrating RfLogger into your project requires the following steps:

  • Include the rf_logger code in your project
  • Create a migration
  • Add a model

Including rf_logger

Place the following in your Gemfile:

gem 'rf_logger', "0.3"

Also make sure you include rf_logger and the logger you're going to be using:



Support Rails 3.2 to ~> 5.0


Alters Rails.logger to append request_id=89f25715-3e5d-4d85-9352-843a1aeec7d0

Rory Requirements

Support Rory => 0.8

Debug Framework detection and loading plug-ins

Will puts to STDOUT frameworks detected and any errors.



If in the context of a request

RfLogger::RequestHeaders.new(type: nil).to_hash
    #=> {"X-Request-Id" => "89f25715-3e5d-4d85-9352-843a1aeec7d0"}

It defaults to content type of JSON

    #=> {"Content-Type" => "application/json"}

Any additional headers can be added

RfLogger::RequestHeaders.new(accepts: "application/json").to_hash
    #=> {"Content-Type" => "application/json", "Accepts" => "application/json"}


Assuming your logger will persist to a database, you'll need to create a table. While the api should make it pretty easy to determine which fields you'll need, here are the guts of what you'd need for both the SequelLogger and RailsLogger:

create_table :logs do
    primary_key :id
    column :actor, :text, :null => false
    column :action, :text, :null => false
    column :target_type, :text
    column :target_id, :text
    column :metadata, :text
    column :created_at, 'timestamp with time zone', :null => false
    Integer :level, :null => false, :default => 0
create_table :logs do |table|
    table.integer :level, null: false, default: 0
    table.string :actor
    table.string :action
    table.string :target_type
    table.string :target_id
    table.string :metadata
    table.timestamps null: false


Again, assuming you'll be using the SequelLogger or RailsLogger (or some other logger that persists to a datasource), you'll want to create a Model that wraps your logger. This is as simple as creating a class that inherits from your logger (though you can make it more complex as your project needs dictate):

class Log < RfLogger::Sequel::Logger
class Log < RfLogger::ActiveRecord::Logger


Configuration mostly sets up additional notifications beyond the actual logging.

RfLogger.configure do |c|
  # environment attempts to determine this for Rails, Sinatra, Padrino, and Rory, but is otherwise
  c.environment = 'production'  required
  # fields from above can be interpolated into the notification subject
  c.notification_subject = "Oh no!  An error of {{level}} severity just occurred."
  c.set_notifier_list do |n|
    c.add_notifier Notification::DefinedElsewhere, :levels => [:error], :except => ['test', 'development']
    c.add_notifier Notification::OhNo, :levels => [:fatal, :error], :only => ['production']
    c.add_notifer Notifcation:VeryVerbose

As you see above, you can specify different notifications for different levels or environments when you log an event.


While you have to implement notifiers yourself, the API is fairly simple. The class must respond to .send_notification. The argument passed in is an object that includes a #subject (which can be defined in the configuration (see above), and #details, which is the metadata in YAML format. Future versions of this may allow for other transformations of the log data.


require 'tinder'
module Notification
  class Campfire
    class << self
      def send_error_notification log_info
        message = log_info.subject + "\n" + log_info.details
        post_message message

      def post_message message
        campfire = Tinder::Campfire.new(config['user'], :token => config['api_token'])
        room = campfire.find_room_by_id(config['room_id'])
        room.paste message

      def config
        @config ||= YAML.load_file(File.join(Rails.root, 'config/campfire.yml'))