fluent-plugin-syslog-gobi-tls 2.1.1

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.
@@ -0,0 +1,139 @@
1
+ # Configuration
2
+
3
+ This plugin allows to configure all syslog message attributes.
4
+
5
+ ## Static configuration
6
+
7
+ Static configuration allow to define connection details, facility and hostname that will
8
+ apply to all messages.
9
+
10
+ ### host
11
+
12
+ Host represents DNS name of endpoint where should be data sent. Example: `syslog.collection.us1.sumologic.com` or `logs1.papertrailapp.com`
13
+
14
+ ### port
15
+
16
+ Example: `6514`
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 signing chain. 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
+
30
+ ### verify_cert_name
31
+
32
+ Whether to verify that the server's cert matches `host`. Enabled by default (except when `ca_cert false`). Recommended; helps prevent MitM attacks. Example: `true`
33
+
34
+ ### token
35
+
36
+ Some services require a token to identify the account. Example: `ABABABABABABA@99999`. Not required for Papertrail.
37
+
38
+ ### client_cert
39
+
40
+ Optionally path to client certificate for TLS connection. Example: `/path/to/crt/file.crt`
41
+
42
+ ### client_key
43
+
44
+ Optionally path to client private key for TLS connection. Example: `/path/to/key/file.key`
45
+
46
+ ### hostname
47
+
48
+ Default hostname that is going to be sent in syslog message. Example: `ip-10-0-0-10`
49
+
50
+ ### facility
51
+
52
+ Default syslog facility for all records. Example: `LOCAL0`
53
+
54
+ ## Per message configuration
55
+
56
+ Its possible to configure the plugin to extract various parts of syslog message header
57
+ from processed record itself. That allows to dynamically set app_name, procid, msgid from
58
+ records if single match is being used to log messages from multiple sources.
59
+
60
+ ### severity_key
61
+
62
+ Optionally record key where to get severity from the record. If not provided default `INFO` will be used.
63
+
64
+ ### facility_key
65
+
66
+ Optionally record key where to get syslog facility from the record. If not provided default `LOCAL0` will be used.
67
+
68
+ ### hostname_key
69
+
70
+ Optionally record key where to get hostname from the record. If not provided hostname is determined by system hostname.
71
+
72
+ ### app_name_key
73
+
74
+ Optionally record key where to get app_name from the record. If not provided nil value will be sent.
75
+
76
+ ### procid_key
77
+
78
+ Optionally record key where to get procid from the record. If not provided nil value will be sent.
79
+
80
+ ### msgid_key
81
+
82
+ Optionally record key where to get msgid from the record. If not provided nil value will be sent.
83
+
84
+ ## Example
85
+
86
+ ```
87
+ <match>
88
+ @type syslog_tls
89
+ host logs1.papertrailapp.com
90
+ port 12345
91
+ idle_timeout 720
92
+
93
+ hostname static-hostname
94
+ facility SYSLOG
95
+
96
+ # You can configure syslog headers to be picked from actual message
97
+ # processed by plugin. If key is not provided '-' value will be sent
98
+ # which is NIL by syslog specification.
99
+ severity_key RECORD_SEVERITY_KEY
100
+ facility_key RECORD_FACILITY_KEY
101
+ hostname_key ...
102
+ app_name_key ...
103
+ procid_key ...
104
+ msgid_key ...
105
+
106
+ # Fluent's standard formatting options are supported. Default is 'json'.
107
+ # Example: For Docker logs sent to Papertrail, send only the log text:
108
+ format single_value
109
+ message_key log
110
+ </match>
111
+ ```
112
+
113
+ ```
114
+ <match>
115
+ @type syslog_tls
116
+ host syslog.collection.us1.sumologic.com
117
+ port 6514
118
+ token [token]@[iana-id]
119
+ client_cert /path/to/cert/file.crt
120
+ client_key /path/to/key/file.key
121
+ verify_cert_name true
122
+
123
+ hostname static-hostname
124
+ facility SYSLOG
125
+
126
+ # You can configure syslog headers to be picked from actual message
127
+ # processed by plugin. If key is not provided '-' value will be sent
128
+ # which is NIL by syslog specification.
129
+ severity_key RECORD_SEVERITY_KEY
130
+ facility_key RECORD_FACILITY_KEY
131
+ hostname_key ...
132
+ app_name_key ...
133
+ procid_key ...
134
+ msgid_key ...
135
+
136
+ # Fluent's standard formatting options are supported. Default is 'json'.
137
+ format json
138
+ </match>
139
+ ```
@@ -0,0 +1,43 @@
1
+ # Copyright 2016 Acquia, Inc.
2
+ # Copyright 2016-2023 t.e.morgan.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ lib = File.expand_path('../lib', __FILE__)
17
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
18
+ require 'syslog_tls/version'
19
+
20
+ Gem::Specification.new do |s|
21
+ s.name = 'fluent-plugin-syslog-gobi-tls'
22
+ s.version = '2.1.1'
23
+ s.summary = %q{Fluent Syslog TLS output plugin}
24
+ s.authors = ['thomas morgan']
25
+ s.email = ['tm@iprog.com']
26
+ s.description = %q{Syslog TLS output plugin with formatting support, for Fluentd}
27
+ s.homepage = 'https://github.com/zarqman/fluent-plugin-syslog-tls'
28
+ s.license = 'Apache v2'
29
+ s.files = `git ls-files`.split($/)
30
+ s.executables = s.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
31
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
32
+ s.require_paths = ['lib']
33
+ s.required_ruby_version = '>= 2.5'
34
+
35
+ s.add_runtime_dependency 'fluentd', [">= 0.14.0", "< 2"]
36
+
37
+ s.add_development_dependency 'minitest', '~> 5.8'
38
+ s.add_development_dependency 'minitest-stub_any_instance', '~> 1.0.0'
39
+ s.add_development_dependency 'rake'
40
+ s.add_development_dependency 'test-unit', '~> 3.1'
41
+ s.add_development_dependency 'webmock', '~> 3.0'
42
+ s.add_development_dependency 'simplecov', '~> 0.11'
43
+ end
@@ -0,0 +1,150 @@
1
+ # Copyright 2016 Acquia, Inc.
2
+ # Copyright 2016-2019 t.e.morgan.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ require 'socket'
17
+ require 'syslog_tls/logger'
18
+ require 'fluent/plugin/output'
19
+
20
+ module Fluent::Plugin
21
+ class SyslogTlsOutput < Output
22
+ Fluent::Plugin.register_output('syslog_tls', self)
23
+
24
+ helpers :inject, :formatter, :compat_parameters
25
+
26
+ DEFAULT_FORMAT_TYPE = 'json'
27
+
28
+ config_param :host, :string
29
+ config_param :port, :integer
30
+ config_param :idle_timeout, :integer, default: nil
31
+ config_param :ca_cert, :string, default: 'system'
32
+ config_param :verify_cert_name, :bool, default: true
33
+ config_param :token, :string, default: nil
34
+ config_param :client_cert, :string, default: nil
35
+ config_param :client_key, :string, default: nil
36
+ config_param :hostname, :string, default: nil
37
+ config_param :facility, :string, default: 'LOCAL0'
38
+
39
+ # Allow to map keys from record to syslog message headers
40
+ SYSLOG_HEADERS = [
41
+ :severity, :facility, :hostname, :app_name, :procid, :msgid
42
+ ]
43
+
44
+ SYSLOG_HEADERS.each do |key_name|
45
+ config_param "#{key_name}_key".to_sym, :string, default: nil
46
+ end
47
+
48
+ config_section :format do
49
+ config_set_default :@type, DEFAULT_FORMAT_TYPE
50
+ end
51
+
52
+ attr_accessor :formatter
53
+
54
+
55
+ def initialize
56
+ super
57
+ @loggers = {}
58
+ end
59
+
60
+ def shutdown
61
+ @loggers.values.each(&:close)
62
+ super
63
+ end
64
+
65
+ # This method is called before starting.
66
+ def configure(conf)
67
+ if conf['output_type'] && !conf['format']
68
+ conf['format'] = conf['output_type']
69
+ end
70
+ compat_parameters_convert(conf, :inject, :formatter)
71
+
72
+ super
73
+ @host = conf['host']
74
+ @port = conf['port']
75
+ @token = conf['token']
76
+ @hostname = conf['hostname'] || Socket.gethostname.split('.').first
77
+
78
+ # Determine mapping of record keys to syslog keys
79
+ @mappings = {}
80
+ SYSLOG_HEADERS.each do |key_name|
81
+ conf_key = "#{key_name}_key"
82
+ @mappings[key_name] = conf[conf_key] if conf.key?(conf_key)
83
+ end
84
+
85
+ @formatter = formatter_create(conf: conf.elements('format').first, default_type: DEFAULT_FORMAT_TYPE)
86
+ end
87
+
88
+ # Get logger for given tag
89
+ def logger(tag)
90
+ # Try to reuse existing logger
91
+ @loggers[tag] ||= new_logger(tag)
92
+
93
+ # Create new logger if old one is closed
94
+ if @loggers[tag].closed?
95
+ @loggers[tag] = new_logger(tag)
96
+ end
97
+
98
+ @loggers[tag]
99
+ end
100
+
101
+ def new_logger(tag)
102
+ transport = ::SyslogTls::SSLTransport.new(host, port,
103
+ idle_timeout: idle_timeout,
104
+ ca_cert: ca_cert,
105
+ client_cert: client_cert,
106
+ client_key: client_key,
107
+ verify_cert_name: verify_cert_name,
108
+ max_retries: 3,
109
+ )
110
+ logger = ::SyslogTls::Logger.new(transport, token)
111
+ logger.facility(facility)
112
+ logger.hostname(hostname)
113
+ logger.app_name(tag)
114
+ logger
115
+ end
116
+
117
+ def format(tag, time, record)
118
+ record = inject_values_to_record(tag, time, record)
119
+ @formatter.format(tag, time, record)
120
+ end
121
+
122
+ def process(tag, es)
123
+ es.each do |time, record|
124
+ record.each_pair do |_, v|
125
+ v.force_encoding('utf-8') if v.is_a?(String)
126
+ end
127
+
128
+ # Check if severity has been provided in record otherwise use INFO
129
+ # by default.
130
+ severity = if @mappings.key?(:severity)
131
+ record[@mappings[:severity]] || 'INFO'
132
+ else
133
+ 'INFO'
134
+ end
135
+
136
+ # Send message to Syslog
137
+ begin
138
+ logger(tag).log(severity, format(tag, time, record), time: Time.at(time)) do |header|
139
+ # Map syslog headers from record
140
+ @mappings.each do |name, record_key|
141
+ header.send("#{name}=", record[record_key]) unless record[record_key].nil?
142
+ end
143
+ end
144
+ rescue => e
145
+ log.error e.to_s
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,46 @@
1
+ # Copyright 2016 Acquia, Inc.
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.
14
+
15
+ require_relative 'lookup_from_const'
16
+
17
+ module SyslogTls
18
+ module Facility
19
+ extend LookupFromConst
20
+ KERN = 0
21
+ USER = 1
22
+ MAIL = 2
23
+ DAEMON = 3
24
+ AUTH = 4
25
+ SYSLOG = 5
26
+ LPR = 6
27
+ NEWS = 7
28
+ UUCP = 8
29
+ CRON = 9
30
+ AUTHPRIV = 10
31
+ FTP = 11
32
+ NTP = 12
33
+ SECURITY = 13
34
+ CONSOLE = 14
35
+ RAS = 15
36
+ LOCAL0 = 16
37
+ LOCAL1 = 17
38
+ LOCAL2 = 18
39
+ LOCAL3 = 19
40
+ LOCAL4 = 20
41
+ LOCAL5 = 21
42
+ LOCAL6 = 22
43
+ LOCAL7 = 23
44
+ NONE = SYSLOG
45
+ end
46
+ end
@@ -0,0 +1,82 @@
1
+ # Copyright 2016 Acquia, Inc.
2
+ # Copyright 2016 t.e.morgan.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ require_relative 'protocol'
17
+ require_relative 'ssl_transport'
18
+
19
+ module SyslogTls
20
+ class Logger
21
+ attr_reader :token
22
+ attr_accessor :transport
23
+
24
+ # Logger accepts transport which should implement IO methods
25
+ # close, closed? and write
26
+ def initialize(transport, token=nil)
27
+ @transport = transport
28
+ @default_header = SyslogTls::Header.new
29
+ @default_structured_data = SyslogTls::StructuredData.new(token)
30
+ end
31
+
32
+ # Sets default facility for each message
33
+ def facility(val)
34
+ @default_header.facility = val
35
+ end
36
+
37
+ # Sets default hostname for each message
38
+ def hostname(val)
39
+ @default_header.hostname = val
40
+ end
41
+
42
+ # Sets default app_name for each message
43
+ def app_name(val)
44
+ @default_header.app_name = val
45
+ end
46
+
47
+ # Sets default procid for message
48
+ def procid(val)
49
+ @default_header.procid = val
50
+ end
51
+
52
+ # Check if IO is closed
53
+ def closed?
54
+ transport && transport.closed?
55
+ end
56
+
57
+ def close
58
+ transport.close
59
+ end
60
+
61
+ # Send log message with severity to syslog
62
+ def log(severity, message, time: nil)
63
+ time ||= Time.now
64
+
65
+ m = SyslogTls::Message.new
66
+
67
+ # Include authentication header
68
+ m.structured_data << @default_structured_data
69
+
70
+ # Adjust header with current timestamp and severity
71
+ m.header = @default_header.dup
72
+ m.header.severity = severity
73
+ m.header.timestamp = time
74
+
75
+ yield m.header if block_given?
76
+
77
+ m.msg = message
78
+
79
+ transport.write(m.to_s)
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,36 @@
1
+ # Copyright 2016 Acquia, Inc.
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.
14
+
15
+ module SyslogTls
16
+ module LookupFromConst
17
+ def setup_constants(dst)
18
+ constants.each do |pri|
19
+ cval = const_get pri
20
+
21
+ dst[pri] = cval
22
+ dst[pri.downcase] = cval
23
+
24
+ dst[:"LOG_#{pri.to_s}"] = cval
25
+ dst[:"LOG_#{pri.downcase.to_s}"] = cval
26
+ const_set :"LOG_#{pri.to_s}", cval
27
+
28
+ dst[pri.to_s] = cval
29
+ dst[pri.downcase.to_s] = cval
30
+
31
+ dst[cval] = cval
32
+ dst[cval.to_s] = cval
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,145 @@
1
+ # Copyright 2016 Acquia, Inc.
2
+ # Copyright 2016 t.e.morgan.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ require 'date'
17
+
18
+ require_relative 'facility'
19
+ require_relative 'severity'
20
+
21
+ # Syslog protocol https://tools.ietf.org/html/rfc5424
22
+ module SyslogTls
23
+ # RFC defined nil value
24
+ NIL_VALUE = '-'
25
+
26
+ # All headers by specification wrapped in single object
27
+ class Header
28
+ attr_accessor :version, :hostname, :app_name, :procid, :msgid
29
+ attr_reader :facility, :severity, :timestamp
30
+
31
+ FACILITIES = {}
32
+ SEVERITIES = {}
33
+
34
+ Facility.setup_constants FACILITIES
35
+ Severity.setup_constants SEVERITIES
36
+
37
+ def initialize
38
+ @timestamp = Time.now
39
+ @severity = 'INFO'
40
+ @facility = 'LOCAL0'
41
+ @version = 1
42
+ @hostname = NIL_VALUE
43
+ @app_name = NIL_VALUE
44
+ @procid = NIL_VALUE
45
+ @msgid = NIL_VALUE
46
+ end
47
+
48
+ def timestamp=(val)
49
+ raise ArgumentError.new("Must provide Time object value instead: #{val.inspect}") unless val.is_a?(Time)
50
+ @timestamp = val
51
+ end
52
+
53
+ def facility=(val)
54
+ raise ArgumentError.new("Invalid facility value: #{val.inspect}") unless FACILITIES.key?(val)
55
+ @facility = val
56
+ end
57
+
58
+ def severity=(val)
59
+ raise ArgumentError.new("Invalid severity value: #{val.inspect}") unless SEVERITIES.key?(val)
60
+ @severity = val
61
+ end
62
+
63
+ # Priority value is calculated by first multiplying the Facility
64
+ # number by 8 and then adding the numerical value of the Severity.
65
+ def pri
66
+ FACILITIES[facility] * 8 + SEVERITIES[severity]
67
+ end
68
+
69
+ def assemble
70
+ [
71
+ "<#{pri}>#{version}",
72
+ timestamp.to_datetime.rfc3339,
73
+ hostname,
74
+ app_name,
75
+ procid,
76
+ msgid
77
+ ].join(' ')
78
+ end
79
+
80
+ def to_s
81
+ assemble
82
+ end
83
+ end
84
+
85
+ # Structured data field
86
+ class StructuredData
87
+ attr_accessor :id, :data
88
+
89
+ def initialize(id)
90
+ @id = id
91
+ @data = {}
92
+ end
93
+
94
+ # Format data structured data to
95
+ # [id k="v" ...]
96
+ def assemble
97
+ return NIL_VALUE unless id
98
+ parts = [id]
99
+ data.each do |k, v|
100
+ # Characters ", ] and \ must be escaped to prevent any parsing errors
101
+ v = v.gsub(/(\"|\]|\\)/) { |match| '\\' + match }
102
+ parts << "#{k}=\"#{v}\""
103
+ end
104
+ "[#{parts.join(' ')}]"
105
+ end
106
+
107
+ def to_s
108
+ assemble
109
+ end
110
+ end
111
+
112
+ # Message represents full message that can be sent to syslog
113
+ class Message
114
+ attr_accessor :structured_data, :msg
115
+ attr_writer :header
116
+
117
+ def initialize
118
+ @msg = ''
119
+ @structured_data = []
120
+ end
121
+
122
+ def header
123
+ @header ||= Header.new
124
+ end
125
+
126
+ def assemble
127
+ # Start with header
128
+ out = [header.to_s]
129
+ # Add all structured data
130
+ if structured_data.length > 0
131
+ out << structured_data.map(&:to_s).join('')
132
+ else
133
+ out << NIL_VALUE
134
+ end
135
+ # Add message
136
+ out << msg if msg.length > 0
137
+ # Message must end with new line delimiter
138
+ out.join(' ') + "\n"
139
+ end
140
+
141
+ def to_s
142
+ assemble
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,30 @@
1
+ # Copyright 2016 Acquia, Inc.
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.
14
+
15
+ require_relative 'lookup_from_const'
16
+
17
+ module SyslogTls
18
+ module Severity
19
+ extend LookupFromConst
20
+ EMERG = PANIC = 0
21
+ ALERT = 1
22
+ CRIT = 2
23
+ ERR = ERROR = 3
24
+ WARN = WARNING = 4
25
+ NOTICE = 5
26
+ INFO = 6
27
+ DEBUG = 7
28
+ NONE = 10
29
+ end
30
+ end