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 CHANGED
@@ -1,2 +1,2 @@
1
1
  source "https://rubygems.org"
2
- gemspec
2
+ gemspec :name => 'log2json'
@@ -1,21 +1,21 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- log2json (0.1.0)
4
+ log2json (0.1.22)
5
5
  jls-grok (~> 0.10.10)
6
- persistent_http (~> 1.0.5)
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.5.0)
12
+ cabin (0.6.1)
13
13
  gene_pool (1.3.0)
14
- jls-grok (0.10.10)
15
- cabin (~> 0.5.0)
16
- persistent_http (1.0.5)
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.3)
18
+ redis (3.0.6)
19
19
 
20
20
  PLATFORMS
21
21
  ruby
@@ -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
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'log2json'
3
- s.version = '0.1.21'
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.21
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-07 00:00:00.000000000 Z
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