fluent-plugin-unix-client 0.1.0 → 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 +4 -4
- data/README.md +59 -0
- data/fluent-plugin-unix-client.gemspec +1 -1
- data/lib/fluent/plugin/in_unix_client.rb +65 -6
- data/test/plugin/test_in_unix_client.rb +97 -10
- metadata +7 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e730565e1f497509cb2d5e579527d5b500ba3240312fa0bb6527972db7e57ff4
|
4
|
+
data.tar.gz: 9d4a45f7a0c3cbf6b30b00be745dc624ed79d5b7e10f9753c7af2a5728148cca
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3a186a0de2333d95f32162f54b38fcab619b2e113122d0e08c7d10338aa9e3b64eb6c838ef34828772fec956d4c255bfd11be5c84af5aa703a631381bb7800b5
|
7
|
+
data.tar.gz: dfd15243ad040f815bd5c9c5dccb24c72bc57cadcbacc118cad2f4a1f0a597bfcbcc4d801e3294d63af04fbd440555d972165a33a08a88ef07a20a19e0c894a9
|
data/README.md
CHANGED
@@ -48,8 +48,20 @@ The payload is read up to this character.
|
|
48
48
|
|
49
49
|
Default value: `"\n"` (newline).
|
50
50
|
|
51
|
+
### format_json (bool) (optional)
|
52
|
+
|
53
|
+
When recieved JSON data splitted by the delimiter is not completed, like '[{...},', trim '[', ']' and ',' characters to format.
|
54
|
+
|
55
|
+
Please see `Sample` below for details.
|
56
|
+
|
57
|
+
Default value: false.
|
58
|
+
|
51
59
|
## Sample
|
52
60
|
|
61
|
+
### For JSON
|
62
|
+
|
63
|
+
Config:
|
64
|
+
|
53
65
|
```
|
54
66
|
<source>
|
55
67
|
@type unix_client
|
@@ -66,6 +78,53 @@ Default value: `"\n"` (newline).
|
|
66
78
|
</match>
|
67
79
|
```
|
68
80
|
|
81
|
+
Assumed Data:
|
82
|
+
|
83
|
+
* ndjson
|
84
|
+
```
|
85
|
+
{"key":0}\n
|
86
|
+
{"key":0}\n
|
87
|
+
...
|
88
|
+
```
|
89
|
+
|
90
|
+
* JSON list
|
91
|
+
```
|
92
|
+
[{"key":0}, {"key":0}, ...]\n
|
93
|
+
[{"key":0}, {"key":0}, ...]\n
|
94
|
+
...
|
95
|
+
```
|
96
|
+
|
97
|
+
### Use `format_json`
|
98
|
+
|
99
|
+
Config:
|
100
|
+
|
101
|
+
```
|
102
|
+
<source>
|
103
|
+
@type unix_client
|
104
|
+
tag debug.unix_client
|
105
|
+
path /tmp/unix.sock
|
106
|
+
<parse>
|
107
|
+
@type json
|
108
|
+
</parse>
|
109
|
+
delimiter "\n"
|
110
|
+
format_json true
|
111
|
+
</source>
|
112
|
+
|
113
|
+
<match debug.**>
|
114
|
+
@type stdout
|
115
|
+
</match>
|
116
|
+
```
|
117
|
+
|
118
|
+
Assumed Data:
|
119
|
+
|
120
|
+
```
|
121
|
+
[{"key":0},\n
|
122
|
+
{"key":0},\n
|
123
|
+
...
|
124
|
+
{"key":0}]\n
|
125
|
+
...
|
126
|
+
```
|
127
|
+
|
69
128
|
## Specification
|
70
129
|
|
71
130
|
* This recieves data from UNIX domain socket which **is opened by another application**.
|
@@ -15,6 +15,7 @@
|
|
15
15
|
|
16
16
|
require "fluent/plugin/input"
|
17
17
|
require 'socket'
|
18
|
+
require "json"
|
18
19
|
|
19
20
|
module Fluent
|
20
21
|
module Plugin
|
@@ -29,11 +30,19 @@ module Fluent
|
|
29
30
|
config_param :path, :string
|
30
31
|
desc 'The payload is read up to this character.'
|
31
32
|
config_param :delimiter, :string, default: "\n"
|
33
|
+
desc "When recieved JSON data splitted by the delimiter is not completed, like '[{...},'," \
|
34
|
+
" trim '[', ']' and ',' characters to format."
|
35
|
+
config_param :format_json, :bool, default: false
|
32
36
|
|
33
37
|
def configure(conf)
|
34
38
|
super
|
35
39
|
@parser = parser_create
|
36
|
-
@socket_handler = SocketHandler.new(
|
40
|
+
@socket_handler = SocketHandler.new(
|
41
|
+
@path,
|
42
|
+
delimiter: @delimiter,
|
43
|
+
format_json: @format_json,
|
44
|
+
log: log,
|
45
|
+
)
|
37
46
|
end
|
38
47
|
|
39
48
|
def start
|
@@ -60,21 +69,34 @@ module Fluent
|
|
60
69
|
|
61
70
|
raw_records.each do |raw_record|
|
62
71
|
@parser.parse(raw_record) do |time, record|
|
63
|
-
|
72
|
+
emit_one_parsed(time, record)
|
64
73
|
end
|
65
74
|
end
|
66
75
|
end
|
76
|
+
|
77
|
+
def emit_one_parsed(time, record)
|
78
|
+
case record
|
79
|
+
when Array
|
80
|
+
es = Fluent::MultiEventStream.new
|
81
|
+
record.each do |e|
|
82
|
+
es.add(time, e)
|
83
|
+
end
|
84
|
+
router.emit_stream(@tag, es)
|
85
|
+
else
|
86
|
+
router.emit(@tag, time, record)
|
87
|
+
end
|
88
|
+
end
|
67
89
|
end
|
68
90
|
|
69
91
|
|
70
92
|
class SocketHandler
|
71
93
|
MAX_LENGTH_RECEIVE_ONCE = 10000
|
72
94
|
|
73
|
-
def initialize(path, delimiter: "\n", log: nil)
|
95
|
+
def initialize(path, delimiter: "\n", format_json: false, log: nil)
|
74
96
|
@path = path
|
75
97
|
@log = log
|
76
98
|
@socket = nil
|
77
|
-
@buf = Buffer.new(delimiter)
|
99
|
+
@buf = Buffer.new(delimiter, format_json: format_json)
|
78
100
|
end
|
79
101
|
|
80
102
|
def connected?
|
@@ -142,9 +164,10 @@ module Fluent
|
|
142
164
|
|
143
165
|
|
144
166
|
class Buffer
|
145
|
-
def initialize(delimiter)
|
167
|
+
def initialize(delimiter, format_json: false)
|
146
168
|
@buf = ""
|
147
169
|
@delimiter = delimiter
|
170
|
+
@format_json = format_json
|
148
171
|
end
|
149
172
|
|
150
173
|
def add(data)
|
@@ -160,7 +183,8 @@ module Fluent
|
|
160
183
|
|
161
184
|
pos_read = 0
|
162
185
|
while pos_next_delimiter = @buf.index(@delimiter, pos_read)
|
163
|
-
|
186
|
+
fixed = fix_format(@buf[pos_read...pos_next_delimiter])
|
187
|
+
records << fixed unless fixed.empty?
|
164
188
|
pos_read = pos_next_delimiter + @delimiter.size
|
165
189
|
end
|
166
190
|
|
@@ -168,6 +192,41 @@ module Fluent
|
|
168
192
|
|
169
193
|
records
|
170
194
|
end
|
195
|
+
|
196
|
+
private
|
197
|
+
|
198
|
+
def fix_format(record)
|
199
|
+
return record if record.empty?
|
200
|
+
return record unless @format_json
|
201
|
+
|
202
|
+
fix_uncompleted_json(record)
|
203
|
+
end
|
204
|
+
|
205
|
+
def fix_uncompleted_json(record)
|
206
|
+
return record if is_correct_json(record)
|
207
|
+
|
208
|
+
# Assume uncompleted JSON such as "[{...},", "{...},", or "{...}]"
|
209
|
+
|
210
|
+
if record[0] == "["
|
211
|
+
record.slice!(0)
|
212
|
+
return record if record.empty?
|
213
|
+
end
|
214
|
+
|
215
|
+
if record[-1] == "," || record[-1] == "]"
|
216
|
+
record.slice!(-1)
|
217
|
+
return record if record.empty?
|
218
|
+
end
|
219
|
+
|
220
|
+
record
|
221
|
+
end
|
222
|
+
|
223
|
+
def is_correct_json(record)
|
224
|
+
# Just to check the format
|
225
|
+
JSON.parse(record)
|
226
|
+
return true
|
227
|
+
rescue JSON::ParserError
|
228
|
+
return false
|
229
|
+
end
|
171
230
|
end
|
172
231
|
end
|
173
232
|
end
|
@@ -9,12 +9,11 @@ require_relative "./unix_server.rb"
|
|
9
9
|
class UnixClientInputTest < Test::Unit::TestCase
|
10
10
|
def setup
|
11
11
|
Fluent::Test.setup
|
12
|
-
@
|
12
|
+
@server_thread = nil
|
13
13
|
end
|
14
14
|
|
15
15
|
def teardown
|
16
|
-
|
17
|
-
@thread = nil
|
16
|
+
stop_server
|
18
17
|
FileUtils.rm_rf(TMP_DIR)
|
19
18
|
end
|
20
19
|
|
@@ -32,6 +31,14 @@ class UnixClientInputTest < Test::Unit::TestCase
|
|
32
31
|
d = create_driver(config_with_json_parser)
|
33
32
|
assert_equal "unix_client", d.instance.tag
|
34
33
|
assert_equal "#{TMP_DIR}/socket.sock", d.instance.path
|
34
|
+
assert_equal false, d.instance.format_json
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_configure_with_format_json
|
38
|
+
d = create_driver(config_with_json_parser_and_format_json)
|
39
|
+
assert_equal "unix_client", d.instance.tag
|
40
|
+
assert_equal "#{TMP_DIR}/socket.sock", d.instance.path
|
41
|
+
assert_equal true, d.instance.format_json
|
35
42
|
end
|
36
43
|
|
37
44
|
def test_receive_json
|
@@ -100,6 +107,67 @@ class UnixClientInputTest < Test::Unit::TestCase
|
|
100
107
|
end
|
101
108
|
end
|
102
109
|
|
110
|
+
def test_receive_json_list
|
111
|
+
d = create_driver(config_with_json_parser_and_format_json)
|
112
|
+
path = d.instance.path
|
113
|
+
delimiter = "\n"
|
114
|
+
|
115
|
+
msgs = ["hoge", "fuga", "foo"]
|
116
|
+
|
117
|
+
start_server(path)
|
118
|
+
|
119
|
+
d.run(expect_records: 3, timeout: 10) do
|
120
|
+
sleep 1
|
121
|
+
UNIXSocket.open(path) do |sock|
|
122
|
+
sock.write("[")
|
123
|
+
sock.write(JSON.generate(raw_data(msg: msgs[0])))
|
124
|
+
sock.write(",")
|
125
|
+
sock.write(delimiter)
|
126
|
+
|
127
|
+
sock.write(JSON.generate(raw_data(msg: msgs[1])))
|
128
|
+
sock.write(",")
|
129
|
+
sock.write(delimiter)
|
130
|
+
|
131
|
+
sock.write(JSON.generate(raw_data(msg: msgs[2])))
|
132
|
+
sock.write(delimiter)
|
133
|
+
sock.write("]")
|
134
|
+
sock.write(delimiter)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
assert_equal 3, d.events.length
|
139
|
+
|
140
|
+
d.events.each_with_index do |event, i|
|
141
|
+
assert_equal msgs[i], event[2]["msg"]
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def test_receive_json_list_with_one_delimiter
|
146
|
+
d = create_driver(config_with_json_parser_and_format_json)
|
147
|
+
path = d.instance.path
|
148
|
+
delimiter = "\n"
|
149
|
+
|
150
|
+
msgs = ["hoge", "fuga", "foo"]
|
151
|
+
|
152
|
+
start_server(path)
|
153
|
+
|
154
|
+
d.run(expect_records: 3, timeout: 10) do
|
155
|
+
sleep 1
|
156
|
+
data = msgs.map {|msg| raw_data(msg: msg)}
|
157
|
+
|
158
|
+
UNIXSocket.open(path) do |sock|
|
159
|
+
sock.write(JSON.generate(data))
|
160
|
+
sock.write(delimiter)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
assert_equal 3, d.events.length
|
165
|
+
|
166
|
+
d.events.each_with_index do |event, i|
|
167
|
+
assert_equal msgs[i], event[2]["msg"]
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
103
171
|
private
|
104
172
|
|
105
173
|
def create_driver(conf)
|
@@ -124,24 +192,43 @@ class UnixClientInputTest < Test::Unit::TestCase
|
|
124
192
|
!
|
125
193
|
end
|
126
194
|
|
195
|
+
def config_with_json_parser_and_format_json
|
196
|
+
BASE_CONFIG + %!
|
197
|
+
format_json true
|
198
|
+
<parse>
|
199
|
+
@type json
|
200
|
+
</parse>
|
201
|
+
!
|
202
|
+
end
|
203
|
+
|
127
204
|
def start_server(path)
|
128
|
-
@
|
205
|
+
@server_thread = Thread.new do
|
129
206
|
server = UnixBroadcastServer.new(path)
|
130
207
|
server.run
|
131
208
|
end
|
132
209
|
sleep 1
|
133
210
|
end
|
134
211
|
|
212
|
+
def stop_server
|
213
|
+
if @server_thread
|
214
|
+
@server_thread.kill if @server_thread
|
215
|
+
@server_thread.join
|
216
|
+
@server_thread = nil
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
135
220
|
def send_json(path, time: nil, msg: DEFAULT_MSG, delimiter: "\n")
|
136
|
-
msg = JSON.generate(
|
137
|
-
{
|
138
|
-
"time" => time.nil? ? Time.now.to_i : time,
|
139
|
-
"msg" => msg
|
140
|
-
}
|
141
|
-
)
|
221
|
+
msg = JSON.generate(raw_data(time: time, msg: msg))
|
142
222
|
UNIXSocket.open(path) do |sock|
|
143
223
|
sock.write(msg)
|
144
224
|
sock.write(delimiter)
|
145
225
|
end
|
146
226
|
end
|
227
|
+
|
228
|
+
def raw_data(time: nil, msg: DEFAULT_MSG)
|
229
|
+
{
|
230
|
+
"time" => time.nil? ? Time.now.to_i : time,
|
231
|
+
"msg" => msg
|
232
|
+
}
|
233
|
+
end
|
147
234
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluent-plugin-unix-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- daipom
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-08-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -72,7 +72,7 @@ dependencies:
|
|
72
72
|
- - "<"
|
73
73
|
- !ruby/object:Gem::Version
|
74
74
|
version: '2'
|
75
|
-
description:
|
75
|
+
description:
|
76
76
|
email:
|
77
77
|
- reangoapyththeorem@gmail.com
|
78
78
|
executables: []
|
@@ -93,7 +93,7 @@ homepage: https://github.com/daipom/fluent-plugin-unix-client
|
|
93
93
|
licenses:
|
94
94
|
- Apache-2.0
|
95
95
|
metadata: {}
|
96
|
-
post_install_message:
|
96
|
+
post_install_message:
|
97
97
|
rdoc_options: []
|
98
98
|
require_paths:
|
99
99
|
- lib
|
@@ -108,8 +108,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
108
108
|
- !ruby/object:Gem::Version
|
109
109
|
version: '0'
|
110
110
|
requirements: []
|
111
|
-
rubygems_version: 3.
|
112
|
-
signing_key:
|
111
|
+
rubygems_version: 3.1.6
|
112
|
+
signing_key:
|
113
113
|
specification_version: 4
|
114
114
|
summary: Fluentd Input plugin to receive data from UNIX domain socket. This is a client
|
115
115
|
version of the default `unix` input plugin.
|