cabin 0.6.1 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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