steno 1.2.2-x86-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +15 -0
  2. data/LICENSE +7136 -0
  3. data/README.md +78 -0
  4. data/Rakefile +16 -0
  5. data/bin/steno-prettify +99 -0
  6. data/lib/steno.rb +133 -0
  7. data/lib/steno/codec.rb +2 -0
  8. data/lib/steno/codec/base.rb +34 -0
  9. data/lib/steno/codec/json.rb +36 -0
  10. data/lib/steno/config.rb +97 -0
  11. data/lib/steno/context.rb +59 -0
  12. data/lib/steno/core_ext.rb +11 -0
  13. data/lib/steno/errors.rb +3 -0
  14. data/lib/steno/http_handler.rb +41 -0
  15. data/lib/steno/json_prettifier.rb +131 -0
  16. data/lib/steno/log_level.rb +24 -0
  17. data/lib/steno/logger.rb +174 -0
  18. data/lib/steno/record.rb +41 -0
  19. data/lib/steno/sink.rb +6 -0
  20. data/lib/steno/sink/base.rb +38 -0
  21. data/lib/steno/sink/counter.rb +44 -0
  22. data/lib/steno/sink/eventlog.rb +46 -0
  23. data/lib/steno/sink/fluentd.rb +31 -0
  24. data/lib/steno/sink/io.rb +72 -0
  25. data/lib/steno/sink/syslog.rb +59 -0
  26. data/lib/steno/tagged_logger.rb +59 -0
  27. data/lib/steno/version.rb +3 -0
  28. data/spec/spec_helper.rb +6 -0
  29. data/spec/support/barrier.rb +22 -0
  30. data/spec/support/null_sink.rb +17 -0
  31. data/spec/support/shared_context_specs.rb +7 -0
  32. data/spec/unit/config_spec.rb +221 -0
  33. data/spec/unit/context_spec.rb +62 -0
  34. data/spec/unit/core_ext_spec.rb +38 -0
  35. data/spec/unit/http_handler_spec.rb +73 -0
  36. data/spec/unit/json_codec_spec.rb +48 -0
  37. data/spec/unit/json_prettifier_spec.rb +84 -0
  38. data/spec/unit/log_level_spec.rb +19 -0
  39. data/spec/unit/logger_spec.rb +101 -0
  40. data/spec/unit/record_spec.rb +30 -0
  41. data/spec/unit/sink/counter_spec.rb +27 -0
  42. data/spec/unit/sink/eventlog_spec.rb +41 -0
  43. data/spec/unit/sink/fluentd_spec.rb +46 -0
  44. data/spec/unit/sink/io_spec.rb +111 -0
  45. data/spec/unit/sink/syslog_spec.rb +74 -0
  46. data/spec/unit/steno_spec.rb +86 -0
  47. data/spec/unit/tagged_logger_spec.rb +33 -0
  48. data/steno-1.2.1.gem +0 -0
  49. data/steno.gemspec +41 -0
  50. metadata +224 -0
@@ -0,0 +1,84 @@
1
+ require "spec_helper"
2
+
3
+ require "steno/json_prettifier"
4
+
5
+ describe Steno::JsonPrettifier do
6
+ let(:prettifier) { Steno::JsonPrettifier.new }
7
+ let(:codec) { Steno::Codec::Json.new }
8
+
9
+ describe "#prettify_line" do
10
+ it "should return a properly formatted string" do
11
+ record = Steno::Record.new("test", :info, "message",
12
+ ["filename", "line", "method"], "test" => "data")
13
+ encoded = codec.encode_record(record)
14
+ prettified = prettifier.prettify_line(encoded)
15
+
16
+ exp_regex = ['\d{4}-\d{2}-\d{2}', # YYYY-MM-DD
17
+ '\d{2}:\d{2}:\d{2}\.\d{6}', # HH:MM:SS.uS
18
+ 'test', # Source
19
+ 'pid=\d+', # Process id
20
+ 'tid=\w{4}', # Thread shortid
21
+ 'fid=\w{4}', # Fiber shortid
22
+ 'filename\/method:line', # Location
23
+ 'test=data', # User supplied data
24
+ 'INFO', # Level
25
+ '--',
26
+ 'message', # Log message
27
+ ].join("\s+") + "\n"
28
+ prettified.should match(exp_regex)
29
+ end
30
+
31
+ it "should always use the largest src len to determine src column width" do
32
+ test_srcs = [
33
+ 'a' * (Steno::JsonPrettifier::MIN_COL_WIDTH - 3),
34
+ 'a' * (Steno::JsonPrettifier::MIN_COL_WIDTH - 1),
35
+ 'a' * (Steno::JsonPrettifier::MIN_COL_WIDTH),
36
+ 'a' * (Steno::JsonPrettifier::MIN_COL_WIDTH + 1),
37
+ 'a' * (Steno::JsonPrettifier::MIN_COL_WIDTH - 3),
38
+ 'a' * (Steno::JsonPrettifier::MIN_COL_WIDTH + 3),
39
+ 'a' * (Steno::JsonPrettifier::MIN_COL_WIDTH - 2),
40
+ 'a' * (Steno::JsonPrettifier::MIN_COL_WIDTH + 2)
41
+ ]
42
+
43
+ regex = ['\d{4}-\d{2}-\d{2}', # YYYY-MM-DD
44
+ '\d{2}:\d{2}:\d{2}\.\d{6}', # HH:MM:SS.uS
45
+ '([a-zA-Z0-9\ ]+)', # Source (to be captured)
46
+ 'pid=\d+', # Process id
47
+ '.+' # Everything else
48
+ ].join("\s") + "\n"
49
+
50
+ max_src_len = Steno::JsonPrettifier::MIN_COL_WIDTH
51
+ test_srcs.each do |src|
52
+ record = Steno::Record.new(src,
53
+ :info,
54
+ "message",
55
+ ["filename", "line", "method"],
56
+ "test" => "data")
57
+
58
+ encoded = codec.encode_record(record)
59
+ prettified = prettifier.prettify_line(encoded)
60
+ src_col = prettified.match(regex)[1]
61
+
62
+ max_src_len = [max_src_len, src.length].max
63
+ src_col.length.should == max_src_len
64
+ end
65
+ end
66
+
67
+ it "should raise a parse error when the json-encoded string is not a hash" do
68
+ expect {
69
+ prettifier.prettify_line("[1,2,3]")
70
+ }.to raise_error(Steno::JsonPrettifier::ParseError)
71
+ end
72
+
73
+ it "should raise a parse error when the json-encoded string is malformed" do
74
+ expect {
75
+ prettifier.prettify_line("blah")
76
+ }.to raise_error(Steno::JsonPrettifier::ParseError)
77
+ end
78
+
79
+ it "should work with a nil data field" do
80
+ line = prettifier.prettify_line(%@{"data":null}@)
81
+ line.should include(" - ")
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,19 @@
1
+ require "spec_helper"
2
+
3
+ describe Steno::LogLevel do
4
+ let(:info_level) { Steno::LogLevel.new(:info, 2) }
5
+ let(:debug_level) { Steno::LogLevel.new(:debug, 1) }
6
+
7
+ it "should be comparable" do
8
+ (info_level > debug_level).should be_true
9
+ (debug_level > info_level).should be_false
10
+ (info_level == info_level).should be_true
11
+ end
12
+
13
+ describe "#to_s" do
14
+ it "should return the name of the level" do
15
+ info_level.to_s.should == "info"
16
+ end
17
+ end
18
+
19
+ end
@@ -0,0 +1,101 @@
1
+ require "spec_helper"
2
+
3
+ describe Steno::Logger do
4
+ let(:logger) { Steno::Logger.new("test", []) }
5
+
6
+ it "should provide #level, #levelf, and #level? methods for each log level" do
7
+ Steno::Logger::LEVELS.each do |name, _|
8
+ [name, name.to_s + "f", name.to_s + "?"].each do |meth|
9
+ logger.respond_to?(meth).should be_true
10
+ end
11
+ end
12
+ end
13
+
14
+ describe "#level_active?" do
15
+ it "should return a boolean indicating if the level is enabled" do
16
+ logger.level_active?(:error).should be_true
17
+ logger.level_active?(:info).should be_true
18
+ logger.level_active?(:debug).should be_false
19
+ end
20
+ end
21
+
22
+ describe "#<level>?" do
23
+ it "should return a boolean indiciating if <level> is enabled" do
24
+ logger.error?.should be_true
25
+ logger.info?.should be_true
26
+ logger.debug?.should be_false
27
+ end
28
+ end
29
+
30
+ describe "#level" do
31
+ it "should return the name of the currently active level" do
32
+ logger.level.should == :info
33
+ end
34
+ end
35
+
36
+ describe "#level=" do
37
+ it "should allow the level to be changed" do
38
+ logger.level = :warn
39
+ logger.level.should == :warn
40
+ logger.level_active?(:info).should be_false
41
+ logger.level_active?(:warn).should be_true
42
+ end
43
+ end
44
+
45
+ describe "#log" do
46
+ it "should not forward any messages for levels that are inactive" do
47
+ sink = double("sink")
48
+ sink.should_not_receive(:add_record)
49
+
50
+ my_logger = Steno::Logger.new("test", [sink])
51
+
52
+ my_logger.debug("test")
53
+ end
54
+
55
+ it "should forward messages for levels that are active" do
56
+ sink = double("sink")
57
+ sink.should_receive(:add_record).with(any_args())
58
+
59
+ my_logger = Steno::Logger.new("test", [sink])
60
+
61
+ my_logger.warn("test")
62
+ end
63
+
64
+ it "should not invoke a supplied block if the level is inactive" do
65
+ invoked = false
66
+ logger.debug { invoked = true }
67
+ invoked.should be_false
68
+ end
69
+
70
+ it "should invoke a supplied block if the level is active" do
71
+ invoked = false
72
+ logger.warn { invoked = true }
73
+ invoked.should be_true
74
+ end
75
+
76
+ it "creates a record with the proper level" do
77
+ sink = double("sink")
78
+ Steno::Record.should_receive(:new).with("test", :warn, "message", anything, anything).and_call_original
79
+ sink.stub(:add_record)
80
+
81
+ my_logger = Steno::Logger.new("test", [sink])
82
+
83
+ my_logger.warn("message")
84
+ end
85
+ end
86
+
87
+ describe "#logf" do
88
+ it "should format messages according to the supplied format string" do
89
+ logger.should_receive(:log).with(:debug, "test 1 2.20")
90
+ logger.debugf("test %d %0.2f", 1, 2.2)
91
+ end
92
+ end
93
+
94
+ describe "#tag" do
95
+ it "should return a tagged logger" do
96
+ tagged_logger = logger.tag("foo" => "bar")
97
+ tagged_logger.should_not be_nil
98
+ tagged_logger.user_data.should == { "foo" => "bar" }
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,30 @@
1
+ require "spec_helper"
2
+
3
+ describe Steno::Record do
4
+ let(:message) { Array("test message") }
5
+ let(:record) { Steno::Record.new("test", :info, message) }
6
+
7
+ it "should set the process id" do
8
+ record.process_id.should == Process.pid
9
+ end
10
+
11
+ it "should set the thread id" do
12
+ record.thread_id.should == Thread.current.object_id
13
+ end
14
+
15
+ it "should set the fiber id(if available)", :needs_fibers => true do
16
+ record.fiber_id.should == Fiber.current.object_id
17
+ end
18
+
19
+ it "should set the source" do
20
+ record.source.should == "test"
21
+ end
22
+
23
+ it "should stringify the message" do
24
+ record.message.should be_a(String)
25
+ end
26
+
27
+ it "should use a UTC timestamp" do
28
+ record.timestamp.to_f.should be_within(0.1).of(Time.now.utc.to_f)
29
+ end
30
+ end
@@ -0,0 +1,27 @@
1
+ require "spec_helper"
2
+
3
+ describe Steno::Sink::Counter do
4
+ let(:level) do
5
+ Steno::Logger.lookup_level(:info)
6
+ end
7
+
8
+ let(:record) do
9
+ Steno::Record.new("source", level.name, "message")
10
+ end
11
+
12
+ describe "add_record" do
13
+ it "counts added records" do
14
+ expect(subject.counts).to be_empty
15
+ subject.add_record(record)
16
+ expect(subject.counts.size).to eq 1
17
+ expect(subject.counts['info']).to eq 1
18
+ end
19
+ end
20
+
21
+ describe "to_json" do
22
+ it "produces a valid json representation" do
23
+ subject.add_record(record)
24
+ expect(subject.to_json).to match '"info":1'
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,41 @@
1
+ require "spec_helper"
2
+ if Steno::Sink::WINDOWS
3
+ describe Steno::Sink::Eventlog do
4
+ let(:level) do
5
+ Steno::Logger.lookup_level(:info)
6
+ end
7
+
8
+ let(:record) do
9
+ Steno::Record.new("source", level.name, "message")
10
+ end
11
+
12
+ describe "#add_record" do
13
+
14
+ it "should append an encoded record with the correct priority" do
15
+ eventlog = double("Win32::EventLog")
16
+ Win32::EventLog.should_receive(:open) \
17
+ .with('Application') \
18
+ .and_return(eventlog)
19
+
20
+ sink = Steno::Sink::Eventlog.instance
21
+ sink.open
22
+
23
+ codec = double("codec")
24
+ codec.should_receive(:encode_record).with(record).and_return(record.message)
25
+ sink.codec = codec
26
+
27
+ eventlog.should_receive(:report_event).with(:source => "CloudFoundry",
28
+ :event_type => Win32::EventLog::INFO,
29
+ :data => record.message)
30
+
31
+ sink.add_record(record)
32
+ end
33
+ end
34
+
35
+ describe "#flush" do
36
+ it "should do nothing" do
37
+ Steno::Sink::Eventlog.instance.flush
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,46 @@
1
+ require "spec_helper"
2
+
3
+ describe Steno::Sink::IO do
4
+ let(:level) do
5
+ Steno::Logger.lookup_level(:info)
6
+ end
7
+
8
+ let(:record) do
9
+ Steno::Record.new("source", level.name, "message")
10
+ end
11
+
12
+ describe "#initialize" do
13
+ it "should initialize FluentLogger with the default option" do
14
+ Fluent::Logger::FluentLogger.should_receive(:new).with("steno", {
15
+ :host => "127.0.0.1",
16
+ :port => 24224,
17
+ :buffer_limit => Fluent::Logger::FluentLogger::BUFFER_LIMIT,
18
+ }).and_return()
19
+ sink = Steno::Sink::Fluentd.new()
20
+ end
21
+
22
+ it "should initialize FliuentLogger with override options" do
23
+ Fluent::Logger::FluentLogger.should_receive(:new).with("vcap", {
24
+ :host => "localhost",
25
+ :port => 8080,
26
+ :buffer_limit => 1024,
27
+ }).and_return()
28
+ sink = Steno::Sink::Fluentd.new({
29
+ :tag_prefix => "vcap",
30
+ :host => "localhost",
31
+ :port => 8080,
32
+ :buffer_limit => 1024
33
+ })
34
+ end
35
+ end
36
+
37
+ describe "#add_record" do
38
+ it "should post an record with the correct tag" do
39
+ fluentd = double("fluentd")
40
+ Fluent::Logger::FluentLogger.should_receive(:new).and_return(fluentd)
41
+ fluentd.should_receive(:post).with("source", record)
42
+ sink = Steno::Sink::Fluentd.new()
43
+ sink.add_record(record)
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,111 @@
1
+ require "spec_helper"
2
+
3
+ describe Steno::Sink::IO do
4
+ let(:level) do
5
+ Steno::Logger.lookup_level(:info)
6
+ end
7
+
8
+ let(:record) do
9
+ Steno::Record.new("source", level.name, "message")
10
+ end
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 = double("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 = double("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 = double("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 = double("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
+
47
+ describe "#add_record" do
48
+ it "should encode the record and write it to the underlying io object" do
49
+ codec = double("codec")
50
+ codec.should_receive(:encode_record).with(record).and_return(record.message)
51
+
52
+ io = double("io")
53
+ io.should_receive(:write).with(record.message)
54
+
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 = double("codec")
60
+ codec.should_receive(:encode_record).with(record).and_return(record.message)
61
+
62
+ io = double("io")
63
+
64
+ io.should_receive(:write).with(record.message).ordered.and_raise(IOError)
65
+
66
+ expect do
67
+ Steno::Sink::IO.new(io, :codec => codec).add_record(record)
68
+ end.to raise_error(IOError)
69
+ end
70
+
71
+ it "should retry not more than specified number of times on IOError" do
72
+ codec = double("codec")
73
+ codec.should_receive(:encode_record).with(record).and_return(record.message)
74
+
75
+ io = double("io")
76
+
77
+ io.should_receive(:write).exactly(3).times.with(record.message).
78
+ and_raise(IOError)
79
+
80
+ expect do
81
+ Steno::Sink::IO.new(io, :codec => codec, :max_retries => 2).
82
+ add_record(record)
83
+ end.to raise_error(IOError)
84
+ end
85
+
86
+ it "should retry on IOError and succeed" do
87
+ codec = double("codec")
88
+ codec.should_receive(:encode_record).with(record).and_return(record.message)
89
+
90
+ io = double("io")
91
+ io.should_receive(:write).with(record.message).once.
92
+ and_raise(IOError)
93
+ io.should_receive(:write).with(record.message).once.ordered.
94
+ and_return(record.message)
95
+
96
+ expect do
97
+ Steno::Sink::IO.new(io, :codec => codec, :max_retries => 1).
98
+ add_record(record)
99
+ end.to_not raise_error(IOError)
100
+ end
101
+ end
102
+
103
+ describe "#flush" do
104
+ it "should call flush on the underlying io object" do
105
+ io = double("io")
106
+ io.should_receive(:flush)
107
+
108
+ Steno::Sink::IO.new(io).flush
109
+ end
110
+ end
111
+ end