lines 0.2.0 → 0.9.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +6 -14
- data/.gitignore +1 -0
- data/.travis.yml +1 -1
- data/CHANGELOG.md +16 -0
- data/Gemfile +1 -8
- data/LICENSE.txt +1 -1
- data/README.md +21 -64
- data/examples/cli.rb +17 -0
- data/lib/lines.rb +111 -395
- data/lib/lines/common.rb +37 -0
- data/lib/lines/generator.rb +168 -0
- data/lib/lines/parser.rb +182 -0
- data/lib/lines/version.rb +1 -1
- data/lines.gemspec +10 -8
- data/spec/lines_generator_bench.rb +45 -0
- data/spec/lines_generator_spec.rb +65 -0
- data/spec/lines_parser_bench.rb +50 -0
- data/spec/{lines_loader_spec.rb → lines_parser_spec.rb} +28 -7
- data/spec/spec_helper.rb +2 -6
- metadata +57 -28
- data/lib/lines/active_record.rb +0 -70
- data/lib/lines/loader.rb +0 -229
- data/lib/lines/logger.rb +0 -61
- data/lib/lines/rack_logger.rb +0 -39
- data/spec/bench.rb +0 -46
- data/spec/lines_spec.rb +0 -190
- data/spec/parse-bench +0 -26
data/lib/lines/logger.rb
DELETED
@@ -1,61 +0,0 @@
|
|
1
|
-
module Lines
|
2
|
-
# Backward-compatible logger
|
3
|
-
# http://ruby-doc.org/stdlib-2.0/libdoc/logger/rdoc/Logger.html#method-i-log
|
4
|
-
class Logger
|
5
|
-
LEVELS = {
|
6
|
-
0 => :debug,
|
7
|
-
1 => :info,
|
8
|
-
2 => :warn,
|
9
|
-
3 => :error,
|
10
|
-
4 => :fatal,
|
11
|
-
5 => :unknown,
|
12
|
-
}
|
13
|
-
|
14
|
-
def initialize(line)
|
15
|
-
@line = line
|
16
|
-
end
|
17
|
-
|
18
|
-
def log(severity, message = nil, progname = nil, &block)
|
19
|
-
pri = LEVELS[severity] || severity
|
20
|
-
if block_given?
|
21
|
-
progname = message
|
22
|
-
message = yield.to_s rescue $!.to_s
|
23
|
-
end
|
24
|
-
|
25
|
-
data = { pri: pri }
|
26
|
-
data[:app] = progname if progname
|
27
|
-
data[:msg] = message if message
|
28
|
-
|
29
|
-
@line.log(data)
|
30
|
-
end
|
31
|
-
|
32
|
-
LEVELS.values.each do |level|
|
33
|
-
define_method(level) do |message=nil, &block|
|
34
|
-
log(level, message, &block)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
alias << info
|
39
|
-
alias unknown info
|
40
|
-
|
41
|
-
def noop(*a); true end
|
42
|
-
%w[add
|
43
|
-
clone
|
44
|
-
datetime_format
|
45
|
-
datetime_format=
|
46
|
-
debug?
|
47
|
-
info?
|
48
|
-
error?
|
49
|
-
fatal?
|
50
|
-
warn?
|
51
|
-
level
|
52
|
-
level=
|
53
|
-
progname
|
54
|
-
progname=
|
55
|
-
sev_threshold
|
56
|
-
sev_threshold=
|
57
|
-
].each do |op|
|
58
|
-
alias_method(op, :noop)
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
data/lib/lines/rack_logger.rb
DELETED
@@ -1,39 +0,0 @@
|
|
1
|
-
require 'rack/commonlogger'
|
2
|
-
require 'lines'
|
3
|
-
|
4
|
-
module Lines
|
5
|
-
class RackLogger < Rack::CommonLogger
|
6
|
-
# In development mode the common logger is always inserted
|
7
|
-
def self.silence_common_logger!
|
8
|
-
Rack::CommonLogger.module_eval('def call(env); @app.call(env); end')
|
9
|
-
self
|
10
|
-
end
|
11
|
-
|
12
|
-
def initialize(app)
|
13
|
-
@app = app
|
14
|
-
end
|
15
|
-
|
16
|
-
def call(env)
|
17
|
-
began_at = Time.now
|
18
|
-
status, header, body = @app.call(env)
|
19
|
-
header = Rack::Utils::HeaderHash.new(header)
|
20
|
-
body = Rack::BodyProxy.new(body) { log(env, status, header, began_at) }
|
21
|
-
[status, header, body]
|
22
|
-
end
|
23
|
-
|
24
|
-
protected
|
25
|
-
|
26
|
-
def log(env, status, header, began_at)
|
27
|
-
Lines.log(
|
28
|
-
remote_addr: env['HTTP_X_FORWARDED_FOR'] || env['REMOTE_ADDR'],
|
29
|
-
remote_user: env['REMOTE_USER'] || '',
|
30
|
-
method: env['REQUEST_METHOD'],
|
31
|
-
path: env['PATH_INFO'],
|
32
|
-
query: env['QUERY_STRING'],
|
33
|
-
status: status.to_s[0..3],
|
34
|
-
length: extract_content_length(header),
|
35
|
-
elapsed: [Time.now - began_at, 's'],
|
36
|
-
)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
data/spec/bench.rb
DELETED
@@ -1,46 +0,0 @@
|
|
1
|
-
require 'benchmark/ips'
|
2
|
-
|
3
|
-
$:.unshift File.expand_path('../../lib', __FILE__)
|
4
|
-
require 'lines'
|
5
|
-
|
6
|
-
class FakeIO
|
7
|
-
def write(*a)
|
8
|
-
end
|
9
|
-
alias syswrite write
|
10
|
-
end
|
11
|
-
|
12
|
-
globals = {
|
13
|
-
app: 'benchmark',
|
14
|
-
at: proc{ Time.now },
|
15
|
-
pid: Process.pid,
|
16
|
-
}
|
17
|
-
|
18
|
-
EX = (raise "FOO" rescue $!)
|
19
|
-
|
20
|
-
Benchmark.ips do |x|
|
21
|
-
x.report "FakeIO write" do |n|
|
22
|
-
Lines.use(FakeIO.new, globals)
|
23
|
-
n.times{ Lines.log EX }
|
24
|
-
end
|
25
|
-
|
26
|
-
x.report "/dev/null write" do |n|
|
27
|
-
dev_null = File.open('/dev/null', 'w')
|
28
|
-
Lines.use(dev_null, globals)
|
29
|
-
n.times{ Lines.log EX }
|
30
|
-
end
|
31
|
-
|
32
|
-
x.report "syslog write" do |n|
|
33
|
-
Lines.use(Syslog, globals)
|
34
|
-
n.times{ Lines.log EX }
|
35
|
-
end
|
36
|
-
|
37
|
-
x.report "real file" do |n|
|
38
|
-
real_file = File.open('real_file.log', 'w')
|
39
|
-
Lines.use(real_file, globals)
|
40
|
-
n.times{ Lines.log EX }
|
41
|
-
end
|
42
|
-
|
43
|
-
x.report "real file logger" do |n|
|
44
|
-
n.times{ Lines.logger.info "Ahoi this is a really cool option" }
|
45
|
-
end
|
46
|
-
end
|
data/spec/lines_spec.rb
DELETED
@@ -1,190 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'lines'
|
3
|
-
require 'stringio'
|
4
|
-
|
5
|
-
NL = "\n"
|
6
|
-
|
7
|
-
describe Lines do
|
8
|
-
let(:outputter) { StringIO.new }
|
9
|
-
let(:output) { outputter.string }
|
10
|
-
before do
|
11
|
-
Lines.use(outputter)
|
12
|
-
end
|
13
|
-
|
14
|
-
context ".log" do
|
15
|
-
it "logs stuff" do
|
16
|
-
Lines.log(foo: 'bar')
|
17
|
-
expect(output).to eq('foo=bar' + NL)
|
18
|
-
end
|
19
|
-
|
20
|
-
it "supports a first msg argument" do
|
21
|
-
Lines.log("this user is annoying", user: 'bob')
|
22
|
-
expect(output).to eq("msg='this user is annoying' user=bob" + NL)
|
23
|
-
end
|
24
|
-
|
25
|
-
it "logs exceptions" do
|
26
|
-
Lines.log(StandardError.new("error time!"), user: 'bob')
|
27
|
-
expect(output).to eq("ex=StandardError msg='error time!' user=bob" + NL)
|
28
|
-
end
|
29
|
-
|
30
|
-
it "logs exception backtraces when available" do
|
31
|
-
ex = (raise "foo" rescue $!)
|
32
|
-
#expect(ex).not_to eq(nil)
|
33
|
-
Lines.log(ex)
|
34
|
-
expect(output).to match(/ex=RuntimeError msg=foo backtrace=\[[^\]]+\]/)
|
35
|
-
end
|
36
|
-
|
37
|
-
it "works with anything" do
|
38
|
-
Lines.log("anything1", "anything2")
|
39
|
-
expect(output).to eq('msg=anything2' + NL)
|
40
|
-
end
|
41
|
-
|
42
|
-
it "doesn't convert nil args to msg" do
|
43
|
-
Lines.log("anything", nil)
|
44
|
-
expect(output).to eq('msg=anything' + NL)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
context ".context" do
|
49
|
-
it "has contextes" do
|
50
|
-
Lines.context(foo: "bar").log(a: 'b')
|
51
|
-
expect(output).to eq('a=b foo=bar' + NL)
|
52
|
-
end
|
53
|
-
|
54
|
-
it "has contextes with blocks" do
|
55
|
-
Lines.context(foo: "bar") do |ctx|
|
56
|
-
ctx.log(a: 'b')
|
57
|
-
end
|
58
|
-
expect(output).to eq('a=b foo=bar' + NL)
|
59
|
-
end
|
60
|
-
|
61
|
-
it "mixes everything" do
|
62
|
-
Lines.global[:app] = :self
|
63
|
-
ctx = Lines.context(foo: "bar")
|
64
|
-
ctx.log('msg', ahoi: true)
|
65
|
-
expect(output).to eq('app=self msg=msg ahoi=#t foo=bar' + NL)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
context ".logger" do
|
70
|
-
it "is provided for backward-compatibility" do
|
71
|
-
l = Lines.logger
|
72
|
-
l.info("hi")
|
73
|
-
expect(output).to eq('pri=info msg=hi' + NL)
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
context ".global" do
|
78
|
-
it "prepends data to the line" do
|
79
|
-
Lines.global["app"] = :self
|
80
|
-
Lines.log 'hey'
|
81
|
-
expect(output).to eq('app=self msg=hey' + NL)
|
82
|
-
end
|
83
|
-
|
84
|
-
it "resolves procs dynamically" do
|
85
|
-
count = 0
|
86
|
-
Lines.global[:count] = proc{ count += 1 }
|
87
|
-
Lines.log 'test1'
|
88
|
-
Lines.log 'test2'
|
89
|
-
expect(output).to eq(
|
90
|
-
'count=1 msg=test1' + NL +
|
91
|
-
'count=2 msg=test2' + NL
|
92
|
-
)
|
93
|
-
end
|
94
|
-
|
95
|
-
it "doesn't fail if a proc has an exception" do
|
96
|
-
Lines.global[:X] = proc{ fail "error" }
|
97
|
-
Lines.log 'test'
|
98
|
-
expect(output).to eq("X='#<RuntimeError: error>' msg=test" + NL)
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
describe Lines::Dumper do
|
104
|
-
subject { Lines::Dumper.new }
|
105
|
-
def expect_dump(obj)
|
106
|
-
expect(subject.dump obj)
|
107
|
-
end
|
108
|
-
|
109
|
-
it do
|
110
|
-
expect_dump(foo: 'bar').to eq('foo=bar')
|
111
|
-
end
|
112
|
-
|
113
|
-
it "dumps true, false and nil as #t, #f and nil" do
|
114
|
-
expect_dump(foo: true).to eq('foo=#t')
|
115
|
-
expect_dump(foo: false).to eq('foo=#f')
|
116
|
-
expect_dump(foo: nil).to eq('foo=nil')
|
117
|
-
end
|
118
|
-
|
119
|
-
it "dumps empty strings correclty" do
|
120
|
-
expect_dump(foo: '').to eq('foo=')
|
121
|
-
end
|
122
|
-
|
123
|
-
it "dumps a string with spaces surrounded by single quotes" do
|
124
|
-
expect_dump(foo: 'some" thing').to eq("foo='some\" thing'")
|
125
|
-
end
|
126
|
-
|
127
|
-
it "dumps a string with spaces and a single quote sourrounded with double quotes" do
|
128
|
-
expect_dump(foo: "foo ' bar").to eq("foo=\"foo ' bar\"")
|
129
|
-
end
|
130
|
-
|
131
|
-
it "can dump a basicobject" do
|
132
|
-
expect_dump(foo: BasicObject.new).to match(/foo='#<BasicObject:0x[0-9a-f]+>'/)
|
133
|
-
end
|
134
|
-
|
135
|
-
it "can dump IO objects" do
|
136
|
-
expect_dump(foo: File.open(__FILE__)).to match(/foo='?#<File:[^>]+>'?/)
|
137
|
-
expect_dump(foo: STDOUT).to match(/^foo='(?:#<IO:<STDOUT>>|#<IO:fd 1>)'$/)
|
138
|
-
end
|
139
|
-
|
140
|
-
it "dumps time as ISO zulu format" do
|
141
|
-
expect_dump(foo: Time.at(1337)).to eq('foo=1970-01-01T00:22:17Z')
|
142
|
-
end
|
143
|
-
|
144
|
-
it "dumps date as ISO date" do
|
145
|
-
expect_dump(foo: Date.new(1968, 3, 7)).to eq('foo=1968-03-07')
|
146
|
-
end
|
147
|
-
|
148
|
-
it "dumps symbols as strings" do
|
149
|
-
expect_dump(foo: :some_symbol).to eq('foo=some_symbol')
|
150
|
-
expect_dump(foo: :"some symbol").to eq("foo='some symbol'")
|
151
|
-
end
|
152
|
-
|
153
|
-
it "dumps numbers appropriately" do
|
154
|
-
expect_dump(foo: 10e3).to eq('foo=10000.0')
|
155
|
-
expect_dump(foo: 1).to eq('foo=1')
|
156
|
-
expect_dump(foo: -1).to eq('foo=-1')
|
157
|
-
# FIXME: don't put all the decimals
|
158
|
-
#expect_dump(foo: 4.0/3).to eq('foo=1.333')
|
159
|
-
end
|
160
|
-
|
161
|
-
it "dumps arrays appropriately" do
|
162
|
-
expect_dump(foo: [1,2,:a]).to eq('foo=[1 2 a]')
|
163
|
-
end
|
164
|
-
|
165
|
-
it "dumps [number, literal] tuples as numberliteral" do
|
166
|
-
expect_dump(foo: [3, :ms]).to eq('foo=3:ms')
|
167
|
-
expect_dump(foo: [54.2, 's']).to eq('foo=54.2:s')
|
168
|
-
end
|
169
|
-
|
170
|
-
it "knows how to handle circular dependencies" do
|
171
|
-
x = {}
|
172
|
-
x[:x] = x
|
173
|
-
expect_dump(x).to eq('x={x={x={x={...}}}}')
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
describe Lines::UniqueIDs do
|
178
|
-
include Lines::UniqueIDs
|
179
|
-
|
180
|
-
it "generates a unique ID" do
|
181
|
-
expect(id.size).to be > 1
|
182
|
-
end
|
183
|
-
|
184
|
-
it "generates a unique ID on each call" do
|
185
|
-
id1 = id
|
186
|
-
id2 = id
|
187
|
-
expect(id1).to_not eq(id2)
|
188
|
-
end
|
189
|
-
|
190
|
-
end
|
data/spec/parse-bench
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
libdir = File.expand_path('../../lib', __FILE__)
|
4
|
-
$:.unshift(libdir) unless $:.include? libdir
|
5
|
-
|
6
|
-
require 'lines'
|
7
|
-
|
8
|
-
loader = Lines.loader
|
9
|
-
|
10
|
-
start = Time.now
|
11
|
-
line_count = 0
|
12
|
-
|
13
|
-
$stdin.lines.each do |line|
|
14
|
-
begin
|
15
|
-
line_count += 1
|
16
|
-
loader.load(line)
|
17
|
-
rescue Lines::Error => ex
|
18
|
-
# Lines seem to get truncated by syslog when too long
|
19
|
-
if line.size < 2000
|
20
|
-
p line
|
21
|
-
p ex
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
puts "Parsed #{line_count / (Time.now - start)} lines per second"
|