vcap_logging 0.1.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/Gemfile +3 -0
- data/Rakefile +10 -0
- data/lib/vcap/logging/error.rb +5 -0
- data/lib/vcap/logging/formatter/base_formatter.rb +30 -0
- data/lib/vcap/logging/formatter/delimited_formatter.rb +96 -0
- data/lib/vcap/logging/formatter.rb +2 -0
- data/lib/vcap/logging/log_record.rb +71 -0
- data/lib/vcap/logging/logger.rb +116 -0
- data/lib/vcap/logging/sink/base_sink.rb +83 -0
- data/lib/vcap/logging/sink/file_sink.rb +120 -0
- data/lib/vcap/logging/sink/stdio_sink.rb +25 -0
- data/lib/vcap/logging/sink/string_sink.rb +18 -0
- data/lib/vcap/logging/sink/syslog_sink.rb +67 -0
- data/lib/vcap/logging/sink.rb +5 -0
- data/lib/vcap/logging/sink_map.rb +62 -0
- data/lib/vcap/logging/version.rb +5 -0
- data/lib/vcap/logging.rb +160 -0
- data/spec/Rakefile +15 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/unit/base_sink_spec.rb +38 -0
- data/spec/unit/delimited_formatter_spec.rb +44 -0
- data/spec/unit/file_sink_spec.rb +79 -0
- data/spec/unit/log_record_spec.rb +51 -0
- data/spec/unit/logger_spec.rb +148 -0
- data/spec/unit/logging_spec.rb +114 -0
- data/spec/unit/sink_map_spec.rb +64 -0
- data/spec/unit/stdio_sink_spec.rb +20 -0
- data/spec/unit/string_sink_spec.rb +13 -0
- data/spec/unit/syslog_sink_spec.rb +23 -0
- metadata +112 -0
@@ -0,0 +1,79 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'spec_helper')
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
require 'tmpdir'
|
5
|
+
|
6
|
+
describe VCAP::Logging::Sink::FileSink do
|
7
|
+
before :each do
|
8
|
+
@tmp_dir = Dir.mktmpdir
|
9
|
+
@logfile = File.join(@tmp_dir, 'test.log')
|
10
|
+
@test_line = "testing 123\n"
|
11
|
+
end
|
12
|
+
|
13
|
+
after :each do
|
14
|
+
FileUtils.rm_rf(@tmp_dir)
|
15
|
+
File.directory?(@tmp_dir).should be_false
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'creates a file if it does not exist' do
|
19
|
+
File.exist?(@logfile).should be_false
|
20
|
+
sink = VCAP::Logging::Sink::FileSink.new(@logfile)
|
21
|
+
File.exist?(@logfile).should be_true
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'writes immediately to the file if buffering is disabled' do
|
25
|
+
fmt = mock(:formatter)
|
26
|
+
fmt.should_receive(:format_record).with(anything()).and_return(@test_line)
|
27
|
+
sink = VCAP::Logging::Sink::FileSink.new(@logfile, fmt)
|
28
|
+
sink.add_record('foo')
|
29
|
+
read_file(@log_file).should == @test_line
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'does not write immediately to the file if buffering is enabled' do
|
33
|
+
buffer_size = @test_line.length * 4 + 1
|
34
|
+
fmt = mock(:formatter)
|
35
|
+
fmt.should_receive(:format_record).exactly(6).times.with(anything()).and_return(@test_line)
|
36
|
+
sink = VCAP::Logging::Sink::FileSink.new(@logfile, fmt, :buffer_size => buffer_size)
|
37
|
+
for x in 0..3
|
38
|
+
sink.add_record('foo')
|
39
|
+
read_file(@logfile).should == ""
|
40
|
+
end
|
41
|
+
|
42
|
+
expected = @test_line * 5
|
43
|
+
# Should flush the buffer
|
44
|
+
sink.add_record('foo')
|
45
|
+
read_file(@log_file).should == expected
|
46
|
+
|
47
|
+
# Should be buffered
|
48
|
+
sink.add_record('foo')
|
49
|
+
read_file(@log_file).should == expected
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'flushes internal buffers when asked' do
|
53
|
+
buffer_size = @test_line.length * 2
|
54
|
+
fmt = mock(:formatter)
|
55
|
+
fmt.should_receive(:format_record).with(anything()).and_return(@test_line)
|
56
|
+
sink = VCAP::Logging::Sink::FileSink.new(@logfile, fmt, :buffer_size => buffer_size)
|
57
|
+
sink.add_record('foo')
|
58
|
+
read_file(@logfile).should == ""
|
59
|
+
sink.flush
|
60
|
+
read_file(@logfile).should == @test_line
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'flushes internal buffers on close' do
|
64
|
+
buffer_size = @test_line.length * 2
|
65
|
+
fmt = mock(:formatter)
|
66
|
+
fmt.should_receive(:format_record).with(anything()).and_return(@test_line)
|
67
|
+
sink = VCAP::Logging::Sink::FileSink.new(@logfile, fmt, :buffer_size => buffer_size)
|
68
|
+
sink.add_record('foo')
|
69
|
+
read_file(@logfile).should == ""
|
70
|
+
sink.close
|
71
|
+
read_file(@logfile).should == @test_line
|
72
|
+
end
|
73
|
+
|
74
|
+
def read_file(file)
|
75
|
+
data = nil
|
76
|
+
File.open(@logfile, 'r') {|f| data = f.read }
|
77
|
+
data
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'spec_helper')
|
2
|
+
|
3
|
+
require 'thread'
|
4
|
+
|
5
|
+
describe VCAP::Logging::LogRecord do
|
6
|
+
before :each do
|
7
|
+
@logger = VCAP::Logging::Logger.new('bar', nil)
|
8
|
+
@tags = ['zaz']
|
9
|
+
@data = 'foo'
|
10
|
+
@log_level = :debug
|
11
|
+
@rec = VCAP::Logging::LogRecord.new(@log_level, @data, @logger, @tags)
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#initialize' do
|
15
|
+
it "sets the current thread id and short id" do
|
16
|
+
@rec.thread_id.should == Thread.current.object_id
|
17
|
+
@rec.thread_shortid.should_not == nil
|
18
|
+
end
|
19
|
+
|
20
|
+
it "sets the current process id" do
|
21
|
+
@rec.process_id.should == Process.pid
|
22
|
+
end
|
23
|
+
|
24
|
+
it "sets the current fiber id and short id" do
|
25
|
+
begin
|
26
|
+
require 'fiber'
|
27
|
+
@rec.fiber_id.should == Fiber.current.object_id
|
28
|
+
@rec.fiber_shortid.should_not == nil
|
29
|
+
rescue LoadError
|
30
|
+
@rec.fiber_id.should == nil
|
31
|
+
@rec.fiber_shortid.should == nil
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
it "sets the logger name" do
|
36
|
+
@rec.logger_name.should == @logger.name
|
37
|
+
end
|
38
|
+
|
39
|
+
it "sets the timestamp of when the record was created" do
|
40
|
+
@rec.timestamp.should_not be_nil
|
41
|
+
end
|
42
|
+
|
43
|
+
it "sets tags" do
|
44
|
+
@rec.tags.should == @tags
|
45
|
+
end
|
46
|
+
|
47
|
+
it "sets the log level" do
|
48
|
+
@rec.log_level.should == @log_level
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'spec_helper')
|
2
|
+
|
3
|
+
describe VCAP::Logging::Logger do
|
4
|
+
before :each do
|
5
|
+
@levels = {:debug => 2, :info => 1, :fatal => 0}
|
6
|
+
@sink_map = VCAP::Logging::SinkMap.new(@levels)
|
7
|
+
@logger = VCAP::Logging::Logger.new('test_logger', @sink_map)
|
8
|
+
VCAP::Logging::Logger.define_log_levels(@levels)
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '.define_log_levels' do
|
12
|
+
it 'should define helper methods corresponding to the name of the log levels' do
|
13
|
+
level_map = {:error => 2, :info => 1, :debug => 0}
|
14
|
+
VCAP::Logging::Logger.define_log_levels(level_map)
|
15
|
+
|
16
|
+
# Check that existing loggers are updated
|
17
|
+
for name in level_map.keys
|
18
|
+
@logger.respond_to?(name).should be_true
|
19
|
+
name_f = name.to_s + 'f'
|
20
|
+
@logger.respond_to?(name_f.to_sym).should be_true
|
21
|
+
end
|
22
|
+
|
23
|
+
# Check that new loggers are updated as well
|
24
|
+
new_logger = VCAP::Logging::Logger.new('test_logger2', VCAP::Logging::SinkMap.new(level_map))
|
25
|
+
for name in level_map.keys
|
26
|
+
new_logger.respond_to?(name).should be_true
|
27
|
+
name_f = name.to_s + 'f'
|
28
|
+
new_logger.respond_to?(name_f.to_sym).should be_true
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should undefine previously defined helpers' do
|
33
|
+
level_map = {:error => 2, :info => 1, :debug => 0}
|
34
|
+
VCAP::Logging::Logger.define_log_levels(level_map)
|
35
|
+
for name in level_map.keys
|
36
|
+
@logger.respond_to?(name).should be_true
|
37
|
+
name_f = name.to_s + 'f'
|
38
|
+
@logger.respond_to?(name_f.to_sym).should be_true
|
39
|
+
end
|
40
|
+
|
41
|
+
# Check that previously defined methods are no longer there, and that the
|
42
|
+
# appropriate methods have been defined
|
43
|
+
new_levels = {:foo => 2, :bar => 1}
|
44
|
+
VCAP::Logging::Logger.define_log_levels(new_levels)
|
45
|
+
for name in level_map.keys
|
46
|
+
@logger.respond_to?(name).should be_false
|
47
|
+
name_f = name.to_s + 'f'
|
48
|
+
@logger.respond_to?(name_f.to_sym).should be_false
|
49
|
+
end
|
50
|
+
for name in new_levels.keys
|
51
|
+
@logger.respond_to?(name).should be_true
|
52
|
+
name_f = name.to_s + 'f'
|
53
|
+
@logger.respond_to?(name_f.to_sym).should be_true
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe '#log' do
|
59
|
+
it 'should raise an exception if called with an invalid level' do
|
60
|
+
lambda { @logger.log(3, 'foo') }.should raise_error(ArgumentError)
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'should use supplied blocks to generate log data' do
|
64
|
+
block_called = false
|
65
|
+
sink = mock(:sink)
|
66
|
+
sink.should_receive(:add_record).with(an_instance_of(VCAP::Logging::LogRecord)).once
|
67
|
+
@sink_map.add_sink(nil, nil, sink)
|
68
|
+
@logger.log_level = :info
|
69
|
+
@logger.log(:fatal) { block_called = true; 'foo' }
|
70
|
+
block_called.should be_true
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'should create log records for active levels' do
|
74
|
+
sink = mock(:sink)
|
75
|
+
sink.should_receive(:add_record).with(an_instance_of(VCAP::Logging::LogRecord)).twice
|
76
|
+
@sink_map.add_sink(nil, nil, sink)
|
77
|
+
@logger.log_level = :info
|
78
|
+
@logger.log(:fatal, 'foo')
|
79
|
+
@logger.log(:info, 'foo')
|
80
|
+
@logger.log(:debug, 'foo')
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'should not create log records for levels that are not active' do
|
84
|
+
sink = mock(:sink)
|
85
|
+
sink.should_not_receive(:add_record)
|
86
|
+
@sink_map.add_sink(nil, nil, sink)
|
87
|
+
@logger.log_level = :info
|
88
|
+
@logger.log(:debug, 'foo')
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'should not call blocks associated with inactive levels' do
|
92
|
+
sink = mock(:sink)
|
93
|
+
sink.should_not_receive(:add_record)
|
94
|
+
@sink_map.add_sink(nil, nil, sink)
|
95
|
+
@logger.log_level = :info
|
96
|
+
block_called = false
|
97
|
+
@logger.log(:debug) { block_called = true; 'foo' }
|
98
|
+
block_called.should be_false
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should add an 'exception' tag when data is a kind of Exception" do
|
102
|
+
@logger.log_level = :info
|
103
|
+
ex = StandardError.new("Testing 123")
|
104
|
+
VCAP::Logging::LogRecord.should_receive(:new).with(:info, ex, @logger, [:exception])
|
105
|
+
@logger.info(ex)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
describe '#logf' do
|
110
|
+
it 'should raise an exception if called with an invalid level' do
|
111
|
+
lambda { @logger.logf(:level3, 'foo') }.should raise_error(ArgumentError)
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'should create log records for active levels' do
|
115
|
+
sink = mock(:sink)
|
116
|
+
sink.should_receive(:add_record).with(an_instance_of(VCAP::Logging::LogRecord)).twice
|
117
|
+
@sink_map.add_sink(nil, nil, sink)
|
118
|
+
@logger.log_level = :info
|
119
|
+
@logger.logf(:fatal, 'foo %s', ['bar'])
|
120
|
+
@logger.logf(:info, 'foo %s', ['baz'])
|
121
|
+
@logger.logf(:debug, 'foo %s', ['jaz'])
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'should not create log records for levels that are not active' do
|
125
|
+
sink = mock(:sink)
|
126
|
+
sink.should_not_receive(:add_record)
|
127
|
+
@sink_map.add_sink(nil, nil, sink)
|
128
|
+
@logger.log_level = :info
|
129
|
+
@logger.logf(:debug, 'foo', [])
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
describe 'helper methods' do
|
134
|
+
it 'should correctly pass their associated log levels' do
|
135
|
+
fmt = '%s'
|
136
|
+
data = 'foo'
|
137
|
+
for name in @levels.keys
|
138
|
+
@logger.should_receive(:log).with(name, data).once
|
139
|
+
@logger.should_receive(:logf).with(name, fmt, [data]).once
|
140
|
+
|
141
|
+
@logger.send(name, data)
|
142
|
+
name_f = name.to_s + 'f'
|
143
|
+
@logger.send(name_f.to_sym, fmt, [data])
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'spec_helper')
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
require 'tmpdir'
|
5
|
+
|
6
|
+
require 'vcap/logging'
|
7
|
+
|
8
|
+
describe VCAP::Logging do
|
9
|
+
before :each do
|
10
|
+
VCAP::Logging.reset
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '.init' do
|
14
|
+
it 'should pick a default log level' do
|
15
|
+
VCAP::Logging.default_log_level.should_not be_nil
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '.logger' do
|
20
|
+
it 'should create a new logger if one does not exist' do
|
21
|
+
logger = VCAP::Logging.logger('foo.bar')
|
22
|
+
logger.should_not be_nil
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should return the same logger for multiple calls' do
|
26
|
+
logger = VCAP::Logging.logger('foo.bar')
|
27
|
+
logger.should_not be_nil
|
28
|
+
|
29
|
+
VCAP::Logging.logger('foo.bar').should == logger
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should set log level to the default if no masks are present' do
|
33
|
+
logger = VCAP::Logging.logger('foo.bar')
|
34
|
+
logger.should_not be_nil
|
35
|
+
logger.log_level.should == VCAP::Logging.default_log_level
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should set log level to the most restrictive mask that matches' do
|
39
|
+
VCAP::Logging.set_log_level('.*', :debug)
|
40
|
+
VCAP::Logging.set_log_level('foo\..*', :fatal)
|
41
|
+
logger = VCAP::Logging.logger('foo.bar')
|
42
|
+
logger.log_level.should == :fatal
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '.set_log_level' do
|
47
|
+
it 'should raise an error if supplied with an unknown level' do
|
48
|
+
lambda { VCAP::Logging.set_log_level('foo', :zazzle) }.should raise_error(ArgumentError)
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'should set the log level on all loggers that match the supplied regex' do
|
52
|
+
level_map = {
|
53
|
+
'foo.bar.baz' => [:debug, :error],
|
54
|
+
'foo.bar.jaz' => [:debug, :error],
|
55
|
+
'foo.bar' => [:info, :info],
|
56
|
+
'foo' => [:warn, :warn],
|
57
|
+
}
|
58
|
+
|
59
|
+
for name, levels in level_map
|
60
|
+
VCAP::Logging.logger(name).log_level = levels[0]
|
61
|
+
end
|
62
|
+
|
63
|
+
VCAP::Logging.set_log_level('foo\.bar\..*', :error)
|
64
|
+
|
65
|
+
for name, levels in level_map
|
66
|
+
VCAP::Logging.logger(name).log_level.should == levels[1]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'should reset loggers at a given level that no longer match to the default level' do
|
71
|
+
logger = VCAP::Logging.logger('foo.bar')
|
72
|
+
VCAP::Logging.set_log_level('foo.bar', :warn)
|
73
|
+
logger.log_level.should == :warn
|
74
|
+
VCAP::Logging.set_log_level('zazzle', :warn)
|
75
|
+
logger.log_level.should == VCAP::Logging.default_log_level
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe '.setup_from_config' do
|
80
|
+
it 'should set the default log level if supplied with a level key' do
|
81
|
+
# Should handle both string/symbol keys
|
82
|
+
VCAP::Logging.setup_from_config(:level => 'debug')
|
83
|
+
VCAP::Logging.default_log_level.should == :debug
|
84
|
+
|
85
|
+
VCAP::Logging.setup_from_config('level' => 'warn')
|
86
|
+
VCAP::Logging.default_log_level.should == :warn
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'should raise an exception if given an invalid level' do
|
90
|
+
lambda { VCAP::Logging.setup_from_config(:level => 'zazzle') }.should raise_error(ArgumentError)
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'should add a stdio sink if no other sinks are configured' do
|
94
|
+
VCAP::Logging.should_receive(:add_sink).with(nil, nil, an_instance_of(VCAP::Logging::Sink::StdioSink)).once
|
95
|
+
VCAP::Logging.setup_from_config(:level => 'debug')
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'should add a file sink if given a file key' do
|
99
|
+
tmpdir = Dir.mktmpdir
|
100
|
+
File.directory?(tmpdir).should be_true
|
101
|
+
|
102
|
+
VCAP::Logging.should_receive(:add_sink).with(nil, nil, an_instance_of(VCAP::Logging::Sink::FileSink)).once
|
103
|
+
VCAP::Logging.setup_from_config('file' => File.join(tmpdir, 'test_file1'))
|
104
|
+
|
105
|
+
FileUtils.rm_rf(tmpdir)
|
106
|
+
File.directory?(tmpdir).should be_false
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'should add a syslog sink if given a syslog key' do
|
110
|
+
VCAP::Logging.should_receive(:add_sink).with(nil, nil, an_instance_of(VCAP::Logging::Sink::SyslogSink)).once
|
111
|
+
VCAP::Logging.setup_from_config('syslog' => 'test1')
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'spec_helper')
|
2
|
+
|
3
|
+
describe VCAP::Logging::SinkMap do
|
4
|
+
before :all do
|
5
|
+
@level_map = {
|
6
|
+
:fatal => 0,
|
7
|
+
:info => 1,
|
8
|
+
:debug => 2,
|
9
|
+
:debug2 => 3,
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#add_sink' do
|
14
|
+
before :each do
|
15
|
+
@sink_map = VCAP::Logging::SinkMap.new(@level_map)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'raises an error for an unknown level' do
|
19
|
+
lambda { @sink_map.add_sink(:zazzle, :info, 'foo') }.should raise_error(ArgumentError)
|
20
|
+
lambda { @sink_map.add_sink(:info, :zazzle, 'foo') }.should raise_error(ArgumentError)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'handles a single level range' do
|
24
|
+
@sink_map.add_sink(:info, :info, 'foo')
|
25
|
+
@sink_map.get_sinks(:info).should == ['foo']
|
26
|
+
[:fatal, :debug, :debug2].each {|l| @sink_map.get_sinks(l).should == [] }
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'handles a range with both start and end set' do
|
30
|
+
@sink_map.add_sink(:debug, :info, 'foo')
|
31
|
+
[:info, :debug].each {|l| @sink_map.get_sinks(l).should == ['foo'] }
|
32
|
+
[:fatal, :debug2].each {|l| @sink_map.get_sinks(l).should == [] }
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'handles a range with only an end set' do
|
36
|
+
@sink_map.add_sink(nil, :info, 'foo')
|
37
|
+
[:info, :debug, :debug2].each {|l| @sink_map.get_sinks(l).should == ['foo'] }
|
38
|
+
@sink_map.get_sinks(:fatal).should == []
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'handles a range with only a start set' do
|
42
|
+
@sink_map.add_sink(:info, nil, 'foo')
|
43
|
+
[:info, :fatal].each {|l| @sink_map.get_sinks(l).should == ['foo'] }
|
44
|
+
[:debug, :debug2].each {|l| @sink_map.get_sinks(l).should == [] }
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'handles a range with no start or end' do
|
48
|
+
@sink_map.add_sink(nil, nil, 'foo')
|
49
|
+
[:fatal, :info, :debug, :debug2].each {|l| @sink_map.get_sinks(l).should == ['foo'] }
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
describe '#each_sink' do
|
55
|
+
it 'maps over each sink only once' do
|
56
|
+
sink_map = VCAP::Logging::SinkMap.new(@level_map)
|
57
|
+
sink_map.add_sink(nil, nil, 'foo')
|
58
|
+
sink_map.add_sink(:info, :info, 'bar')
|
59
|
+
sinks = []
|
60
|
+
sink_map.each_sink {|s| sinks << s }
|
61
|
+
sinks.should == ['foo', 'bar']
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|