fluent-plugin-parser 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE.txt +13 -0
- data/fluent-plugin-parser.gemspec +2 -1
- data/lib/fluent/plugin/fixed_parser.rb +136 -0
- data/lib/fluent/plugin/out_parser.rb +5 -21
- data/test/plugin/test_out_parser.rb +0 -10
- metadata +20 -3
- data/LICENSE +0 -22
data/LICENSE.txt
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Copyright (c) 2012- TAGOMORI Satoshi
|
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.
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
Gem::Specification.new do |gem|
|
3
3
|
gem.name = "fluent-plugin-parser"
|
4
|
-
gem.version = "0.1.
|
4
|
+
gem.version = "0.1.1"
|
5
5
|
gem.authors = ["TAGOMORI Satoshi"]
|
6
6
|
gem.email = ["tagomoris@gmail.com"]
|
7
7
|
gem.description = %q{fluentd plugin to parse single field, or to combine log structure into single field}
|
@@ -13,6 +13,7 @@ Gem::Specification.new do |gem|
|
|
13
13
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
14
|
gem.require_paths = ["lib"]
|
15
15
|
|
16
|
+
gem.add_development_dependency "rake"
|
16
17
|
gem.add_development_dependency "fluentd"
|
17
18
|
gem.add_runtime_dependency "fluentd"
|
18
19
|
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
#
|
2
|
+
# This module is copied from fluentd/lib/fluent/parser.rb and
|
3
|
+
# fixed not to overwrite 'time' (reserve nil) when time not found in parsed string.
|
4
|
+
module FluentExt; end
|
5
|
+
|
6
|
+
class FluentExt::TextParser
|
7
|
+
class RegexpParser
|
8
|
+
include Fluent::Configurable
|
9
|
+
|
10
|
+
config_param :time_format, :string, :default => nil
|
11
|
+
|
12
|
+
def initialize(regexp, conf={})
|
13
|
+
super()
|
14
|
+
@regexp = regexp
|
15
|
+
unless conf.empty?
|
16
|
+
configure(conf)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def call(text)
|
21
|
+
m = @regexp.match(text)
|
22
|
+
unless m
|
23
|
+
$log.debug "pattern not match: #{text}"
|
24
|
+
# TODO?
|
25
|
+
return nil, nil
|
26
|
+
end
|
27
|
+
|
28
|
+
time = nil
|
29
|
+
record = {}
|
30
|
+
|
31
|
+
m.names.each {|name|
|
32
|
+
if value = m[name]
|
33
|
+
case name
|
34
|
+
when "time"
|
35
|
+
if @time_format
|
36
|
+
time = Time.strptime(value, @time_format).to_i
|
37
|
+
else
|
38
|
+
time = Time.parse(value).to_i
|
39
|
+
end
|
40
|
+
else
|
41
|
+
record[name] = value
|
42
|
+
end
|
43
|
+
end
|
44
|
+
}
|
45
|
+
|
46
|
+
return time, record
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class JSONParser
|
51
|
+
include Fluent::Configurable
|
52
|
+
|
53
|
+
config_param :time_key, :string, :default => 'time'
|
54
|
+
config_param :time_format, :string, :default => nil
|
55
|
+
|
56
|
+
def call(text)
|
57
|
+
record = Yajl.load(text)
|
58
|
+
|
59
|
+
time = nil
|
60
|
+
|
61
|
+
if value = record.delete(@time_key)
|
62
|
+
if @time_format
|
63
|
+
time = Time.strptime(value, @time_format).to_i
|
64
|
+
else
|
65
|
+
time = value.to_i
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
return time, record
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
TEMPLATES = {
|
74
|
+
'apache' => RegexpParser.new(/^(?<host>[^ ]*) [^ ]* (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^ ]*) +\S*)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)")?$/, {'time_format'=>"%d/%b/%Y:%H:%M:%S %z"}),
|
75
|
+
'syslog' => RegexpParser.new(/^(?<time>[^ ]*\s*[^ ]* [^ ]*) (?<host>[^ ]*) (?<ident>[a-zA-Z0-9_\/\.\-]*)(?:\[(?<pid>[0-9]+)\])?[^\:]*\: *(?<message>.*)$/, {'time_format'=>"%b %d %H:%M:%S"}),
|
76
|
+
'json' => JSONParser.new,
|
77
|
+
}
|
78
|
+
|
79
|
+
def self.register_template(name, regexp_or_proc, time_format=nil)
|
80
|
+
if regexp_or_proc.is_a?(Regexp)
|
81
|
+
pr = regexp_or_proc
|
82
|
+
else
|
83
|
+
regexp = regexp_or_proc
|
84
|
+
pr = RegexpParser.new(regexp, {'time_format'=>time_format})
|
85
|
+
end
|
86
|
+
|
87
|
+
TEMPLATES[name] = pr
|
88
|
+
end
|
89
|
+
|
90
|
+
def initialize
|
91
|
+
@parser = nil
|
92
|
+
end
|
93
|
+
|
94
|
+
def configure(conf, required=true)
|
95
|
+
format = conf['format']
|
96
|
+
|
97
|
+
if format == nil
|
98
|
+
if required
|
99
|
+
raise Fluent::ConfigError, "'format' parameter is required"
|
100
|
+
else
|
101
|
+
return nil
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
if format[0] == ?/ && format[format.length-1] == ?/
|
106
|
+
# regexp
|
107
|
+
begin
|
108
|
+
regexp = Regexp.new(format[1..-2])
|
109
|
+
if regexp.named_captures.empty?
|
110
|
+
raise "No named captures"
|
111
|
+
end
|
112
|
+
rescue
|
113
|
+
raise Fluent::ConfigError, "Invalid regexp '#{format[1..-2]}': #{$!}"
|
114
|
+
end
|
115
|
+
|
116
|
+
@parser = RegexpParser.new(regexp)
|
117
|
+
|
118
|
+
else
|
119
|
+
# built-in template
|
120
|
+
@parser = TEMPLATES[format]
|
121
|
+
unless @parser
|
122
|
+
raise ConfigError, "Unknown format template '#{format}'"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
if @parser.respond_to?(:configure)
|
127
|
+
@parser.configure(conf)
|
128
|
+
end
|
129
|
+
|
130
|
+
return true
|
131
|
+
end
|
132
|
+
|
133
|
+
def parse(text)
|
134
|
+
return @parser.call(text)
|
135
|
+
end
|
136
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require_relative './fixed_parser'
|
2
|
+
|
1
3
|
class Fluent::ParserOutput < Fluent::Output
|
2
4
|
Fluent::Plugin.register_output('parser', self)
|
3
5
|
|
@@ -29,26 +31,8 @@ class Fluent::ParserOutput < Fluent::Output
|
|
29
31
|
@added_prefix_string = @add_prefix + '.'
|
30
32
|
end
|
31
33
|
|
32
|
-
@parser =
|
34
|
+
@parser = FluentExt::TextParser.new
|
33
35
|
@parser.configure(conf)
|
34
|
-
|
35
|
-
m = if @parser.regexp.named_captures['time']
|
36
|
-
method(:parse_with_time)
|
37
|
-
else
|
38
|
-
method(:parse_without_time)
|
39
|
-
end
|
40
|
-
(class << self; self; end).module_eval do
|
41
|
-
define_method(:parse, m)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
def parse_with_time(value)
|
46
|
-
@parser.parse(value)
|
47
|
-
end
|
48
|
-
|
49
|
-
def parse_without_time(value)
|
50
|
-
t,r = @parser.parse(value)
|
51
|
-
return [nil, r]
|
52
36
|
end
|
53
37
|
|
54
38
|
def emit(tag, es, chain)
|
@@ -72,7 +56,7 @@ class Fluent::ParserOutput < Fluent::Output
|
|
72
56
|
es.each {|time,record|
|
73
57
|
value = record[@key_name]
|
74
58
|
t,values = if value
|
75
|
-
parse(value)
|
59
|
+
@parser.parse(value)
|
76
60
|
else
|
77
61
|
[nil, {}]
|
78
62
|
end
|
@@ -84,7 +68,7 @@ class Fluent::ParserOutput < Fluent::Output
|
|
84
68
|
es.each {|time,record|
|
85
69
|
value = record[@key_name]
|
86
70
|
t,values = if value
|
87
|
-
parse(value)
|
71
|
+
@parser.parse(value)
|
88
72
|
else
|
89
73
|
[nil, {}]
|
90
74
|
end
|
@@ -51,16 +51,6 @@ class ParserOutputTest < Test::Unit::TestCase
|
|
51
51
|
key_name foo
|
52
52
|
]
|
53
53
|
}
|
54
|
-
assert_raise(Fluent::ConfigError) {
|
55
|
-
d = create_driver %[
|
56
|
-
remove_prefix foo.baz
|
57
|
-
add_prefix foo.bar
|
58
|
-
format /(?<x>.)/
|
59
|
-
key_name foo
|
60
|
-
time_format %Y%m%d
|
61
|
-
]
|
62
|
-
}
|
63
|
-
|
64
54
|
d = create_driver %[
|
65
55
|
tag foo.bar
|
66
56
|
key_name foo
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluent-plugin-parser
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,8 +9,24 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-06-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rake
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
14
30
|
- !ruby/object:Gem::Dependency
|
15
31
|
name: fluentd
|
16
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -53,10 +69,11 @@ extra_rdoc_files: []
|
|
53
69
|
files:
|
54
70
|
- .gitignore
|
55
71
|
- Gemfile
|
56
|
-
- LICENSE
|
72
|
+
- LICENSE.txt
|
57
73
|
- README.md
|
58
74
|
- Rakefile
|
59
75
|
- fluent-plugin-parser.gemspec
|
76
|
+
- lib/fluent/plugin/fixed_parser.rb
|
60
77
|
- lib/fluent/plugin/out_deparser.rb
|
61
78
|
- lib/fluent/plugin/out_parser.rb
|
62
79
|
- test/helper.rb
|
data/LICENSE
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
Copyright (c) 2012 TAGOMORI Satoshi
|
2
|
-
|
3
|
-
MIT License
|
4
|
-
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
-
a copy of this software and associated documentation files (the
|
7
|
-
"Software"), to deal in the Software without restriction, including
|
8
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
-
permit persons to whom the Software is furnished to do so, subject to
|
11
|
-
the following conditions:
|
12
|
-
|
13
|
-
The above copyright notice and this permission notice shall be
|
14
|
-
included in all copies or substantial portions of the Software.
|
15
|
-
|
16
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
-
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
-
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
-
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|