yell 1.3.0 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +3 -1
- data/.travis.yml +1 -2
- data/Gemfile +5 -1
- data/README.md +67 -14
- data/examples/004.1-colorizing-the-log-output.rb +4 -4
- data/lib/yell.rb +19 -10
- data/lib/yell/adapters.rb +23 -26
- data/lib/yell/adapters/base.rb +8 -2
- data/lib/yell/adapters/datefile.rb +45 -42
- data/lib/yell/adapters/file.rb +10 -5
- data/lib/yell/adapters/io.rb +52 -48
- data/lib/yell/adapters/streams.rb +10 -2
- data/lib/yell/configuration.rb +1 -1
- data/lib/yell/event.rb +4 -4
- data/lib/yell/formatter.rb +11 -25
- data/lib/yell/helpers/adapters.rb +51 -0
- data/lib/yell/helpers/base.rb +19 -0
- data/lib/yell/helpers/formatter.rb +31 -0
- data/lib/yell/helpers/level.rb +36 -0
- data/lib/yell/helpers/silencer.rb +32 -0
- data/lib/yell/helpers/tracer.rb +48 -0
- data/lib/yell/level.rb +38 -47
- data/lib/yell/logger.rb +53 -73
- data/lib/yell/repository.rb +31 -29
- data/lib/yell/silencer.rb +69 -0
- data/lib/yell/version.rb +1 -1
- data/spec/spec_helper.rb +21 -9
- data/spec/yell/adapters/base_spec.rb +17 -34
- data/spec/yell/adapters/datefile_spec.rb +109 -66
- data/spec/yell/adapters/file_spec.rb +18 -18
- data/spec/yell/adapters/io_spec.rb +17 -13
- data/spec/yell/adapters/streams_spec.rb +7 -7
- data/spec/yell/adapters_spec.rb +18 -23
- data/spec/yell/configuration_spec.rb +7 -7
- data/spec/yell/event_spec.rb +25 -27
- data/spec/yell/formatter_spec.rb +89 -82
- data/spec/yell/level_spec.rb +119 -94
- data/spec/yell/loggable_spec.rb +6 -5
- data/spec/yell/logger_spec.rb +106 -66
- data/spec/yell/repository_spec.rb +23 -38
- data/spec/yell/silencer_spec.rb +49 -0
- data/spec/yell_spec.rb +24 -27
- 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
|
+
|
data/lib/yell/version.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -3,12 +3,29 @@ $:.unshift File.expand_path('../../lib', __FILE__)
|
|
3
3
|
|
4
4
|
ENV['YELL_ENV'] = 'test'
|
5
5
|
|
6
|
-
require '
|
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
|
6
|
-
|
7
|
-
|
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
|
-
|
13
|
-
|
14
|
-
end
|
15
|
-
end
|
9
|
+
it "should set the level" do
|
10
|
+
adapter = Yell::Adapters::Base.new(:level => level)
|
16
11
|
|
17
|
-
|
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
|
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
|
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(
|
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(
|
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(
|
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(
|
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(:
|
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(
|
18
|
+
Timecop.freeze(today)
|
10
19
|
end
|
11
20
|
|
12
21
|
it { should be_kind_of Yell::Adapters::File }
|
13
22
|
|
14
|
-
describe
|
15
|
-
let(:
|
23
|
+
describe "#write" do
|
24
|
+
let(:today_lines) { File.readlines(today_filename) }
|
16
25
|
|
17
|
-
|
18
|
-
adapter.write(
|
19
|
-
|
20
|
-
File.exist?(datefile_filename).should be_true
|
26
|
+
before do
|
27
|
+
adapter.write(event)
|
21
28
|
end
|
22
29
|
|
23
|
-
it "should
|
24
|
-
|
30
|
+
it "should be output to filename with date pattern" do
|
31
|
+
expect(File.exist?(today_filename)).to be_true
|
25
32
|
|
26
|
-
|
27
|
-
|
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
|
-
|
31
|
-
|
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
|
-
|
35
|
-
|
36
|
-
|
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
|
-
|
44
|
+
it "should not open file handle again" do
|
45
|
+
dont_allow(File).open(anything, anything)
|
39
46
|
|
40
|
-
|
41
|
-
adapter.write( event )
|
42
|
-
end
|
47
|
+
adapter.write(event)
|
43
48
|
end
|
44
|
-
end
|
45
49
|
|
46
|
-
|
47
|
-
|
50
|
+
context "on rollover" do
|
51
|
+
let(:tomorrow_lines) { File.readlines(tomorrow_filename) }
|
48
52
|
|
49
|
-
|
50
|
-
|
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
|
-
|
59
|
-
|
60
|
-
|
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
|
66
|
-
|
67
|
-
|
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
|
-
|
70
|
-
|
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
|
-
|
73
|
-
|
77
|
+
Timecop.freeze(tomorrow) { adapter.write(event) }
|
78
|
+
expect(Dir[fixture_path + '/*.log'].size).to eq(2)
|
74
79
|
|
75
|
-
|
76
|
-
|
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
|
80
|
-
|
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
|
-
|
83
|
-
|
96
|
+
it "should be recreated upon rollover" do
|
97
|
+
Timecop.freeze(tomorrow) { adapter.write(event) }
|
84
98
|
|
85
|
-
|
86
|
-
|
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
|
92
|
-
|
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?(
|
112
|
+
expect(File.symlink?(filename)).to be_false
|
98
113
|
end
|
99
114
|
end
|
100
115
|
end
|
101
116
|
|
102
|
-
describe
|
103
|
-
let(:
|
104
|
-
let(:header) { File.open(datefile_filename, &:readline) }
|
117
|
+
describe "#header" do
|
118
|
+
let(:header) { File.open(today_filename, &:readline) }
|
105
119
|
|
106
|
-
|
107
|
-
|
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
|
-
|
111
|
-
|
150
|
+
context "another adapter with the same :filename" do
|
151
|
+
let(:another_adapter) { Yell::Adapters::Datefile.new(:filename => filename) }
|
112
152
|
|
113
|
-
|
153
|
+
before do
|
154
|
+
adapter.write(event)
|
114
155
|
end
|
115
156
|
|
116
|
-
it "should not
|
117
|
-
|
118
|
-
adapter.write( event )
|
157
|
+
it "should not write the header again" do
|
158
|
+
another_adapter.write(event)
|
119
159
|
|
120
|
-
|
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(
|
7
|
+
stub(File).open(anything, anything) { devnull }
|
8
8
|
end
|
9
9
|
|
10
|
-
it { should be_kind_of
|
10
|
+
it { should be_kind_of(Yell::Adapters::Io) }
|
11
11
|
|
12
|
-
context
|
13
|
-
subject { Yell::Adapters::File.new.send
|
12
|
+
context "#stream" do
|
13
|
+
subject { Yell::Adapters::File.new.send(:stream) }
|
14
14
|
|
15
|
-
it { should be_kind_of
|
15
|
+
it { should be_kind_of(File) }
|
16
16
|
end
|
17
17
|
|
18
|
-
context
|
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(
|
27
|
+
mock(File).open(filename, File::WRONLY|File::APPEND|File::CREAT) { devnull }
|
28
28
|
|
29
|
-
adapter.write(
|
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(
|
35
|
+
let(:adapter) { Yell::Adapters::File.new(:filename => filename) }
|
36
36
|
|
37
37
|
it "should print to file" do
|
38
|
-
mock(
|
38
|
+
mock(File).open(filename, File::WRONLY|File::APPEND|File::CREAT) { devnull }
|
39
39
|
|
40
|
-
adapter.write(
|
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(
|
49
|
+
mock(File).open(pathname.to_s, File::WRONLY|File::APPEND|File::CREAT) { devnull }
|
50
50
|
|
51
|
-
adapter.write(
|
51
|
+
adapter.write(event)
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
|
-
context
|
55
|
+
context "#sync" do
|
56
56
|
let(:adapter) { Yell::Adapters::File.new }
|
57
57
|
|
58
58
|
it "should sync by default" do
|
59
|
-
mock(
|
59
|
+
mock(devnull).sync=(true)
|
60
60
|
|
61
|
-
adapter.write(
|
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(
|
67
|
+
mock(devnull).sync=(false)
|
68
68
|
|
69
|
-
adapter.write(
|
69
|
+
adapter.write(event)
|
70
70
|
end
|
71
71
|
end
|
72
72
|
end
|