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,17 @@
1
+ class NullSink
2
+ attr_accessor :records
3
+
4
+ def initialize
5
+ @records = []
6
+ end
7
+
8
+ def add_record(record)
9
+ @records << record
10
+
11
+ nil
12
+ end
13
+
14
+ def flush
15
+ nil
16
+ end
17
+ end
@@ -0,0 +1,7 @@
1
+ shared_context :steno_context do
2
+ it "should support clearing context local data" do
3
+ context.data["test"] = "value"
4
+ context.clear
5
+ context.data["test"].should be_nil
6
+ end
7
+ end
@@ -0,0 +1,221 @@
1
+ require "fileutils"
2
+ require "yaml"
3
+
4
+ require "spec_helper"
5
+
6
+ describe Steno::Config do
7
+
8
+ if Steno::Sink::WINDOWS
9
+ describe ".from_hash" do
10
+ before :each do
11
+ @log_path = "some_file"
12
+
13
+ @mock_sink_file = double("sink")
14
+ @mock_sink_file.stub(:codec=)
15
+ Steno::Sink::IO.should_receive(:for_file).with(@log_path,
16
+ :max_retries => 5)
17
+ .and_return(@mock_sink_file)
18
+
19
+ @mock_sink_eventlog = double("sink")
20
+ @mock_sink_eventlog.stub(:codec=)
21
+ @mock_sink_eventlog.should_receive(:open).with("test")
22
+ Steno::Sink::Eventlog.should_receive(:instance).twice()
23
+ .and_return(@mock_sink_eventlog)
24
+ end
25
+
26
+ after :each do
27
+ @config = Steno::Config.from_hash(@hash)
28
+
29
+ @config.default_log_level.should == :debug2
30
+ @config.context.should.class == Steno::Context::Null
31
+ @config.codec.should.class == Steno::Codec::Json
32
+
33
+ @config.sinks.size.should == 2
34
+ @config.sinks.should =~ [@mock_sink_file, @mock_sink_eventlog]
35
+ end
36
+
37
+ it "should work for symbolized keys" do
38
+ @hash = {
39
+ :file => @log_path,
40
+ :level => "debug2",
41
+ :default_log_level => "warn",
42
+ :eventlog => "test",
43
+ :max_retries => 5,
44
+ }
45
+ end
46
+
47
+ it "should work for non-symbolized keys" do
48
+ @hash = {
49
+ "file" => @log_path,
50
+ "level" => "debug2",
51
+ "default_log_level" => "warn",
52
+ "eventlog" => "test",
53
+ "max_retries" => 5,
54
+ }
55
+ end
56
+
57
+ end
58
+ else
59
+ describe ".from_hash" do
60
+ before :each do
61
+ @log_path = "some_file"
62
+
63
+ @mock_sink_file = double("sink")
64
+ @mock_sink_file.stub(:codec=)
65
+ Steno::Sink::IO.should_receive(:for_file).with(@log_path,
66
+ :max_retries => 5)
67
+ .and_return(@mock_sink_file)
68
+
69
+ @mock_sink_syslog = double("sink")
70
+ @mock_sink_syslog.stub(:codec=)
71
+ @mock_sink_syslog.should_receive(:open).with("test")
72
+ Steno::Sink::Syslog.should_receive(:instance).twice()
73
+ .and_return(@mock_sink_syslog)
74
+ end
75
+
76
+ after :each do
77
+ @config = Steno::Config.from_hash(@hash)
78
+
79
+ @config.default_log_level.should == :debug2
80
+ @config.context.should.class == Steno::Context::Null
81
+ @config.codec.should.class == Steno::Codec::Json
82
+
83
+ @config.sinks.size.should == 2
84
+ @config.sinks.should =~ [@mock_sink_file, @mock_sink_syslog]
85
+ end
86
+
87
+ it "should work for symbolized keys" do
88
+ @hash = {
89
+ :file => @log_path,
90
+ :level => "debug2",
91
+ :default_log_level => "warn",
92
+ :syslog => "test",
93
+ :max_retries => 5,
94
+ }
95
+ end
96
+
97
+ it "should work for non-symbolized keys" do
98
+ @hash = {
99
+ "file" => @log_path,
100
+ "level" => "debug2",
101
+ "default_log_level" => "warn",
102
+ "syslog" => "test",
103
+ "max_retries" => 5,
104
+ }
105
+ end
106
+
107
+ end
108
+ end
109
+
110
+ describe ".from_file" do
111
+ before :each do
112
+ @tmpdir = Dir.mktmpdir
113
+ @config_path = File.join(@tmpdir, "config.yml")
114
+ @log_path = File.join(@tmpdir, "test.log")
115
+ end
116
+
117
+ after :each do
118
+ FileUtils.rm_rf(@tmpdir)
119
+ end
120
+
121
+ it "should return Steno::Config instance with sane defaults" do
122
+ write_config(@config_path, {})
123
+
124
+ config = Steno::Config.from_file(@config_path)
125
+
126
+ config.sinks.size.should == 1
127
+ config.sinks[0].class.should == Steno::Sink::IO
128
+
129
+ config.default_log_level.should == :info
130
+
131
+ config.context.should.class == Steno::Context::Null
132
+
133
+ config.codec.should.class == Steno::Codec::Json
134
+ end
135
+
136
+ it "should set the default_log_level if a key with the same name is supplied" do
137
+ write_config(@config_path, {"level" => "debug2"})
138
+ Steno::Config.from_file(@config_path).default_log_level.should == :debug2
139
+
140
+ write_config(@config_path, {"default_log_level" => "debug2"})
141
+ Steno::Config.from_file(@config_path).default_log_level.should == :debug2
142
+ end
143
+
144
+ it "should read the 'level' key if both default_log_level and level are spscified" do
145
+ write_config(@config_path, {"level" => "debug2",
146
+ "default_log_level" => "warn"})
147
+ Steno::Config.from_file(@config_path).default_log_level.should == :debug2
148
+ end
149
+
150
+ it "should add a file sink if the 'file' key is specified" do
151
+ write_config(@config_path, {"file" => @log_path, "max_retries" => 2})
152
+ mock_sink = double("sink")
153
+ mock_sink.stub(:codec=)
154
+
155
+ Steno::Sink::IO.should_receive(:for_file).
156
+ with(@log_path, :max_retries => 2).and_return(mock_sink)
157
+ config = Steno::Config.from_file(@config_path)
158
+ config.sinks.size.should == 1
159
+ config.sinks[0].should == mock_sink
160
+ end
161
+
162
+ if Steno::Sink::WINDOWS
163
+ it "should add a event sink if the 'eventlog' key is specified" do
164
+ write_config(@config_path, {"eventlog" => "test"})
165
+ mock_sink = double("sink")
166
+ mock_sink.should_receive(:open).with("test")
167
+ mock_sink.stub(:codec=)
168
+
169
+ Steno::Sink::Eventlog.should_receive(:instance).twice().and_return(mock_sink)
170
+
171
+ config = Steno::Config.from_file(@config_path)
172
+ config.sinks.size.should == 1
173
+ config.sinks[0].should == mock_sink
174
+ end
175
+ else
176
+ it "should add a syslog sink if the 'syslog' key is specified" do
177
+ write_config(@config_path, {"syslog" => "test"})
178
+ mock_sink = double("sink")
179
+ mock_sink.should_receive(:open).with("test")
180
+ mock_sink.stub(:codec=)
181
+
182
+ Steno::Sink::Syslog.should_receive(:instance).twice().and_return(mock_sink)
183
+
184
+ config = Steno::Config.from_file(@config_path)
185
+ config.sinks.size.should == 1
186
+ config.sinks[0].should == mock_sink
187
+ end
188
+ end
189
+
190
+
191
+
192
+ it "should add an io sink to stdout if no sinks are explicitly specified in the config file" do
193
+ write_config(@config_path, {})
194
+ mock_sink = double("sink")
195
+ mock_sink.stub(:codec=)
196
+
197
+ Steno::Sink::IO.should_receive(:new).with(STDOUT).and_return(mock_sink)
198
+
199
+ config = Steno::Config.from_file(@config_path)
200
+ config.sinks.size.should == 1
201
+ config.sinks[0].should == mock_sink
202
+ end
203
+
204
+ it "should merge supplied overrides with the file based config" do
205
+ write_config(@config_path, {"default_log_level" => "debug"})
206
+
207
+ context = Steno::Context::ThreadLocal.new
208
+ config = Steno::Config.from_file(@config_path,
209
+ :default_log_level => "warn",
210
+ :context => context)
211
+ config.context.should == context
212
+ config.default_log_level.should == :warn
213
+ end
214
+ end
215
+
216
+ def write_config(path, config)
217
+ File.open(path, "w+") do |f|
218
+ f.write(YAML.dump({"logging" => config}))
219
+ end
220
+ end
221
+ end
@@ -0,0 +1,62 @@
1
+ require "spec_helper"
2
+
3
+ describe Steno::Context::Null do
4
+ include_context :steno_context
5
+
6
+ let(:context) { Steno::Context::Null.new }
7
+
8
+ it "should store no data" do
9
+ context.data.should == {}
10
+ context.data["foo"] = "bar"
11
+ context.data.should == {}
12
+ end
13
+ end
14
+
15
+ describe Steno::Context::ThreadLocal do
16
+ include_context :steno_context
17
+
18
+ let (:context) { Steno::Context::ThreadLocal.new }
19
+
20
+ it "should store data local to threads" do
21
+ b1 = Barrier.new
22
+ b2 = Barrier.new
23
+
24
+ t1 = Thread.new do
25
+ context.data["thread"] = "t1"
26
+ b1.release
27
+ b2.wait
28
+ context.data["thread"].should == "t1"
29
+ end
30
+
31
+ t2 = Thread.new do
32
+ b1.wait
33
+ context.data["thread"].should be_nil
34
+ context.data["thread"] = "t2"
35
+ b2.release
36
+ end
37
+
38
+ t1.join
39
+ t2.join
40
+ end
41
+ end
42
+
43
+ describe Steno::Context::FiberLocal do
44
+ include_context :steno_context
45
+
46
+ let(:context) { Steno::Context::FiberLocal.new }
47
+
48
+ it "should store data local to fibers" do
49
+ f2 = Fiber.new do
50
+ context.data["fiber"].should be_nil
51
+ context.data["fiber"] = "f2"
52
+ end
53
+
54
+ f1 = Fiber.new do
55
+ context.data["fiber"] = "f1"
56
+ f2.resume
57
+ context.data["fiber"].should == "f1"
58
+ end
59
+
60
+ f1.resume
61
+ end
62
+ end
@@ -0,0 +1,38 @@
1
+ require "spec_helper"
2
+
3
+ require "steno/core_ext"
4
+
5
+ module Foo
6
+ class Bar
7
+ end
8
+ end
9
+
10
+ describe Module do
11
+ describe "#logger" do
12
+ it "should request a logger named after itself" do
13
+ x = Foo.logger
14
+ x.should be_a(Steno::Logger)
15
+ x.name.should include("Foo")
16
+ end
17
+ end
18
+ end
19
+
20
+ describe Class do
21
+ describe "#logger" do
22
+ it "should request a logger named after itself" do
23
+ x = Foo::Bar.logger
24
+ x.should be_a(Steno::Logger)
25
+ x.name.should include("Foo::Bar")
26
+ end
27
+ end
28
+ end
29
+
30
+ describe Object do
31
+ describe "#logger" do
32
+ it "should request a logger named after its class" do
33
+ x = Foo::Bar.new.logger
34
+ x.should be_a(Steno::Logger)
35
+ x.name.should include("Foo::Bar")
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,73 @@
1
+ require "spec_helper"
2
+
3
+ require "steno/http_handler"
4
+
5
+ describe Steno::HttpHandler do
6
+ include Rack::Test::Methods
7
+
8
+ let(:config) { Steno::Config.new }
9
+
10
+ before :each do
11
+ Steno.init(config)
12
+ end
13
+
14
+ def app
15
+ Steno::HttpHandler
16
+ end
17
+
18
+ describe "GET /loggers/levels" do
19
+ it "returns a hash of logger name to level" do
20
+ get "/loggers/levels"
21
+ json_body.should == {}
22
+
23
+ foo = Steno.logger("foo")
24
+ foo.level = :debug
25
+
26
+ bar = Steno.logger("bar")
27
+ bar.level = :info
28
+
29
+ get "/loggers/levels"
30
+ json_body.should == { "foo" => "debug", "bar" => "info" }
31
+ end
32
+ end
33
+
34
+ describe "PUT /loggers/levels" do
35
+ it "returns an error on missing parameters" do
36
+ put "/loggers/levels"
37
+ last_response.status.should == 400
38
+ json_body["error"].should match(/Missing query parameters/)
39
+
40
+ put "/loggers/levels", :regexp => "hi"
41
+ last_response.status.should == 400
42
+ json_body["error"].should match(/Missing query parameters/)
43
+
44
+ put "/loggers/levels", :level => "debug"
45
+ last_response.status.should == 400
46
+ json_body["error"].should match(/Missing query parameters/)
47
+ end
48
+
49
+ it "returns an error on invalid log levels" do
50
+ put "/loggers/levels", :regexp => "hi", :level => "foobar"
51
+ last_response.status.should == 400
52
+ json_body["error"].should match(/Unknown level/)
53
+ end
54
+
55
+ it "updates log levels for loggers whose name matches the regexp" do
56
+ foo = Steno.logger("foo")
57
+ foo.level = :debug
58
+
59
+ bar = Steno.logger("bar")
60
+ bar.level = :warn
61
+
62
+ put "/loggers/levels", :regexp => "f", :level => "error"
63
+ last_response.status.should == 200
64
+
65
+ foo.level.should == :error
66
+ bar.level.should == :warn
67
+ end
68
+ end
69
+
70
+ def json_body
71
+ Yajl::Parser.parse(last_response.body)
72
+ end
73
+ end
@@ -0,0 +1,48 @@
1
+ require "spec_helper"
2
+
3
+ describe Steno::Codec::Json do
4
+ let(:codec) { Steno::Codec::Json.new }
5
+ let(:record) { make_record(:data => { "user" => "data" }) }
6
+
7
+ describe "#encode_record" do
8
+ it "should encode records as json hashes" do
9
+ parsed = Yajl::Parser.parse(codec.encode_record(record))
10
+ parsed.class.should == Hash
11
+ end
12
+
13
+ it "should encode the timestamp as a float" do
14
+ parsed = Yajl::Parser.parse(codec.encode_record(record))
15
+ parsed["timestamp"].class.should == Float
16
+ end
17
+
18
+ it "should escape newlines" do
19
+ rec = make_record(:message => "newline\ntest")
20
+ codec.encode_record(rec).should match(/newline\\ntest/)
21
+ end
22
+
23
+ it "should escape carriage returns" do
24
+ rec = make_record(:message => "newline\rtest")
25
+ codec.encode_record(rec).should match(/newline\\rtest/)
26
+ end
27
+
28
+ it "should allow messages with valid encodings to pass through untouched" do
29
+ msg = "HI\u2600"
30
+ rec = make_record(:message => msg)
31
+ codec.encode_record(rec).should match(/#{msg}/)
32
+ end
33
+
34
+ it "should treat messages with invalid encodings as binary data" do
35
+ msg = "HI\u2026".force_encoding("US-ASCII")
36
+ rec = make_record(:message => msg)
37
+ codec.encode_record(rec).should match(/HI\\\\xe2\\\\x80\\\\xa6/)
38
+ end
39
+ end
40
+
41
+ def make_record(opts = {})
42
+ Steno::Record.new(opts[:source] || "my_source",
43
+ opts[:level] || :debug,
44
+ opts[:message] || "test message",
45
+ nil,
46
+ opts[:data] || {})
47
+ end
48
+ end