vcap_logging 0.1.4

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