fluent-plugin-tail-multiline 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +13 -0
- data/README.md +83 -0
- data/Rakefile +10 -0
- data/fluent-plugin-tail-multiline.gemspec +21 -0
- data/lib/fluent/plugin/in_tail_multiline.rb +192 -0
- data/test/helper.rb +28 -0
- data/test/plugin/test_in_tail_multiline.rb +203 -0
- metadata +68 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 30ae0c4b7c3d24c02a04d5fef674ca5e24f133ae
|
4
|
+
data.tar.gz: 10ac8354faf5e40d599d9dd9f8753c4ce46ecc4d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 352fdfcb3089d9553db4930a7514cb0a843b47c73e8f0e3c7da5617b7faf090357340e807d2cc65fd4ef12acb6ad1b4c218f8627d33637ae10d124c1afcc9ec7
|
7
|
+
data.tar.gz: 663c365b32692660f80eb0c4b4c22985ed3733d73bf4020689d2b8c864fd37c9da1908265020e2de7c219b45f26aa0ace0152a93ac67a08aee8410675f1a98a6
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Copyright (c) 2013 - Tomohisa Ota
|
2
|
+
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
you may not use this file except in compliance with the License.
|
5
|
+
You may obtain a copy of the License at
|
6
|
+
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
See the License for the specific language governing permissions and
|
13
|
+
limitations under the License.
|
data/README.md
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
# Fluent::Plugin::Tail-Multiline
|
2
|
+
|
3
|
+
Tail-Multiline plugin extends built-in tail plugin with following features
|
4
|
+
+ Support log with multiple line output such as stacktrace
|
5
|
+
+ RegEx parameter to detect first line
|
6
|
+
+ Save raw log data
|
7
|
+
|
8
|
+
**built-in templates are not supported. It does not support multiple line log anyway**
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
Use ruby gem as :
|
13
|
+
|
14
|
+
gem 'fluent-plugin-tail-multiline'
|
15
|
+
|
16
|
+
Or, if you're using td-client, you can call td-client's gem
|
17
|
+
|
18
|
+
$ /usr/lib64/fluent/ruby/bin/gem install fluent-plugin-tail-multiline
|
19
|
+
|
20
|
+
## Base Configuration
|
21
|
+
Tail-Multiline extends [tail plugin](http://docs.fluentd.org/categories/in_tail).
|
22
|
+
|
23
|
+
## Configuration
|
24
|
+
### Additional Parameters
|
25
|
+
name | type | description
|
26
|
+
----------------------|---------------------------------|---------------------------
|
27
|
+
format_firstline | string(default = format) | RegEx to detect first line of multiple line log, no name capture required
|
28
|
+
rawdata_key | string(default = null) | Store raw data with given key
|
29
|
+
|
30
|
+
## Examples
|
31
|
+
### Java log with exception
|
32
|
+
#### Input
|
33
|
+
```
|
34
|
+
2013-3-03 14:27:33 [main] INFO Main - Start
|
35
|
+
2013-3-03 14:27:33 [main] ERROR Main - Exception
|
36
|
+
javax.management.RuntimeErrorException: null
|
37
|
+
at Main.main(Main.java:16) ~[bin/:na]
|
38
|
+
2013-3-03 14:27:33 [main] INFO Main - End
|
39
|
+
```
|
40
|
+
#### Parameters
|
41
|
+
```
|
42
|
+
tag test
|
43
|
+
format /^(?<time>\d{4}-\d{1,2}-\d{1,2} \d{1,2}:\d{1,2}:\d{1,2}) \[(?<thread>.*)\] (?<level>[^\s]+)(?<message>.*)/
|
44
|
+
```
|
45
|
+
#### Output
|
46
|
+
```
|
47
|
+
2013-03-03 14:27:33 +0900 test: {"thread":"main","level":"INFO","message":" Main - Start"}
|
48
|
+
2013-03-03 14:27:33 +0900 test: {"thread":"main","level":"ERROR","message":" Main - Exception\njavax.management.RuntimeErrorException: null\n\tat Main.main(Main.java:16) ~[bin/:na]"}
|
49
|
+
2013-03-03 14:27:33 +0900 test: {"thread":"main","level":"INFO","message":" Main - End\n"}
|
50
|
+
```
|
51
|
+
|
52
|
+
### Case where first line does not have any name capture
|
53
|
+
#### Input
|
54
|
+
```
|
55
|
+
----
|
56
|
+
time=2013-3-03 14:27:33
|
57
|
+
message=test1
|
58
|
+
----
|
59
|
+
time=2013-3-03 14:27:34
|
60
|
+
message=test2
|
61
|
+
```
|
62
|
+
|
63
|
+
#### Parameters
|
64
|
+
```
|
65
|
+
tag test
|
66
|
+
format /time=(?<time>\d{4}-\d{1,2}-\d{1,2} \d{1,2}:\d{1,2}:\d{1,2}).*message=(?<message>.*)/
|
67
|
+
format_firstline /----/
|
68
|
+
```
|
69
|
+
|
70
|
+
#### Output
|
71
|
+
```
|
72
|
+
2013-03-03 14:27:33 +0900 test: {"message":"test1"}
|
73
|
+
2013-03-03 14:27:34 +0900 test: {"message":"test2"}
|
74
|
+
```
|
75
|
+
|
76
|
+
## Contributing
|
77
|
+
|
78
|
+
1. Fork it
|
79
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
80
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
81
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
82
|
+
5. Create new Pull Request
|
83
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
Gem::Specification.new do |gem|
|
6
|
+
gem.name = "fluent-plugin-tail-multiline"
|
7
|
+
gem.version = "0.1.0"
|
8
|
+
gem.authors = ["Tomohisa Ota"]
|
9
|
+
gem.email = ["tomohisa.ota+github@gmail.com"]
|
10
|
+
gem.description = ""
|
11
|
+
gem.summary = gem.description
|
12
|
+
gem.homepage = "http://github.com/tomohisaota/fluent-plugin-tail-multiline"
|
13
|
+
|
14
|
+
gem.files = `git ls-files`.split($/)
|
15
|
+
gem.files.reject! { |fn| fn.include? "doc/" }
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_runtime_dependency "fluentd"
|
21
|
+
end
|
@@ -0,0 +1,192 @@
|
|
1
|
+
module Fluent
|
2
|
+
require 'fluent/plugin/in_tail'
|
3
|
+
class TailMultilineInput < TailInput
|
4
|
+
|
5
|
+
class MultilineTextParser < TextParser
|
6
|
+
def configure(conf, required=true)
|
7
|
+
format = conf['format']
|
8
|
+
if format == nil
|
9
|
+
raise ConfigError, "'format' parameter is required"
|
10
|
+
elsif format[0] != ?/ || format[format.length-1] != ?/
|
11
|
+
raise ConfigError, "'format' should be RegEx. Template is not supported in multiline mode"
|
12
|
+
end
|
13
|
+
|
14
|
+
begin
|
15
|
+
@regex = Regexp.new(format[1..-2],Regexp::MULTILINE)
|
16
|
+
if @regex.named_captures.empty?
|
17
|
+
raise "No named captures"
|
18
|
+
end
|
19
|
+
rescue
|
20
|
+
raise ConfigError, "Invalid regexp in format '#{format[1..-2]}': #{$!}"
|
21
|
+
end
|
22
|
+
|
23
|
+
@parser = RegexpParser.new(@regex)
|
24
|
+
|
25
|
+
if @parser.respond_to?(:configure)
|
26
|
+
@parser.configure(conf)
|
27
|
+
end
|
28
|
+
|
29
|
+
format_firstline = conf['format_firstline']
|
30
|
+
if format_firstline
|
31
|
+
# Use custom matcher for 1st line
|
32
|
+
if format_firstline[0] == '/' && format_firstline[format_firstline.length-1] == '/'
|
33
|
+
@regex = Regexp.new(format_firstline[1..-2])
|
34
|
+
else
|
35
|
+
raise ConfigError, "Invalid regexp in format_firstline '#{format_firstline[1..-2]}': #{$!}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
return true
|
40
|
+
end
|
41
|
+
|
42
|
+
def match_firstline(text)
|
43
|
+
@regex.match(text)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
Plugin.register_input('tail_multiline', self)
|
48
|
+
|
49
|
+
config_param :format, :string
|
50
|
+
config_param :format_firstline, :string, :default => nil
|
51
|
+
config_param :rawdata_key, :string, :default => nil
|
52
|
+
config_param :auto_flush_sec, :integer, :default => 1
|
53
|
+
|
54
|
+
def initialize
|
55
|
+
super
|
56
|
+
@locker = Monitor.new
|
57
|
+
@logbuf = nil
|
58
|
+
@logbuf_flusher = CallLater::new
|
59
|
+
end
|
60
|
+
|
61
|
+
def configure_parser(conf)
|
62
|
+
@parser = MultilineTextParser.new
|
63
|
+
@parser.configure(conf)
|
64
|
+
end
|
65
|
+
|
66
|
+
def receive_lines(lines)
|
67
|
+
@logbuf_flusher.cancel()
|
68
|
+
es = MultiEventStream.new
|
69
|
+
@locker.synchronize do
|
70
|
+
lines.each {|line|
|
71
|
+
if @parser.match_firstline(line)
|
72
|
+
time, record = parse_logbuf(@logbuf)
|
73
|
+
if time && record
|
74
|
+
es.add(time, record)
|
75
|
+
end
|
76
|
+
@logbuf = line
|
77
|
+
else
|
78
|
+
@logbuf += line if(@logbuf)
|
79
|
+
end
|
80
|
+
}
|
81
|
+
end
|
82
|
+
unless es.empty?
|
83
|
+
begin
|
84
|
+
Engine.emit_stream(@tag, es)
|
85
|
+
rescue
|
86
|
+
# ignore errors. Engine shows logs and backtraces.
|
87
|
+
end
|
88
|
+
end
|
89
|
+
@logbuf_flusher.call_later(@auto_flush_sec) do
|
90
|
+
flush_logbuf()
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def shutdown
|
95
|
+
super
|
96
|
+
flush_logbuf()
|
97
|
+
@logbuf_flusher.shutdown()
|
98
|
+
end
|
99
|
+
|
100
|
+
def flush_logbuf
|
101
|
+
time, record = nil,nil
|
102
|
+
@locker.synchronize do
|
103
|
+
time, record = parse_logbuf(@logbuf)
|
104
|
+
@logbuf = nil
|
105
|
+
end
|
106
|
+
if time && record
|
107
|
+
Engine.emit(@tag, time, record)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def parse_logbuf(buf)
|
112
|
+
return nil,nil unless buf
|
113
|
+
buf.chomp!
|
114
|
+
begin
|
115
|
+
time, record = @parser.parse(buf)
|
116
|
+
rescue
|
117
|
+
$log.warn line.dump, :error=>$!.to_s
|
118
|
+
$log.debug_backtrace
|
119
|
+
end
|
120
|
+
return nil,nil unless time && record
|
121
|
+
record[@rawdata_key] = buf if @rawdata_key
|
122
|
+
return time, record
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
class CallLater
|
128
|
+
def initialize
|
129
|
+
@locker = Monitor::new
|
130
|
+
@thread = Thread.new(&method(:run))
|
131
|
+
initExecBlock()
|
132
|
+
end
|
133
|
+
|
134
|
+
def call_later(delay,&block)
|
135
|
+
@locker.synchronize do
|
136
|
+
@exec_time = Engine.now + delay
|
137
|
+
@exec_block = block
|
138
|
+
end
|
139
|
+
@thread.run
|
140
|
+
end
|
141
|
+
|
142
|
+
def run
|
143
|
+
@running = true
|
144
|
+
while true
|
145
|
+
sleepSec = -1
|
146
|
+
@locker.synchronize do
|
147
|
+
now = Engine.now
|
148
|
+
if @exec_block && @exec_time <= now
|
149
|
+
@exec_block.call()
|
150
|
+
initExecBlock()
|
151
|
+
end
|
152
|
+
return unless @running
|
153
|
+
unless(@exec_time == -1)
|
154
|
+
sleepSec = @exec_time - now
|
155
|
+
end
|
156
|
+
end
|
157
|
+
if (sleepSec == -1)
|
158
|
+
sleep()
|
159
|
+
else
|
160
|
+
sleep(sleepSec)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
rescue => e
|
164
|
+
puts e
|
165
|
+
end
|
166
|
+
|
167
|
+
def cancel()
|
168
|
+
initExecBlock()
|
169
|
+
end
|
170
|
+
|
171
|
+
def shutdown()
|
172
|
+
@locker.synchronize do
|
173
|
+
@running = false
|
174
|
+
end
|
175
|
+
if(@thread)
|
176
|
+
@thread.run
|
177
|
+
@thread.join
|
178
|
+
@thread = nil
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
private
|
183
|
+
|
184
|
+
def initExecBlock()
|
185
|
+
@locker.synchronize do
|
186
|
+
@exec_time = -1
|
187
|
+
@exec_block = nil
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
end
|
192
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'test/unit'
|
11
|
+
|
12
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
13
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
14
|
+
require 'fluent/test'
|
15
|
+
unless ENV.has_key?('VERBOSE')
|
16
|
+
nulllogger = Object.new
|
17
|
+
nulllogger.instance_eval {|obj|
|
18
|
+
def method_missing(method, *args)
|
19
|
+
# pass
|
20
|
+
end
|
21
|
+
}
|
22
|
+
$log = nulllogger
|
23
|
+
end
|
24
|
+
|
25
|
+
require 'fluent/plugin/in_tail_multiline'
|
26
|
+
|
27
|
+
class Test::Unit::TestCase
|
28
|
+
end
|
@@ -0,0 +1,203 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
require 'tempfile'
|
4
|
+
|
5
|
+
class TailMultilineInputTest < Test::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
Fluent::Test.setup
|
8
|
+
end
|
9
|
+
|
10
|
+
CONFIG = %[
|
11
|
+
]
|
12
|
+
# CONFIG = %[
|
13
|
+
# path #{TMP_DIR}/out_file_test
|
14
|
+
# compress gz
|
15
|
+
# utc
|
16
|
+
# ]
|
17
|
+
|
18
|
+
def create_driver(conf = CONFIG)
|
19
|
+
Fluent::Test::InputTestDriver.new(Fluent::TailMultilineInput).configure(conf)
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_emit_no_additional_option
|
23
|
+
tmpFile = Tempfile.new("in_tail_multiline-")
|
24
|
+
begin
|
25
|
+
d = create_driver %[
|
26
|
+
path #{tmpFile.path}
|
27
|
+
tag test
|
28
|
+
format /^[s|f] (?<message>.*)/
|
29
|
+
]
|
30
|
+
d.run do
|
31
|
+
File.open(tmpFile.path, "w") {|f|
|
32
|
+
f.puts "f test1"
|
33
|
+
f.puts "s test2"
|
34
|
+
f.puts "f test3"
|
35
|
+
f.puts "f test4"
|
36
|
+
f.puts "s test5"
|
37
|
+
f.puts "s test6"
|
38
|
+
f.puts "f test7"
|
39
|
+
f.puts "s test8"
|
40
|
+
}
|
41
|
+
sleep 1
|
42
|
+
end
|
43
|
+
|
44
|
+
emits = d.emits
|
45
|
+
assert_equal(true, emits.length > 0)
|
46
|
+
assert_equal({"message"=>"test1"}, emits[0][2])
|
47
|
+
assert_equal({"message"=>"test2"}, emits[1][2])
|
48
|
+
assert_equal({"message"=>"test3"}, emits[2][2])
|
49
|
+
assert_equal({"message"=>"test4"}, emits[3][2])
|
50
|
+
assert_equal({"message"=>"test5"}, emits[4][2])
|
51
|
+
assert_equal({"message"=>"test6"}, emits[5][2])
|
52
|
+
assert_equal({"message"=>"test7"}, emits[6][2])
|
53
|
+
assert_equal({"message"=>"test8"}, emits[7][2])
|
54
|
+
ensure
|
55
|
+
tmpFile.close(true)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_emit_with_rawdata
|
60
|
+
tmpFile = Tempfile.new("in_tail_multiline-")
|
61
|
+
begin
|
62
|
+
d = create_driver %[
|
63
|
+
path #{tmpFile.path}
|
64
|
+
tag test
|
65
|
+
format /^[s|f] (?<message>.*)/
|
66
|
+
rawdata_key rawdata
|
67
|
+
]
|
68
|
+
d.run do
|
69
|
+
File.open(tmpFile.path, "w") {|f|
|
70
|
+
f.puts "f test1"
|
71
|
+
f.puts "s test2"
|
72
|
+
f.puts "f test3"
|
73
|
+
f.puts "f test4"
|
74
|
+
f.puts "s test5"
|
75
|
+
f.puts "s test6"
|
76
|
+
f.puts "f test7"
|
77
|
+
f.puts "s test8"
|
78
|
+
}
|
79
|
+
sleep 1
|
80
|
+
end
|
81
|
+
|
82
|
+
emits = d.emits
|
83
|
+
assert_equal(true, emits.length > 0)
|
84
|
+
assert_equal({"message"=>"test1","rawdata"=>"f test1"}, emits[0][2])
|
85
|
+
assert_equal({"message"=>"test2","rawdata"=>"s test2"}, emits[1][2])
|
86
|
+
assert_equal({"message"=>"test3","rawdata"=>"f test3"}, emits[2][2])
|
87
|
+
assert_equal({"message"=>"test4","rawdata"=>"f test4"}, emits[3][2])
|
88
|
+
assert_equal({"message"=>"test5","rawdata"=>"s test5"}, emits[4][2])
|
89
|
+
assert_equal({"message"=>"test6","rawdata"=>"s test6"}, emits[5][2])
|
90
|
+
assert_equal({"message"=>"test7","rawdata"=>"f test7"}, emits[6][2])
|
91
|
+
assert_equal({"message"=>"test8","rawdata"=>"s test8"}, emits[7][2])
|
92
|
+
ensure
|
93
|
+
tmpFile.close(true)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
def test_emit_with_format_firstline
|
97
|
+
tmpFile = Tempfile.new("in_tail_multiline-")
|
98
|
+
begin
|
99
|
+
d = create_driver %[
|
100
|
+
path #{tmpFile.path}
|
101
|
+
tag test
|
102
|
+
format /^[s|f] (?<message>.*)/
|
103
|
+
format_firstline /^[s]/
|
104
|
+
]
|
105
|
+
d.run do
|
106
|
+
File.open(tmpFile.path, "w") {|f|
|
107
|
+
f.puts "f test1"
|
108
|
+
f.puts "s test2"
|
109
|
+
f.puts "f test3"
|
110
|
+
f.puts "f test4"
|
111
|
+
f.puts "s test5"
|
112
|
+
f.puts "s test6"
|
113
|
+
f.puts "f test7"
|
114
|
+
f.puts "s test8"
|
115
|
+
}
|
116
|
+
sleep 1
|
117
|
+
end
|
118
|
+
|
119
|
+
emits = d.emits
|
120
|
+
assert_equal(true, emits.length > 0)
|
121
|
+
n = -1
|
122
|
+
assert_equal({"message"=>"test2\nf test3\nf test4"}, emits[0][2])
|
123
|
+
assert_equal({"message"=>"test5"}, emits[1][2])
|
124
|
+
assert_equal({"message"=>"test6\nf test7"}, emits[2][2])
|
125
|
+
assert_equal({"message"=>"test8"}, emits[3][2])
|
126
|
+
ensure
|
127
|
+
tmpFile.close(true)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def test_emit_with_format_firstline_with_rawdata
|
132
|
+
tmpFile = Tempfile.new("in_tail_multiline-")
|
133
|
+
begin
|
134
|
+
d = create_driver %[
|
135
|
+
path #{tmpFile.path}
|
136
|
+
tag test
|
137
|
+
format /^[s|f] (?<message>.*)/
|
138
|
+
format_firstline /^[s]/
|
139
|
+
rawdata_key rawdata
|
140
|
+
]
|
141
|
+
d.run do
|
142
|
+
File.open(tmpFile.path, "w") {|f|
|
143
|
+
f.puts "f test1"
|
144
|
+
f.puts "s test2"
|
145
|
+
f.puts "f test3"
|
146
|
+
f.puts "f test4"
|
147
|
+
f.puts "s test5"
|
148
|
+
f.puts "s test6"
|
149
|
+
f.puts "f test7"
|
150
|
+
f.puts "s test8"
|
151
|
+
}
|
152
|
+
sleep 1
|
153
|
+
end
|
154
|
+
|
155
|
+
emits = d.emits
|
156
|
+
assert_equal(true, emits.length > 0)
|
157
|
+
n = -1
|
158
|
+
assert_equal({"message"=>"test2\nf test3\nf test4","rawdata"=>"s test2\nf test3\nf test4"}, emits[0][2])
|
159
|
+
assert_equal({"message"=>"test5","rawdata"=>"s test5"}, emits[1][2])
|
160
|
+
assert_equal({"message"=>"test6\nf test7","rawdata"=>"s test6\nf test7"}, emits[2][2])
|
161
|
+
assert_equal({"message"=>"test8","rawdata"=>"s test8"}, emits[3][2])
|
162
|
+
ensure
|
163
|
+
tmpFile.close(true)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def test_multilinelog
|
168
|
+
tmpFile = Tempfile.new("in_tail_multiline-")
|
169
|
+
begin
|
170
|
+
d = create_driver %[
|
171
|
+
path #{tmpFile.path}
|
172
|
+
tag test
|
173
|
+
format /^s (?<message1>[^\\n]+)(\\nf (?<message2>[^\\n]+))?(\\nf (?<message3>.*))?/
|
174
|
+
format_firstline /^[s]/
|
175
|
+
rawdata_key rawdata
|
176
|
+
]
|
177
|
+
d.run do
|
178
|
+
File.open(tmpFile.path, "w") {|f|
|
179
|
+
f.puts "f test1"
|
180
|
+
f.puts "s test2"
|
181
|
+
f.puts "f test3"
|
182
|
+
f.puts "f test4"
|
183
|
+
f.puts "s test5"
|
184
|
+
f.puts "s test6"
|
185
|
+
f.puts "f test7"
|
186
|
+
f.puts "s test8"
|
187
|
+
}
|
188
|
+
sleep 1
|
189
|
+
end
|
190
|
+
|
191
|
+
emits = d.emits
|
192
|
+
assert_equal(true, emits.length > 0)
|
193
|
+
n = -1
|
194
|
+
assert_equal({"message1"=>"test2","message2"=>"test3","message3"=>"test4","rawdata"=>"s test2\nf test3\nf test4"}, emits[0][2])
|
195
|
+
assert_equal({"message1"=>"test5","rawdata"=>"s test5"}, emits[1][2])
|
196
|
+
assert_equal({"message1"=>"test6","message2"=>"test7","rawdata"=>"s test6\nf test7"}, emits[2][2])
|
197
|
+
assert_equal({"message1"=>"test8","rawdata"=>"s test8"}, emits[3][2])
|
198
|
+
ensure
|
199
|
+
tmpFile.close(true)
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
end
|
metadata
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fluent-plugin-tail-multiline
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tomohisa Ota
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-03-04 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: fluentd
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ! '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ! '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
description: ''
|
28
|
+
email:
|
29
|
+
- tomohisa.ota+github@gmail.com
|
30
|
+
executables: []
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- .gitignore
|
35
|
+
- Gemfile
|
36
|
+
- LICENSE.txt
|
37
|
+
- README.md
|
38
|
+
- Rakefile
|
39
|
+
- fluent-plugin-tail-multiline.gemspec
|
40
|
+
- lib/fluent/plugin/in_tail_multiline.rb
|
41
|
+
- test/helper.rb
|
42
|
+
- test/plugin/test_in_tail_multiline.rb
|
43
|
+
homepage: http://github.com/tomohisaota/fluent-plugin-tail-multiline
|
44
|
+
licenses: []
|
45
|
+
metadata: {}
|
46
|
+
post_install_message:
|
47
|
+
rdoc_options: []
|
48
|
+
require_paths:
|
49
|
+
- lib
|
50
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ! '>='
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '0'
|
60
|
+
requirements: []
|
61
|
+
rubyforge_project:
|
62
|
+
rubygems_version: 2.0.0
|
63
|
+
signing_key:
|
64
|
+
specification_version: 4
|
65
|
+
summary: ''
|
66
|
+
test_files:
|
67
|
+
- test/helper.rb
|
68
|
+
- test/plugin/test_in_tail_multiline.rb
|