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.
@@ -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