fluent-plugin-filter-logs 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 59d84bba5af478dc7dfe86b84851947315acebfd2ab4f4ec22e5e5c9492d4903
4
+ data.tar.gz: 01aaf411dc9fb3afe540d5d12c70b938159cd2205722449398af102b2341a8bf
5
+ SHA512:
6
+ metadata.gz: e24e8ee7deacbf24ab054f506c33035f5259b51f2d1633d8fb08d9250a48129eadae56998e4f0cf58620d0a9a8920345f532aac223ddd1e90bf045b5ddcbf3ce
7
+ data.tar.gz: 707c97d804c6634c1bd6618ca1bbd3127b98bbd84fe315c521658b43a738400865805b92636524863973b90189a094e867c50407c6fafef52c671f10b5d39d43
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,52 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ fluent-plugin-filter-logs (1.0.4)
5
+ fluentd (>= 0.14.10, < 2)
6
+ logfmt (~> 0.0.9)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ byebug (11.1.1)
12
+ concurrent-ruby (1.1.6)
13
+ cool.io (1.6.0)
14
+ fluentd (1.10.0)
15
+ cool.io (>= 1.4.5, < 2.0.0)
16
+ http_parser.rb (>= 0.5.1, < 0.7.0)
17
+ msgpack (>= 1.3.1, < 2.0.0)
18
+ serverengine (>= 2.0.4, < 3.0.0)
19
+ sigdump (~> 0.2.2)
20
+ strptime (>= 0.2.2, < 1.0.0)
21
+ tzinfo (>= 1.0, < 3.0)
22
+ tzinfo-data (~> 1.0)
23
+ yajl-ruby (~> 1.0)
24
+ http_parser.rb (0.6.0)
25
+ logfmt (0.0.9)
26
+ msgpack (1.3.3)
27
+ power_assert (1.1.3)
28
+ rake (12.3.3)
29
+ serverengine (2.2.1)
30
+ sigdump (~> 0.2.2)
31
+ sigdump (0.2.4)
32
+ strptime (0.2.3)
33
+ test-unit (3.2.9)
34
+ power_assert
35
+ tzinfo (2.0.1)
36
+ concurrent-ruby (~> 1.0)
37
+ tzinfo-data (1.2019.3)
38
+ tzinfo (>= 1.0.0)
39
+ yajl-ruby (1.4.1)
40
+
41
+ PLATFORMS
42
+ ruby
43
+
44
+ DEPENDENCIES
45
+ bundler
46
+ byebug
47
+ fluent-plugin-filter-logs!
48
+ rake (~> 12.0)
49
+ test-unit (~> 3.0)
50
+
51
+ BUNDLED WITH
52
+ 2.1.4
data/LICENSE ADDED
@@ -0,0 +1,202 @@
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright [yyyy] [name of copyright owner]
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ http://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,43 @@
1
+ # fluent-plugin-filter-logs
2
+
3
+ [Fluentd](https://fluentd.org/) filter plugin to do something.
4
+
5
+ TODO: write description for you plugin.
6
+
7
+ ## Installation
8
+
9
+ ### RubyGems
10
+
11
+ ```
12
+ $ gem install fluent-plugin-filter-logs
13
+ ```
14
+
15
+ ### Bundler
16
+
17
+ Add following line to your Gemfile:
18
+
19
+ ```ruby
20
+ gem "fluent-plugin-filter-logs"
21
+ ```
22
+
23
+ And then execute:
24
+
25
+ ```
26
+ $ bundle
27
+ ```
28
+
29
+ ## Configuration
30
+
31
+ You can generate configuration template:
32
+
33
+ ```
34
+ $ fluent-plugin-config-format filter filter-logs
35
+ ```
36
+
37
+ You can copy and paste generated documents here.
38
+
39
+ ## Copyright
40
+
41
+ * Copyright(c) 2020- Camille Meulien
42
+ * License
43
+ * Apache License, Version 2.0
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ require "bundler"
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require "rake/testtask"
5
+
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs.push("lib", "test")
8
+ t.test_files = FileList["test/**/test_*.rb"]
9
+ t.verbose = true
10
+ t.warning = true
11
+ end
12
+
13
+ task default: [:test]
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'fluent-plugin-filter-logs'
8
+ spec.version = '1.0.4'
9
+ spec.authors = ['Camille Meulien']
10
+ spec.email = ['cmeulien@heliostech.fr']
11
+
12
+ spec.summary = 'Logs parser filter plugin for fluentd'
13
+ spec.description = 'Parse mixed type of logs (JSON, Rails, fmtlogs, ...)'
14
+ spec.homepage = 'https://github.com/openware/fluent-plugin-filter-logs'
15
+ spec.license = 'Apache-2.0'
16
+
17
+ test_files, files = `git ls-files -z`.split("\x0").partition do |f|
18
+ f.match(%r{^(test|spec|features)/})
19
+ end
20
+ spec.files = files
21
+ spec.executables = files.grep(%r{^bin/}) { |f| File.basename(f) }
22
+ spec.test_files = test_files
23
+ spec.require_paths = ['lib']
24
+ spec.add_runtime_dependency 'logfmt', '~> 0.0.9'
25
+
26
+ spec.add_development_dependency 'byebug'
27
+ spec.add_development_dependency 'bundler'
28
+ spec.add_development_dependency 'rake', '~> 12.0'
29
+ spec.add_development_dependency 'test-unit', '~> 3.0'
30
+ spec.add_runtime_dependency 'fluentd', ['>= 0.14.10', '< 2']
31
+ end
@@ -0,0 +1,146 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright 2020- Camille Meulien
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+
18
+ require 'json'
19
+ require 'date'
20
+ require 'logfmt'
21
+ require 'fluent/plugin/filter'
22
+
23
+ module Fluent
24
+ module Plugin
25
+ class LogsFilter < Filter
26
+ Fluent::Plugin.register_filter('logs', self)
27
+ REGEXPS_LOGS = [
28
+ [/^(?<upstream_ip>\S+) - - \[(?<time>\S+ \+\d{4})\] "(?<message>\S+ \S+ [^"]+)" (?<status_code>\d{3}) (?<content_size>\d+|-) "(?<referer>.*?)" "(?<user_agent>[^"]+)" "(?<user_ip>[^"]+)"$/],
29
+ [/^\[[^\]]+\] (?<upstream_ip>\S+) - [^ ]+ \[(?<time>[^\]]+)\] "(?<message>\S+ \S+ [^"]+)" (?<status_code>\d{3}) (?<content_size>\d+|-) "(?<referer>.*?)" "(?<user_agent>[^"]+)"/],
30
+ [/^(?<time>\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}\S+) \[(?<level>[^\]]+)\] (?<message>.*)/],
31
+ [/^.. \[(?<time>[^\]]+?)( \#\d+)?\] +(?<level>\S+) -- : (?<message>.*)$/],
32
+ [%r{^(?<time>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) UTC (?<message>(?:\S+ ){1,2}#\d+ (?<level>\S+) import (?<peers>\d+)/(?<peers_max>\d+) peers? .*)$},
33
+ lambda do |r|
34
+ ratio = r['peers'].to_f / r['peers_max'].to_f
35
+ l = ratio <= 0.1 ? 'ERROR' : ratio <= 0.2 ? 'WARN' : 'INFO'
36
+ return { 'level' => l }
37
+ end],
38
+ [/^(?<time>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) UTC (?<message>(?:\S+ ){1,2}#\d+ (?<level>\S+) .*)$/],
39
+ [/^ranger_\S+: \d+$/, { 'level' => 'INFO' }]
40
+ ].freeze
41
+
42
+ REGEXPS_DATES = [
43
+ [/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6}/, '%FT%T.%L'],
44
+ [/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}/, '%FT%T.%L%z'],
45
+ [/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/, '%FT%T%z'],
46
+ [/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}/, '%F %T.%L'],
47
+ [/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/, '%F %T'],
48
+ [%r{\d{2}/[a-zA-Z]+/\d{4}:\d{2}:\d{2}:\d{2}}, '%d/%b/%Y:%H:%M:%S %z']
49
+ ].freeze
50
+
51
+ def ow_parse_time(str)
52
+ return nil if str.nil?
53
+
54
+ REGEXPS_DATES.each do |pattern, format|
55
+ if str.match(pattern)
56
+ return DateTime.strptime(str, format).to_time.to_i
57
+ end
58
+ end
59
+ DateTime.strptime(str).to_time.to_i
60
+ rescue ArgumentError => e
61
+ log.warn "#{e}, time str: #{str}"
62
+ end
63
+
64
+ def ow_parse_logs(text)
65
+ if text[0] == '{'
66
+ begin
67
+ return JSON.parse(text)
68
+ rescue JSON::ParserError
69
+ # byebug
70
+ end
71
+ end
72
+
73
+ REGEXPS_LOGS.each do |r, additional|
74
+ m = text.match(r)
75
+ next unless m
76
+
77
+ record = m.named_captures
78
+ if additional
79
+ record.merge!(additional) if additional.is_a?(Hash)
80
+ record.merge!(additional.call(record)) if additional.is_a?(Proc)
81
+ end
82
+ return record
83
+ end
84
+
85
+ if text.match(/^(?:[a-zA-Z0-9]+=(?:\"[^"]*\"|\S*) ?)+/)
86
+ return Logfmt.parse(text)
87
+ end
88
+
89
+ {}
90
+ end
91
+
92
+ RENAME_MAP = [
93
+ %w[msg message],
94
+ %w[lvl level]
95
+ ].freeze
96
+
97
+ FORMATTERS = [
98
+ ['level', lambda do |value|
99
+ return 'WARN' if value.match(/warning/i)
100
+ return 'INFO' if value.match(/note/i)
101
+
102
+ value.upcase
103
+ end]
104
+ ].freeze
105
+
106
+ def ow_post_process(record)
107
+ text = record['log']
108
+ record.delete('log')
109
+
110
+ RENAME_MAP.each do |src, dst|
111
+ if record[src] && record[dst].nil?
112
+ record[dst] = record[src]
113
+ record.delete(src)
114
+ end
115
+ end
116
+
117
+ FORMATTERS.each do |k, formatter|
118
+ record[k] = formatter.call(record[k]) if record[k]
119
+ end
120
+
121
+ record['message'] ||= text
122
+ record
123
+ end
124
+
125
+ def filter(_tag, _time, record)
126
+ log.trace { "filter_logs: (#{record.class}) #{record.inspect}" }
127
+ unless record['log']
128
+ if record['data']
129
+ record['level'] = 'DEBUG'
130
+ record['message'] = JSON.dump(record.delete('data'))
131
+ end
132
+ return record
133
+ end
134
+
135
+ record = record.merge(ow_parse_logs(record['log']))
136
+ record = ow_post_process(record)
137
+
138
+ if record['time']
139
+ record['timestamp'] = ow_parse_time(record['time'])
140
+ record.delete('time')
141
+ end
142
+ record
143
+ end
144
+ end
145
+ end
146
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,8 @@
1
+ $LOAD_PATH.unshift(File.expand_path("../../", __FILE__))
2
+ require "test-unit"
3
+ require "fluent/test"
4
+ require "fluent/test/driver/filter"
5
+ require "fluent/test/helpers"
6
+
7
+ Test::Unit::TestCase.include(Fluent::Test::Helpers)
8
+ Test::Unit::TestCase.extend(Fluent::Test::Helpers)
@@ -0,0 +1,401 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'byebug'
4
+ require 'helper'
5
+ require 'fluent/plugin/filter_logs.rb'
6
+
7
+ class LogsFilterTest < Test::Unit::TestCase
8
+ setup do
9
+ Fluent::Test.setup
10
+ end
11
+
12
+ def create_driver(conf)
13
+ Fluent::Test::Driver::Filter.new(Fluent::Plugin::LogsFilter).configure(conf)
14
+ end
15
+
16
+ def filter(messages, conf = '')
17
+ d = create_driver(conf)
18
+ d.run(default_tag: 'input.access') do
19
+ messages.each do |message|
20
+ d.feed(message)
21
+ end
22
+ end
23
+ d.filtered_records
24
+ end
25
+
26
+ test 'basic unformated message' do
27
+ messages = [
28
+ { 'message' => 'This is test message' }
29
+ ]
30
+ expected = [
31
+ { 'message' => 'This is test message' }
32
+ ]
33
+ assert_equal(expected, filter(messages))
34
+ end
35
+
36
+ test 'basic fmtlog parsing' do
37
+ messages = [
38
+ { 'message' => 'time="2018-01-01 00:00:00" aaa=111 bbb=222' }
39
+ ]
40
+ expected = [
41
+ { 'message' => 'time="2018-01-01 00:00:00" aaa=111 bbb=222' }
42
+ ]
43
+ assert_equal(expected, filter(messages))
44
+ end
45
+
46
+ test 'json fmt logs' do
47
+ text = '{"container_id":"2caa236b7c","container_name":"/traefik-lb_traefik_1","source":"stdout","log":"time=\"2020-03-31T08:46:44Z\" level=debug msg=\"Filtering disabled container\" providerName=docker container=deposit-collection-edge-11facecb13"}'
48
+ messages = [
49
+ JSON.parse(text)
50
+ ]
51
+ expected = [
52
+ {
53
+ 'container_id' => '2caa236b7c',
54
+ 'container_name' => '/traefik-lb_traefik_1',
55
+ 'source' => 'stdout',
56
+ 'level' => 'DEBUG',
57
+ 'message' => 'Filtering disabled container',
58
+ 'providerName' => 'docker',
59
+ 'container' => 'deposit-collection-edge-11facecb13',
60
+ 'timestamp' => 1_585_644_404
61
+ }
62
+ ]
63
+ assert_equal(expected, filter(messages))
64
+ end
65
+
66
+ test 'json apache logs (nginx example)' do
67
+ text = '{"container_name":"/demo_frontend_1","source":"stdout","log":"192.168.80.32 - - [27/Mar/2020:19:26:18 +0000] \"GET /static/media/search.f6cf3254.svg HTTP/1.1\" 200 329 \"https://demo.openware.work/trading/copyright/batusdt\" \"Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-J330FN/J330FNXXS3BSE1) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/11.1 Chrome/75.0.3770.143 Mobile Safari/537.36\" \"123.456.789.0\"","container_id":"1888b6a06ef7"}'
68
+ messages = [
69
+ JSON.parse(text)
70
+ ]
71
+ expected = [
72
+ {
73
+ 'container_id' => '1888b6a06ef7',
74
+ 'container_name' => '/demo_frontend_1',
75
+ 'content_size' => '329',
76
+ 'referer' => 'https://demo.openware.work/trading/copyright/batusdt',
77
+ 'message' => 'GET /static/media/search.f6cf3254.svg HTTP/1.1',
78
+ 'source' => 'stdout',
79
+ 'status_code' => '200',
80
+ 'timestamp' => 1_585_337_178,
81
+ 'upstream_ip' => '192.168.80.32',
82
+ 'user_agent' => 'Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-J330FN/J330FNXXS3BSE1) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/11.1 Chrome/75.0.3770.143 Mobile Safari/537.36',
83
+ 'user_ip' => '123.456.789.0'
84
+ }
85
+ ]
86
+ assert_equal(expected, filter(messages))
87
+ end
88
+
89
+ test 'json apache logs (influx example)' do
90
+ text = '{"source":"stderr","log":"[httpd] 192.168.128.5 - root [31/Mar/2020:08:26:58 +0000] \"GET /query?db=peatio_production&epoch=s&p=%5BREDACTED%5D&precision=s&q=SELECT+%2A+FROM+candles_3d+WHERE+market%3D%27ethusd%27+ORDER+BY+desc+LIMIT+1 HTTP/1.1\" 200 181 \"-\" \"Ruby\" 6371fccd-7329-11ea-aef5-0242c0a8800b 384","container_id":"c0f3b3778","container_name":"/dev01_influxdb_1"}'
91
+ messages = [
92
+ JSON.parse(text)
93
+ ]
94
+ expected = [
95
+ {
96
+ 'container_id' => 'c0f3b3778',
97
+ 'container_name' => '/dev01_influxdb_1',
98
+ 'content_size' => '181',
99
+ 'referer' => '-',
100
+ 'message' => 'GET /query?db=peatio_production&epoch=s&p=%5BREDACTED%5D&precision=s&q=SELECT+%2A+FROM+candles_3d+WHERE+market%3D%27ethusd%27+ORDER+BY+desc+LIMIT+1 HTTP/1.1',
101
+ 'source' => 'stderr',
102
+ 'status_code' => '200',
103
+ 'timestamp' => 1_585_643_218,
104
+ 'upstream_ip' => '192.168.128.5',
105
+ 'user_agent' => 'Ruby'
106
+ }
107
+ ]
108
+ assert_equal(expected, filter(messages))
109
+ end
110
+
111
+ test 'json vault logs (with level)' do
112
+ text = '{"container_name":"/demo_vault_1","source":"stderr","log":"2020-03-30T09:53:21.323Z [WARNING] no `api_addr` value specified in config or in VAULT_API_ADDR; falling back to detection if possible, but this value should be manually set","container_id":"4f82763814e"}'
113
+ messages = [
114
+ JSON.parse(text)
115
+ ]
116
+ expected = [
117
+ {
118
+ 'container_id' => '4f82763814e',
119
+ 'container_name' => '/demo_vault_1',
120
+ 'level' => 'WARN',
121
+ 'message' => ' no `api_addr` value specified in config or in VAULT_API_ADDR; falling back to detection if possible, but this value should be manually set',
122
+ 'source' => 'stderr',
123
+ 'timestamp' => 1_585_562_001
124
+ }
125
+ ]
126
+ assert_equal(expected, filter(messages))
127
+ end
128
+
129
+ test 'json vault logs (unformated)' do
130
+ text = '{"container_name":"/demo_vault_1","source":"stdout","log":"Version: Vault v1.3.0","container_id":"4f82763814e"}'
131
+ messages = [
132
+ JSON.parse(text)
133
+ ]
134
+ expected = [
135
+ {
136
+ 'container_id' => '4f82763814e',
137
+ 'container_name' => '/demo_vault_1',
138
+ 'message' => 'Version: Vault v1.3.0',
139
+ 'source' => 'stdout'
140
+ }
141
+ ]
142
+ assert_equal(expected, filter(messages))
143
+ end
144
+
145
+ test 'json rabbitmq logs' do
146
+ text = '{"source":"stdout","log":"2020-03-30 09:54:51.627 [note] <0.734.0> connection <0.734.0> (192.168.128.5:49388 -> 192.168.128.4:5672): user \'guest\' authenticated and granted access to vhost \'/\'","container_id":"40b5e1bde","container_name":"/dev01_rabbitmq_1"}'
147
+ messages = [
148
+ JSON.parse(text)
149
+ ]
150
+
151
+ expected = [
152
+ {
153
+ 'container_id' => '40b5e1bde',
154
+ 'container_name' => '/dev01_rabbitmq_1',
155
+ 'message' => '<0.734.0> connection <0.734.0> (192.168.128.5:49388 -> 192.168.128.4:5672): user \'guest\' authenticated and granted access to vhost \'/\'',
156
+ 'source' => 'stdout',
157
+ 'level' => 'INFO',
158
+ 'timestamp' => 1_585_562_091
159
+ }
160
+ ]
161
+ assert_equal(expected, filter(messages))
162
+ end
163
+
164
+ test 'json ruby (json error simple)' do
165
+ text = '{"container_id":"7d3ac22","container_name":"/dev01_blockchain_1","source":"stderr","log":"{\"level\":\"ERROR\",\"time\":\"2020-03-31 21:54:05\",\"message\":\"#<Peatio::Blockchain::ClientError: Failed to open TCP connection to parity:8545 (getaddrinfo: Name or service not known)>\"}"}'
166
+ messages = [
167
+ JSON.parse(text)
168
+ ]
169
+
170
+ expected = [
171
+ {
172
+ 'container_id' => '7d3ac22',
173
+ 'container_name' => '/dev01_blockchain_1',
174
+ 'message' => '#<Peatio::Blockchain::ClientError: Failed to open TCP connection to parity:8545 (getaddrinfo: Name or service not known)>',
175
+ 'source' => 'stderr',
176
+ 'level' => 'ERROR',
177
+ 'timestamp' => 1_585_691_645
178
+ }
179
+ ]
180
+ assert_equal(expected, filter(messages))
181
+ end
182
+
183
+ test 'json ruby (json error 2)' do
184
+ text = '{"container_id":"7d3ac22","container_name":"/dev01_blockchain_1","source":"stderr","log":"{\"level\":\"ERROR\",\"time\":\"2020-03-31 21:55:56\",\"message\":\"/home/app/lib/peatio/ethereum/blockchain.rb:60:in `rescue in latest_block_number\'\\\\n/home/app/lib/peatio/ethereum/blockchain.rb:57:in `latest_block_number\'\\\\n/home/app/app/services/blockchain_service.rb:16:in `latest_block_number\'\\\\n/home/app/app/workers/daemons/blockchain.rb:22:in `process\'\\\\n/home/app/app/workers/daemons/blockchain.rb:9:in `block (3 levels) in run\'\"}"}'
185
+ messages = [
186
+ JSON.parse(text)
187
+ ]
188
+
189
+ expected = [
190
+ {
191
+ 'container_id' => '7d3ac22',
192
+ 'container_name' => '/dev01_blockchain_1',
193
+ 'message' =>
194
+ "/home/app/lib/peatio/ethereum/blockchain.rb:60:in `rescue in latest_block_number'\n" \
195
+ "/home/app/lib/peatio/ethereum/blockchain.rb:57:in `latest_block_number'\n" \
196
+ "/home/app/app/services/blockchain_service.rb:16:in `latest_block_number'\n" \
197
+ "/home/app/app/workers/daemons/blockchain.rb:22:in `process'\n" \
198
+ "/home/app/app/workers/daemons/blockchain.rb:9:in `block (3 levels) in run'",
199
+ 'source' => 'stderr',
200
+ 'level' => 'ERROR',
201
+ 'timestamp' => 1_585_691_756
202
+ }
203
+ ]
204
+ assert_equal(expected, filter(messages))
205
+ end
206
+
207
+ test 'json ruby (logger example debug)' do
208
+ text = '{"container_id":"7d3ac22","container_name":"/dev01_blockchain_1","source":"stderr","log":"D, [2020-04-01T13:04:30.445223 #1] DEBUG -- : received websocket message: [156,\\"te\\",[431756335,1585746269293,0.6,131.83]]"}'
209
+ messages = [
210
+ JSON.parse(text)
211
+ ]
212
+
213
+ expected = [
214
+ {
215
+ 'container_id' => '7d3ac22',
216
+ 'container_name' => '/dev01_blockchain_1',
217
+ 'message' => 'received websocket message: [156,"te",[431756335,1585746269293,0.6,131.83]]',
218
+ 'source' => 'stderr',
219
+ 'level' => 'DEBUG',
220
+ 'timestamp' => 1_585_746_270
221
+ }
222
+ ]
223
+ assert_equal(expected, filter(messages))
224
+ end
225
+
226
+ test 'json ruby (logger example info 1)' do
227
+ text = '{"container_id":"7d3ac22","container_name":"/dev01_blockchain_1","source":"stderr","log":"I, [2020-04-01T13:04:30.471779 #1] INFO -- : Publishing trade event: {\\"tid\\"=>431756335, \\"amount\\"=>0.6e0, \\"price\\"=>131.83, \\"date\\"=>1585746269, \\"taker_type\\"=>\\"buy\\"\\}"}'
228
+ messages = [
229
+ JSON.parse(text)
230
+ ]
231
+
232
+ expected = [
233
+ {
234
+ 'container_id' => '7d3ac22',
235
+ 'container_name' => '/dev01_blockchain_1',
236
+ 'message' => 'Publishing trade event: {"tid"=>431756335, "amount"=>0.6e0, "price"=>131.83, "date"=>1585746269, "taker_type"=>"buy"}',
237
+ 'source' => 'stderr',
238
+ 'level' => 'INFO',
239
+ 'timestamp' => 1_585_746_270
240
+ }
241
+ ]
242
+ assert_equal(expected, filter(messages))
243
+ end
244
+
245
+ test 'json ruby (logger example info 2)' do
246
+ text = '{"container_id":"7d3ac22","container_name":"/dev01_blockchain_1","source":"stderr","log":"I, [2020-04-01T18:47:00.480183 #1] INFO -- : [3ce041fb-32f9-462b-950b-34e1ba4904f7] Completed 200 OK in 7ms (Views: 5.6ms | Allocations: 6356)"}'
247
+ messages = [
248
+ JSON.parse(text)
249
+ ]
250
+
251
+ expected = [
252
+ {
253
+ 'container_id' => '7d3ac22',
254
+ 'container_name' => '/dev01_blockchain_1',
255
+ 'message' => '[3ce041fb-32f9-462b-950b-34e1ba4904f7] Completed 200 OK in 7ms (Views: 5.6ms | Allocations: 6356)',
256
+ 'source' => 'stderr',
257
+ 'level' => 'INFO',
258
+ 'timestamp' => 1_585_766_820
259
+ }
260
+ ]
261
+ assert_equal(expected, filter(messages))
262
+ end
263
+
264
+ test 'json parity (block imported)' do
265
+ text = '{"container_id":"7d3ac22","container_name":"/dev01_parity_1","source":"stderr","log":"2020-04-02 08:00:53 UTC Verifier #7 INFO import Imported #17687508 0xf356…d999 (0 txs, 0.00 Mgas, 1 ms, 0.58 KiB) + another 1 block(s) containing 0 tx(s)"}'
266
+ messages = [
267
+ JSON.parse(text)
268
+ ]
269
+
270
+ expected = [
271
+ {
272
+ 'container_id' => '7d3ac22',
273
+ 'container_name' => '/dev01_parity_1',
274
+ 'message' => 'Verifier #7 INFO import Imported #17687508 0xf356…d999 (0 txs, 0.00 Mgas, 1 ms, 0.58 KiB) + another 1 block(s) containing 0 tx(s)',
275
+ 'source' => 'stderr',
276
+ 'level' => 'INFO',
277
+ 'timestamp' => 1_585_814_453
278
+ }
279
+ ]
280
+ assert_equal(expected, filter(messages))
281
+ end
282
+
283
+ test 'json parity (peer report ok)' do
284
+ text = '{"container_id":"7d3ac22","container_name":"/dev01_parity_1","source":"stderr","log":"2020-04-02 08:00:53 UTC IO Worker #0 INFO import 19/50 peers 6 MiB chain 10 MiB db 0 bytes queue 19 KiB sync RPC: 0 conn, 122 req/s, 856 µs"}'
285
+ messages = [
286
+ JSON.parse(text)
287
+ ]
288
+
289
+ expected = [
290
+ {
291
+ 'container_id' => '7d3ac22',
292
+ 'container_name' => '/dev01_parity_1',
293
+ 'message' => 'IO Worker #0 INFO import 19/50 peers 6 MiB chain 10 MiB db 0 bytes queue 19 KiB sync RPC: 0 conn, 122 req/s, 856 µs',
294
+ 'peers' => '19',
295
+ 'peers_max' => '50',
296
+ 'source' => 'stderr',
297
+ 'level' => 'INFO',
298
+ 'timestamp' => 1_585_814_453
299
+ }
300
+ ]
301
+ assert_equal(expected, filter(messages))
302
+ end
303
+
304
+ test 'json parity (peer report warn)' do
305
+ text = '{"container_id":"7d3ac22","container_name":"/dev01_parity_1","source":"stderr","log":"2020-04-02 08:00:53 UTC IO Worker #0 INFO import 10/50 peers 6 MiB chain 10 MiB db 0 bytes queue 19 KiB sync RPC: 0 conn, 122 req/s, 856 µs"}'
306
+ messages = [
307
+ JSON.parse(text)
308
+ ]
309
+
310
+ expected = [
311
+ {
312
+ 'container_id' => '7d3ac22',
313
+ 'container_name' => '/dev01_parity_1',
314
+ 'message' => 'IO Worker #0 INFO import 10/50 peers 6 MiB chain 10 MiB db 0 bytes queue 19 KiB sync RPC: 0 conn, 122 req/s, 856 µs',
315
+ 'peers' => '10',
316
+ 'peers_max' => '50',
317
+ 'source' => 'stderr',
318
+ 'level' => 'WARN',
319
+ 'timestamp' => 1_585_814_453
320
+ }
321
+ ]
322
+ assert_equal(expected, filter(messages))
323
+ end
324
+
325
+ test 'json parity (peer report error)' do
326
+ text = '{"container_id":"7d3ac22","container_name":"/dev01_parity_1","source":"stderr","log":"2020-04-02 08:00:53 UTC IO Worker #0 INFO import 5/50 peers 6 MiB chain 10 MiB db 0 bytes queue 19 KiB sync RPC: 0 conn, 122 req/s, 856 µs"}'
327
+ messages = [
328
+ JSON.parse(text)
329
+ ]
330
+
331
+ expected = [
332
+ {
333
+ 'container_id' => '7d3ac22',
334
+ 'container_name' => '/dev01_parity_1',
335
+ 'message' => 'IO Worker #0 INFO import 5/50 peers 6 MiB chain 10 MiB db 0 bytes queue 19 KiB sync RPC: 0 conn, 122 req/s, 856 µs',
336
+ 'peers' => '5',
337
+ 'peers_max' => '50',
338
+ 'source' => 'stderr',
339
+ 'level' => 'ERROR',
340
+ 'timestamp' => 1_585_814_453
341
+ }
342
+ ]
343
+ assert_equal(expected, filter(messages))
344
+ end
345
+
346
+ test 'json ranger metrics 1' do
347
+ text = '{"container_id":"7d3ac22","container_name":"/dev01_ranger_1","source":"stderr","log":"ranger_connections_total{auth=\\"public\\"}: 44"}'
348
+ messages = [
349
+ JSON.parse(text)
350
+ ]
351
+
352
+ expected = [
353
+ {
354
+ 'container_id' => '7d3ac22',
355
+ 'container_name' => '/dev01_ranger_1',
356
+ 'message' => 'ranger_connections_total{auth="public"}: 44',
357
+ 'source' => 'stderr',
358
+ 'level' => 'INFO'
359
+ }
360
+ ]
361
+ assert_equal(expected, filter(messages))
362
+ end
363
+
364
+ test 'json ranger metrics 2' do
365
+ text = '{"container_id":"7d3ac22","container_name":"/dev01_ranger_1","source":"stderr","log":"ranger_subscriptions_current: 0"}'
366
+ messages = [
367
+ JSON.parse(text)
368
+ ]
369
+
370
+ expected = [
371
+ {
372
+ 'container_id' => '7d3ac22',
373
+ 'container_name' => '/dev01_ranger_1',
374
+ 'message' => 'ranger_subscriptions_current: 0',
375
+ 'source' => 'stderr',
376
+ 'level' => 'INFO'
377
+ }
378
+ ]
379
+ assert_equal(expected, filter(messages))
380
+ end
381
+
382
+ test 'json rails grappe debug logs' do
383
+ text = '{"container_id":"7d3ac22","container_name":"/demo_barong_1","source":"stdout","date":"2020-04-02T14:05:44.550+00:00","severity":"WARN","data":{"status":200,"time":{"total":3.09,"db":0.71,"view":2.38},"method":"DELETE","path":"/api/v2/identity/sessions","params":{},"host":"wiprex.openware.work","response":[200],"ip":"","ua":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36 OPR/67.0.3575.97","headers":{"Version":"HTTP/1.1","Host":"wiprex.openware.work","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36 OPR/67.0.3575.97","Accept":"application/json, text/plain, */*","Accept-Encoding":"gzip, deflate, br","Accept-Language":"en-GB,en-US;q=0.9,en;q=0.8","Cookie":"_ga=GA1.2.234775274.1582223639; _barong_session=1c67047cf6e58f69ec75eed56c66d652","Origin":"https://wiprex.openware.work","Referer":"https://wiprex.openware.work/tower/users/user-directory/IDBA90D58E76/main","Sec-Fetch-Dest":"empty","Sec-Fetch-Mode":"cors","Sec-Fetch-Site":"same-origin","X-Forwarded-For":"","X-Forwarded-Host":"wiprex.openware.work","X-Forwarded-Port":"443","X-Forwarded-Proto":"https","X-Forwarded-Server":"2caa236b7c38","X-Real-Ip":"93.73.59.123","X-Request-Id":"855cfd0a-2796-4bc1-a5a9-2c5e776bcdaa","X-Envoy-Expected-Rq-Timeout-Ms":"15000","X-Envoy-Original-Path":"/api/v2/barong/identity/sessions"}},"message":"{\"date\":\"2020-04-02T14:05:44.550+00:00\",\"severity\":\"WARN\",\"data\":{\"status\":200,\"time\":{\"total\":3.09,\"db\":0.71,\"view\":2.38},\"method\":\"DELETE\",\"path\":\"/api/v2/identity/sessions\",\"params\":{},\"host\":\"wiprex.openware.work\",\"response\":[200],\"ip\":\"\",\"ua\":\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36 OPR/67.0.3575.97\",\"headers\":{\"Version\":\"HTTP/1.1\",\"Host\":\"wiprex.openware.work\",\"User-Agent\":\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36 OPR/67.0.3575.97\",\"Accept\":\"application/json, text/plain, */*\",\"Accept-Encoding\":\"gzip, deflate, br\",\"Accept-Language\":\"en-GB,en-US;q=0.9,en;q=0.8\",\"Cookie\":\"_ga=GA1.2.234775274.1582223639; _barong_session=1c67047cf6e58f69ec75eed56c66d652\",\"Origin\":\"https://wiprex.openware.work\",\"Referer\":\"https://wiprex.openware.work/tower/users/user-directory/IDBA90D58E76/main\",\"Sec-Fetch-Dest\":\"empty\",\"Sec-Fetch-Mode\":\"cors\",\"Sec-Fetch-Site\":\"same-origin\",\"X-Forwarded-For\":\"\",\"X-Forwarded-Host\":\"wiprex.openware.work\",\"X-Forwarded-Port\":\"443\",\"X-Forwarded-Proto\":\"https\",\"X-Forwarded-Server\":\"2caa236b7c38\",\"X-Real-Ip\":\"93.73.59.123\",\"X-Request-Id\":\"855cfd0a-2796-4bc1-a5a9-2c5e776bcdaa\",\"X-Envoy-Expected-Rq-Timeout-Ms\":\"15000\",\"X-Envoy-Original-Path\":\"/api/v2/barong/identity/sessions\"}}}"}'
384
+ messages = [
385
+ JSON.parse(text)
386
+ ]
387
+
388
+ expected = [
389
+ {
390
+ 'container_id' => '7d3ac22',
391
+ 'container_name' => '/demo_barong_1',
392
+ 'date' => '2020-04-02T14:05:44.550+00:00',
393
+ 'level' => 'DEBUG',
394
+ 'message' => '{"status":200,"time":{"total":3.09,"db":0.71,"view":2.38},"method":"DELETE","path":"/api/v2/identity/sessions","params":{},"host":"wiprex.openware.work","response":[200],"ip":"","ua":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36 OPR/67.0.3575.97","headers":{"Version":"HTTP/1.1","Host":"wiprex.openware.work","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36 OPR/67.0.3575.97","Accept":"application/json, text/plain, */*","Accept-Encoding":"gzip, deflate, br","Accept-Language":"en-GB,en-US;q=0.9,en;q=0.8","Cookie":"_ga=GA1.2.234775274.1582223639; _barong_session=1c67047cf6e58f69ec75eed56c66d652","Origin":"https://wiprex.openware.work","Referer":"https://wiprex.openware.work/tower/users/user-directory/IDBA90D58E76/main","Sec-Fetch-Dest":"empty","Sec-Fetch-Mode":"cors","Sec-Fetch-Site":"same-origin","X-Forwarded-For":"","X-Forwarded-Host":"wiprex.openware.work","X-Forwarded-Port":"443","X-Forwarded-Proto":"https","X-Forwarded-Server":"2caa236b7c38","X-Real-Ip":"93.73.59.123","X-Request-Id":"855cfd0a-2796-4bc1-a5a9-2c5e776bcdaa","X-Envoy-Expected-Rq-Timeout-Ms":"15000","X-Envoy-Original-Path":"/api/v2/barong/identity/sessions"}}',
395
+ 'source' => 'stdout',
396
+ 'severity' => 'WARN'
397
+ }
398
+ ]
399
+ assert_equal(expected, filter(messages))
400
+ end
401
+ end
metadata ADDED
@@ -0,0 +1,144 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fluent-plugin-filter-logs
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.4
5
+ platform: ruby
6
+ authors:
7
+ - Camille Meulien
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-04-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: logfmt
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.0.9
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.0.9
27
+ - !ruby/object:Gem::Dependency
28
+ name: byebug
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '12.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '12.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: test-unit
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: fluentd
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: 0.14.10
90
+ - - "<"
91
+ - !ruby/object:Gem::Version
92
+ version: '2'
93
+ type: :runtime
94
+ prerelease: false
95
+ version_requirements: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: 0.14.10
100
+ - - "<"
101
+ - !ruby/object:Gem::Version
102
+ version: '2'
103
+ description: Parse mixed type of logs (JSON, Rails, fmtlogs, ...)
104
+ email:
105
+ - cmeulien@heliostech.fr
106
+ executables: []
107
+ extensions: []
108
+ extra_rdoc_files: []
109
+ files:
110
+ - Gemfile
111
+ - Gemfile.lock
112
+ - LICENSE
113
+ - README.md
114
+ - Rakefile
115
+ - fluent-plugin-filter-logs.gemspec
116
+ - lib/fluent/plugin/filter_logs.rb
117
+ - test/helper.rb
118
+ - test/plugin/test_filter_logs.rb
119
+ homepage: https://github.com/openware/fluent-plugin-filter-logs
120
+ licenses:
121
+ - Apache-2.0
122
+ metadata: {}
123
+ post_install_message:
124
+ rdoc_options: []
125
+ require_paths:
126
+ - lib
127
+ required_ruby_version: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ required_rubygems_version: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ requirements: []
138
+ rubygems_version: 3.0.6
139
+ signing_key:
140
+ specification_version: 4
141
+ summary: Logs parser filter plugin for fluentd
142
+ test_files:
143
+ - test/helper.rb
144
+ - test/plugin/test_filter_logs.rb