fluent-plugin-syslog-tls 0.5.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.
@@ -0,0 +1,121 @@
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
+ ### token
19
+
20
+ Some services require a token to identify the account. Example: `ABABABABABABA@99999`. Not required for Papertrail.
21
+
22
+ ### cert
23
+
24
+ Optionally path to client certificate for TLS connection. Example: `/path/to/crt/file.crt`
25
+
26
+ ### key
27
+
28
+ Optionally path to client private key for TLS connection. Example: `/path/to/key/file.key`
29
+
30
+ ### hostname
31
+
32
+ Default hostname that is going to be sent in syslog message. Example: `ip-10-0-0-10`
33
+
34
+ ### facility
35
+
36
+ Default syslog facility for all records. Example: `LOCAL0`
37
+
38
+ ## Per message configuration
39
+
40
+ Its possible to configure the plugin to extract various parts of syslog message header
41
+ from processed record itself. That allows to dynamically set app_name, procid, msgid from
42
+ records if single match is being used to log messages from multiple sources.
43
+
44
+ ### severity_key
45
+
46
+ Optionally record key where to get severity from the record. If not provided default `INFO` will be used.
47
+
48
+ ### facility_key
49
+
50
+ Optionally record key where to get syslog facility from the record. If not provided default `LOCAL0` will be used.
51
+
52
+ ### hostname_key
53
+
54
+ Optionally record key where to get hostname from the record. If not provided hostname is determined by system hostname.
55
+
56
+ ### app_name_key
57
+
58
+ Optionally record key where to get app_name from the record. If not provided nil value will be sent.
59
+
60
+ ### procid_key
61
+
62
+ Optionally record key where to get procid from the record. If not provided nil value will be sent.
63
+
64
+ ### msgid_key
65
+
66
+ Optionally record key where to get msgid from the record. If not provided nil value will be sent.
67
+
68
+ ## Example
69
+
70
+ ```
71
+ <match>
72
+ @type syslog_tls
73
+ host logs1.papertrailapp.com
74
+ port 12345
75
+
76
+ hostname static-hostname
77
+ facility SYSLOG
78
+
79
+ # You can configure syslog headers to be picked from actual message
80
+ # processed by plugin. If key is not provided '-' value will be sent
81
+ # which is NIL by syslog specification.
82
+ severity_key RECORD_SEVERITY_KEY
83
+ facility_key RECORD_FACILITY_KEY
84
+ hostname_key ...
85
+ app_name_key ...
86
+ procid_key ...
87
+ msgid_key ...
88
+
89
+ # Fluent's standard formatting options are supported. Default is 'json'.
90
+ # Example: For Docker logs sent to Papertrail, sending only the log text:
91
+ format single_value
92
+ message_key log
93
+ </match>
94
+ ```
95
+
96
+ ```
97
+ <match>
98
+ @type syslog_tls
99
+ host syslog.collection.us1.sumologic.com
100
+ port 6514
101
+ token [token]@[iana-id]
102
+ cert /path/to/cert/file.crt
103
+ key /path/to/key/file.key
104
+
105
+ hostname static-hostname
106
+ facility SYSLOG
107
+
108
+ # You can configure syslog headers to be picked from actual message
109
+ # processed by plugin. If key is not provided '-' value will be sent
110
+ # which is NIL by syslog specification.
111
+ severity_key RECORD_SEVERITY_KEY
112
+ facility_key RECORD_FACILITY_KEY
113
+ hostname_key ...
114
+ app_name_key ...
115
+ procid_key ...
116
+ msgid_key ...
117
+
118
+ # Fluent's standard formatting options are supported. Default is 'json'.
119
+ format json
120
+ </match>
121
+ ```
@@ -0,0 +1,44 @@
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
+ 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-tls'
22
+ s.version = SyslogTls::VERSION
23
+ s.authors = ['thomas morgan']
24
+ s.email = ['tm@iprog.com']
25
+ s.summary = %q{Fluent Syslog TLS output plugin}
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.0.0'
34
+
35
+ s.add_runtime_dependency 'fluentd', '~> 0.12.0'
36
+ s.add_runtime_dependency 'fluent-mixin-config-placeholders', '~> 0.3'
37
+
38
+ s.add_development_dependency 'minitest', '~> 5.8'
39
+ s.add_development_dependency 'minitest-stub_any_instance', '~> 1.0.0'
40
+ s.add_development_dependency 'rake', '~> 10.5'
41
+ s.add_development_dependency 'test-unit', '~> 3.1'
42
+ s.add_development_dependency 'webmock', '~> 2.0'
43
+ s.add_development_dependency 'simplecov', '~> 0.11'
44
+ end
@@ -0,0 +1,133 @@
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 'fluent/mixin/config_placeholders'
17
+ require 'socket'
18
+
19
+ module Fluent
20
+ class SyslogTlsOutput < Fluent::Output
21
+ Fluent::Plugin.register_output('syslog_tls', self)
22
+
23
+ include Fluent::Mixin::ConfigPlaceholders
24
+ include Fluent::HandleTagNameMixin
25
+
26
+ DEFAULT_FORMAT_TYPE = 'json'
27
+
28
+ config_param :host, :string
29
+ config_param :port, :integer
30
+ config_param :token, :string, :default => nil
31
+ config_param :cert, :string, :default => nil
32
+ config_param :key, :string, :default => nil
33
+ config_param :hostname, :string, :default => nil
34
+ config_param :facility, :string, :default => 'LOCAL0'
35
+
36
+ # Allow to map keys from record to syslog message headers
37
+ SYSLOG_HEADERS = [
38
+ :severity, :facility, :hostname, :app_name, :procid, :msgid
39
+ ]
40
+
41
+ SYSLOG_HEADERS.each do |key_name|
42
+ config_param "#{key_name}_key".to_sym, :string, :default => nil
43
+ end
44
+
45
+ config_param :format, :string, default: DEFAULT_FORMAT_TYPE
46
+
47
+
48
+ def initialize
49
+ super
50
+ require 'syslog_tls/logger'
51
+ @loggers = {}
52
+ end
53
+
54
+ def shutdown
55
+ super
56
+ @loggers.values.each(&:close)
57
+ end
58
+
59
+ # This method is called before starting.
60
+ def configure(conf)
61
+ super
62
+ @host = conf['host']
63
+ @port = conf['port']
64
+ @token = conf['token']
65
+ @hostname = conf['hostname'] || Socket.gethostname.split('.').first
66
+
67
+ # Determine mapping of record keys to syslog keys
68
+ @mappings = {}
69
+ SYSLOG_HEADERS.each do |key_name|
70
+ conf_key = "#{key_name}_key"
71
+ @mappings[key_name] = conf[conf_key] if conf.key?(conf_key)
72
+ end
73
+
74
+ @formatter = Plugin.new_formatter(@format)
75
+ @formatter.configure(conf)
76
+ end
77
+
78
+ # Get logger for given tag
79
+ def logger(tag)
80
+ # Try to reuse existing logger
81
+ @loggers[tag] ||= new_logger(tag)
82
+
83
+ # Create new logger if old one is closed
84
+ if @loggers[tag].closed?
85
+ @loggers[tag] = new_logger(tag)
86
+ end
87
+
88
+ @loggers[tag]
89
+ end
90
+
91
+ def new_logger(tag)
92
+ transport = ::SyslogTls::SSLTransport.new(host, port, cert: cert, key: key, max_retries: 3)
93
+ logger = ::SyslogTls::Logger.new(transport, token)
94
+ logger.facility(facility)
95
+ logger.hostname(hostname)
96
+ logger.app_name(tag)
97
+ logger
98
+ end
99
+
100
+ def format(tag, time, record)
101
+ @formatter.format(tag, time, record)
102
+ end
103
+
104
+ def emit(tag, es, chain)
105
+ chain.next
106
+ es.each do |time, record|
107
+ record.each_pair do |_, v|
108
+ v.force_encoding('utf-8') if v.is_a?(String)
109
+ end
110
+
111
+ # Check if severity has been provided in record otherwise use INFO
112
+ # by default.
113
+ severity = if @mappings.key?(:severity)
114
+ record[@mappings[:severity]] || 'INFO'
115
+ else
116
+ 'INFO'
117
+ end
118
+
119
+ # Send message to Syslog
120
+ begin
121
+ logger(tag).log(severity, format(tag, time, record), time: Time.at(time)) do |header|
122
+ # Map syslog headers from record
123
+ @mappings.each do |name, record_key|
124
+ header.send("#{name}=", record[record_key]) unless record[record_key].nil?
125
+ end
126
+ end
127
+ rescue => e
128
+ log.error e.to_s
129
+ end
130
+ end
131
+ end
132
+ end
133
+ 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