log2json 0.1.21 → 0.1.22
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.
- data/Gemfile +1 -1
- data/Gemfile.lock +7 -7
- data/lib/log2json.rb +6 -3
- data/lib/log2json/mlogbuffer.rb +134 -0
- data/log2json.gemspec +1 -1
- metadata +3 -2
data/Gemfile
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
source "https://rubygems.org"
|
2
|
-
gemspec
|
2
|
+
gemspec :name => 'log2json'
|
data/Gemfile.lock
CHANGED
@@ -1,21 +1,21 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
log2json (0.1.
|
4
|
+
log2json (0.1.22)
|
5
5
|
jls-grok (~> 0.10.10)
|
6
|
-
persistent_http (~> 1.0.
|
6
|
+
persistent_http (~> 1.0.6)
|
7
7
|
redis (~> 3.0.2)
|
8
8
|
|
9
9
|
GEM
|
10
10
|
remote: https://rubygems.org/
|
11
11
|
specs:
|
12
|
-
cabin (0.
|
12
|
+
cabin (0.6.1)
|
13
13
|
gene_pool (1.3.0)
|
14
|
-
jls-grok (0.10.
|
15
|
-
cabin (
|
16
|
-
persistent_http (1.0.
|
14
|
+
jls-grok (0.10.12)
|
15
|
+
cabin (>= 0.6.0)
|
16
|
+
persistent_http (1.0.6)
|
17
17
|
gene_pool (>= 1.3)
|
18
|
-
redis (3.0.
|
18
|
+
redis (3.0.6)
|
19
19
|
|
20
20
|
PLATFORMS
|
21
21
|
ruby
|
data/lib/log2json.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'json'
|
2
2
|
require 'grok-pure'
|
3
3
|
|
4
|
+
require 'log2json/mlogbuffer'
|
5
|
+
|
4
6
|
module Log2Json
|
5
7
|
|
6
8
|
def self.main(filters, opts={}, &block)
|
@@ -13,7 +15,7 @@ def self.main(filters, opts={}, &block)
|
|
13
15
|
key = name.to_s.downcase
|
14
16
|
config[name] = ENV[key] if ENV.member?(key)
|
15
17
|
end
|
16
|
-
spitter = ::Log2Json::Spitter.new(STDIN, ENV['type'], config)
|
18
|
+
spitter = ::Log2Json::Spitter.new(STDIN, ENV['type'], config.merge(opts))
|
17
19
|
end
|
18
20
|
if block.nil?
|
19
21
|
block = proc do |rec|
|
@@ -63,7 +65,8 @@ class Spitter
|
|
63
65
|
UTC_TIMESTAMP_FORMAT: "%FT%T.%6NZ",
|
64
66
|
SOURCE_SEPERATOR_REGEX: Regexp.new("^==> (.+) <=="),
|
65
67
|
# because /.../ screws up syntax highlighting in vim so I use Regexp.new(...)
|
66
|
-
|
68
|
+
|
69
|
+
KEEP_EMTPY_LINES: false,
|
67
70
|
TAGS: '',
|
68
71
|
FIELDS: '',
|
69
72
|
}
|
@@ -96,7 +99,7 @@ class Spitter
|
|
96
99
|
@input.each_line do |line|
|
97
100
|
line.force_encoding(options[:LOG_INPUT_ENCODING])
|
98
101
|
line.chomp!
|
99
|
-
next if line.empty?
|
102
|
+
next if line.empty? unless @options[:KEEP_EMPTY_LINES]
|
100
103
|
if line =~ options[:SOURCE_SEPERATOR_REGEX]
|
101
104
|
@source_path = $1
|
102
105
|
next
|
@@ -0,0 +1,134 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module Log2Json
|
4
|
+
|
5
|
+
|
6
|
+
class MultilineLogBuffer
|
7
|
+
|
8
|
+
LOG = Logger.new(STDERR)
|
9
|
+
|
10
|
+
# This class workaround the flaw that for some applications a log record may consist
|
11
|
+
# of mulitple lines without an end-of-record marker.
|
12
|
+
#
|
13
|
+
# Example 1:
|
14
|
+
#
|
15
|
+
# [ERROR:12980 2013-11-05 09:46:29] IO_ENCODER
|
16
|
+
# Traceback (most recent call last):
|
17
|
+
# File "/opt/score_feeder/feeds/rotowire/worker.py", line 59, in process_queue
|
18
|
+
# (errorlog, rs), processed = method(xmldoc), True
|
19
|
+
# File "/opt/score_feeder/feeds/__init__.py", line 206, in handle
|
20
|
+
# results = fn(*args, **kwargs)
|
21
|
+
# File "/opt/score_feeder/feeds/__init__.py", line 229, in handle
|
22
|
+
# results = fn(*args, **kwargs)
|
23
|
+
# File "/opt/score_feeder/feeds/__init__.py", line 141, in handle
|
24
|
+
# results = fn(*args, **kwargs)
|
25
|
+
# File "/opt/score_feeder/feeds/__init__.py", line 261, in handle
|
26
|
+
# results = fn(*args, **kwargs)
|
27
|
+
# File "/opt/score_feeder/feeds/__init__.py", line 174, in handle
|
28
|
+
# results = fn(*args, **kwargs)
|
29
|
+
# File "/opt/score_feeder/feeds/rotowire/leagues/nfl/player_news.py", line 40, in NFL_PLAYER_NEWS
|
30
|
+
# snippet = xml_parse(xml_serialize(snippet))
|
31
|
+
# File "/opt/score_feeder/lib/utils.py", line 239, in xml_serialize
|
32
|
+
# xmlstr = lxml.etree.tostring(node).strip()
|
33
|
+
# File "lxml.etree.pyx", line 3119, in lxml.etree.tostring (src/lxml/lxml.etree.c:64447)
|
34
|
+
# File "serializer.pxi", line 132, in lxml.etree._tostring (src/lxml/lxml.etree.c:101602)
|
35
|
+
# File "serializer.pxi", line 192, in lxml.etree._raiseSerialisationError (src/lxml/lxml.etree.c:102217)
|
36
|
+
# SerialisationError: IO_ENCODER
|
37
|
+
#
|
38
|
+
# Example 2:
|
39
|
+
#
|
40
|
+
# [INFO:7091 2013-11-05 09:32:46] [job 6, pri 0, req 0] NBA_MOVEMENTS finished. [c 1, u 0, d 1]
|
41
|
+
# No players that match global id [2] and name [Abdul-Wahad, Tariq]. Skipping.
|
42
|
+
# league: nba, method: NBA_MOVEMENTS, filename: TPnBh5movements_basketball_ab.xml
|
43
|
+
#
|
44
|
+
# No players that match global id [3] and name [Abdur-Rahim, Shareef]. Skipping.
|
45
|
+
# league: nba, method: NBA_MOVEMENTS, filename: TPnBh5movements_basketball_ab.xml
|
46
|
+
#
|
47
|
+
# No players that match global id [3358] and name [Abromaitis, Tim]. Skipping.
|
48
|
+
# league: nba, method: NBA_MOVEMENTS, filename: TPnBh5movements_basketball_ab.xml#
|
49
|
+
#
|
50
|
+
# This problem is addressed by accumulating log lines in the buffer until another start-of-log-
|
51
|
+
# record line appears. In the case that a multi-line log record is the last record, it will
|
52
|
+
# be flushed after a timeout. This assumes that even for a multi-line log record, it's often
|
53
|
+
# that all the lines are written out by the application together as one log record.
|
54
|
+
#
|
55
|
+
|
56
|
+
STDOUT_LOCK = Mutex.new
|
57
|
+
def self.write_log_record(rec)
|
58
|
+
if not rec.nil?
|
59
|
+
STDOUT_LOCK.synchronize do
|
60
|
+
STDOUT.write(rec.to_json << "\n")
|
61
|
+
STDOUT.flush()
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def initialize(timeout=5, &block)
|
67
|
+
@lock = Mutex.new
|
68
|
+
@flush_timeout = timeout
|
69
|
+
|
70
|
+
# buffer to aggregate a multi-line log record
|
71
|
+
# The first item will be a log record and the rest will
|
72
|
+
# be lines that are part of the @message field of the log record.
|
73
|
+
@log_buffer = []
|
74
|
+
|
75
|
+
@last_popped_record = nil
|
76
|
+
|
77
|
+
if not block.nil?
|
78
|
+
Thread.new do
|
79
|
+
begin
|
80
|
+
loop do
|
81
|
+
sleep @flush_timeout
|
82
|
+
rec = pop_push
|
83
|
+
block.call(rec) if not rec.nil?
|
84
|
+
end
|
85
|
+
rescue => e
|
86
|
+
LOG.error(e.backtrace.join("\n"))
|
87
|
+
retry
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# push a log record or part of its message to the buffer.
|
94
|
+
def push_part(part)
|
95
|
+
@lock.synchronize do
|
96
|
+
# LOG.debug("pushing part: #{part}") unless @log_buffer.empty?
|
97
|
+
@log_buffer << part unless @log_buffer.empty?
|
98
|
+
# Note: we skip pushing any partial lines before there's a log record.
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# pops the log record off the buffer and then optionally push a log record into the buffer.
|
103
|
+
# returns the popped record.
|
104
|
+
def pop_push(in_record=nil)
|
105
|
+
rec = nil
|
106
|
+
@lock.synchronize do
|
107
|
+
rec = @log_buffer.shift()
|
108
|
+
unless rec.nil?
|
109
|
+
if not rec.is_a?(Hash)
|
110
|
+
# the only way this can happen is that a timeout happened
|
111
|
+
# and the buffered multi-line log record got popped off before
|
112
|
+
# all its lines were pushed to the buffer.
|
113
|
+
@log_buffer.unshift(rec)
|
114
|
+
rec = @last_popped_record
|
115
|
+
end
|
116
|
+
rest = @log_buffer.join("\n")
|
117
|
+
if not rest.empty?
|
118
|
+
rec['@message'] += "\n" + rest
|
119
|
+
rec['@tags'] << 'multiline'
|
120
|
+
end
|
121
|
+
@log_buffer.clear()
|
122
|
+
@last_popped_record = rec
|
123
|
+
end
|
124
|
+
@log_buffer << in_record unless in_record.nil?
|
125
|
+
end
|
126
|
+
# LOG.debug("Popped #{rec}")
|
127
|
+
# LOG.debug("Pushed #{in_record}")
|
128
|
+
rec
|
129
|
+
end
|
130
|
+
|
131
|
+
end # end MultilineLogBuffer
|
132
|
+
|
133
|
+
|
134
|
+
end # end Log2Json module
|
data/log2json.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'log2json'
|
3
|
-
s.version = '0.1.
|
3
|
+
s.version = '0.1.22'
|
4
4
|
s.summary = "Read, filter and ship logs. ie, poor man's roll-your-own, light-weight logstash replacement."
|
5
5
|
s.description = IO.read(File.join(File.dirname(__FILE__), 'README'))
|
6
6
|
s.authors = ['Jack Kuan']
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: log2json
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.22
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-11-
|
12
|
+
date: 2013-11-15 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: jls-grok
|
@@ -125,6 +125,7 @@ files:
|
|
125
125
|
- lib/log2json/filters/base.patterns
|
126
126
|
- lib/log2json/filters/nginx_access.rb
|
127
127
|
- lib/log2json/filters/syslog.rb
|
128
|
+
- lib/log2json/mlogbuffer.rb
|
128
129
|
- lib/log2json/railslogger.rb
|
129
130
|
- log2json-loggers.gemspec
|
130
131
|
- log2json.gemspec
|