fluent-plugin-syslog-tls 1.0.0 → 1.1.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/CHANGELOG.md +17 -0
- data/README.md +3 -5
- data/docs/configuration.md +18 -5
- data/fluent-plugin-syslog-tls.gemspec +2 -2
- data/lib/fluent/plugin/out_syslog_tls.rb +9 -7
- data/lib/syslog_tls/ssl_transport.rb +121 -11
- data/lib/syslog_tls/version.rb +1 -1
- data/test/fluent/test_out_syslog_tls.rb +15 -15
- data/test/syslog_tls/test_ssl_transport.rb +2 -2
- metadata +7 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3d451a9db525bf51ce92a8fb6ba314e07ef4fde7
|
4
|
+
data.tar.gz: 578fa7e673a40b1a469bb7eb70681f0cfe102878
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e8f97eb7e0028c5a41735c8c474128b0ec6181aaac527e5772c984a22ee9ba4e5e424cd1aceae806bebe5f42b4768e3647d8d3d07a44e4c0db14b630e7660a55
|
7
|
+
data.tar.gz: d8121c0078122038002ccb99c7888a125656e3728d2a75588408ccbd55e23563d5d5ce1ac6a7945ee68c8933c78549e401af02e2b76d7791360d0bd263123ee9
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#### 1.1.0
|
2
|
+
|
3
|
+
* Renamed `cert` and `key` to `client_cert` and `client_key` respectively.
|
4
|
+
* Change to short timeouts on network calls so logging doesn't go dead for extended periods.
|
5
|
+
* Added `idle_timeout` to force upstream reconnection after a period of time with no traffic for a particular tag. Useful for low-traffic senders. Not recommended for high-traffic.
|
6
|
+
* Added `ca_cert` to validate the remote certificate. Defaults to 'system' which uses the system certificate store.
|
7
|
+
|
8
|
+
|
9
|
+
#### 1.0.0
|
10
|
+
|
11
|
+
* Standard fluent formatting plugins are supported. Json output remains the default.
|
12
|
+
* `token` (Structured Data in syslog terms) is now optional, for syslog hosts that don't require it.
|
13
|
+
* Message payload in the syslog packet no longer duplicates Time or includes Tag by default.
|
14
|
+
|
15
|
+
|
16
|
+
#### < 1.0.0
|
17
|
+
From [Fluent::Plugin::SumologicCloudSyslog](https://github.com/acquia/fluent-plugin-sumologic-cloud-syslog)
|
data/README.md
CHANGED
@@ -17,6 +17,8 @@ or
|
|
17
17
|
$ td-agent-gem install fluent-plugin-syslog-tls
|
18
18
|
```
|
19
19
|
|
20
|
+
Note: `fluent-plugin-syslog-tls` is compatible with Fluent 0.14.
|
21
|
+
|
20
22
|
|
21
23
|
## Configuration
|
22
24
|
---
|
@@ -48,11 +50,7 @@ For more configuration options see [configuration docs](docs/configuration.md)
|
|
48
50
|
|
49
51
|
## Origin/History
|
50
52
|
|
51
|
-
This plugin is derived from [Fluent::Plugin::SumologicCloudSyslog](https://github.com/acquia/fluent-plugin-sumologic-cloud-syslog). Changes
|
52
|
-
|
53
|
-
* Standard fluent formatting plugins are supported. Json output remains the default.
|
54
|
-
* `token` (Structured Data in syslog terms) is now optional, for syslog hosts that don't require it.
|
55
|
-
* Message payload in the syslog packet no longer duplicates Time or includes Tag by default.
|
53
|
+
This plugin is derived from [Fluent::Plugin::SumologicCloudSyslog](https://github.com/acquia/fluent-plugin-sumologic-cloud-syslog). Changes are in the [Changelog](CHANGELOG.md).
|
56
54
|
|
57
55
|
|
58
56
|
## License
|
data/docs/configuration.md
CHANGED
@@ -15,15 +15,27 @@ Host represents DNS name of endpoint where should be data sent. Example: `syslog
|
|
15
15
|
|
16
16
|
Example: `6514`
|
17
17
|
|
18
|
+
### idle_timeout
|
19
|
+
|
20
|
+
If a given tag has gone this many seconds between log messages, disconnect and reconnect before sending logs. Useful in low-traffic logging situations with remote hosts that disconnect after a period of time. Disabled by default. Example: `600`
|
21
|
+
|
22
|
+
### ca_cert
|
23
|
+
|
24
|
+
Whether and how to verify the server's TLS certificate. Examples:
|
25
|
+
* ca_cert system - Default; use the system CA certificate store (which must then be configured correctly)
|
26
|
+
* ca_cert false - Disable verification; not recommended
|
27
|
+
* ca_cert /path/to/file - A path+filename to a single CA file
|
28
|
+
* ca_cert /path/to/dir/ - A directory of CA files (in format that OpenSSL can parse); must end with /
|
29
|
+
|
18
30
|
### token
|
19
31
|
|
20
32
|
Some services require a token to identify the account. Example: `ABABABABABABA@99999`. Not required for Papertrail.
|
21
33
|
|
22
|
-
###
|
34
|
+
### client_cert
|
23
35
|
|
24
36
|
Optionally path to client certificate for TLS connection. Example: `/path/to/crt/file.crt`
|
25
37
|
|
26
|
-
###
|
38
|
+
### client_key
|
27
39
|
|
28
40
|
Optionally path to client private key for TLS connection. Example: `/path/to/key/file.key`
|
29
41
|
|
@@ -72,6 +84,7 @@ Optionally record key where to get msgid from the record. If not provided nil va
|
|
72
84
|
@type syslog_tls
|
73
85
|
host logs1.papertrailapp.com
|
74
86
|
port 12345
|
87
|
+
idle_timeout 720
|
75
88
|
|
76
89
|
hostname static-hostname
|
77
90
|
facility SYSLOG
|
@@ -87,7 +100,7 @@ Optionally record key where to get msgid from the record. If not provided nil va
|
|
87
100
|
msgid_key ...
|
88
101
|
|
89
102
|
# Fluent's standard formatting options are supported. Default is 'json'.
|
90
|
-
# Example: For Docker logs sent to Papertrail,
|
103
|
+
# Example: For Docker logs sent to Papertrail, send only the log text:
|
91
104
|
format single_value
|
92
105
|
message_key log
|
93
106
|
</match>
|
@@ -99,8 +112,8 @@ Optionally record key where to get msgid from the record. If not provided nil va
|
|
99
112
|
host syslog.collection.us1.sumologic.com
|
100
113
|
port 6514
|
101
114
|
token [token]@[iana-id]
|
102
|
-
|
103
|
-
|
115
|
+
client_cert /path/to/cert/file.crt
|
116
|
+
client_key /path/to/key/file.key
|
104
117
|
|
105
118
|
hostname static-hostname
|
106
119
|
facility SYSLOG
|
@@ -30,9 +30,9 @@ Gem::Specification.new do |s|
|
|
30
30
|
s.executables = s.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
31
31
|
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
32
32
|
s.require_paths = ['lib']
|
33
|
-
s.required_ruby_version = '>= 2.
|
33
|
+
s.required_ruby_version = '>= 2.3.0'
|
34
34
|
|
35
|
-
s.add_runtime_dependency 'fluentd', '~> 0.
|
35
|
+
s.add_runtime_dependency 'fluentd', '~> 0.14.0'
|
36
36
|
s.add_runtime_dependency 'fluent-mixin-config-placeholders', '~> 0.3'
|
37
37
|
|
38
38
|
s.add_development_dependency 'minitest', '~> 5.8'
|
@@ -29,11 +29,13 @@ module Fluent
|
|
29
29
|
|
30
30
|
config_param :host, :string
|
31
31
|
config_param :port, :integer
|
32
|
-
config_param :
|
33
|
-
config_param :
|
34
|
-
config_param :
|
35
|
-
config_param :
|
36
|
-
config_param :
|
32
|
+
config_param :idle_timeout, :integer, default: nil
|
33
|
+
config_param :ca_cert, :string, default: 'system'
|
34
|
+
config_param :token, :string, default: nil
|
35
|
+
config_param :client_cert, :string, default: nil
|
36
|
+
config_param :client_key, :string, default: nil
|
37
|
+
config_param :hostname, :string, default: nil
|
38
|
+
config_param :facility, :string, default: 'LOCAL0'
|
37
39
|
|
38
40
|
# Allow to map keys from record to syslog message headers
|
39
41
|
SYSLOG_HEADERS = [
|
@@ -41,7 +43,7 @@ module Fluent
|
|
41
43
|
]
|
42
44
|
|
43
45
|
SYSLOG_HEADERS.each do |key_name|
|
44
|
-
config_param "#{key_name}_key".to_sym, :string, :
|
46
|
+
config_param "#{key_name}_key".to_sym, :string, default: nil
|
45
47
|
end
|
46
48
|
|
47
49
|
config_section :format do
|
@@ -99,7 +101,7 @@ module Fluent
|
|
99
101
|
end
|
100
102
|
|
101
103
|
def new_logger(tag)
|
102
|
-
transport = ::SyslogTls::SSLTransport.new(host, port,
|
104
|
+
transport = ::SyslogTls::SSLTransport.new(host, port, idle_timeout: idle_timeout, ca_cert: ca_cert, client_cert: client_cert, client_key: client_key, max_retries: 3)
|
103
105
|
logger = ::SyslogTls::Logger.new(transport, token)
|
104
106
|
logger.facility(facility)
|
105
107
|
logger.hostname(hostname)
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# Copyright 2016 Acquia, Inc.
|
2
|
+
# Copyright 2016 t.e.morgan.
|
2
3
|
#
|
3
4
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
5
|
# you may not use this file except in compliance with the License.
|
@@ -18,17 +19,23 @@ require 'openssl'
|
|
18
19
|
module SyslogTls
|
19
20
|
# Supports SSL connection to remote host
|
20
21
|
class SSLTransport
|
22
|
+
CONNECT_TIMEOUT = 10
|
23
|
+
# READ_TIMEOUT = 5
|
24
|
+
WRITE_TIMEOUT = 5
|
25
|
+
|
21
26
|
attr_accessor :socket
|
22
27
|
|
23
|
-
attr_reader :host, :port, :
|
28
|
+
attr_reader :host, :port, :idle_timeout, :ca_cert, :client_cert, :client_key, :ssl_version
|
24
29
|
|
25
30
|
attr_writer :retries
|
26
31
|
|
27
|
-
def initialize(host, port,
|
32
|
+
def initialize(host, port, idle_timeout: nil, ca_cert: 'system', client_cert: nil, client_key: nil, ssl_version: :TLSv1_2, max_retries: 1)
|
28
33
|
@host = host
|
29
34
|
@port = port
|
30
|
-
@
|
31
|
-
@
|
35
|
+
@idle_timeout = idle_timeout
|
36
|
+
@ca_cert = ca_cert
|
37
|
+
@client_cert = client_cert
|
38
|
+
@client_key = client_key
|
32
39
|
@ssl_version = ssl_version
|
33
40
|
@retries = max_retries
|
34
41
|
connect
|
@@ -36,28 +43,96 @@ module SyslogTls
|
|
36
43
|
|
37
44
|
def connect
|
38
45
|
@socket = get_ssl_connection
|
39
|
-
|
46
|
+
begin
|
47
|
+
begin
|
48
|
+
@socket.connect_nonblock
|
49
|
+
rescue Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitReadable
|
50
|
+
select_with_timeout(@socket, :connect_read) && retry
|
51
|
+
rescue IO::WaitWritable
|
52
|
+
select_with_timeout(@socket, :connect_write) && retry
|
53
|
+
end
|
54
|
+
rescue Errno::ETIMEDOUT
|
55
|
+
raise 'Socket timeout during connect'
|
56
|
+
end
|
57
|
+
@last_write = Time.now if idle_timeout
|
58
|
+
end
|
59
|
+
|
60
|
+
def get_tcp_connection
|
61
|
+
tcp = nil
|
62
|
+
|
63
|
+
family = Socket::Constants::AF_UNSPEC
|
64
|
+
sock_type = Socket::Constants::SOCK_STREAM
|
65
|
+
addr_info = Socket.getaddrinfo(host, port, family, sock_type, nil, nil, false).first
|
66
|
+
_, port, _, address, family, sock_type = addr_info
|
67
|
+
|
68
|
+
begin
|
69
|
+
sock_addr = Socket.sockaddr_in(port, address)
|
70
|
+
tcp = Socket.new(family, sock_type, 0)
|
71
|
+
tcp.setsockopt(Socket::SOL_SOCKET, Socket::Constants::SO_REUSEADDR, true)
|
72
|
+
tcp.setsockopt(Socket::SOL_SOCKET, Socket::Constants::SO_REUSEPORT, true)
|
73
|
+
tcp.connect_nonblock(sock_addr)
|
74
|
+
rescue Errno::EINPROGRESS
|
75
|
+
select_with_timeout(tcp, :connect_write)
|
76
|
+
begin
|
77
|
+
tcp.connect_nonblock(sock_addr)
|
78
|
+
rescue Errno::EISCONN
|
79
|
+
# all good
|
80
|
+
rescue SystemCallError
|
81
|
+
tcp.close rescue nil
|
82
|
+
raise
|
83
|
+
end
|
84
|
+
rescue SystemCallError
|
85
|
+
tcp.close rescue nil
|
86
|
+
raise
|
87
|
+
end
|
88
|
+
|
89
|
+
tcp.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, true)
|
90
|
+
tcp
|
40
91
|
end
|
41
92
|
|
42
93
|
def get_ssl_connection
|
43
|
-
tcp =
|
94
|
+
tcp = get_tcp_connection
|
44
95
|
|
45
96
|
ctx = OpenSSL::SSL::SSLContext.new
|
46
|
-
ctx.
|
97
|
+
ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
47
98
|
ctx.ssl_version = ssl_version
|
48
99
|
|
49
|
-
|
50
|
-
|
51
|
-
|
100
|
+
case ca_cert
|
101
|
+
when true, 'true', 'system'
|
102
|
+
# use system certs, same as openssl cli
|
103
|
+
ctx.cert_store = OpenSSL::X509::Store.new
|
104
|
+
ctx.cert_store.set_default_paths
|
105
|
+
when false, 'false'
|
106
|
+
ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
107
|
+
when %r{/$} # ends in /
|
108
|
+
ctx.ca_path = ca_cert
|
109
|
+
when String
|
110
|
+
ctx.ca_file = ca_cert
|
111
|
+
end
|
112
|
+
|
113
|
+
ctx.cert = OpenSSL::X509::Certificate.new(File.read(client_cert)) if client_cert
|
114
|
+
ctx.key = OpenSSL::PKey::read(File.read(client_key)) if client_key
|
115
|
+
socket = OpenSSL::SSL::SSLSocket.new(tcp, ctx)
|
116
|
+
socket.sync_close = true
|
117
|
+
socket
|
52
118
|
end
|
53
119
|
|
54
120
|
# Allow to retry on failed writes
|
55
121
|
def write(s)
|
122
|
+
if idle_timeout
|
123
|
+
if (t=Time.now) > @last_write + idle_timeout
|
124
|
+
@socket.close rescue nil
|
125
|
+
connect
|
126
|
+
else
|
127
|
+
@last_write = t
|
128
|
+
end
|
129
|
+
end
|
56
130
|
begin
|
57
131
|
retry_id ||= 0
|
58
|
-
|
132
|
+
do_write(s)
|
59
133
|
rescue => e
|
60
134
|
if (retry_id += 1) < @retries
|
135
|
+
@socket.close rescue nil
|
61
136
|
connect
|
62
137
|
retry
|
63
138
|
else
|
@@ -66,6 +141,41 @@ module SyslogTls
|
|
66
141
|
end
|
67
142
|
end
|
68
143
|
|
144
|
+
def do_write(data)
|
145
|
+
data.force_encoding('BINARY') # so we can break in the middle of multi-byte characters
|
146
|
+
loop do
|
147
|
+
sent = 0
|
148
|
+
begin
|
149
|
+
sent = @socket.write_nonblock(data)
|
150
|
+
rescue OpenSSL::SSL::SSLError, Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitWritable => e
|
151
|
+
if e.is_a?(OpenSSL::SSL::SSLError) && e.message !~ /write would block/
|
152
|
+
raise e
|
153
|
+
else
|
154
|
+
select_with_timeout(@socket, :write) && retry
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
break if sent >= data.size
|
159
|
+
data = data[sent, data.size]
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def select_with_timeout(tcp, type)
|
164
|
+
o = case type
|
165
|
+
when :connect_read
|
166
|
+
args = [[tcp], nil, nil, CONNECT_TIMEOUT]
|
167
|
+
when :connect_write
|
168
|
+
args = [nil, [tcp], nil, CONNECT_TIMEOUT]
|
169
|
+
# when :read
|
170
|
+
# args = [[tcp], nil, nil, READ_TIMEOUT]
|
171
|
+
when :write
|
172
|
+
args = [nil, [tcp], nil, WRITE_TIMEOUT]
|
173
|
+
else
|
174
|
+
raise "Unknown select type #{type}"
|
175
|
+
end
|
176
|
+
IO.select(*args) || raise("Socket timeout during #{type}")
|
177
|
+
end
|
178
|
+
|
69
179
|
# Forward any methods directly to SSLSocket
|
70
180
|
def method_missing(method_sym, *arguments, &block)
|
71
181
|
@socket.send(method_sym, *arguments, &block)
|
data/lib/syslog_tls/version.rb
CHANGED
@@ -52,16 +52,16 @@ class SyslogTlsOutputTest < Test::Unit::TestCase
|
|
52
52
|
config = %{
|
53
53
|
host syslog.collection.us1.sumologic.com
|
54
54
|
port 6514
|
55
|
-
|
56
|
-
|
55
|
+
client_cert
|
56
|
+
client_key
|
57
57
|
token 1234567890
|
58
58
|
}
|
59
59
|
instance = driver('test', config).instance
|
60
60
|
|
61
61
|
assert_equal 'syslog.collection.us1.sumologic.com', instance.host
|
62
62
|
assert_equal '6514', instance.port
|
63
|
-
assert_equal '', instance.
|
64
|
-
assert_equal '', instance.
|
63
|
+
assert_equal '', instance.client_cert
|
64
|
+
assert_equal '', instance.client_key
|
65
65
|
assert_equal '1234567890', instance.token
|
66
66
|
end
|
67
67
|
|
@@ -69,8 +69,8 @@ class SyslogTlsOutputTest < Test::Unit::TestCase
|
|
69
69
|
config = %{
|
70
70
|
host syslog.collection.us1.sumologic.com
|
71
71
|
port 6514
|
72
|
-
|
73
|
-
|
72
|
+
client_cert
|
73
|
+
client_key
|
74
74
|
}
|
75
75
|
instance = driver('test', config).instance
|
76
76
|
|
@@ -91,8 +91,8 @@ class SyslogTlsOutputTest < Test::Unit::TestCase
|
|
91
91
|
config = %{
|
92
92
|
host syslog.collection.us1.sumologic.com
|
93
93
|
port 6514
|
94
|
-
|
95
|
-
|
94
|
+
client_cert
|
95
|
+
client_key
|
96
96
|
token 1234567890
|
97
97
|
hostname_key hostname
|
98
98
|
procid_key procid
|
@@ -118,8 +118,8 @@ class SyslogTlsOutputTest < Test::Unit::TestCase
|
|
118
118
|
config = %{
|
119
119
|
host syslog.collection.us1.sumologic.com
|
120
120
|
port 6514
|
121
|
-
|
122
|
-
|
121
|
+
client_cert
|
122
|
+
client_key
|
123
123
|
token 1234567890
|
124
124
|
severity_key severity
|
125
125
|
}
|
@@ -142,11 +142,11 @@ class SyslogTlsOutputTest < Test::Unit::TestCase
|
|
142
142
|
config = %{
|
143
143
|
host syslog.collection.us1.sumologic.com
|
144
144
|
port 6514
|
145
|
-
|
146
|
-
|
145
|
+
client_cert
|
146
|
+
client_key
|
147
147
|
token 1234567890
|
148
148
|
format out_file
|
149
|
-
|
149
|
+
localtime false
|
150
150
|
}
|
151
151
|
instance = driver('test', config).instance
|
152
152
|
|
@@ -178,8 +178,8 @@ class SyslogTlsOutputTest < Test::Unit::TestCase
|
|
178
178
|
config = %{
|
179
179
|
host localhost
|
180
180
|
port #{server.addr[1]}
|
181
|
-
|
182
|
-
|
181
|
+
client_cert
|
182
|
+
client_key
|
183
183
|
token 1234567890
|
184
184
|
hostname_key hostname
|
185
185
|
procid_key procid
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluent-plugin-syslog-tls
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- thomas morgan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-11-
|
11
|
+
date: 2016-11-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fluentd
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 0.14.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 0.14.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: fluent-mixin-config-placeholders
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -132,6 +132,7 @@ files:
|
|
132
132
|
- ".coveralls.yml"
|
133
133
|
- ".gitignore"
|
134
134
|
- ".travis.yml"
|
135
|
+
- CHANGELOG.md
|
135
136
|
- Gemfile
|
136
137
|
- LICENSE
|
137
138
|
- README.md
|
@@ -164,7 +165,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
164
165
|
requirements:
|
165
166
|
- - ">="
|
166
167
|
- !ruby/object:Gem::Version
|
167
|
-
version: 2.
|
168
|
+
version: 2.3.0
|
168
169
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
169
170
|
requirements:
|
170
171
|
- - ">="
|
@@ -172,7 +173,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
172
173
|
version: '0'
|
173
174
|
requirements: []
|
174
175
|
rubyforge_project:
|
175
|
-
rubygems_version: 2.5.
|
176
|
+
rubygems_version: 2.5.2
|
176
177
|
signing_key:
|
177
178
|
specification_version: 4
|
178
179
|
summary: Fluent Syslog TLS output plugin
|