class Cabin::Channel
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}
Attributes
All channels come with a metrics provider.
Public Class Methods
Register a new action. The block is passed the event. It is expected to modify that event or otherwise do nothing.
# File lib/cabin/channel.rb, line 87 def action(&block) actions << block end
Get a list of actions included in this class.
# File lib/cabin/channel.rb, line 80 def actions @actions ||= [] end
Decide to publish the event based on conditions and subscription options
# File lib/cabin/channel.rb, line 104 def allow_event?(event, subscription) conditions.all? { |condition| condition.call(event, subscription) } end
Register a new condition. The block must expect an event and a subscription. It is expected to either return true (allow the event) or false (reject it).
# File lib/cabin/channel.rb, line 99 def condition(&block) conditions << block end
Get a list of conditions included in this class.
# File lib/cabin/channel.rb, line 93 def conditions @conditions ||= [] end
# File lib/cabin/channel.rb, line 71 def each(&block) @channel_lock.synchronize do @channels.each do |identifier, channel| yield identifier, channel end end end
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.
# File lib/cabin/channel.rb, line 63 def get(identifier=$0) return @channel_lock.synchronize { @channels[identifier] } end
Create a new logging channel. The default log level is 'info'
# File lib/cabin/channel.rb, line 122 def initialize @subscribers = {} @data = {} @level = :info @metrics = Cabin::Metrics.new @metrics.channel = self @subscriber_lock = Mutex.new end
# File lib/cabin/channel.rb, line 67 def set(identifier, channel) return @channel_lock.synchronize { @channels[identifier] = channel } end
Public Instance Methods
Get a context value by name.
# File lib/cabin/channel.rb, line 162 def [](key) @data[key] end
Set some contextual map value
# File lib/cabin/channel.rb, line 157 def []=(key, value) @data[key] = value end
# File lib/cabin/channel.rb, line 202 def context ctx = Cabin::Context.new(self) return ctx end
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.
# File lib/cabin/channel.rb, line 178 def publish(data, &block) event = {} self.class.actions.each do |action| action.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 |_, subscriber| append = block_given? ? block.call(subscriber, event) : true if append && self.class.allow_event?(event, subscriber) subscriber << event end end end end
Remove a context value by name.
# File lib/cabin/channel.rb, line 167 def remove(key) @data.delete(key) end
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
# File lib/cabin/channel.rb, line 136 def subscribe(output, options = {}) # 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] = Cabin::Subscriber.new(output, options) end return output.object_id end
Unsubscribe. Takes a 'subscription id' as returned by the subscribe method
# File lib/cabin/channel.rb, line 150 def unsubscribe(id) @subscriber_lock.synchronize do @subscribers.delete(id) end end
Private Instance Methods
# File lib/cabin/channel.rb, line 207 def dataify(data) if data.is_a?(String) data = { :message => data } end return data end