fluent-plugin-sumologic-cloud-syslog 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile ADDED
@@ -0,0 +1,24 @@
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 'bundler/gem_tasks'
16
+ require 'rake/testtask'
17
+
18
+ Rake::TestTask.new(:test) do |test|
19
+ test.libs << 'test'
20
+ test.pattern = 'test/**/test_*.rb'
21
+ test.verbose = true
22
+ end
23
+
24
+ task :default => :test
@@ -0,0 +1,119 @@
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`
13
+
14
+ ### port
15
+
16
+ Example: `6514`
17
+
18
+ ### token
19
+
20
+ Private token that is unique per account. Example: `ABABABABABABA@99999`
21
+
22
+ ### cert
23
+
24
+ Optionally path to private certificate for TLS connection. Example: `/path/to/crt/file.crt`
25
+
26
+ ### key
27
+
28
+ Optionally path to 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
+ ## Additional configuration
69
+
70
+ This plugin makes use of [Fluent::Mixin::PlainTextFormatter](https://github.com/tagomoris/fluent-mixin-plaintextformatter) please check out its documentation for more configuration options.
71
+
72
+ ## Puppet
73
+
74
+ If you are using Puppet for configuration management then an example configuration
75
+ using the [wywygmbh/puppet-fluentd](http://github.com/wywygmbh/puppet-fluentd) puppet module would be:
76
+
77
+ ```
78
+ ::fluentd::plugin { 'fluent-plugin-sumologic-cloud-syslog':
79
+ type => 'gem',
80
+ }
81
+
82
+ ::fluentd::match { 'sumologic_cloud_syslog':
83
+ priority => 10,
84
+ pattern => '**',
85
+ config => {
86
+ 'type' => 'sumologic_cloud_syslog',
87
+ 'host' => 'syslog.collection.us1.sumologic.com',
88
+ 'port' => 6514,
89
+ 'token' => $token,
90
+ 'cert' => $cert,
91
+ 'key' => $key,
92
+ },
93
+ }
94
+ ```
95
+
96
+ ## Example
97
+
98
+ ```
99
+ <match>
100
+ host syslog.collection.us1.sumologic.com
101
+ port 6514
102
+ token [token]@[iana-id]
103
+ cert /path/to/cert/file.crt
104
+ key /path/to/key/file.key
105
+
106
+ hostname static-hostname
107
+ facility SYSLOG
108
+
109
+ # You can configure syslog headers to be picked from actual message
110
+ # processed by plugin. If key is not provided '-' value will be sent
111
+ # which is NIL by syslog specification.
112
+ severity_key RECORD_SEVERITY_KEY
113
+ facility_key RECORD_FACILITY_KEY
114
+ hostname_key ...
115
+ app_name_key ...
116
+ procid_key ...
117
+ msgid_key ...
118
+ </match>
119
+ ```
@@ -0,0 +1,43 @@
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
+ lib = File.expand_path('../lib', __FILE__)
16
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
17
+ require 'sumologic_cloud_syslog/version'
18
+
19
+ Gem::Specification.new do |s|
20
+ s.name = 'fluent-plugin-sumologic-cloud-syslog'
21
+ s.version = SumologicCloudSyslog::VERSION
22
+ s.authors = ['Acquia Engineering']
23
+ s.email = ['engineering@acquia.com']
24
+ s.summary = %q{Fluent Sumologic Cloud Syslog plugin}
25
+ s.description = %q{Sumologic Cloud Syslog output plugin for Fluent event collector}
26
+ s.homepage = 'https://github.com/acquia/fluent-plugin-sumologic-cloud-syslog'
27
+ s.license = 'Apache v2'
28
+ s.files = `git ls-files`.split($/)
29
+ s.executables = s.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
30
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
31
+ s.require_paths = ['lib']
32
+ s.required_ruby_version = '>= 2.0.0'
33
+
34
+ s.add_runtime_dependency 'fluentd', '~> 0.12'
35
+ s.add_runtime_dependency 'fluent-mixin-config-placeholders', '~> 0.3'
36
+ s.add_runtime_dependency 'fluent-mixin-plaintextformatter', '~> 0.2'
37
+
38
+ s.add_development_dependency 'minitest', '~> 5.8'
39
+ s.add_development_dependency 'rake', '~> 10.5'
40
+ s.add_development_dependency 'test-unit', '~> 3.1'
41
+ s.add_development_dependency 'webmock', '~> 2.0'
42
+ s.add_development_dependency 'simplecov', '~> 0.11'
43
+ end
@@ -0,0 +1,118 @@
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 'fluent/mixin/config_placeholders'
16
+ require 'fluent/mixin/plaintextformatter'
17
+ require 'socket'
18
+
19
+ module Fluent
20
+ class SumologicCloudSyslogOutput < Fluent::Output
21
+ Fluent::Plugin.register_output('sumologic_cloud_syslog', self)
22
+
23
+ include Fluent::Mixin::PlainTextFormatter
24
+ include Fluent::Mixin::ConfigPlaceholders
25
+ include Fluent::HandleTagNameMixin
26
+
27
+ config_param :host, :string
28
+ config_param :port, :integer
29
+ config_param :token, :string
30
+ config_param :cert, :string, :default => nil
31
+ config_param :key, :string, :default => nil
32
+ config_param :hostname, :string, :default => nil
33
+ config_param :facility, :string, :default => 'LOCAL0'
34
+
35
+ # Allow to map keys from record to syslog message headers
36
+ SYSLOG_HEADERS = [
37
+ :severity, :facility, :hostname, :app_name, :procid, :msgid
38
+ ]
39
+
40
+ SYSLOG_HEADERS.each do |key_name|
41
+ config_param "#{key_name}_key".to_sym, :string, :default => nil
42
+ end
43
+
44
+ def initialize
45
+ super
46
+ require 'sumologic_cloud_syslog/logger'
47
+ @loggers = {}
48
+ end
49
+
50
+ def shutdown
51
+ super
52
+ @loggers.values.each(&:close)
53
+ end
54
+
55
+ # This method is called before starting.
56
+ def configure(conf)
57
+ super
58
+ @host = conf['host']
59
+ @port = conf['port']
60
+ @token = conf['token']
61
+ @hostname = conf['hostname'] || Socket.gethostname.split('.').first
62
+
63
+ # Determine mapping of record keys to syslog keys
64
+ @mappings = {}
65
+ SYSLOG_HEADERS.each do |key_name|
66
+ conf_key = "#{key_name}_key"
67
+ @mappings[key_name] = conf[conf_key] if conf.key?(conf_key)
68
+ end
69
+ end
70
+
71
+ # Get logger for given tag
72
+ def logger(tag)
73
+ # Try to reuse existing logger
74
+ @loggers[tag] ||= new_logger(tag)
75
+
76
+ # Create new logger if old one is closed
77
+ if @loggers[tag].closed?
78
+ @loggers[tag] = new_logger(tag)
79
+ end
80
+
81
+ @loggers[tag]
82
+ end
83
+
84
+ def new_logger(tag)
85
+ transport = ::SumologicCloudSyslog::SSLTransport.new(host, port, cert: cert, key: key)
86
+ logger = ::SumologicCloudSyslog::Logger.new(transport, token)
87
+ logger.facility(facility)
88
+ logger.hostname(hostname)
89
+ logger.app_name(tag)
90
+ logger
91
+ end
92
+
93
+ def emit(tag, es, chain)
94
+ chain.next
95
+ es.each do |time, record|
96
+ record.each_pair do |_, v|
97
+ v.force_encoding('utf-8') if v.is_a?(String)
98
+ end
99
+
100
+ # Check if severity has been provided in record otherwise use INFO
101
+ # by default.
102
+ severity = if @mappings.key?(:severity)
103
+ record[@mappings[:severity]] || 'INFO'
104
+ else
105
+ 'INFO'
106
+ end
107
+
108
+ # Send message to Sumo
109
+ logger(tag).log(severity, format(tag, time, record), time: Time.at(time)) { |header|
110
+ # Map syslog headers from record
111
+ @mappings.each do |name, record_key|
112
+ header.send("#{name}=", record[record_key]) unless record[record_key].nil?
113
+ end
114
+ }
115
+ end
116
+ end
117
+ end
118
+ 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 SumologicCloudSyslog
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,81 @@
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 'protocol'
16
+ require_relative 'ssl_transport'
17
+
18
+ module SumologicCloudSyslog
19
+ class Logger
20
+ attr_reader :token
21
+ attr_accessor :transport
22
+
23
+ # Logger accepts transport which should implement IO methods
24
+ # close, closed? and write
25
+ def initialize(transport, token)
26
+ @transport = transport
27
+ @default_header = SumologicCloudSyslog::Header.new
28
+ @default_structured_data = SumologicCloudSyslog::StructuredData.new(token)
29
+ end
30
+
31
+ # Sets default facility for each message
32
+ def facility(val)
33
+ @default_header.facility = val
34
+ end
35
+
36
+ # Sets default hostname for each message
37
+ def hostname(val)
38
+ @default_header.hostname = val
39
+ end
40
+
41
+ # Sets default app_name for each message
42
+ def app_name(val)
43
+ @default_header.app_name = val
44
+ end
45
+
46
+ # Sets default procid for message
47
+ def procid(val)
48
+ @default_header.procid = val
49
+ end
50
+
51
+ # Check if IO is closed
52
+ def closed?
53
+ transport && transport.closed?
54
+ end
55
+
56
+ def close
57
+ transport.close
58
+ end
59
+
60
+ # Send log message with severity to Sumologic
61
+ def log(severity, message, time: nil)
62
+ time ||= Time.now
63
+
64
+ m = SumologicCloudSyslog::Message.new
65
+
66
+ # Include authentication header
67
+ m.structured_data << @default_structured_data
68
+
69
+ # Adjust header with current timestamp and severity
70
+ m.header = @default_header.dup
71
+ m.header.severity = severity
72
+ m.header.timestamp = time
73
+
74
+ yield m.header if block_given?
75
+
76
+ m.msg = message
77
+
78
+ transport.write(m.to_s)
79
+ end
80
+ end
81
+ 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 SumologicCloudSyslog
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