fluent-plugin-json-in-json-2 1.0.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e99746f88495ff8ed13fd6d295a4522cc641172c
4
+ data.tar.gz: 870714d1b589915f6642de346c7ca21f19f7a0cb
5
+ SHA512:
6
+ metadata.gz: f0ebd7c9647c3e36afa83c732929339c8ddab29b5d02b592799e76687024842f5f51c15cc29640a2a4397577290c128f8bbfe798d087a7e25a40ae2f5f51f38b
7
+ data.tar.gz: 4ee7b4768620d0179f60e63776b631207b63650d766de565a689ead87ac75a8deda9ed913f2b0f234a29f05ef98a0bb42abf4437b63b4f9339bcffddd78c81e6
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in fluent-plugin-json-in-json.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,49 @@
1
+ # fluent-plugin-json-in-json
2
+
3
+ ## Requirements
4
+
5
+ | fluent-plugin-json-in-json| Fluentd | Ruby |
6
+ |---------------------------|-------------|--------|
7
+ | >= 1.0.0 | >= v0.14.0 | >= 2.1 |
8
+ | < 1.0.0 | >= v0.12.0 | >= 1.9 |
9
+
10
+ This fluentd parser plugin parses JSON log lines with nested JSON strings. For
11
+ example, given a docker log of ``{"log": "{\"foo\": \"bar\"}"}``, the log record
12
+ will be parsed into ``{:log => { :foo => "bar" }}``.
13
+
14
+ ## Installation
15
+
16
+ Add this line to your application's Gemfile:
17
+
18
+ gem 'fluent-plugin-json-in-json'
19
+
20
+ And then execute:
21
+
22
+ $ bundle
23
+
24
+ Or install it yourself as:
25
+
26
+ $ gem install fluent-plugin-json-in-json
27
+
28
+
29
+ ## Usage
30
+
31
+ ```
32
+ <source>
33
+ type tail
34
+ path /var/lib/docker/containers/*/*-json.log
35
+ pos_file /var/log/fluentd-docker.pos
36
+ time_format %Y-%m-%dT%H:%M:%S
37
+ tag docker.*
38
+ format json_in_json
39
+ read_from_head true
40
+ </source>
41
+ ```
42
+
43
+ ## Contributing
44
+
45
+ 1. Fork it
46
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
47
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
48
+ 4. Push to the branch (`git push origin my-new-feature`)
49
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs << 'test'
6
+ t.test_files = FileList['test/test*.rb']
7
+ t.verbose = true
8
+ t.warning = true
9
+ t.ruby_opts = ['-Eascii-8bit:ascii-8bit']
10
+ end
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ Gem::Specification.new do |spec|
3
+ spec.name = "fluent-plugin-json-in-json-2"
4
+ spec.version = "1.0.0"
5
+ spec.authors = ["Gavin M. Roy", "Arcadiy Ivanov", "Alik Khilazhev"]
6
+ spec.email = ["gavinmroy@gmail.com", "arcadiy@ivanov.biz", "alikhil@mail.ru"]
7
+ spec.description = %q{Parser plugin that parses JSON attributes with JSON strings in them}
8
+ spec.summary = %q{Parser plugin that parses JSON attributes with JSON strings in them}
9
+ spec.homepage = "https://github.com/arcivanov/fluent-plugin-json-in-json"
10
+ spec.license = "BSD"
11
+
12
+ spec.files = `git ls-files`.split($/)
13
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
14
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
15
+ spec.require_paths = ["lib"]
16
+
17
+ spec.add_runtime_dependency 'fluentd', ['>= 0.14.0', '< 2']
18
+ spec.add_runtime_dependency 'yajl-ruby', '~> 1.0'
19
+
20
+ spec.add_development_dependency 'rake', '~> 12.3'
21
+ spec.add_development_dependency 'bundler', '~> 1.16'
22
+
23
+ spec.add_development_dependency 'test-unit', ['~> 3.2']
24
+ spec.add_development_dependency 'test-unit-rr', ['~> 1.0']
25
+ end
@@ -0,0 +1,46 @@
1
+ require 'fluent/parser'
2
+ require 'yajl'
3
+
4
+ module Fluent
5
+ module Plugin
6
+ class JSONInJSONParser < Parser
7
+ Plugin.register_parser('json_in_json', self)
8
+
9
+ config_set_default :time_key, 'time'
10
+ config_set_default :time_type, :float
11
+
12
+ def configure(conf)
13
+ if conf.has_key?('time_format')
14
+ conf['time_type'] ||= 'string'
15
+ end
16
+
17
+ super
18
+ end
19
+
20
+ def parse(text)
21
+ record = Yajl.load(text)
22
+
23
+ values = Hash.new
24
+
25
+ record.each do |k, v|
26
+ if v.is_a?(String) && /^\s*(\{|\[)/ =~ v
27
+ deserialized = Yajl.load(v)
28
+ if deserialized.is_a?(Hash)
29
+ values.merge!(deserialized)
30
+ record.delete k
31
+ elsif deserialized.is_a?(Array)
32
+ values[k] = deserialized
33
+ end
34
+ end
35
+ end
36
+ record.merge!(values)
37
+
38
+ time, record = convert_values(parse_time(record), record)
39
+
40
+ yield time, record
41
+ rescue Yajl::ParseError
42
+ yield nil, nil
43
+ end
44
+ end
45
+ end
46
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,128 @@
1
+ # Some tests use Hash instead of Element for configure.
2
+ # We should rewrite these tests in the future and remove this ad-hoc code
3
+ class Hash
4
+ def corresponding_proxies
5
+ @corresponding_proxies ||= []
6
+ end
7
+
8
+ def to_masked_element
9
+ self
10
+ end
11
+ end
12
+
13
+ require 'rr'
14
+ require 'test/unit'
15
+ require 'test/unit/rr'
16
+ require 'fileutils'
17
+ require 'fluent/config/element'
18
+ require 'fluent/log'
19
+ require 'fluent/test'
20
+ require 'fluent/test/helpers'
21
+ require 'fluent/plugin/base'
22
+ require 'fluent/plugin_id'
23
+ require 'fluent/plugin_helper'
24
+ require 'fluent/msgpack_factory'
25
+ require 'fluent/time'
26
+ require 'serverengine'
27
+
28
+ module Fluent
29
+ module Plugin
30
+ class TestBase < Base
31
+ # a base plugin class, but not input nor output
32
+ # mainly for helpers and owned plugins
33
+ include PluginId
34
+ include PluginLoggerMixin
35
+ include PluginHelper::Mixin
36
+ end
37
+ end
38
+ end
39
+
40
+ unless defined?(Test::Unit::AssertionFailedError)
41
+ class Test::Unit::AssertionFailedError < StandardError
42
+ end
43
+ end
44
+
45
+ include Fluent::Test::Helpers
46
+
47
+ def unused_port(num = 1, protocol: :tcp, bind: "0.0.0.0")
48
+ case protocol
49
+ when :tcp
50
+ unused_port_tcp(num)
51
+ when :udp
52
+ unused_port_udp(num, bind: bind)
53
+ else
54
+ raise ArgumentError, "unknown protocol: #{protocol}"
55
+ end
56
+ end
57
+
58
+ def unused_port_tcp(num = 1)
59
+ ports = []
60
+ sockets = []
61
+ num.times do
62
+ s = TCPServer.open(0)
63
+ sockets << s
64
+ ports << s.addr[1]
65
+ end
66
+ sockets.each{|s| s.close }
67
+ if num == 1
68
+ return ports.first
69
+ else
70
+ return *ports
71
+ end
72
+ end
73
+
74
+ PORT_RANGE_AVAILABLE = (1024...65535)
75
+
76
+ def unused_port_udp(num = 1, bind: "0.0.0.0")
77
+ family = IPAddr.new(IPSocket.getaddress(bind)).ipv4? ? ::Socket::AF_INET : ::Socket::AF_INET6
78
+ ports = []
79
+ sockets = []
80
+ while ports.size < num
81
+ port = rand(PORT_RANGE_AVAILABLE)
82
+ u = UDPSocket.new(family)
83
+ if (u.bind(bind, port) rescue nil)
84
+ ports << port
85
+ sockets << u
86
+ else
87
+ u.close
88
+ end
89
+ end
90
+ sockets.each{|s| s.close }
91
+ if num == 1
92
+ return ports.first
93
+ else
94
+ return *ports
95
+ end
96
+ end
97
+
98
+ def waiting(seconds, logs: nil, plugin: nil)
99
+ begin
100
+ Timeout.timeout(seconds) do
101
+ yield
102
+ end
103
+ rescue Timeout::Error
104
+ if logs
105
+ STDERR.print(*logs)
106
+ elsif plugin
107
+ STDERR.print(*plugin.log.out.logs)
108
+ end
109
+ raise
110
+ end
111
+ end
112
+
113
+ def ipv6_enabled?
114
+ require 'socket'
115
+
116
+ begin
117
+ TCPServer.open("::1", 0)
118
+ true
119
+ rescue
120
+ false
121
+ end
122
+ end
123
+
124
+ dl_opts = {}
125
+ dl_opts[:log_level] = ServerEngine::DaemonLogger::WARN
126
+ logdev = Fluent::Test::DummyLogDevice.new
127
+ logger = ServerEngine::DaemonLogger.new(logdev, dl_opts)
128
+ $log ||= Fluent::Log.new(logger)
@@ -0,0 +1,54 @@
1
+ require_relative 'helper'
2
+ require 'fluent/test/driver/parser'
3
+ require 'fluent/plugin/parser_json_in_json'
4
+
5
+ class JsonInJsonParserTest < ::Test::Unit::TestCase
6
+ def setup
7
+ Fluent::Test.setup
8
+ @parser = Fluent::Test::Driver::Parser.new(Fluent::Plugin::JSONInJSONParser)
9
+ end
10
+
11
+ def test_parse_float_time()
12
+ @parser.configure({})
13
+ @parser.instance.parse('{"time":1362020400,"host":"192.168.0.1","size":777,"method":"PUT","log_json":" {\\"field1\\":\\"field1 value\\",\\"field2\\":40}"}') { |time, record|
14
+ assert_equal(event_time('2013-02-28 12:00:00 +0900').to_f, time.to_f)
15
+ assert_equal({
16
+ 'host' => '192.168.0.1',
17
+ 'size' => 777,
18
+ 'method' => 'PUT',
19
+ 'field1' => 'field1 value',
20
+ 'field2' => 40
21
+ }, record)
22
+ }
23
+ @parser.instance.parse('{"time":1362020400,"host":"192.168.0.1","size":777,"method":"PUT","log_json":"{\\"field1\\":"}') { |time, record|
24
+ assert_equal(event_time('2013-02-28 12:00:00 +0900').to_f, time.to_f)
25
+ assert_equal({
26
+ 'host' => '192.168.0.1',
27
+ 'size' => 777,
28
+ 'method' => 'PUT',
29
+ 'log_json' => '{"field1":'
30
+ }, record)
31
+ }
32
+ @parser.instance.parse('{"time":1362020400,"host":"192.168.0.1","size":777,"method":"PUT","log_json":"[\\"val1\\",\\"val2\\"]"') { |time, record|
33
+ assert_equal(event_time('2013-02-28 12:00:00 +0900').to_f, time.to_f)
34
+ assert_equal({
35
+ 'host' => '192.168.0.1',
36
+ 'size' => 777,
37
+ 'method' => 'PUT',
38
+ 'log_json' => ['val1', 'val2']
39
+ }, record)
40
+ }
41
+ end
42
+
43
+ def test_parse_string_time()
44
+ @parser.configure('time_format' => '%Y-%m-%dT%H:%M:%S.%NZ', 'keep_time_key' => 'true')
45
+ @parser.instance.parse('{"log":"2018-06-26 13:20:44.075 INFO --- [pool-8-thread-3] outgoing","stream":"stdout","time":"2018-06-26T13:20:44.076022960Z"}') { |time, record|
46
+ assert_equal(event_time('2018-06-26 13:20:44.076022960 -0400').to_f, time.to_f)
47
+ assert_equal({
48
+ 'log'=>'2018-06-26 13:20:44.075 INFO --- [pool-8-thread-3] outgoing',
49
+ 'stream'=>'stdout',
50
+ 'time'=>'2018-06-26T13:20:44.076022960Z'
51
+ }, record)
52
+ }
53
+ end
54
+ end
metadata ADDED
@@ -0,0 +1,148 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fluent-plugin-json-in-json-2
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Gavin M. Roy
8
+ - Arcadiy Ivanov
9
+ - Alik Khilazhev
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2019-06-17 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: fluentd
17
+ requirement: !ruby/object:Gem::Requirement
18
+ requirements:
19
+ - - ">="
20
+ - !ruby/object:Gem::Version
21
+ version: 0.14.0
22
+ - - "<"
23
+ - !ruby/object:Gem::Version
24
+ version: '2'
25
+ type: :runtime
26
+ prerelease: false
27
+ version_requirements: !ruby/object:Gem::Requirement
28
+ requirements:
29
+ - - ">="
30
+ - !ruby/object:Gem::Version
31
+ version: 0.14.0
32
+ - - "<"
33
+ - !ruby/object:Gem::Version
34
+ version: '2'
35
+ - !ruby/object:Gem::Dependency
36
+ name: yajl-ruby
37
+ requirement: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '1.0'
42
+ type: :runtime
43
+ prerelease: false
44
+ version_requirements: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '1.0'
49
+ - !ruby/object:Gem::Dependency
50
+ name: rake
51
+ requirement: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '12.3'
56
+ type: :development
57
+ prerelease: false
58
+ version_requirements: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: '12.3'
63
+ - !ruby/object:Gem::Dependency
64
+ name: bundler
65
+ requirement: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '1.16'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: '1.16'
77
+ - !ruby/object:Gem::Dependency
78
+ name: test-unit
79
+ requirement: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - "~>"
82
+ - !ruby/object:Gem::Version
83
+ version: '3.2'
84
+ type: :development
85
+ prerelease: false
86
+ version_requirements: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - "~>"
89
+ - !ruby/object:Gem::Version
90
+ version: '3.2'
91
+ - !ruby/object:Gem::Dependency
92
+ name: test-unit-rr
93
+ requirement: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - "~>"
96
+ - !ruby/object:Gem::Version
97
+ version: '1.0'
98
+ type: :development
99
+ prerelease: false
100
+ version_requirements: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - "~>"
103
+ - !ruby/object:Gem::Version
104
+ version: '1.0'
105
+ description: Parser plugin that parses JSON attributes with JSON strings in them
106
+ email:
107
+ - gavinmroy@gmail.com
108
+ - arcadiy@ivanov.biz
109
+ - alikhil@mail.ru
110
+ executables: []
111
+ extensions: []
112
+ extra_rdoc_files: []
113
+ files:
114
+ - ".gitignore"
115
+ - Gemfile
116
+ - README.md
117
+ - Rakefile
118
+ - fluent-plugin-json-in-json.gemspec
119
+ - lib/fluent/plugin/parser_json_in_json.rb
120
+ - test/helper.rb
121
+ - test/test_parser.rb
122
+ homepage: https://github.com/arcivanov/fluent-plugin-json-in-json
123
+ licenses:
124
+ - BSD
125
+ metadata: {}
126
+ post_install_message:
127
+ rdoc_options: []
128
+ require_paths:
129
+ - lib
130
+ required_ruby_version: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ required_rubygems_version: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ requirements: []
141
+ rubyforge_project:
142
+ rubygems_version: 2.5.2
143
+ signing_key:
144
+ specification_version: 4
145
+ summary: Parser plugin that parses JSON attributes with JSON strings in them
146
+ test_files:
147
+ - test/helper.rb
148
+ - test/test_parser.rb