Class: Timber::Logger

Inherits:
Logger
  • Object
show all
Includes:
ActiveSupport::LoggerThreadSafeLevel, LoggerSilence
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 "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: JSONFormatter, PassThroughFormatter, SimpleFormatter, StringFormatter

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


185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/timber/logger.rb', line 185

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 = StringFormatter.new
  end

  self.level = environment_level

  after_initialize if respond_to?(:after_initialize)

  @initialized = true
end

Instance Method Details

#formatter=(value) ⇒ Object



206
207
208
209
210
211
212
213
214
# File 'lib/timber/logger.rb', line 206

def formatter=(value)
  if @initialized && @logdev && @logdev.dev.is_a?(Timber::LogDevices::HTTP) && !value.is_a?(PassThroughFormatter)
    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

  super
end

#with_context(context, &block) ⇒ Object

Convenience method for adding context. Please see Timber::Logger.{Timber{Timber::CurrentContext{Timber::CurrentContext.with} for a more detailed description and examples.



218
219
220
# File 'lib/timber/logger.rb', line 218

def with_context(context, &block)
  Timber::CurrentContext.with(context, &block)
end