steno 0.0.20 → 1.0.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.
@@ -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