steno 1.2.2-x86-mingw32
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.
- checksums.yaml +15 -0
- data/LICENSE +7136 -0
- data/README.md +78 -0
- data/Rakefile +16 -0
- data/bin/steno-prettify +99 -0
- data/lib/steno.rb +133 -0
- data/lib/steno/codec.rb +2 -0
- data/lib/steno/codec/base.rb +34 -0
- data/lib/steno/codec/json.rb +36 -0
- data/lib/steno/config.rb +97 -0
- data/lib/steno/context.rb +59 -0
- data/lib/steno/core_ext.rb +11 -0
- data/lib/steno/errors.rb +3 -0
- data/lib/steno/http_handler.rb +41 -0
- data/lib/steno/json_prettifier.rb +131 -0
- data/lib/steno/log_level.rb +24 -0
- data/lib/steno/logger.rb +174 -0
- data/lib/steno/record.rb +41 -0
- data/lib/steno/sink.rb +6 -0
- data/lib/steno/sink/base.rb +38 -0
- data/lib/steno/sink/counter.rb +44 -0
- data/lib/steno/sink/eventlog.rb +46 -0
- data/lib/steno/sink/fluentd.rb +31 -0
- data/lib/steno/sink/io.rb +72 -0
- data/lib/steno/sink/syslog.rb +59 -0
- data/lib/steno/tagged_logger.rb +59 -0
- data/lib/steno/version.rb +3 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/support/barrier.rb +22 -0
- data/spec/support/null_sink.rb +17 -0
- data/spec/support/shared_context_specs.rb +7 -0
- data/spec/unit/config_spec.rb +221 -0
- data/spec/unit/context_spec.rb +62 -0
- data/spec/unit/core_ext_spec.rb +38 -0
- data/spec/unit/http_handler_spec.rb +73 -0
- data/spec/unit/json_codec_spec.rb +48 -0
- data/spec/unit/json_prettifier_spec.rb +84 -0
- data/spec/unit/log_level_spec.rb +19 -0
- data/spec/unit/logger_spec.rb +101 -0
- data/spec/unit/record_spec.rb +30 -0
- data/spec/unit/sink/counter_spec.rb +27 -0
- data/spec/unit/sink/eventlog_spec.rb +41 -0
- data/spec/unit/sink/fluentd_spec.rb +46 -0
- data/spec/unit/sink/io_spec.rb +111 -0
- data/spec/unit/sink/syslog_spec.rb +74 -0
- data/spec/unit/steno_spec.rb +86 -0
- data/spec/unit/tagged_logger_spec.rb +33 -0
- data/steno-1.2.1.gem +0 -0
- data/steno.gemspec +41 -0
- metadata +224 -0
@@ -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
|