yell 1.3.0 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +3 -1
  3. data/.travis.yml +1 -2
  4. data/Gemfile +5 -1
  5. data/README.md +67 -14
  6. data/examples/004.1-colorizing-the-log-output.rb +4 -4
  7. data/lib/yell.rb +19 -10
  8. data/lib/yell/adapters.rb +23 -26
  9. data/lib/yell/adapters/base.rb +8 -2
  10. data/lib/yell/adapters/datefile.rb +45 -42
  11. data/lib/yell/adapters/file.rb +10 -5
  12. data/lib/yell/adapters/io.rb +52 -48
  13. data/lib/yell/adapters/streams.rb +10 -2
  14. data/lib/yell/configuration.rb +1 -1
  15. data/lib/yell/event.rb +4 -4
  16. data/lib/yell/formatter.rb +11 -25
  17. data/lib/yell/helpers/adapters.rb +51 -0
  18. data/lib/yell/helpers/base.rb +19 -0
  19. data/lib/yell/helpers/formatter.rb +31 -0
  20. data/lib/yell/helpers/level.rb +36 -0
  21. data/lib/yell/helpers/silencer.rb +32 -0
  22. data/lib/yell/helpers/tracer.rb +48 -0
  23. data/lib/yell/level.rb +38 -47
  24. data/lib/yell/logger.rb +53 -73
  25. data/lib/yell/repository.rb +31 -29
  26. data/lib/yell/silencer.rb +69 -0
  27. data/lib/yell/version.rb +1 -1
  28. data/spec/spec_helper.rb +21 -9
  29. data/spec/yell/adapters/base_spec.rb +17 -34
  30. data/spec/yell/adapters/datefile_spec.rb +109 -66
  31. data/spec/yell/adapters/file_spec.rb +18 -18
  32. data/spec/yell/adapters/io_spec.rb +17 -13
  33. data/spec/yell/adapters/streams_spec.rb +7 -7
  34. data/spec/yell/adapters_spec.rb +18 -23
  35. data/spec/yell/configuration_spec.rb +7 -7
  36. data/spec/yell/event_spec.rb +25 -27
  37. data/spec/yell/formatter_spec.rb +89 -82
  38. data/spec/yell/level_spec.rb +119 -94
  39. data/spec/yell/loggable_spec.rb +6 -5
  40. data/spec/yell/logger_spec.rb +106 -66
  41. data/spec/yell/repository_spec.rb +23 -38
  42. data/spec/yell/silencer_spec.rb +49 -0
  43. data/spec/yell_spec.rb +24 -27
  44. metadata +16 -9
@@ -0,0 +1,69 @@
1
+ # encoding: utf-8
2
+ module Yell #:nodoc:
3
+
4
+ # The +Yell::Silencer+ is your handly helper for stiping out unwanted log messages.
5
+ class Silencer
6
+
7
+ def initialize( *patterns )
8
+ @patterns = patterns.dup
9
+ end
10
+
11
+ # Add one or more patterns to the silencer
12
+ #
13
+ # @example
14
+ # add( 'password' )
15
+ # add( 'username', 'password' )
16
+ #
17
+ # @example Add regular expressions
18
+ # add( /password/ )
19
+ #
20
+ # @return [Array] All set patterns
21
+ def add( *patterns )
22
+ @patterns = @patterns | patterns.compact
23
+ end
24
+
25
+ # Clears out all the messages that would match any defined pattern
26
+ #
27
+ # @example
28
+ # silence('username', 'password')
29
+ # #=> ['username]
30
+ #
31
+ # @return [Array<String>] The remaining messages
32
+ def silence( *messages )
33
+ messages.reject { |m| matches?(m) }
34
+ end
35
+
36
+ # Anything to silence at all?
37
+ #
38
+ # @return [Boolean] true or false
39
+ def silence?
40
+ @patterns.any?
41
+ end
42
+
43
+ # Get a pretty string
44
+ def inspect
45
+ "#<#{self.class.name} patterns: #{@patterns.inspect}>"
46
+ end
47
+
48
+ # @private
49
+ def patterns
50
+ @patterns
51
+ end
52
+
53
+
54
+ private
55
+
56
+ # Check if the provided message matches any of the defined patterns.
57
+ #
58
+ # @example
59
+ # matches?('password')
60
+ # #=> true
61
+ #
62
+ # @return [Boolean] true or false
63
+ def matches?( message )
64
+ @patterns.any? { |pattern| message.match(pattern) }
65
+ end
66
+
67
+ end
68
+ end
69
+
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Yell #:nodoc:
4
- VERSION = "1.3.0"
4
+ VERSION = "1.4.0"
5
5
 
6
6
  end
7
7
 
@@ -3,12 +3,29 @@ $:.unshift File.expand_path('../../lib', __FILE__)
3
3
 
4
4
  ENV['YELL_ENV'] = 'test'
5
5
 
6
- require 'yell'
7
-
8
- require 'rspec'
6
+ require 'rspec/core'
7
+ require 'rspec/expectations'
9
8
  require 'rr'
10
9
  require 'timecop'
11
10
 
11
+ begin
12
+ require 'coveralls'
13
+
14
+ require 'simplecov'
15
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
16
+ SimpleCov::Formatter::HTMLFormatter,
17
+ Coveralls::SimpleCov::Formatter
18
+ ]
19
+
20
+ SimpleCov.start do
21
+ add_filter 'spec'
22
+ end
23
+ rescue LoadError
24
+ STDERR.puts "Not running coverage..."
25
+ end
26
+
27
+ require 'yell'
28
+
12
29
  RSpec.configure do |config|
13
30
  config.mock_framework = :rr
14
31
 
@@ -19,8 +36,7 @@ RSpec.configure do |config|
19
36
  end
20
37
 
21
38
  config.after do
22
- # release time after each test
23
- Timecop.return
39
+ Timecop.return # release time after each test
24
40
  end
25
41
 
26
42
 
@@ -30,9 +46,5 @@ RSpec.configure do |config|
30
46
  File.expand_path( "fixtures", File.dirname(__FILE__) )
31
47
  end
32
48
 
33
- def datefile_filename( pattern = Yell::Adapters::Datefile::DefaultDatePattern )
34
- fixture_path + "/test.#{Time.now.strftime(pattern)}.log"
35
- end
36
-
37
49
  end
38
50
 
@@ -2,57 +2,40 @@ require 'spec_helper'
2
2
 
3
3
  describe Yell::Adapters::Base do
4
4
 
5
- context "initialize with :level" do
6
- before do
7
- any_instance_of( Yell::Adapters::Base ) do |base|
8
- mock( base ).level= :info
9
- end
10
- end
5
+ context "initialize" do
6
+ context ":level" do
7
+ let(:level) { Yell::Level.new(:warn) }
11
8
 
12
- it "should set the level" do
13
- Yell::Adapters::Base.new(:level => :info)
14
- end
15
- end
9
+ it "should set the level" do
10
+ adapter = Yell::Adapters::Base.new(:level => level)
16
11
 
17
- context "insitialize with :block" do
18
- context :level do
19
- before do
20
- any_instance_of( Yell::Adapters::Base ) do |base|
21
- mock( base ).level= :info
22
- end
12
+ expect(adapter.level).to eq(level)
23
13
  end
24
14
 
25
- it "should set the level" do
26
- Yell::Adapters::Base.new(:level => :info)
15
+ it "should set the level when block was given" do
16
+ adapter = Yell::Adapters::Base.new { |a| a.level = level }
17
+
18
+ expect(adapter.level).to eq(level)
27
19
  end
28
20
  end
29
21
  end
30
22
 
31
- context :options do
32
- let(:options) { {:my => :options} }
33
- let(:adapter) { Yell::Adapters::Base.new(options) }
34
-
35
- it { options.should == options }
36
- end
37
-
38
- context :write do
23
+ context "#write" do
39
24
  let(:logger) { Yell::Logger.new }
40
25
  subject { Yell::Adapters::Base.new(:level => 1) }
41
26
 
42
27
  it "should delegate :event to :write!" do
43
- event = Yell::Event.new( logger, 1, "Hello World!" )
44
-
45
- mock( subject ).write!( event )
28
+ event = Yell::Event.new(logger, 1, "Hello World!")
29
+ mock(subject).write!(event)
46
30
 
47
- subject.write( event )
31
+ subject.write(event)
48
32
  end
49
33
 
50
34
  it "should not write when event does not have the right level" do
51
- event = Yell::Event.new( logger, 0, "Hello World!" )
52
-
53
- dont_allow( subject ).write!( event )
35
+ event = Yell::Event.new(logger, 0, "Hello World!")
36
+ dont_allow(subject).write!(event)
54
37
 
55
- subject.write( event )
38
+ subject.write(event)
56
39
  end
57
40
  end
58
41
 
@@ -2,122 +2,165 @@ require 'spec_helper'
2
2
 
3
3
  describe Yell::Adapters::Datefile do
4
4
  let(:logger) { Yell::Logger.new }
5
+ let(:message) { "Hello World" }
6
+ let(:event) { Yell::Event.new(logger, 1, message) }
7
+
8
+ let(:today) { Time.now }
9
+ let(:tomorrow) { Time.now + 86400 }
10
+
5
11
  let(:filename) { fixture_path + '/test.log' }
6
- let(:event) { Yell::Event.new(logger, 1, "Hello World") }
12
+ let(:today_filename) { fixture_path + "/test.#{today.strftime(Yell::Adapters::Datefile::DefaultDatePattern)}.log" }
13
+ let(:tomorrow_filename) { fixture_path + "/test.#{tomorrow.strftime(Yell::Adapters::Datefile::DefaultDatePattern)}.log" }
14
+
15
+ let(:adapter) { Yell::Adapters::Datefile.new(:filename => filename, :format => "%m") }
7
16
 
8
17
  before do
9
- Timecop.freeze( Time.now )
18
+ Timecop.freeze(today)
10
19
  end
11
20
 
12
21
  it { should be_kind_of Yell::Adapters::File }
13
22
 
14
- describe :filename do
15
- let(:adapter) { Yell::Adapters::Datefile.new(:filename => filename, :symlink => false) }
23
+ describe "#write" do
24
+ let(:today_lines) { File.readlines(today_filename) }
16
25
 
17
- it "should be replaced with date_pattern" do
18
- adapter.write( event )
19
-
20
- File.exist?(datefile_filename).should be_true
26
+ before do
27
+ adapter.write(event)
21
28
  end
22
29
 
23
- it "should open file handle only once" do
24
- mock( File ).open( datefile_filename, anything ) { File.new('/dev/null', 'w') }
30
+ it "should be output to filename with date pattern" do
31
+ expect(File.exist?(today_filename)).to be_true
25
32
 
26
- adapter.write( event )
27
- Timecop.freeze( Time.now + 10 ) { adapter.write(event) }
33
+ expect(today_lines.size).to eq(2) # includes header line
34
+ expect(today_lines.last).to match(message)
28
35
  end
29
36
 
30
- context "rollover" do
31
- let(:tomorrow) { Time.now + 86400 }
32
- let(:tomorrow_datefile_filename) { fixture_path + "/test.#{tomorrow.strftime(Yell::Adapters::Datefile::DefaultDatePattern)}.log" }
37
+ it "should output to the same file" do
38
+ adapter.write(event)
33
39
 
34
- it "should rotate when date has passed" do
35
- mock( File ).open( datefile_filename, anything ) { File.new('/dev/null', 'w') }
36
- adapter.write( event )
40
+ expect(File.exist?(today_filename)).to be_true
41
+ expect(today_lines.size).to eq(3) # includes header line
42
+ end
37
43
 
38
- Timecop.freeze( tomorrow )
44
+ it "should not open file handle again" do
45
+ dont_allow(File).open(anything, anything)
39
46
 
40
- mock( File ).open( tomorrow_datefile_filename, anything ) { File.new('/dev/null', 'w') }
41
- adapter.write( event )
42
- end
47
+ adapter.write(event)
43
48
  end
44
- end
45
49
 
46
- describe :keep do
47
- let(:adapter) { Yell::Adapters::Datefile.new(:keep => 2, :filename => filename, :symlink => false, :date_pattern => "%M") }
50
+ context "on rollover" do
51
+ let(:tomorrow_lines) { File.readlines(tomorrow_filename) }
48
52
 
49
- it "should keep the specified number or files upon rollover" do
50
- adapter.write( event )
51
- Dir[ fixture_path + '/*.log' ].size.should == 1
52
-
53
- Timecop.freeze( Time.now + 60 ) do
54
- adapter.write( event )
55
- Dir[ fixture_path + '/*.log' ].size.should == 2
53
+ before do
54
+ Timecop.freeze(tomorrow) { adapter.write(event) }
56
55
  end
57
56
 
58
- Timecop.freeze( Time.now + 120 ) do
59
- adapter.write( event )
60
- Dir[ fixture_path + '/*.log' ].size.should == 2
57
+ it "should rotate file" do
58
+ expect(File.exist?(tomorrow_filename)).to be_true
59
+
60
+ expect(tomorrow_lines.size).to eq(2) # includes header line
61
+ expect(tomorrow_lines.last).to match(message)
61
62
  end
62
63
  end
63
64
  end
64
65
 
65
- describe :symlink do
66
- let(:time) { Time.now }
67
- before { Timecop.freeze(time) }
66
+ describe "#keep" do
67
+ before do
68
+ adapter.symlink = false # to not taint the Dir
69
+ adapter.keep = 2
70
+
71
+ adapter.write(event)
72
+ end
68
73
 
69
- context "default (true)" do
70
- let(:adapter) { Yell::Adapters::Datefile.new(:filename => filename, :date_pattern => "%M") }
74
+ it "should keep the specified number or files upon rollover" do
75
+ expect(Dir[fixture_path + '/*.log'].size).to eq(1)
71
76
 
72
- it "should create the sylink the original filename" do
73
- adapter.write( event )
77
+ Timecop.freeze(tomorrow) { adapter.write(event) }
78
+ expect(Dir[fixture_path + '/*.log'].size).to eq(2)
74
79
 
75
- File.symlink?( filename ).should be_true
76
- File.readlink( filename ).should == datefile_filename(adapter.date_pattern)
80
+ Timecop.freeze(tomorrow + 86400 ) { adapter.write(event) }
81
+ expect(Dir[fixture_path + '/*.log'].size).to eq(2)
82
+ end
83
+ end
84
+
85
+ describe "#symlink" do
86
+ context "when true (default)" do
87
+ before do
88
+ adapter.write(event)
77
89
  end
78
90
 
79
- it "should symlink upon rollover" do
80
- adapter.write( event )
91
+ it "should be created on the original filename" do
92
+ expect(File.symlink?(filename)).to be_true
93
+ expect(File.readlink(filename)).to eq(today_filename)
94
+ end
81
95
 
82
- Timecop.freeze( time + 120 ) do
83
- adapter.write( event )
96
+ it "should be recreated upon rollover" do
97
+ Timecop.freeze(tomorrow) { adapter.write(event) }
84
98
 
85
- File.symlink?( filename ).should be_true
86
- File.readlink( filename ).should == datefile_filename(adapter.date_pattern)
87
- end
99
+ expect(File.symlink?(filename)).to be_true
100
+ expect(File.readlink(filename)).to eq(tomorrow_filename)
88
101
  end
89
102
  end
90
103
 
91
- context "when set to false" do
92
- let(:adapter) { Yell::Adapters::Datefile.new(:symlink => false, :filename => filename, :date_pattern => "%M") }
104
+ context "when false" do
105
+ before do
106
+ adapter.symlink = false
107
+ end
93
108
 
94
109
  it "should not create the sylink the original filename" do
95
110
  adapter.write( event )
96
111
 
97
- File.symlink?( filename ).should be_false
112
+ expect(File.symlink?(filename)).to be_false
98
113
  end
99
114
  end
100
115
  end
101
116
 
102
- describe :header do
103
- let(:adapter) { Yell::Adapters::Datefile.new(:filename => filename) }
104
- let(:header) { File.open(datefile_filename, &:readline) }
117
+ describe "#header" do
118
+ let(:header) { File.open(today_filename, &:readline) }
105
119
 
106
- before do
107
- adapter.format = "%m" # easier to parse
120
+ context "when true (default)" do
121
+ before do
122
+ adapter.write(event)
123
+ end
124
+
125
+ it "should be written" do
126
+ expect(header).to match(Yell::Adapters::Datefile::HeaderRegexp)
127
+ end
128
+
129
+ it "should be rewritten upon rollover" do
130
+ Timecop.freeze(tomorrow) { adapter.write(event) }
131
+
132
+ expect(File.symlink?(filename)).to be_true
133
+ expect(File.readlink(filename)).to eq(tomorrow_filename)
134
+ end
135
+ end
136
+
137
+ context "when false" do
138
+ before do
139
+ adapter.header = false
140
+ end
141
+
142
+ it "should not be written" do
143
+ adapter.write(event)
144
+
145
+ expect(header).to eq("Hello World\n")
146
+ end
108
147
  end
148
+ end
109
149
 
110
- it "should be written by default" do
111
- adapter.write( event )
150
+ context "another adapter with the same :filename" do
151
+ let(:another_adapter) { Yell::Adapters::Datefile.new(:filename => filename) }
112
152
 
113
- header.should match(Yell::Adapters::Datefile::HeaderRegexp)
153
+ before do
154
+ adapter.write(event)
114
155
  end
115
156
 
116
- it "should not be written when false" do
117
- adapter.header = false
118
- adapter.write( event )
157
+ it "should not write the header again" do
158
+ another_adapter.write(event)
119
159
 
120
- header.should == "Hello World\n"
160
+ # 1: header
161
+ # 2: adapter write
162
+ # 3: another_adapter: write
163
+ expect(File.readlines(today_filename).size).to eq(3)
121
164
  end
122
165
  end
123
166
 
@@ -4,18 +4,18 @@ describe Yell::Adapters::File do
4
4
  let(:devnull) { File.new('/dev/null', 'w') }
5
5
 
6
6
  before do
7
- stub( File ).open( anything, anything ) { devnull }
7
+ stub(File).open(anything, anything) { devnull }
8
8
  end
9
9
 
10
- it { should be_kind_of Yell::Adapters::Io }
10
+ it { should be_kind_of(Yell::Adapters::Io) }
11
11
 
12
- context :stream do
13
- subject { Yell::Adapters::File.new.send :stream }
12
+ context "#stream" do
13
+ subject { Yell::Adapters::File.new.send(:stream) }
14
14
 
15
- it { should be_kind_of File }
15
+ it { should be_kind_of(File) }
16
16
  end
17
17
 
18
- context :write do
18
+ context "#write" do
19
19
  let(:logger) { Yell::Logger.new }
20
20
  let(:event) { Yell::Event.new(logger, 1, "Hello World") }
21
21
 
@@ -24,20 +24,20 @@ describe Yell::Adapters::File do
24
24
  let(:adapter) { Yell::Adapters::File.new }
25
25
 
26
26
  it "should print to file" do
27
- mock( File ).open( filename, File::WRONLY|File::APPEND|File::CREAT ) { devnull }
27
+ mock(File).open(filename, File::WRONLY|File::APPEND|File::CREAT) { devnull }
28
28
 
29
- adapter.write( event )
29
+ adapter.write(event)
30
30
  end
31
31
  end
32
32
 
33
33
  context "with given :filename" do
34
34
  let(:filename) { fixture_path + '/filename.log' }
35
- let(:adapter) { Yell::Adapters::File.new( :filename => filename ) }
35
+ let(:adapter) { Yell::Adapters::File.new(:filename => filename) }
36
36
 
37
37
  it "should print to file" do
38
- mock( File ).open( filename, File::WRONLY|File::APPEND|File::CREAT ) { devnull }
38
+ mock(File).open(filename, File::WRONLY|File::APPEND|File::CREAT) { devnull }
39
39
 
40
- adapter.write( event )
40
+ adapter.write(event)
41
41
  end
42
42
  end
43
43
 
@@ -46,27 +46,27 @@ describe Yell::Adapters::File do
46
46
  let(:adapter) { Yell::Adapters::File.new( :filename => pathname ) }
47
47
 
48
48
  it "should accept pathanme as filename" do
49
- mock( File ).open( pathname.to_s, File::WRONLY|File::APPEND|File::CREAT ) { devnull }
49
+ mock(File).open(pathname.to_s, File::WRONLY|File::APPEND|File::CREAT) { devnull }
50
50
 
51
- adapter.write( event )
51
+ adapter.write(event)
52
52
  end
53
53
  end
54
54
 
55
- context :sync do
55
+ context "#sync" do
56
56
  let(:adapter) { Yell::Adapters::File.new }
57
57
 
58
58
  it "should sync by default" do
59
- mock( devnull ).sync=( true )
59
+ mock(devnull).sync=(true)
60
60
 
61
- adapter.write( event )
61
+ adapter.write(event)
62
62
  end
63
63
 
64
64
  it "pass the option to File" do
65
65
  adapter.sync = false
66
66
 
67
- mock( devnull ).sync=( false )
67
+ mock(devnull).sync=(false)
68
68
 
69
- adapter.write( event )
69
+ adapter.write(event)
70
70
  end
71
71
  end
72
72
  end