steno 0.0.20 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -42,7 +42,9 @@ class Steno::Config
42
42
  }
43
43
 
44
44
  if hash[:file]
45
- opts[:sinks] << Steno::Sink::IO.for_file(hash[:file])
45
+ max_retries = hash[:max_retries]
46
+ opts[:sinks] << Steno::Sink::IO.for_file(hash[:file],
47
+ :max_retries => max_retries)
46
48
  end
47
49
 
48
50
  if hash[:syslog]
@@ -50,7 +52,10 @@ class Steno::Config
50
52
  opts[:sinks] << Steno::Sink::Syslog.instance
51
53
  end
52
54
 
53
- opts[:sinks] << Steno::Sink::IO.new(STDOUT) if opts[:sinks].empty?
55
+ if opts[:sinks].empty?
56
+ opts[:sinks] << Steno::Sink::IO.new(STDOUT)
57
+ end
58
+
54
59
  opts
55
60
  end
56
61
 
@@ -10,24 +10,36 @@ class Steno::Sink::IO < Steno::Sink::Base
10
10
  # Returns a new sink configured to append to the file at path.
11
11
  #
12
12
  # @param [String] path
13
- # @param [True, False] autoflush If true, encoded records will not be
14
- # buffered by Ruby.
15
- #
13
+ # @param [Hash] If the key :autoflush is set to true, encoded records
14
+ # will not be buffered by Ruby. The key :max_retries
15
+ # is forwarded to Steno::Sink::IO object during creation.
16
16
  # @return [Steno::Sink::IO]
17
- def for_file(path, autoflush = true)
17
+ def for_file(path, opts = {})
18
+ autoflush = true
19
+ if opts.include?(:autoflush)
20
+ autoflush = opts[:autoflush]
21
+ end
22
+
18
23
  io = File.open(path, "a+")
19
24
 
20
25
  io.sync = autoflush
21
26
 
22
- new(io)
27
+ new(io, :max_retries => opts[:max_retries])
23
28
  end
24
29
  end
25
30
 
26
- # @param [IO] io The IO object that will be written to
27
- # @param [Steno::Codec::Base] codec
28
- def initialize(io, codec = nil)
29
- super(codec)
31
+ attr_reader :max_retries
30
32
 
33
+ # @param [IO] io The IO object that will be written to
34
+ # @param [Hash] opts Key :codec is used to specify a codec inheriting from
35
+ # Steno::Codec::Base.
36
+ # Key :max_retries takes an integer value which specifies
37
+ # the number of times the write operation can be retried
38
+ # when IOError is raised while writing a record.
39
+ def initialize(io, opts = {})
40
+ super(opts[:codec])
41
+
42
+ @max_retries = opts[:max_retries] || -1
31
43
  @io_lock = Mutex.new
32
44
  @io = io
33
45
  end
@@ -35,7 +47,19 @@ class Steno::Sink::IO < Steno::Sink::Base
35
47
  def add_record(record)
36
48
  bytes = @codec.encode_record(record)
37
49
 
38
- @io_lock.synchronize { @io.write(bytes) }
50
+ @io_lock.synchronize do
51
+ retries = 0
52
+ begin
53
+ @io.write(bytes)
54
+ rescue IOError => e
55
+ if retries < @max_retries
56
+ retries += 1
57
+ retry
58
+ else
59
+ raise e
60
+ end
61
+ end
62
+ end
39
63
 
40
64
  nil
41
65
  end
@@ -1,3 +1,3 @@
1
1
  module Steno
2
- VERSION = "0.0.20"
2
+ VERSION = "1.0.0"
3
3
  end
@@ -10,7 +10,8 @@ describe Steno::Config do
10
10
 
11
11
  @mock_sink_file = mock("sink")
12
12
  @mock_sink_file.stub(:codec=)
13
- Steno::Sink::IO.should_receive(:for_file).with(@log_path)
13
+ Steno::Sink::IO.should_receive(:for_file).with(@log_path,
14
+ :max_retries => 5)
14
15
  .and_return(@mock_sink_file)
15
16
 
16
17
  @mock_sink_syslog = mock("sink")
@@ -36,7 +37,8 @@ describe Steno::Config do
36
37
  :file => @log_path,
37
38
  :level => "debug2",
38
39
  :default_log_level => "warn",
39
- :syslog => "test"
40
+ :syslog => "test",
41
+ :max_retries => 5,
40
42
  }
41
43
  end
42
44
 
@@ -45,7 +47,8 @@ describe Steno::Config do
45
47
  "file" => @log_path,
46
48
  "level" => "debug2",
47
49
  "default_log_level" => "warn",
48
- "syslog" => "test"
50
+ "syslog" => "test",
51
+ "max_retries" => 5,
49
52
  }
50
53
  end
51
54
  end
@@ -90,11 +93,12 @@ describe Steno::Config do
90
93
  end
91
94
 
92
95
  it "should add a file sink if the 'file' key is specified" do
93
- write_config(@config_path, { "file" => @log_path })
96
+ write_config(@config_path, { "file" => @log_path, "max_retries" => 2 })
94
97
  mock_sink = mock("sink")
95
98
  mock_sink.stub(:codec=)
96
99
 
97
- Steno::Sink::IO.should_receive(:for_file).with(@log_path).and_return(mock_sink)
100
+ Steno::Sink::IO.should_receive(:for_file).
101
+ with(@log_path, :max_retries => 2).and_return(mock_sink)
98
102
  config = Steno::Config.from_file(@config_path)
99
103
  config.sinks.size.should == 1
100
104
  config.sinks[0].should == mock_sink
@@ -113,6 +117,18 @@ describe Steno::Config do
113
117
  config.sinks[0].should == mock_sink
114
118
  end
115
119
 
120
+ it "should add an io sink to stdout if no sinks are explicitly specified in the config file" do
121
+ write_config(@config_path, {})
122
+ mock_sink = mock("sink")
123
+ mock_sink.stub(:codec=)
124
+
125
+ Steno::Sink::IO.should_receive(:new).with(STDOUT).and_return(mock_sink)
126
+
127
+ config = Steno::Config.from_file(@config_path)
128
+ config.sinks.size.should == 1
129
+ config.sinks[0].should == mock_sink
130
+ end
131
+
116
132
  it "should merge supplied overrides with the file based config" do
117
133
  write_config(@config_path, { "default_log_level" => "debug" })
118
134
 
@@ -9,6 +9,41 @@ describe Steno::Sink::IO do
9
9
  Steno::Record.new("source", level, "message")
10
10
  end
11
11
 
12
+ describe ".for_file" do
13
+ it "should return a new sink configured to append to the file at path with autosync set to true by default" do
14
+ mock_handle = mock("file handle")
15
+
16
+ File.should_receive(:open).with("path", "a+").and_return(mock_handle)
17
+ mock_handle.should_receive(:sync=).with(true)
18
+
19
+ mock_sink = mock("sink")
20
+ Steno::Sink::IO.should_receive(:new).with(mock_handle,
21
+ :max_retries => 10).
22
+ and_return(mock_sink)
23
+
24
+ returned = Steno::Sink::IO.for_file("path",
25
+ :max_retries => 10)
26
+ returned.should == mock_sink
27
+ end
28
+
29
+ it "should return a new sink configured to append to the file at path with specified options" do
30
+ mock_handle = mock("file handle")
31
+
32
+ File.should_receive(:open).with("path", "a+").and_return(mock_handle)
33
+ mock_handle.should_receive(:sync=).with(false)
34
+
35
+ mock_sink = mock("sink")
36
+ Steno::Sink::IO.should_receive(:new).with(mock_handle,
37
+ :max_retries => 10).
38
+ and_return(mock_sink)
39
+
40
+ returned = Steno::Sink::IO.for_file("path",
41
+ :autoflush => false,
42
+ :max_retries => 10)
43
+ returned.should == mock_sink
44
+ end
45
+ end
46
+
12
47
  describe "#add_record" do
13
48
  it "should encode the record and write it to the underlying io object" do
14
49
  codec = mock("codec")
@@ -17,7 +52,35 @@ describe Steno::Sink::IO do
17
52
  io = mock("io")
18
53
  io.should_receive(:write).with(record.message)
19
54
 
20
- Steno::Sink::IO.new(io, codec).add_record(record)
55
+ Steno::Sink::IO.new(io, :codec => codec).add_record(record)
56
+ end
57
+
58
+ it "should by default not retry on IOError" do
59
+ codec = mock("codec")
60
+ codec.should_receive(:encode_record).with(record).and_return(record.message)
61
+
62
+ io = mock("io")
63
+
64
+ io.should_receive(:write).with(record.message).ordered.and_raise(IOError)
65
+
66
+ expect {
67
+ Steno::Sink::IO.new(io, :codec => codec).add_record(record)
68
+ }.to raise_error(IOError)
69
+ end
70
+
71
+ it "should retry not more than specified number of times on IOError" do
72
+ codec = mock("codec")
73
+ codec.should_receive(:encode_record).with(record).and_return(record.message)
74
+
75
+ io = mock("io")
76
+
77
+ io.should_receive(:write).exactly(3).times.with(record.message).ordered.
78
+ and_raise(IOError)
79
+
80
+ expect {
81
+ Steno::Sink::IO.new(io, :codec => codec, :max_retries => 2).
82
+ add_record(record)
83
+ }.to raise_error(IOError)
21
84
  end
22
85
  end
23
86
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: steno
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.20
4
+ version: 1.0.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-10-10 00:00:00.000000000 Z
12
+ date: 2012-10-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: grape