yell 1.3.0 → 1.4.0

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