lines 0.2.0 → 0.9.1
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 +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"
|