cabin 0.4.3 → 0.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/cabin/channel.rb +43 -16
- data/lib/cabin/mixins/logger.rb +1 -1
- data/lib/cabin/outputs/io.rb +8 -4
- data/test/test_logging.rb +2 -3
- metadata +10 -5
data/lib/cabin/channel.rb
CHANGED
@@ -6,7 +6,8 @@ require "cabin/context"
|
|
6
6
|
require "cabin/outputs/stdlib-logger"
|
7
7
|
require "cabin/outputs/io"
|
8
8
|
require "cabin/metrics"
|
9
|
-
require "logger"
|
9
|
+
require "logger" # stdlib
|
10
|
+
require "thread"
|
10
11
|
|
11
12
|
# A wonderful channel for logging.
|
12
13
|
#
|
@@ -46,6 +47,9 @@ require "logger"
|
|
46
47
|
# I, [2011-10-11T01:00:57.993575 #1209] INFO -- : {:timestamp=>"2011-10-11T01:00:57.993517-0700", :message=>"Done in foo", :level=>:info}
|
47
48
|
#
|
48
49
|
class Cabin::Channel
|
50
|
+
@channel_lock = Mutex.new
|
51
|
+
@channels = Hash.new { |h,k| h[k] = Cabin::Channel.new }
|
52
|
+
|
49
53
|
class << self
|
50
54
|
# Get a channel for a given identifier. If this identifier has never been
|
51
55
|
# used, a new channel is created for it.
|
@@ -54,10 +58,21 @@ class Cabin::Channel
|
|
54
58
|
# This is useful for using the same Cabin::Channel across your
|
55
59
|
# entire application.
|
56
60
|
def get(identifier=$0)
|
57
|
-
@
|
58
|
-
return @channels[identifier]
|
61
|
+
return @channel_lock.synchronize { @channels[identifier] }
|
59
62
|
end # def Cabin::Channel.get
|
60
63
|
|
64
|
+
def set(identifier, channel)
|
65
|
+
return @channel_lock.synchronize { @channels[identifier] = channel }
|
66
|
+
end # def Cabin::Channel.set
|
67
|
+
|
68
|
+
def each(&block)
|
69
|
+
@channel_lock.synchronize do
|
70
|
+
@channels.each do |identifier, channel|
|
71
|
+
yield identifier, channel
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end # def Cabin::Channel.each
|
75
|
+
|
61
76
|
# Get a list of filters included in this class.
|
62
77
|
def filters
|
63
78
|
@filters ||= []
|
@@ -71,8 +86,8 @@ class Cabin::Channel
|
|
71
86
|
end
|
72
87
|
end # class << self
|
73
88
|
|
74
|
-
include Cabin::Mixins::Logger
|
75
89
|
include Cabin::Mixins::Timestamp
|
90
|
+
include Cabin::Mixins::Logger
|
76
91
|
include Cabin::Mixins::Timer
|
77
92
|
|
78
93
|
# All channels come with a metrics provider.
|
@@ -83,16 +98,19 @@ class Cabin::Channel
|
|
83
98
|
# Create a new logging channel.
|
84
99
|
# The default log level is 'info'
|
85
100
|
def initialize
|
86
|
-
@
|
101
|
+
@subscribers = {}
|
87
102
|
@data = {}
|
88
103
|
@level = :info
|
89
104
|
@metrics = Cabin::Metrics.new
|
90
105
|
@metrics.channel = self
|
106
|
+
@subscriber_lock = Mutex.new
|
91
107
|
end # def initialize
|
92
108
|
|
93
109
|
# Subscribe a new input
|
94
110
|
# New events will be sent to the subscriber using the '<<' method
|
95
111
|
# foo << event
|
112
|
+
#
|
113
|
+
# Returns a subscription id you can use later to unsubscribe
|
96
114
|
def subscribe(output)
|
97
115
|
# Wrap ruby stdlib Logger if given.
|
98
116
|
if output.is_a?(::Logger)
|
@@ -100,10 +118,18 @@ class Cabin::Channel
|
|
100
118
|
elsif output.is_a?(::IO)
|
101
119
|
output = Cabin::Outputs::IO.new(output)
|
102
120
|
end
|
103
|
-
@
|
104
|
-
|
105
|
-
|
121
|
+
@subscriber_lock.synchronize do
|
122
|
+
@subscribers[output.object_id] = output
|
123
|
+
end
|
124
|
+
return output.object_id
|
106
125
|
end # def subscribe
|
126
|
+
|
127
|
+
# Unsubscribe. Takes a 'subscription id' as returned by the subscribe method
|
128
|
+
def unsubscribe(id)
|
129
|
+
@subscriber_lock.synchronize do
|
130
|
+
@subscribers.delete(id)
|
131
|
+
end
|
132
|
+
end # def unsubscribe
|
107
133
|
|
108
134
|
# Set some contextual map value
|
109
135
|
def []=(key, value)
|
@@ -129,20 +155,21 @@ class Cabin::Channel
|
|
129
155
|
# is a string ISO8601 timestamp with microsecond precision.
|
130
156
|
def publish(data)
|
131
157
|
event = {}
|
132
|
-
|
158
|
+
self.class.filters.each do |filter|
|
159
|
+
filter.call(event)
|
160
|
+
end
|
133
161
|
|
134
162
|
if data.is_a?(String)
|
135
163
|
event[:message] = data
|
136
164
|
else
|
137
165
|
event.merge!(data)
|
138
166
|
end
|
167
|
+
event.merge!(@data) # Merge any logger context
|
139
168
|
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
@outputs.each do |out|
|
145
|
-
out << event
|
169
|
+
@subscriber_lock.synchronize do
|
170
|
+
@subscribers.each do |id, output|
|
171
|
+
output << event
|
172
|
+
end
|
146
173
|
end
|
147
174
|
end # def publish
|
148
175
|
|
@@ -158,5 +185,5 @@ class Cabin::Channel
|
|
158
185
|
return data
|
159
186
|
end # def dataify
|
160
187
|
|
161
|
-
public(:initialize, :context, :subscribe, :[]=, :[], :remove, :publish, :time, :context)
|
188
|
+
public(:initialize, :context, :subscribe, :unsubscribe, :[]=, :[], :remove, :publish, :time, :context)
|
162
189
|
end # class Cabin::Channel
|
data/lib/cabin/mixins/logger.rb
CHANGED
@@ -93,7 +93,7 @@ module Cabin::Mixins::Logger
|
|
93
93
|
data[:exception] = message.class
|
94
94
|
data[:backtrace] = message.backtrace
|
95
95
|
else
|
96
|
-
data
|
96
|
+
data = { :message => message }.merge(data)
|
97
97
|
end
|
98
98
|
|
99
99
|
# Add extra debugging bits (file, line, method) if level is debug.
|
data/lib/cabin/outputs/io.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require "cabin"
|
2
2
|
require "json"
|
3
|
+
require "thread"
|
3
4
|
|
4
5
|
# Wrap IO objects with a reasonable log output.
|
5
6
|
#
|
@@ -42,14 +43,17 @@ class Cabin::Outputs::IO
|
|
42
43
|
|
43
44
|
def initialize(io)
|
44
45
|
@io = io
|
46
|
+
@lock = Mutex.new
|
45
47
|
end # def initialize
|
46
48
|
|
47
49
|
# Receive an event
|
48
50
|
def <<(event)
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
51
|
+
@lock.synchronize do
|
52
|
+
if !@io.tty?
|
53
|
+
@io.puts(event.to_json)
|
54
|
+
else
|
55
|
+
tty_write(event)
|
56
|
+
end
|
53
57
|
end
|
54
58
|
end # def <<
|
55
59
|
|
data/test/test_logging.rb
CHANGED
@@ -56,12 +56,11 @@ describe Cabin::Channel do
|
|
56
56
|
assert(event[:duration].is_a?(Numeric))
|
57
57
|
end
|
58
58
|
|
59
|
-
test "double subscription" do
|
59
|
+
test "double subscription should still only subscribe once" do
|
60
60
|
@logger.subscribe(@target)
|
61
61
|
@logger.publish("Hello world")
|
62
|
-
assert_equal(
|
62
|
+
assert_equal(1, @target.data.length)
|
63
63
|
assert_equal("Hello world", @target.data[0][:message])
|
64
|
-
assert_equal("Hello world", @target.data[1][:message])
|
65
64
|
end
|
66
65
|
|
67
66
|
test "context values" do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cabin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-03-
|
12
|
+
date: 2012-03-23 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: json
|
16
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,7 +21,12 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
25
30
|
description: This is an experiment to try and make logging more flexible and more
|
26
31
|
consumable. Plain text logs are bullshit, let's emit structured and contextual logs.
|
27
32
|
Metrics, too!
|
@@ -88,7 +93,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
88
93
|
version: '0'
|
89
94
|
requirements: []
|
90
95
|
rubyforge_project:
|
91
|
-
rubygems_version: 1.8.
|
96
|
+
rubygems_version: 1.8.18
|
92
97
|
signing_key:
|
93
98
|
specification_version: 3
|
94
99
|
summary: Experiments in structured and contextual logging
|