Class: Cabin::Channel

Inherits:
Object
  • Object
show all
Includes:
Mixins::Logger, Mixins::Timer, Mixins::Timestamp
Defined in:
lib/cabin/channel.rb

Overview

A wonderful channel for logging.

You can log normal messages through here, but you should be really shipping structured data. A message is just part of your data. “An error occurred” - in what? when? why? how?

Logging channels support the usual ‘info’ ‘warn’ and other logger methods provided by Ruby’s stdlib Logger class

It additionally allows you to store arbitrary pieces of data in it like a hash, so your call stack can do be this:

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

def foo(val)
  context = @logger.context()
  context[:foo] = val
  context[:example] = 100
  bar()

  # Clear any context we just wanted bar() to know about
  context.clear()

  @logger.info("Done in foo")
end

def bar
  @logger.info("Fizzle")
end

The result:

I, [2011-10-11T01:00:57.993200 #1209]  INFO -- : {:timestamp=>"2011-10-11T01:00:57.992353-0700", :foo=>"Hello", :example=>100, :message=>"Fizzle", :level=>:info}
I, [2011-10-11T01:00:57.993575 #1209]  INFO -- : {:timestamp=>"2011-10-11T01:00:57.993517-0700", :message=>"Done in foo", :level=>:info}

Constant Summary

Constants included from Mixins::Logger

Mixins::Logger::BACKTRACE_RE, Mixins::Logger::LEVELS

Instance Attribute Summary collapse

Attributes included from Mixins::Logger

#level

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Mixins::Timer

#time

Methods included from Mixins::Logger

#log

Methods included from Mixins::Timestamp

extended, included

Constructor Details

#initializeChannel

Create a new logging channel. The default log level is ‘info’



100
101
102
103
104
105
106
107
# File 'lib/cabin/channel.rb', line 100

def initialize
  @subscribers = {}
  @data = {}
  @level = :info
  @metrics = Cabin::Metrics.new
  @metrics.channel = self
  @subscriber_lock = Mutex.new
end

Instance Attribute Details

#metricsObject

All channels come with a metrics provider.



94
95
96
# File 'lib/cabin/channel.rb', line 94

def metrics
  @metrics
end

Class Method Details

.each(&block) ⇒ Object

def Cabin::Channel.set



68
69
70
71
72
73
74
# File 'lib/cabin/channel.rb', line 68

def each(&block)
  @channel_lock.synchronize do
    @channels.each do |identifier, channel|
      yield identifier, channel
    end
  end
end

.filter(&block) ⇒ Object

Register a new filter. The block is passed the event. It is expected to modify that event or otherwise do nothing.



83
84
85
86
# File 'lib/cabin/channel.rb', line 83

def filter(&block)
  @filters ||= []
  @filters << block
end

.filtersObject

Get a list of filters included in this class.



77
78
79
# File 'lib/cabin/channel.rb', line 77

def filters
  @filters ||= []
end

.get(identifier = $0) ⇒ Object

Get a channel for a given identifier. If this identifier has never been used, a new channel is created for it. The default identifier is the application executable name.

This is useful for using the same Cabin::Channel across your entire application.



60
61
62
# File 'lib/cabin/channel.rb', line 60

def get(identifier=$0)
  return @channel_lock.synchronize { @channels[identifier] }
end

.set(identifier, channel) ⇒ Object

def Cabin::Channel.get



64
65
66
# File 'lib/cabin/channel.rb', line 64

def set(identifier, channel)
  return @channel_lock.synchronize { @channels[identifier] = channel }
end

Instance Method Details

#contextObject

def publish



176
177
178
179
# File 'lib/cabin/channel.rb', line 176

def context
  ctx = Cabin::Context.new(self)
  return ctx
end

#publish(data) ⇒ Object

Publish data to all outputs. The data is expected to be a hash or a string.

A new hash is generated based on the data given. If data is a string, then it will be added to the new event hash with key :message.

A special key :timestamp is set at the time of this method call. The value is a string ISO8601 timestamp with microsecond precision.



156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/cabin/channel.rb', line 156

def publish(data)
  event = {}
  self.class.filters.each do |filter|
    filter.call(event)
  end

  if data.is_a?(String)
    event[:message] = data
  else
    event.merge!(data)
  end
  event.merge!(@data) # Merge any logger context

  @subscriber_lock.synchronize do
    @subscribers.each do |id, output|
      output << event
    end
  end
end

#remove(key) ⇒ Object

Remove a context value by name.



145
146
147
# File 'lib/cabin/channel.rb', line 145

def remove(key)
  @data.delete(key)
end

#subscribe(output) ⇒ Object

Subscribe a new input New events will be sent to the subscriber using the ‘<<’ method

foo << event

Returns a subscription id you can use later to unsubscribe



114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/cabin/channel.rb', line 114

def subscribe(output)
  # Wrap ruby stdlib Logger if given.
  if output.is_a?(::Logger)
    output = Cabin::Outputs::StdlibLogger.new(output)
  elsif output.is_a?(::IO)
    output = Cabin::Outputs::IO.new(output)
  end
  @subscriber_lock.synchronize do
    @subscribers[output.object_id] = output
  end
  return output.object_id
end

#unsubscribe(id) ⇒ Object

Unsubscribe. Takes a ‘subscription id’ as returned by the subscribe method



128
129
130
131
132
# File 'lib/cabin/channel.rb', line 128

def unsubscribe(id)
  @subscriber_lock.synchronize do
    @subscribers.delete(id)
  end
end