Class: Timber::Logger

Inherits:
Logger
  • Object
show all
Defined in:
lib/timber/logger.rb

Overview

The Timber Logger behaves exactly like ‘::Logger`, except that it supports a transparent API for logging structured messages. It ensures your log messages are communicated properly with the Timber.io API.

To adhere to our no code debt / no lock-in promise, the Timber Logger will never deviate from the ‘::Logger` interface. That is, it will never add methods, or alter any method signatures. This ensures Timber can be removed without consequence.

Examples:

Basic example (the original ::Logger interface remains untouched):

logger.info "Payment rejected for customer #{customer_id}"

Using a Hash

# The :message key is required, the other additional key is your event type and data
# :type is the namespace used in timber for the :data
logger.info message: "Payment rejected", payment_rejected: {customer_id: customer_id, amount: 100}

Using a Struct (a simple, more structured way, to define events)

PaymentRejectedEvent = Struct.new(:customer_id, :amount, :reason) do
  # `#message` and `#type` are required, otherwise they will not be logged properly.
  # `#type` is the namespace used in timber for the struct data
  def message; "Payment rejected for #{customer_id}"; end
  def type; :payment_rejected; end
end
Logger.info PaymentRejectedEvent.new("abcd1234", 100, "Card expired")

Using typed Event classes

# Event implementation is left to you. Events should be simple classes.
# The only requirement is that it responds to #to_timber_event and return the
# appropriate Timber::Events::* type.
class Event
  def to_hash
    hash = {}
    instance_variables.each { |var| hash[var.to_s.delete("@")] = instance_variable_get(var) }
    hash
  end
  alias to_h to_hash

  def to_timber_event
    Timber::Events::Custom.new(type: type, message: message, data: to_hash)
  end

  def message; raise NotImplementedError.new; end
  def type; raise NotImplementedError.new; end
end

class PaymentRejectedEvent < Event
  attr_accessor :customer_id, :amount
  def initialize(customer_id, amount)
    @customer_id = customer_id
    @amount = amount
  end
  def message; "Payment rejected for customer #{customer_id}"; end
  def type; :payment_rejected_event; end
end

Logger.info PymentRejectedEvent.new("abcd1234", 100)

Defined Under Namespace

Classes: HybridFormatter, JSONFormatter, PassThroughFormatter

Instance Method Summary collapse

Constructor Details

#initialize(*args) ⇒ Logger

Creates a new Timber::Logger instances. Accepts the same arguments as ‘::Logger.new`. The only difference is that it default the formatter to HybridFormatter. Using a different formatter is easy. For example, if you prefer your logs in JSON.

Examples:

Changing your formatter

logger = Timber::Logger.new(STDOUT)
logger.formatter = Timber::Logger::JSONFormatter.new


163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/timber/logger.rb', line 163

def initialize(*args)
  super(*args)

  # Ensure we sync STDOUT to avoid buffering
  if args.size == 1 and args.first.respond_to?(:"sync=")
    args.first.sync = true
  end

  if args.size == 1 and args.first.is_a?(LogDevices::HTTP)
    self.formatter = PassThroughFormatter.new
  else
    self.formatter = HybridFormatter.new
  end

  self.level = environment_level
end

Instance Method Details

#formatter=(value) ⇒ Object



180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/timber/logger.rb', line 180

def formatter=(value)
  if @dev.is_a?(Timber::LogDevices::HTTP)
    raise ArgumentError.new("The formatter cannot be changed when using the " +
      "Timber::LogDevices::HTTP log device. The PassThroughFormatter must be used for proper " +
      "delivery.")
  end

  if !value.is_a?(Timber::Logger::Formatter)
    # silently discard this value since rails calls this during initialization :/
    nil
  else
    super
  end
end