fluent-plugin-sekoia-io 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 1e2dfb7c081bd780c5d7d44a7be676d44d7038509682c885293c538aa7ca72af
4
+ data.tar.gz: 45f03e81f8cec162944d13c6e41147f51bb7c52e2e719fba3d09e52f2b5af3f1
5
+ SHA512:
6
+ metadata.gz: 066f14bc603db32514dca4884d97eb1373f8bbe3cd915413683233f7b1a6798b38dc6a6d59b09b181255bbb744948d1839f0d74fb6e4fe270870fb0e138c8acc
7
+ data.tar.gz: dfdf89a0fb3e1999764aeb9f349fee3deed245f851ed538e48537cc1f068b287d3c90da7b6298d6aec8a73631c1207943e834c243c672ae8a3c83b685e8eb680
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ .idea
10
+
11
+ # rspec failure tracking
12
+ .rspec_status
13
+
14
+ #binary
15
+ fluent-plugin-syslog_rfc5424-*.gem
16
+
17
+ Gemfile.lock
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.4.2
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ before_install: gem install bundler -v 2.0.2
data/Dockerfile ADDED
@@ -0,0 +1,7 @@
1
+ FROM ruby:2.7-slim-buster
2
+
3
+ RUN apt update -y && \
4
+ apt install -y entr git gcc make
5
+
6
+ VOLUME /app
7
+ WORKDIR /app
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in the gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,9 @@
1
+ Copyright 2019 Cloud Foundry
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8
+
9
+
data/Makefile ADDED
@@ -0,0 +1,6 @@
1
+ dev:
2
+ docker build -t ruby-dev .
3
+ docker run --rm -it -v ${PWD}:/app --entrypoint bash ruby-dev
4
+
5
+ download:
6
+ curl https://app.sekoia.io/assets/files/SEKOIA-IO-intake.pem > resources/SEKOIA-IO-intake.pem
data/README.md ADDED
@@ -0,0 +1,103 @@
1
+ # FluentD Output & Formatter Plugins: SyslogSEKOIA
2
+
3
+ This plugin is HEAVILY based on the work done on https://github.com/cloudfoundry/fluent-plugin-syslog_rfc5424
4
+
5
+ Formatter plugin adheres to [RFC5424](https://tools.ietf.org/html/rfc5424).
6
+
7
+ Output plugin adheres to [RFC6587](https://tools.ietf.org/html/rfc6587) and [RFC5424](https://tools.ietf.org/html/rfc5424).
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ ```ruby
14
+ gem 'fluent-plugin-sekoia'
15
+ ```
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install fluent-plugin-sekoia
24
+
25
+ ## Output Usage
26
+
27
+ ```
28
+ <match **>
29
+ @type sekoia
30
+ <buffer>
31
+ @type memory
32
+ flush_interval 10s
33
+ </buffer>
34
+ </match>
35
+ ```
36
+
37
+ ### Configuration
38
+
39
+ | name | type | description |
40
+ | -------------- | ------- | --------------------------------- |
41
+ | host | string | syslog target host |
42
+ | port | integer | syslog target port |
43
+ | transport | string | transport protocol (tls [default], udp, or tcp) |
44
+ | insecure | boolean | skip ssl validation |
45
+ | trusted_ca_path | string | file path to ca to trust |
46
+
47
+ #### Format Section
48
+
49
+ Defaults to `sekoia`
50
+
51
+ | name | type | description |
52
+ | -------------- | ------- | ------- |
53
+ | rfc6587_message_size | boolean | prepends message length for syslog transmission (false by default) |
54
+ | app_name_field | string | sets app name in syslog from field in fluentd, delimited by '.' (default kubernetes.labels.app) |
55
+ | proc_id_field | string | sets proc id in syslog from field in fluentd, delimited by '.' (default kubernete.pod_name) |
56
+ | intake_key_field | string | sets intake_key in structured data for sekoia.io. delimited by '.' (default kubernetes.annotations.sekoia-io-intake-key) |
57
+
58
+
59
+ ## Formatter Usage
60
+
61
+ ```
62
+ <match **>
63
+ @type sekoia
64
+ <format>
65
+ @type sekoia
66
+ app_name_field example.custom_field_1
67
+ intake_key_field kubernetes.annotations.custom-annotation-that-contains-intake-key
68
+ </format>
69
+ </match>
70
+ ```
71
+
72
+
73
+ ## Development
74
+
75
+ After checking out the repo, run `bundle install` to install dependencies. Then, run `bundle exec rake` to run the tests. You can also run `bundle console` for an interactive prompt that will allow you to experiment.
76
+
77
+ To install this gem onto your local machine, run `bundle exec rake install`.
78
+
79
+ To release a new version,
80
+ 1. update the version number in `fluent-plugin-sekoia.gemspec`,
81
+ 1. download latest sekoia.io certificate `make download`
82
+ 1. then run `bundle exec rake release`, which will create a git tag for the version,
83
+ 1. push git commits and tags
84
+ 1. push the `.gem` file to [rubygems.org](https://rubygems.org).
85
+
86
+ ### Using the dev docker environment
87
+
88
+ Run the command `make dev` to start a docker with the current folder mounted in the docker. Then use the following commands to start the tests at each code modifications:
89
+
90
+ ```bash
91
+ bundle install
92
+ find . | entr -s 'bundle exec rake'
93
+ ```
94
+
95
+ ## Publishing
96
+
97
+ 1. Run tests `bundle exec rake`
98
+ 1. Download latest sekoia.io certificate `make download`
99
+ 1. Push changes
100
+ 1. Create & push git tag with version
101
+ 1. Change version in `.gemspec`
102
+ 1. Build gem `gem build fluent-plugin-sekoia`
103
+ 1. Push `.gem` file to rubygems `gem push pkg/fluent-plugin-sekoia-io-0.0.1`
data/Rakefile ADDED
@@ -0,0 +1,15 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/testtask'
3
+ require 'fluent-plugin-sekoia-io/version'
4
+
5
+ Rake::TestTask.new(:test) do |test|
6
+ test.libs << "lib" << "test"
7
+ test.pattern = "test/**/*_spec.rb"
8
+ test.verbose = true
9
+ end
10
+
11
+ task default: :test
12
+
13
+ task :version do
14
+ puts FluentSEKOIAOutputPlugin::VERSION
15
+ end
@@ -0,0 +1,29 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'fluent-plugin-sekoia-io/version'
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "fluent-plugin-sekoia-io"
7
+ spec.version = FluentSEKOIAIOOutputPlugin::VERSION
8
+ spec.authors = ["Pivotal"]
9
+ spec.email = %w(cf-loggregator@pivotal.io)
10
+ spec.homepage = "https://github.com/SekoiaLab/fluent-plugin-sekoia-io"
11
+
12
+ spec.summary = %q{FluentD output plugin to send messages via rfc5424 for sekoia}
13
+ spec.description = %q{FluentD output plugin to send messages via Syslog rfc5424 for sekoia.}
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_development_dependency "bundler", "~> 2.0"
21
+ spec.add_development_dependency "rake", "~> 13.0"
22
+ spec.add_development_dependency "test-unit", "~> 3.3"
23
+ spec.add_development_dependency "test-unit-rr", "~> 1.0"
24
+ spec.add_development_dependency "pry", "~> 0.12"
25
+ spec.add_development_dependency "minitest", "~> 5.14"
26
+
27
+ spec.add_runtime_dependency "fluentd", "~> 1.7"
28
+ end
29
+
@@ -0,0 +1,41 @@
1
+ require 'sekoia/formatter'
2
+
3
+ module Fluent
4
+ module Plugin
5
+ class FormatterSEKOIA < Formatter
6
+ Fluent::Plugin.register_formatter('sekoia', self)
7
+
8
+ config_param :rfc6587_message_size, :bool, default: false
9
+ config_param :app_name_field, :string, default: "kubernetes.labels.app"
10
+ config_param :proc_id_field, :string, default: "kubernetes.pod_name"
11
+ config_param :intake_key_field, :string, default: "kubernetes.annotations.sekoia-io-intake-key"
12
+
13
+ def configure(conf)
14
+ super
15
+ @app_name_field_array = @app_name_field.split(".")
16
+ @proc_id_field_array = @proc_id_field.split(".")
17
+ @intake_key_array = @intake_key_field.split(".")
18
+ end
19
+
20
+ def format(tag, time, record)
21
+ log.debug("Record")
22
+ log.debug(record.map { |k, v| "#{k}=#{v}" }.join('&'))
23
+
24
+ msg = SEKOIA::Formatter.format(
25
+ log: record['log'],
26
+ timestamp: time,
27
+ app_name: record.dig(*@app_name_field_array) || "-",
28
+ proc_id: record.dig(*@proc_id_field_array) || "-",
29
+ intake_key: record.dig(*@intake_key_array) || ""
30
+ )
31
+
32
+ log.debug("RFC 5424 Message")
33
+ log.debug(msg)
34
+
35
+ return msg + "\n" unless @rfc6587_message_size
36
+
37
+ msg.length.to_s + ' ' + msg
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,72 @@
1
+ require 'fluent/plugin/output'
2
+
3
+ module Fluent
4
+ module Plugin
5
+ class OutSyslogSEKOIA < Output
6
+ Fluent::Plugin.register_output('syslog_sekoia', self)
7
+
8
+ helpers :socket, :formatter
9
+ DEFAULT_FORMATTER = "sekoia"
10
+
11
+ config_param :host, :string, default: "intake.sekoia.io"
12
+ config_param :port, :integer, default: 10514
13
+ config_param :transport, :string, default: "tls"
14
+ config_param :insecure, :bool, default: false
15
+ config_param :trusted_ca_path, :string, default: nil
16
+ config_section :format do
17
+ config_set_default :@type, DEFAULT_FORMATTER
18
+ end
19
+
20
+ def configure(config)
21
+ super
22
+ @sockets = {}
23
+ @formatter = formatter_create
24
+ end
25
+
26
+ def write(chunk)
27
+ socket = find_or_create_socket(@transport.to_sym, @host, @port)
28
+ tag = chunk.metadata.tag
29
+ chunk.each do |time, record|
30
+ begin
31
+ socket.write_nonblock @formatter.format(tag, time, record)
32
+ IO.select(nil, [socket], nil, 1) || raise(StandardError.new "ReconnectError")
33
+ rescue => e
34
+ @sockets.delete(socket_key(@transport.to_sym, @host, @port))
35
+ socket.close
36
+ raise e
37
+ end
38
+ end
39
+ end
40
+
41
+ def close
42
+ super
43
+ @sockets.each_value { |s| s.close }
44
+ @sockets = {}
45
+ end
46
+
47
+ private
48
+
49
+ def find_or_create_socket(transport, host, port)
50
+ socket = find_socket(transport, host, port)
51
+ return socket if socket
52
+
53
+ @sockets[socket_key(transport, host, port)] = socket_create(transport.to_sym, host, port, socket_options)
54
+ end
55
+
56
+ def socket_options
57
+ return {} unless @transport == 'tls'
58
+
59
+ # TODO: make timeouts configurable
60
+ { insecure: @insecure, verify_fqdn: !@insecure, cert_paths: @trusted_ca_path } #, connect_timeout: 1, send_timeout: 1, recv_timeout: 1, linger_timeout: 1 }
61
+ end
62
+
63
+ def socket_key(transport, host, port)
64
+ "#{host}:#{port}:#{transport}"
65
+ end
66
+
67
+ def find_socket(transport, host, port)
68
+ @sockets[socket_key(transport, host, port)]
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,3 @@
1
+ module FluentSEKOIAIOOutputPlugin
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,34 @@
1
+ require 'date'
2
+
3
+ module SEKOIA
4
+ class Formatter
5
+ SekoiaID = "SEKOIA@53288"
6
+ Format = "<%d>1 %s %s %s %s %s %s %s"
7
+
8
+ class << self
9
+ def format(
10
+ priority: 14,
11
+ timestamp: nil,
12
+ log: "",
13
+ hostname: "-",
14
+ app_name: "-",
15
+ proc_id: "-",
16
+ msg_id: "-",
17
+ intake_key: ""
18
+ )
19
+ Format % [priority, format_time(timestamp), hostname[0..254], app_name[0..47], proc_id[0..127], msg_id[0..31], format_structured_data(intake_key), log]
20
+ end
21
+
22
+ def format_structured_data(intake_key)
23
+ %{[#{SekoiaID} intake_key="#{intake_key}"]}
24
+ end
25
+
26
+ def format_time(timestamp)
27
+ return "-" if timestamp.nil?
28
+ return Time.at(timestamp.to_r).utc.to_datetime.rfc3339(6) if timestamp.is_a?(Fluent::EventTime)
29
+
30
+ DateTime.strptime(timestamp.to_s, '%s').rfc3339(6)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,47 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
3
+ MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
4
+ DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
5
+ SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
6
+ GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
7
+ AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
8
+ q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
9
+ SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
10
+ Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
11
+ a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
12
+ /PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
13
+ AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
14
+ CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
15
+ bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
16
+ c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
17
+ VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
18
+ ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
19
+ MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
20
+ Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
21
+ AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
22
+ uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
23
+ wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
24
+ X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
25
+ PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
26
+ KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
27
+ -----END CERTIFICATE-----
28
+ -----BEGIN CERTIFICATE-----
29
+ MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/
30
+ MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
31
+ DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow
32
+ PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD
33
+ Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
34
+ AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O
35
+ rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq
36
+ OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b
37
+ xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw
38
+ 7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD
39
+ aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
40
+ HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG
41
+ SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69
42
+ ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr
43
+ AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz
44
+ R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5
45
+ JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo
46
+ Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
47
+ -----END CERTIFICATE-----
@@ -0,0 +1,122 @@
1
+ require "test_helper"
2
+ require "fluent/plugin/formatter_sekoia"
3
+
4
+ class FormatterSEKOIATest < Test::Unit::TestCase
5
+ def setup
6
+ Fluent::Test.setup
7
+ end
8
+
9
+ def create_driver(conf = CONFIG)
10
+ Fluent::Test::Driver::Formatter.new(Fluent::Plugin::FormatterSEKOIA).configure(conf)
11
+ end
12
+
13
+ def test_format_default
14
+ formatter_driver = create_driver %(
15
+ @type sekoia
16
+ )
17
+ tag = "test-formatter"
18
+ time = Fluent::EventTime.new(0, 123456000)
19
+ record = {"log" => "test-log"}
20
+ assert_equal "<14>1 1970-01-01T00:00:00.123456+00:00 - - - - [SEKOIA@53288 intake_key=\"\"] test-log\n",
21
+ formatter_driver.instance.format(tag, time, record)
22
+ end
23
+
24
+ def test_format_without_message_size
25
+ formatter_driver = create_driver %(
26
+ @type sekoia
27
+ )
28
+ tag = "test-formatter"
29
+ time = Fluent::EventTime.new(0, 123456000)
30
+ record = {"log" => "test-log"}
31
+ assert_equal "<14>1 1970-01-01T00:00:00.123456+00:00 - - - - [SEKOIA@53288 intake_key=\"\"] test-log\n",
32
+ formatter_driver.instance.format(tag, time, record)
33
+ end
34
+
35
+ def test_format_with_message_size
36
+ formatter_driver = create_driver %(
37
+ @type sekoia
38
+ rfc6587_message_size true
39
+ )
40
+ tag = "test-formatter"
41
+ time = Fluent::EventTime.new(0, 123456000)
42
+ record = {"log" => "test-log"}
43
+
44
+ formatted_message = "<14>1 1970-01-01T00:00:00.123456+00:00 - - - - [SEKOIA@53288 intake_key=\"\"] test-log"
45
+ message_size = formatted_message.length
46
+ assert_equal "#{message_size} #{formatted_message}",
47
+ formatter_driver.instance.format(tag, time, record)
48
+ end
49
+
50
+ def test_format_with_app_name
51
+ formatter_driver = create_driver %(
52
+ @type sekoia
53
+ app_name_field example.custom_field
54
+ )
55
+ tag = "test-formatter"
56
+ time = Fluent::EventTime.new(0, 123456000)
57
+ record = {"log" => "test-log", "example" => {"custom_field" => "custom-value"}}
58
+
59
+ formatted_message = "<14>1 1970-01-01T00:00:00.123456+00:00 - custom-value - - [SEKOIA@53288 intake_key=\"\"] test-log\n"
60
+ assert_equal "#{formatted_message}",
61
+ formatter_driver.instance.format(tag, time, record)
62
+ end
63
+
64
+ def test_format_with_proc_id
65
+ formatter_driver = create_driver %(
66
+ @type sekoia
67
+ proc_id_field example.custom_field
68
+ )
69
+ tag = "test-formatter"
70
+ time = Fluent::EventTime.new(0, 123456000)
71
+ record = {"log" => "test-log", "example" => {"custom_field" => "custom-value"}}
72
+
73
+ formatted_message = "<14>1 1970-01-01T00:00:00.123456+00:00 - - custom-value - [SEKOIA@53288 intake_key=\"\"] test-log\n"
74
+ assert_equal "#{formatted_message}",
75
+ formatter_driver.instance.format(tag, time, record)
76
+ end
77
+
78
+ def test_format_with_intake_key
79
+ formatter_driver = create_driver %(
80
+ @type sekoia
81
+ app_name_field example.custom_field
82
+ intake_key_field field.intake_key
83
+ )
84
+ tag = "test-formatter"
85
+ time = Fluent::EventTime.new(0, 123456000)
86
+ record = {
87
+ "log" => "test-log",
88
+ "example" => {
89
+ "custom_field" => "custom-value"
90
+ },
91
+ "field" => {
92
+ "intake_key" => "testIntakeKey"
93
+ }
94
+ }
95
+ formatted_message = "<14>1 1970-01-01T00:00:00.123456+00:00 - custom-value - - [SEKOIA@53288 intake_key=\"testIntakeKey\"] test-log\n"
96
+ assert_equal "#{formatted_message}",
97
+ formatter_driver.instance.format(tag, time, record)
98
+ end
99
+
100
+ def test_format_with_intake_key_and_default_path
101
+ formatter_driver = create_driver %(
102
+ @type sekoia
103
+ )
104
+ tag = "test-formatter"
105
+ time = Fluent::EventTime.new(0, 123456000)
106
+ record = {
107
+ "log" => "test-log",
108
+ "kubernetes" => {
109
+ "annotations" => {
110
+ "sekoia-io-intake-key" => "1234"
111
+ },
112
+ "labels" => {
113
+ "app" => "test"
114
+ }
115
+ }
116
+ }
117
+ formatted_message = "<14>1 1970-01-01T00:00:00.123456+00:00 - test - - [SEKOIA@53288 intake_key=\"1234\"] test-log\n"
118
+ assert_equal "#{formatted_message}",
119
+ formatter_driver.instance.format(tag, time, record)
120
+ end
121
+
122
+ end
@@ -0,0 +1,168 @@
1
+ require "test_helper"
2
+ require "fluent/plugin/out_sekoia"
3
+
4
+ class OutSyslogSEKOIATest < Test::Unit::TestCase
5
+ def setup
6
+ Fluent::Test.setup
7
+ @time = Fluent::EventTime.new(0, 123456)
8
+ @formatted_log = "<14>1 1970-01-01T00:00:00.000123+00:00 - - - - [SEKOIA@53288 intake_key=\"\"] hi\n"
9
+ end
10
+
11
+ def create_driver(conf = CONFIG)
12
+ Fluent::Test::Driver::Output.new(Fluent::Plugin::OutSyslogSEKOIA).configure(conf)
13
+ end
14
+
15
+ def test_configure
16
+ output_driver = create_driver %(
17
+ @type sekoia
18
+ host example.com
19
+ port 123
20
+ )
21
+
22
+ assert_equal "example.com", output_driver.instance.instance_variable_get(:@host)
23
+ assert_equal 123, output_driver.instance.instance_variable_get(:@port)
24
+ end
25
+
26
+ def test_sends_a_message
27
+ output_driver = create_driver %(
28
+ @type sekoia
29
+ host example.com
30
+ port 123
31
+ )
32
+
33
+ socket = Object.new
34
+ mock(socket).write_nonblock(@formatted_log)
35
+ stub(socket).close
36
+
37
+ stub(IO).select(nil, [socket], nil, 1) { ["not an error"] }
38
+
39
+ any_instance_of(Fluent::Plugin::OutSyslogSEKOIA) do |fluent_plugin|
40
+ mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :cert_paths=>nil}).returns(socket)
41
+ end
42
+
43
+ output_driver.run do
44
+ output_driver.feed("tag", @time, {"log" => "hi"})
45
+ end
46
+ end
47
+
48
+ def test_reconnects
49
+ output_driver = create_driver %(
50
+ @type sekoia
51
+ host example.com
52
+ port 123
53
+ )
54
+
55
+ bad_socket = Object.new
56
+ mock(bad_socket).write_nonblock(@formatted_log)
57
+ stub(bad_socket).close
58
+
59
+ good_socket = Object.new
60
+ mock(good_socket).write_nonblock(@formatted_log)
61
+ stub(good_socket).close
62
+
63
+ mock(IO).select(nil, [bad_socket], nil, 1)
64
+ mock(IO).select(nil, [good_socket], nil, 1) { ["not an error"] }
65
+
66
+ any_instance_of(Fluent::Plugin::OutSyslogSEKOIA) do |fluent_plugin|
67
+ mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :cert_paths=>nil}).returns(bad_socket)
68
+ mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :cert_paths=>nil}).returns(good_socket)
69
+ end
70
+
71
+ output_driver.run(shutdown: false, force_flush_retry: true) do
72
+ output_driver.feed("tag", @time, {"log" => "hi"})
73
+ end
74
+ end
75
+
76
+ def test_non_tls
77
+ output_driver = create_driver %(
78
+ @type sekoia
79
+ host example.com
80
+ port 123
81
+ transport tcp
82
+ )
83
+
84
+ socket = Object.new
85
+ mock(socket).write_nonblock(@formatted_log)
86
+ stub(socket).close
87
+
88
+ stub(IO).select(nil, [socket], nil, 1) { ["not an error"] }
89
+
90
+ any_instance_of(Fluent::Plugin::OutSyslogSEKOIA) do |fluent_plugin|
91
+ mock(fluent_plugin).socket_create(:tcp, "example.com", 123, {}).returns(socket)
92
+ end
93
+
94
+ output_driver.run do
95
+ output_driver.feed("tag", @time, {"log" => "hi"})
96
+ end
97
+ end
98
+
99
+ def test_insecure_tls
100
+ output_driver = create_driver %(
101
+ @type sekoia
102
+ host example.com
103
+ port 123
104
+ transport tls
105
+ insecure true
106
+ )
107
+
108
+ socket = Object.new
109
+ mock(socket).write_nonblock(@formatted_log)
110
+ stub(socket).close
111
+
112
+ stub(IO).select(nil, [socket], nil, 1) { ["not an error"] }
113
+
114
+ any_instance_of(Fluent::Plugin::OutSyslogSEKOIA) do |fluent_plugin|
115
+ mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>true, :verify_fqdn=>false, :cert_paths=>nil}).returns(socket)
116
+ end
117
+
118
+ output_driver.run do
119
+ output_driver.feed("tag", @time, {"log" => "hi"})
120
+ end
121
+ end
122
+
123
+ def test_secure_tls
124
+ output_driver = create_driver %(
125
+ @type sekoia
126
+ host example.com
127
+ port 123
128
+ transport tls
129
+ trusted_ca_path supertrustworthy
130
+ )
131
+
132
+ socket = Object.new
133
+ mock(socket).write_nonblock(@formatted_log)
134
+ stub(socket).close
135
+
136
+ stub(IO).select(nil, [socket], nil, 1) { ["not an error"] }
137
+
138
+ any_instance_of(Fluent::Plugin::OutSyslogSEKOIA) do |fluent_plugin|
139
+ mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :cert_paths=>"supertrustworthy"}).returns(socket)
140
+ end
141
+
142
+ output_driver.run do
143
+ output_driver.feed("tag", @time, {"log" => "hi"})
144
+ end
145
+ end
146
+
147
+ def test_close_is_called_on_sockets
148
+ output_driver = create_driver %(
149
+ @type sekoia
150
+ host example.com
151
+ port 123
152
+ )
153
+
154
+ socket = Object.new
155
+ stub(socket).write_nonblock(@formatted_log)
156
+ mock(socket).close
157
+
158
+ stub(IO).select(nil, [socket], nil, 1) { ["not an error"] }
159
+
160
+ any_instance_of(Fluent::Plugin::OutSyslogSEKOIA) do |fluent_plugin|
161
+ mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :cert_paths=>nil}).returns(socket)
162
+ end
163
+
164
+ output_driver.run do
165
+ output_driver.feed("tag", @time , {"log" => "hi"})
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,72 @@
1
+ require "test_helper"
2
+ require "sekoia/formatter"
3
+
4
+ class SEKOIA::FormatterTest < Test::Unit::TestCase
5
+ def test_only_log
6
+ log = SEKOIA::Formatter.format(log: "test-log")
7
+ assert_equal log, "<14>1 - - - - - [SEKOIA@53288 intake_key=\"\"] test-log"
8
+ end
9
+
10
+ # RFC 3339
11
+ # Adding fractional seconds: https://github.com/fluent/fluentd/issues/1862
12
+ def test_with_timestamp
13
+ log = SEKOIA::Formatter.format(timestamp: 0, log: "test-log")
14
+ assert_equal log, "<14>1 1970-01-01T00:00:00.000000+00:00 - - - - [SEKOIA@53288 intake_key=\"\"] test-log"
15
+ end
16
+
17
+ def test_with_timestamp_nano
18
+ log = SEKOIA::Formatter.format(timestamp: Fluent::EventTime.new(0, 123456000), log: "test-log")
19
+
20
+ assert_equal log, "<14>1 1970-01-01T00:00:00.123456+00:00 - - - - [SEKOIA@53288 intake_key=\"\"] test-log"
21
+ end
22
+
23
+ def test_with_priority
24
+ log = SEKOIA::Formatter.format( priority: 1, log: "test-log")
25
+ assert_equal log, "<1>1 - - - - - [SEKOIA@53288 intake_key=\"\"] test-log"
26
+ end
27
+
28
+ def test_with_hostname
29
+ log = SEKOIA::Formatter.format( hostname: "host", log: "test-log")
30
+ assert_equal log, "<14>1 - host - - - [SEKOIA@53288 intake_key=\"\"] test-log"
31
+ end
32
+
33
+ def test_with_overly_long_hostname
34
+ log = SEKOIA::Formatter.format( hostname: "a"*300, log: "test-log")
35
+ assert_equal log, "<14>1 - #{"a"*255} - - - [SEKOIA@53288 intake_key=\"\"] test-log"
36
+ end
37
+
38
+ def test_with_app_name
39
+ log = SEKOIA::Formatter.format( app_name: "app-name", log: "test-log")
40
+ assert_equal log, "<14>1 - - app-name - - [SEKOIA@53288 intake_key=\"\"] test-log"
41
+ end
42
+
43
+ def test_with_overly_long_app_name
44
+ log = SEKOIA::Formatter.format( app_name: "a"*300, log: "test-log")
45
+ assert_equal log, "<14>1 - - #{"a"*48} - - [SEKOIA@53288 intake_key=\"\"] test-log"
46
+ end
47
+
48
+ def test_with_proc_id
49
+ log = SEKOIA::Formatter.format( proc_id: "proc-id", log: "test-log")
50
+ assert_equal log, "<14>1 - - - proc-id - [SEKOIA@53288 intake_key=\"\"] test-log"
51
+ end
52
+
53
+ def test_with_overly_long_proc_id
54
+ log = SEKOIA::Formatter.format( proc_id: "a"*300, log: "test-log")
55
+ assert_equal log, "<14>1 - - - #{"a"*128} - [SEKOIA@53288 intake_key=\"\"] test-log"
56
+ end
57
+
58
+ def test_with_msg_id
59
+ log = SEKOIA::Formatter.format( msg_id: "msg-id", log: "test-log")
60
+ assert_equal log, "<14>1 - - - - msg-id [SEKOIA@53288 intake_key=\"\"] test-log"
61
+ end
62
+
63
+ def test_with_overly_long_msg_id
64
+ log = SEKOIA::Formatter.format( msg_id: "a"*300, log: "test-log")
65
+ assert_equal log, "<14>1 - - - - #{"a"*32} [SEKOIA@53288 intake_key=\"\"] test-log"
66
+ end
67
+
68
+ def test_with_intake_key
69
+ log = SEKOIA::Formatter.format( msg_id: "a"*300, log: "test-log", intake_key: "testIntakeKey")
70
+ assert_equal log, "<14>1 - - - - #{"a"*32} [SEKOIA@53288 intake_key=\"testIntakeKey\"] test-log"
71
+ end
72
+ end
@@ -0,0 +1,14 @@
1
+ require "bundler/setup"
2
+ require "test/unit"
3
+
4
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
5
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
6
+
7
+ require "fluent/test"
8
+ require "fluent/test/driver/output"
9
+ require "fluent/test/driver/formatter"
10
+
11
+ require "test/unit/rr"
12
+ require "minitest/mock"
13
+
14
+ require 'pry'
metadata ADDED
@@ -0,0 +1,164 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fluent-plugin-sekoia-io
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Pivotal
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-04-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '13.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '13.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: test-unit
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.3'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: test-unit-rr
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.12'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.12'
83
+ - !ruby/object:Gem::Dependency
84
+ name: minitest
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '5.14'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '5.14'
97
+ - !ruby/object:Gem::Dependency
98
+ name: fluentd
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '1.7'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '1.7'
111
+ description: FluentD output plugin to send messages via Syslog rfc5424 for sekoia.
112
+ email:
113
+ - cf-loggregator@pivotal.io
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - ".gitignore"
119
+ - ".ruby-version"
120
+ - ".travis.yml"
121
+ - Dockerfile
122
+ - Gemfile
123
+ - LICENSE
124
+ - Makefile
125
+ - README.md
126
+ - Rakefile
127
+ - fluent-plugin-sekoia-io.gemspec
128
+ - lib/fluent-plugin-sekoia-io/version.rb
129
+ - lib/fluent/plugin/formatter_sekoia.rb
130
+ - lib/fluent/plugin/out_sekoia.rb
131
+ - lib/sekoia/formatter.rb
132
+ - resources/SEKOIA-IO-intake.pem
133
+ - test/plugin/formatter_sekoia_spec.rb
134
+ - test/plugin/out_sekoia_spec.rb
135
+ - test/sekoia/formatter_spec.rb
136
+ - test/test_helper.rb
137
+ homepage: https://github.com/SekoiaLab/fluent-plugin-sekoia-io
138
+ licenses:
139
+ - MIT
140
+ metadata: {}
141
+ post_install_message:
142
+ rdoc_options: []
143
+ require_paths:
144
+ - lib
145
+ required_ruby_version: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - ">="
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ required_rubygems_version: !ruby/object:Gem::Requirement
151
+ requirements:
152
+ - - ">="
153
+ - !ruby/object:Gem::Version
154
+ version: '0'
155
+ requirements: []
156
+ rubygems_version: 3.1.2
157
+ signing_key:
158
+ specification_version: 4
159
+ summary: FluentD output plugin to send messages via rfc5424 for sekoia
160
+ test_files:
161
+ - test/plugin/formatter_sekoia_spec.rb
162
+ - test/plugin/out_sekoia_spec.rb
163
+ - test/sekoia/formatter_spec.rb
164
+ - test/test_helper.rb