cabin 0.6.1 → 0.7.1

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 23a9c344930f27313647006b4a9a445a8d49f852
4
+ data.tar.gz: 42ac4012db8a1f4acfd9a5a49ffd0f4800b91ac1
5
+ SHA512:
6
+ metadata.gz: 2ee17db0377d6fcf16088b3896f81f65edf0b3cfbad2b229a2d0331ba9f6069ef2d385e7cb5ead49ec3f1d24c39ee06b60d542d1d2a0261a88f4290ea477ea66
7
+ data.tar.gz: 55f18ad6421077a8ee9b76aad0f17857156e55925ea5112b6ff948aa94b6bb83063c824c19a1c02d329efa45e3828a2bf456b9fed2fa31e4b86d835da9992370
@@ -2,6 +2,7 @@ require "cabin/mixins/logger"
2
2
  require "cabin/mixins/pipe"
3
3
  require "cabin/mixins/timestamp"
4
4
  require "cabin/mixins/timer"
5
+ require "cabin/mixins/terminal"
5
6
  require "cabin/namespace"
6
7
  require "cabin/context"
7
8
  require "cabin/outputs/stdlib-logger"
@@ -91,6 +92,7 @@ class Cabin::Channel
91
92
  include Cabin::Mixins::Logger
92
93
  include Cabin::Mixins::Pipe
93
94
  include Cabin::Mixins::Timer
95
+ include Cabin::Mixins::Terminal
94
96
 
95
97
  # All channels come with a metrics provider.
96
98
  attr_accessor :metrics
@@ -155,7 +157,7 @@ class Cabin::Channel
155
157
  #
156
158
  # A special key :timestamp is set at the time of this method call. The value
157
159
  # is a string ISO8601 timestamp with microsecond precision.
158
- def publish(data)
160
+ def publish(data, &block)
159
161
  event = {}
160
162
  self.class.filters.each do |filter|
161
163
  filter.call(event)
@@ -170,7 +172,8 @@ class Cabin::Channel
170
172
 
171
173
  @subscriber_lock.synchronize do
172
174
  @subscribers.each do |id, output|
173
- output << event
175
+ append = block_given? ? block.call(output, event) : true
176
+ output << event if append
174
177
  end
175
178
  end
176
179
  end # def publish
@@ -119,7 +119,7 @@ module Cabin::Mixins::Logger
119
119
 
120
120
  data[:file] = file
121
121
  data[:line] = line
122
- data[:method] = method if data[:method]
122
+ data[:method] = method
123
123
  end # def debugharder
124
124
 
125
125
  public(:log)
@@ -28,7 +28,7 @@ module Cabin::Mixins::Pipe
28
28
  # write(1, "Fri Jan 11 22:49:42 PST 2013\n", 29) = 29 {"level":"error"}
29
29
  # Fri Jan 11 22:49:42 PST 2013 {"level":"info"}
30
30
  # +++ exited with 0 +++ {"level":"error"}
31
- def pipe(io_to_method_map)
31
+ def pipe(io_to_method_map, &block)
32
32
  fds = io_to_method_map.keys
33
33
 
34
34
  while !fds.empty?
@@ -43,6 +43,7 @@ module Cabin::Mixins::Pipe
43
43
  end
44
44
 
45
45
  method_name = io_to_method_map[fd]
46
+ block.call(line, method_name) if block_given?
46
47
  send(method_name, line)
47
48
  end # readers.each
48
49
  end # while !fds.empty?
@@ -0,0 +1,11 @@
1
+ require "cabin/namespace"
2
+
3
+ module Cabin::Mixins::Terminal
4
+
5
+ def terminal(message)
6
+ publish(message) do |output, event|
7
+ output.respond_to?(:tty?) && output.tty?
8
+ end
9
+ end
10
+
11
+ end
@@ -48,7 +48,7 @@ class Cabin::Outputs::IO
48
48
  # Receive an event
49
49
  def <<(event)
50
50
  @lock.synchronize do
51
- if !@io.tty?
51
+ if !tty?
52
52
  @io.puts(event.inspect)
53
53
  else
54
54
  tty_write(event)
@@ -56,6 +56,9 @@ class Cabin::Outputs::IO
56
56
  end
57
57
  end # def <<
58
58
 
59
+ def tty?
60
+ @io.tty?
61
+ end
59
62
  private
60
63
  def tty_write(event)
61
64
  # The io is attached to a tty, so make pretty colors.
@@ -1,7 +1,7 @@
1
1
  require "cabin"
2
2
 
3
3
  # Wrap Ruby stdlib's logger. This allows you to output to a normal ruby logger
4
- # with Cabin. Since Ruby's Logger has a love for strings alone, this
4
+ # with Cabin. Since Ruby's Logger has a love for strings alone, this
5
5
  # wrapper will convert the data/event to ruby inspect format before sending it
6
6
  # to Logger.
7
7
  class Cabin::Outputs::StdlibLogger
@@ -17,7 +17,11 @@ class Cabin::Outputs::StdlibLogger
17
17
  if !event.include?(:level)
18
18
  event[:level] = :info
19
19
  end
20
- method = event[:level].downcase.to_sym || :info
20
+ if event[:level].is_a?(Symbol)
21
+ method = event[:level]
22
+ else
23
+ method = event[:level].downcase.to_sym || :info
24
+ end
21
25
  event.delete(:level)
22
26
 
23
27
  data = event.clone
@@ -27,6 +27,12 @@ describe Cabin::Channel do
27
27
  end
28
28
  end # class Receiver
29
29
 
30
+ class TtyReceiver < Receiver
31
+ def tty?
32
+ true
33
+ end
34
+ end
35
+
30
36
  before do
31
37
  @logger = Cabin::Channel.new
32
38
  @target = Receiver.new
@@ -105,6 +111,19 @@ describe Cabin::Channel do
105
111
  end
106
112
  end
107
113
 
114
+ test "standard use case, 'terminal' logging when there is no tty" do
115
+ @logger.terminal('Hello world')
116
+ assert_equal(true, @target.data.empty?)
117
+ end
118
+
119
+ test "standard use case, 'terminal' logging when there is a tty" do
120
+ tty_target = TtyReceiver.new
121
+ id = @logger.subscribe(tty_target)
122
+ @logger.terminal('Hello world')
123
+ assert_equal('Hello world', tty_target.data[0][:message])
124
+ @logger.unsubscribe(id)
125
+ end
126
+
108
127
  test "extra debugging data" do
109
128
  @logger.level = :debug
110
129
  @logger.info("Hello world")
@@ -0,0 +1,84 @@
1
+ $: << File.dirname(__FILE__)
2
+ $: << File.join(File.dirname(__FILE__), '..', 'lib')
3
+
4
+ require 'rubygems'
5
+ require 'minitest-patch'
6
+ require 'cabin'
7
+ require 'stringio'
8
+ require 'minitest/autorun' if __FILE__ == $0
9
+
10
+ describe Cabin::Channel do
11
+ class Receiver
12
+ attr_accessor :data
13
+
14
+ public
15
+ def initialize
16
+ @data = []
17
+ end
18
+
19
+ def <<(data)
20
+ @data << data
21
+ end
22
+ end # class Receiver
23
+
24
+ before do
25
+ @logger = Cabin::Channel.new
26
+ @target = Receiver.new
27
+ @logger.subscribe(@target)
28
+
29
+ @info_reader, @info_writer = IO.pipe
30
+ @error_reader, @error_writer = IO.pipe
31
+ end
32
+
33
+ after do
34
+ @logger.unsubscribe(@target.object_id)
35
+ [ @info_reader, @info_writer,
36
+ @error_reader, @error_writer ].each do |io|
37
+ io.close unless io.closed?
38
+ end
39
+ end
40
+
41
+ test 'Piping one IO' do
42
+ @info_writer.puts 'Hello world'
43
+ @info_writer.close
44
+
45
+ @logger.pipe(@info_reader => :info)
46
+ assert_equal(1, @target.data.length)
47
+ assert_equal('Hello world', @target.data[0][:message])
48
+ end
49
+
50
+ test 'Piping multiple IOs' do
51
+ @info_writer.puts 'Hello world'
52
+ @info_writer.close
53
+
54
+ @error_writer.puts 'Goodbye world'
55
+ @error_writer.close
56
+
57
+ @logger.pipe(@info_reader => :info, @error_reader => :error)
58
+ assert_equal(2, @target.data.length)
59
+ assert_equal('Hello world', @target.data[0][:message])
60
+ assert_equal(:info, @target.data[0][:level])
61
+ assert_equal('Goodbye world', @target.data[1][:message])
62
+ assert_equal(:error, @target.data[1][:level])
63
+ end
64
+
65
+ test 'Piping with a block' do
66
+ @info_writer.puts 'Hello world'
67
+ @info_writer.close
68
+
69
+ @error_writer.puts 'Goodbye world'
70
+ @error_writer.close
71
+
72
+ info = StringIO.new
73
+ error = StringIO.new
74
+
75
+ @logger.pipe(@info_reader => :info, @error_reader => :error) do |message, level|
76
+ info << message if level == :info
77
+ error << message if level == :error
78
+ end
79
+
80
+ assert_equal('Hello world', info.string)
81
+ assert_equal('Goodbye world', error.string)
82
+ end
83
+ end
84
+
metadata CHANGED
@@ -1,106 +1,88 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: cabin
3
- version: !ruby/object:Gem::Version
4
- hash: 5
5
- prerelease:
6
- segments:
7
- - 0
8
- - 6
9
- - 1
10
- version: 0.6.1
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.7.1
11
5
  platform: ruby
12
- authors:
6
+ authors:
13
7
  - Jordan Sissel
14
8
  autorequire:
15
9
  bindir: bin
16
10
  cert_chain: []
17
-
18
- date: 2013-06-18 00:00:00 Z
11
+ date: 2015-01-26 00:00:00.000000000 Z
19
12
  dependencies: []
20
-
21
- description: This is an experiment to try and make logging more flexible and more consumable. Plain text logs are bullshit, let's emit structured and contextual logs. Metrics, too!
22
- email:
13
+ description: This is an experiment to try and make logging more flexible and more
14
+ consumable. Plain text logs are bullshit, let's emit structured and contextual logs.
15
+ Metrics, too!
16
+ email:
23
17
  - jls@semicomplete.com
24
- executables:
18
+ executables:
25
19
  - rubygems-cabin-test
26
20
  extensions: []
27
-
28
21
  extra_rdoc_files: []
29
-
30
- files:
31
- - lib/cabin/metrics/timer.rb
32
- - lib/cabin/metrics/meter.rb
33
- - lib/cabin/metrics/histogram.rb
34
- - lib/cabin/metrics/gauge.rb
35
- - lib/cabin/metrics/counter.rb
36
- - lib/cabin/outputs/stdlib-logger.rb
37
- - lib/cabin/outputs/em/stdlib-logger.rb
38
- - lib/cabin/outputs/io.rb
39
- - lib/cabin/outputs/zeromq.rb
40
- - lib/cabin/metric.rb
22
+ files:
23
+ - CHANGELIST
24
+ - LICENSE
25
+ - bin/rubygems-cabin-test
26
+ - examples/fibonacci-timing.rb
27
+ - examples/metrics.rb
28
+ - examples/pipe.rb
29
+ - examples/sample.rb
30
+ - examples/sinatra-logging.rb
31
+ - lib/cabin.rb
32
+ - lib/cabin/channel.rb
41
33
  - lib/cabin/context.rb
42
- - lib/cabin/timer.rb
43
34
  - lib/cabin/inspectable.rb
44
- - lib/cabin/publisher.rb
45
- - lib/cabin/mixins/logger.rb
46
- - lib/cabin/mixins/timer.rb
35
+ - lib/cabin/metric.rb
36
+ - lib/cabin/metrics.rb
37
+ - lib/cabin/metrics/counter.rb
38
+ - lib/cabin/metrics/gauge.rb
39
+ - lib/cabin/metrics/histogram.rb
40
+ - lib/cabin/metrics/meter.rb
41
+ - lib/cabin/metrics/timer.rb
42
+ - lib/cabin/mixins/CAPSLOCK.rb
47
43
  - lib/cabin/mixins/colors.rb
48
44
  - lib/cabin/mixins/dragons.rb
49
- - lib/cabin/mixins/timestamp.rb
50
- - lib/cabin/mixins/CAPSLOCK.rb
45
+ - lib/cabin/mixins/logger.rb
51
46
  - lib/cabin/mixins/pipe.rb
47
+ - lib/cabin/mixins/terminal.rb
48
+ - lib/cabin/mixins/timer.rb
49
+ - lib/cabin/mixins/timestamp.rb
52
50
  - lib/cabin/namespace.rb
53
- - lib/cabin/metrics.rb
54
- - lib/cabin/channel.rb
55
- - lib/cabin.rb
56
- - examples/sinatra-logging.rb
57
- - examples/fibonacci-timing.rb
58
- - examples/sample.rb
59
- - examples/pipe-spoon.rb
60
- - examples/metrics.rb
61
- - examples/pipe.rb
51
+ - lib/cabin/outputs/em/stdlib-logger.rb
52
+ - lib/cabin/outputs/io.rb
53
+ - lib/cabin/outputs/stdlib-logger.rb
54
+ - lib/cabin/outputs/zeromq.rb
55
+ - lib/cabin/publisher.rb
56
+ - lib/cabin/timer.rb
62
57
  - test/all.rb
63
58
  - test/minitest-patch.rb
59
+ - test/test_logging.rb
64
60
  - test/test_metrics.rb
61
+ - test/test_pipe.rb
65
62
  - test/test_zeromq.rb
66
- - test/test_logging.rb
67
- - LICENSE
68
- - CHANGELIST
69
- - bin/rubygems-cabin-test
70
63
  homepage: https://github.com/jordansissel/ruby-cabin
71
- licenses:
64
+ licenses:
72
65
  - Apache License (2.0)
66
+ metadata: {}
73
67
  post_install_message:
74
68
  rdoc_options: []
75
-
76
- require_paths:
69
+ require_paths:
77
70
  - lib
78
71
  - lib
79
- required_ruby_version: !ruby/object:Gem::Requirement
80
- none: false
81
- requirements:
72
+ required_ruby_version: !ruby/object:Gem::Requirement
73
+ requirements:
82
74
  - - ">="
83
- - !ruby/object:Gem::Version
84
- hash: 3
85
- segments:
86
- - 0
87
- version: "0"
88
- required_rubygems_version: !ruby/object:Gem::Requirement
89
- none: false
90
- requirements:
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ required_rubygems_version: !ruby/object:Gem::Requirement
78
+ requirements:
91
79
  - - ">="
92
- - !ruby/object:Gem::Version
93
- hash: 3
94
- segments:
95
- - 0
96
- version: "0"
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
97
82
  requirements: []
98
-
99
83
  rubyforge_project:
100
- rubygems_version: 1.8.25
84
+ rubygems_version: 2.2.2
101
85
  signing_key:
102
- specification_version: 3
86
+ specification_version: 4
103
87
  summary: Experiments in structured and contextual logging
104
88
  test_files: []
105
-
106
- has_rdoc:
@@ -1,25 +0,0 @@
1
- require "cabin"
2
- require "spoon"
3
-
4
-
5
- logger = Cabin::Channel.get
6
- logger.subscribe(STDOUT)
7
- logger.level = :info
8
-
9
- fileactions = Spoon::FileActions.new
10
- fileactions.close(0)
11
- cor, cow = IO.pipe # child stdout
12
- cer, cew = IO.pipe # child stderr
13
- fileactions.dup2(cow.fileno, 1)
14
- fileactions.dup2(cew.fileno, 2)
15
-
16
- spawn_attr = Spoon::SpawnAttributes.new
17
- pid = Spoon.posix_spawn("/bin/sh", fileactions, spawn_attr, ["sh", "-c"] + ARGV)
18
- puts pid
19
- cow.close
20
- cew.close
21
-
22
- logger.pipe(cor => :info, cer => :error)
23
- pid, status = Process.waitpid2(pid)
24
-
25
- puts status.inspect