fluent-plugin-dynatrace 0.1.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.
- checksums.yaml +7 -0
- data/.github/workflows/integration.yaml +50 -0
- data/.github/workflows/lint.yaml +21 -0
- data/.github/workflows/release.yaml +28 -0
- data/.github/workflows/unit.yaml +24 -0
- data/.gitignore +63 -0
- data/.rubocop.yml +8 -0
- data/CODE_OF_CONDUCT.md +76 -0
- data/Gemfile +5 -0
- data/LICENSE +201 -0
- data/README.md +97 -0
- data/Rakefile +37 -0
- data/fluent-plugin-dynatrace.gemspec +30 -0
- data/lib/fluent/plugin/dynatrace_constants.rb +27 -0
- data/lib/fluent/plugin/out_dynatrace.rb +139 -0
- data/test/.rubocop.yml +5 -0
- data/test/integration/fixtures/docker-compose.yaml +27 -0
- data/test/integration/fixtures/fluent/Dockerfile +30 -0
- data/test/integration/fixtures/fluent/entrypoint.sh +17 -0
- data/test/integration/fixtures/fluent/fluent.conf +30 -0
- data/test/integration/fixtures/logsink/Dockerfile +18 -0
- data/test/integration/fixtures/logsink/server.js +46 -0
- data/test/integration/integration_test.rb +50 -0
- data/test/plugin/out_dynatrace_test.rb +152 -0
- metadata +152 -0
@@ -0,0 +1,18 @@
|
|
1
|
+
# Copyright 2021 Dynatrace LLC
|
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
|
+
FROM node:lts-alpine
|
16
|
+
COPY server.js /logsink/server.js
|
17
|
+
|
18
|
+
CMD node /logsink/server.js
|
@@ -0,0 +1,46 @@
|
|
1
|
+
/**
|
2
|
+
* Copyright 2021 Dynatrace LLC
|
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
|
+
|
17
|
+
const http = require("http");
|
18
|
+
|
19
|
+
process.on('SIGINT', () => {
|
20
|
+
process.exit(0)
|
21
|
+
});
|
22
|
+
|
23
|
+
process.on('SIGTERM', () => {
|
24
|
+
process.exit(0)
|
25
|
+
});
|
26
|
+
|
27
|
+
const server = http.createServer((req, res) => {
|
28
|
+
const ua = req.headers['user-agent'];
|
29
|
+
if (typeof ua != 'string') {
|
30
|
+
process.stdout.write("Missing user agent header");
|
31
|
+
}
|
32
|
+
|
33
|
+
if (!ua.match(/^fluent-plugin-dynatrace v\d+\.\d+\.\d+$/)) {
|
34
|
+
process.stdout.write("Invalid user agent header");
|
35
|
+
}
|
36
|
+
|
37
|
+
req.on('data', (chunk) => {
|
38
|
+
process.stdout.write(chunk);
|
39
|
+
});
|
40
|
+
|
41
|
+
req.on("end", () => {
|
42
|
+
res.end();
|
43
|
+
});
|
44
|
+
})
|
45
|
+
|
46
|
+
server.listen(8080);
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2021 Dynatrace LLC
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
require 'test/unit'
|
18
|
+
require 'net/http'
|
19
|
+
|
20
|
+
class TestFluentIntegration < Test::Unit::TestCase
|
21
|
+
def setup
|
22
|
+
puts `cd test/integration/fixtures && docker-compose up -d --force-recreate --build`
|
23
|
+
puts 'waiting 5s for integration test to start'
|
24
|
+
sleep 5
|
25
|
+
end
|
26
|
+
|
27
|
+
def teardown
|
28
|
+
puts `cd test/integration/fixtures && docker-compose down`
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_integration
|
32
|
+
puts 'sending logs'
|
33
|
+
uri = URI.parse('http://localhost:8080/dt.match')
|
34
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
35
|
+
|
36
|
+
req = Net::HTTP::Post.new(uri.path, { 'Content-Type' => 'application/json' })
|
37
|
+
|
38
|
+
req.body = '[{"foo":"bar"},{"abc":"def"},{"xyz":"123"},{"abc":"def"},{"xyz":"123"},{"abc":"def"},{"xyz":"123"}]'
|
39
|
+
http.request(req)
|
40
|
+
|
41
|
+
puts 'waiting 10s for output plugin to flush'
|
42
|
+
sleep 10
|
43
|
+
|
44
|
+
logs = `docker logs fixtures_logsink_1`
|
45
|
+
|
46
|
+
line1 = '[{"foo":"bar"},{"abc":"def"},{"xyz":"123"},{"abc":"def"},{"xyz":"123"}]'
|
47
|
+
line2 = '[{"abc":"def"},{"xyz":"123"}]'
|
48
|
+
assert_equal("#{line1}\n#{line2}\n", logs)
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2021 Dynatrace LLC
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
require 'fluent/test'
|
18
|
+
require 'fluent/test/helpers'
|
19
|
+
require 'fluent/test/driver/output'
|
20
|
+
require 'fluent/plugin/out_dynatrace'
|
21
|
+
require 'fluent/plugin/dynatrace_constants'
|
22
|
+
require 'webrick'
|
23
|
+
|
24
|
+
class FakeAgent
|
25
|
+
Result = Struct.new('Result', :data, :headers)
|
26
|
+
|
27
|
+
attr_reader :result, :original_agent
|
28
|
+
attr_accessor :use_ssl, :verify_mode
|
29
|
+
|
30
|
+
def initialize(original_agent)
|
31
|
+
@result = Result.new(nil, {})
|
32
|
+
@started = false
|
33
|
+
@original_agent = original_agent
|
34
|
+
end
|
35
|
+
|
36
|
+
def started?
|
37
|
+
@started
|
38
|
+
end
|
39
|
+
|
40
|
+
def start
|
41
|
+
raise 'already started' if @started
|
42
|
+
|
43
|
+
@started = true
|
44
|
+
end
|
45
|
+
|
46
|
+
def finish; end
|
47
|
+
|
48
|
+
def request(req, body)
|
49
|
+
raise 'expected POST' unless req.method == 'POST'
|
50
|
+
raise 'expected application/json' unless req.content_type == 'application/json'
|
51
|
+
|
52
|
+
req.each do |key, value|
|
53
|
+
@result.headers[key] = value
|
54
|
+
end
|
55
|
+
|
56
|
+
@result.data = JSON.parse(body)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class MyOutputTest < Test::Unit::TestCase
|
61
|
+
include Fluent::Test::Helpers
|
62
|
+
|
63
|
+
DEFAULT_LOGGER = ::WEBrick::Log.new($stdout, ::WEBrick::BasicLog::FATAL)
|
64
|
+
|
65
|
+
def server_port
|
66
|
+
19_881
|
67
|
+
end
|
68
|
+
|
69
|
+
def base_endpoint
|
70
|
+
"http://127.0.0.1:#{server_port}"
|
71
|
+
end
|
72
|
+
|
73
|
+
def setup
|
74
|
+
Fluent::Test.setup
|
75
|
+
end
|
76
|
+
|
77
|
+
# default configuration for tests
|
78
|
+
def config
|
79
|
+
%(
|
80
|
+
active_gate_url #{base_endpoint}/logs
|
81
|
+
api_token secret
|
82
|
+
)
|
83
|
+
end
|
84
|
+
|
85
|
+
def events
|
86
|
+
[
|
87
|
+
{ 'message' => 'hello', 'num' => 10, 'bool' => true },
|
88
|
+
{ 'message' => 'hello', 'num' => 11, 'bool' => false }
|
89
|
+
]
|
90
|
+
end
|
91
|
+
|
92
|
+
def create_driver(conf = config)
|
93
|
+
d = Fluent::Test::Driver::Output.new(Fluent::Plugin::DynatraceOutput).configure(conf)
|
94
|
+
@agent = FakeAgent.new(d.instance.agent)
|
95
|
+
d.instance.agent = @agent
|
96
|
+
d
|
97
|
+
end
|
98
|
+
|
99
|
+
sub_test_case 'configuration' do
|
100
|
+
test 'required configurations are applied' do
|
101
|
+
d = create_driver
|
102
|
+
assert_equal "http://127.0.0.1:#{server_port}/logs", d.instance.active_gate_url
|
103
|
+
assert_equal 'secret', d.instance.api_token
|
104
|
+
end
|
105
|
+
|
106
|
+
test 'ssl_verify_none false by default' do
|
107
|
+
d = create_driver
|
108
|
+
assert_equal false, d.instance.ssl_verify_none
|
109
|
+
end
|
110
|
+
|
111
|
+
test 'use ssl and verify certificates if https endpoint provided' do
|
112
|
+
d = create_driver(%(
|
113
|
+
active_gate_url https://example.dynatrace.com/logs
|
114
|
+
api_token secret
|
115
|
+
))
|
116
|
+
|
117
|
+
assert_equal true, d.instance.agent.original_agent.use_ssl?
|
118
|
+
assert_nil d.instance.agent.original_agent.verify_mode
|
119
|
+
end
|
120
|
+
|
121
|
+
test 'use ssl and skip verification if https endpoint and ssl_verify_none' do
|
122
|
+
d = create_driver(%(
|
123
|
+
active_gate_url https://example.dynatrace.com/logs
|
124
|
+
api_token secret
|
125
|
+
ssl_verify_none true
|
126
|
+
))
|
127
|
+
|
128
|
+
assert_equal true, d.instance.agent.original_agent.use_ssl?
|
129
|
+
assert_equal OpenSSL::SSL::VERIFY_NONE, d.instance.agent.original_agent.verify_mode
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
sub_test_case 'tests for #write' do
|
134
|
+
test 'Write all records as a JSON array' do
|
135
|
+
d = create_driver
|
136
|
+
t = event_time('2016-06-10 19:46:32 +0900')
|
137
|
+
d.run do
|
138
|
+
d.feed('tag', t, { 'message' => 'this is a test message', 'amount' => 53 })
|
139
|
+
d.feed('tag', t, { 'message' => 'this is a second test message', 'amount' => 54 })
|
140
|
+
end
|
141
|
+
|
142
|
+
assert_equal 2, d.instance.agent.result.data.length
|
143
|
+
|
144
|
+
content = d.instance.agent.result.data[0]
|
145
|
+
|
146
|
+
assert_equal "fluent-plugin-dynatrace v#{Fluent::Plugin::DynatraceOutputConstants.version}",
|
147
|
+
d.instance.agent.result.headers['user-agent']
|
148
|
+
assert_equal content['message'], 'this is a test message'
|
149
|
+
assert_equal content['amount'], 53
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
metadata
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fluent-plugin-dynatrace
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Dynatrace Open Source Engineering
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-02-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: fluentd
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.14.22
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '2'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.14.22
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '2'
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: bundler
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '2'
|
40
|
+
- - "<"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '3'
|
43
|
+
type: :development
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '2'
|
50
|
+
- - "<"
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '3'
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: rake
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - '='
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: 13.0.3
|
60
|
+
type: :development
|
61
|
+
prerelease: false
|
62
|
+
version_requirements: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - '='
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: 13.0.3
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: rubocop
|
69
|
+
requirement: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - '='
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: 1.9.1
|
74
|
+
type: :development
|
75
|
+
prerelease: false
|
76
|
+
version_requirements: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - '='
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: 1.9.1
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
name: rubocop-rake
|
83
|
+
requirement: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - '='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: 0.5.1
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - '='
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: 0.5.1
|
95
|
+
description:
|
96
|
+
email:
|
97
|
+
- opensource@dynatrace.com
|
98
|
+
executables: []
|
99
|
+
extensions: []
|
100
|
+
extra_rdoc_files: []
|
101
|
+
files:
|
102
|
+
- ".github/workflows/integration.yaml"
|
103
|
+
- ".github/workflows/lint.yaml"
|
104
|
+
- ".github/workflows/release.yaml"
|
105
|
+
- ".github/workflows/unit.yaml"
|
106
|
+
- ".gitignore"
|
107
|
+
- ".rubocop.yml"
|
108
|
+
- CODE_OF_CONDUCT.md
|
109
|
+
- Gemfile
|
110
|
+
- LICENSE
|
111
|
+
- README.md
|
112
|
+
- Rakefile
|
113
|
+
- fluent-plugin-dynatrace.gemspec
|
114
|
+
- lib/fluent/plugin/dynatrace_constants.rb
|
115
|
+
- lib/fluent/plugin/out_dynatrace.rb
|
116
|
+
- test/.rubocop.yml
|
117
|
+
- test/integration/fixtures/docker-compose.yaml
|
118
|
+
- test/integration/fixtures/fluent/Dockerfile
|
119
|
+
- test/integration/fixtures/fluent/entrypoint.sh
|
120
|
+
- test/integration/fixtures/fluent/fluent.conf
|
121
|
+
- test/integration/fixtures/logsink/Dockerfile
|
122
|
+
- test/integration/fixtures/logsink/server.js
|
123
|
+
- test/integration/integration_test.rb
|
124
|
+
- test/plugin/out_dynatrace_test.rb
|
125
|
+
homepage: https://www.dynatrace.com/
|
126
|
+
licenses:
|
127
|
+
- Apache-2.0
|
128
|
+
metadata:
|
129
|
+
bug_tracker_uri: https://github.com/dynatrace-oss/fluent-plugin-dynatrace/issues
|
130
|
+
documentation_uri: https://github.com/dynatrace-oss/fluent-plugin-dynatrace
|
131
|
+
source_code_uri: https://github.com/dynatrace-oss/fluent-plugin-dynatrace
|
132
|
+
post_install_message:
|
133
|
+
rdoc_options: []
|
134
|
+
require_paths:
|
135
|
+
- lib
|
136
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
137
|
+
requirements:
|
138
|
+
- - ">="
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: 2.4.0
|
141
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
requirements: []
|
147
|
+
rubygems_version: 3.1.4
|
148
|
+
signing_key:
|
149
|
+
specification_version: 4
|
150
|
+
summary: A fluentd output plugin for sending logs to the Dynatrace Generic log ingest
|
151
|
+
API v2
|
152
|
+
test_files: []
|