Logging in Ruby

and why we created Logr

Peter Marton

Backend Engineer @ SSP

What is logging?

And why do we need it?

  • "Unit testing, design documentation, logging - all of these are secondary development activities that we know we really should be doing!"
  • Because nobody needs it 99% of the time
  • There is TDD, there is no such movement for logging
  • Usually there is loads of it, and it's hard to find the stuff you're looking for
  • Recording state and events to a secondary interface
  • And it got even harder with microservices and Docker

What's already out there

core ruby Logger

Logging

Log4r

Cabin

Core Ruby Logger

  • severity, datetime, progname, msg
  • Can be custom formatted
  • Built in log rotation
  • No support for multiple locations and hard to work around if you need rotation too
require 'logger'

log = Logger.new(STDOUT)
log.level = Logger::WARN

log.info("Program started")

begin
  unless line =~ /^(\w+) = (.*)$/
    log.error("Line in wrong format: #{line}")
  end
rescue => err
  log.fatal("Caught exception; exiting")
  log.fatal(err)
end

# [2016-06-26T19:55:03.317327 #16323] ERROR -- : Line in wrong format: nyehh

Logging

  • Supports multiple locations (appenders)

  • Can be extended with gems through little-plugger
class FirstClass
  def initialize
    @logger = Logging.logger[self]
    @logger.add_appenders(Logging.appenders.stdout, Logging.appenders.file('example.log'))
  end

  def some_method
    @logger.debug "some method was called on #{self.inspect}"
  end
end
  • Same format as core ruby Logger

Log4r

  • Custom levels from configuration

  • Somewhat more advanced than Logging, but similar

  • XML and YAML configuration

  • Far less advanced than log4j

Cabin

  • "I want context and structured data because logging with printf makes it hard to read later."

  • "Structured data means you don't need crazy regular expression skills to make sense of logs."
  • API encourages tracking metrics, latencies, etc

  • It's self-described as an experiment and does not feel prod ready

  • The whole API feels a little cumbersome and "too different"

  • Very similar premise to what we were trying to achieve

  • Poorly documented too

Cabin

@logger = Cabin::Channel.new
rubylog = Logger.new(STDOUT) # ruby's stlib logger
@logger.subscribe(rubylog)

context = @logger.context()
context[:foo] = "Hello"
context[:example] = 100
@logger.info("Bar")

context.clear()

# [2011-10-11T01:00:57.993200 #1209]  INFO -- : 
            {:timestamp="2011-10-11T01:00:57.992353-0700", :foo="Hello", 
             :example=100, :message="Bar", :level=:info}

Logr to the rescue

  • Builds on top of core ruby Logger

  • Block support as in core ruby Logger

  • Outputs JSON

A machine friendly logging library for ruby

  • Support for events and metrics

Logr to the rescue

{
  "timestamp":"2015-11-16 16:47:42 UTC",
  "level":"INFO",
  "logger":"your-logger-name",
  "event":{
    "name":"event-name",
    "arbitrary":"context",
    "add_what":"you_need",
    "monitored":true,
    "title":"Title of the event",
    "text":"A longer description."},
  "metrics":[
    {
      "name":"metric-name",
      "value":34.35,
      "type":"counter"
    },
    {
      "name":"loglines",
      "value":1234535,
      "type":"counter"
    }],
  "message":"Human readable old-school logline"
}

Logr to the rescue

require 'logr'

class YourClass
  def self.logger
    @logger ||= Logr::Logger.new('your-logger-name')
  end

  .
  .
  .

  # A complex event that you want to monitor and has metrics associated
  YourClass.logger.event('event-name', arbitrary: 'context', add_what: 'you_need')
                  .monitored('Title of the event', 'A longer description.')
                  .metric('metric-name', 34.35)
                  .metric('loglines', 1234535, type: 'counter')
                  .info('Human readable old-school logline')

  # A simple logline
  YourClass.logger.warn('Oh-oh something is fishy!')
end

Thanks! Questions?

Fancy working on stuff like this? http://sspinc.workable.com

More to read

http://www.codeproject.com/Articles/42354/The-Art-of-Logging

https://github.com/sspinc/logr

Logging in Ruby

By Secret Sauce Partners, Inc.

Logging in Ruby

  • 1,791