fluent-plugin-syslog-tls 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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