fluent-plugin-dynatrace 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,97 @@
1
+ # fluent-plugin-dynatrace, a plugin for [fluentd](https://www.fluentd.org/)
2
+
3
+ > This project is developed and maintained by Dynatrace R&D.
4
+ Currently, this is a prototype and not intended for production use.
5
+ It is not covered by Dynatrace support.
6
+
7
+ A fluentd output plugin for sending logs to the Dynatrace [Generic log ingest API v2](https://www.dynatrace.com/support/help/how-to-use-dynatrace/log-monitoring/log-monitoring-v2/post-log-ingest/).
8
+
9
+ ## Requirements
10
+
11
+ - An instance of fluentd from which logs should be exported
12
+ - An ActiveGate with the Generic log ingest API v2 enabled as described in the [Dynatrace documentation](https://www.dynatrace.com/support/help/how-to-use-dynatrace/log-monitoring/log-monitoring-v2/log-data-ingestion/)
13
+ - A [Dynatrace API token](https://www.dynatrace.com/support/help/dynatrace-api/basics/dynatrace-api-authentication/) with the `Log import` permission
14
+
15
+ ## Configuration options
16
+
17
+ Below is an example configuration which sends all logs with tags starting with `dt.` to Dynatrace.
18
+
19
+ ```
20
+ <match dt.*>
21
+ @type dynatrace
22
+ active_gate_url https://abc12345.live.dynatrace.com/api/v2/logs/ingest
23
+ api_token api_token
24
+ ssl_verify_none false
25
+ </match>
26
+ ```
27
+
28
+ ### match directive
29
+
30
+ - `required`
31
+
32
+ The `match` directive is required to use an output plugin and tells fluentd which tags should be sent to the output plugin. In the above example, any tag that starts with `dt.` will be sent to Dynatrace. For more information see [how do match patterns work?](https://docs.fluentd.org/configuration/config-file#how-do-the-match-patterns-work).
33
+
34
+ ### @type
35
+
36
+ - `required`
37
+
38
+ The `@type` directive tells fluentd which plugin should be used for the corresponding match block. This should always be `dynatrace` when you want to use the Dynatrace output plugin.
39
+
40
+ ### `active_gate_url`
41
+
42
+ - `required`
43
+
44
+ This is the full URL of the [Generic log ingest API v2](https://www.dynatrace.com/support/help/how-to-use-dynatrace/log-monitoring/log-monitoring-v2/post-log-ingest/) endpoint on your ActiveGate.
45
+
46
+ ### `api_token`
47
+
48
+ - `required`
49
+
50
+ This is the [Dynatrace API token](https://www.dynatrace.com/support/help/dynatrace-api/basics/dynatrace-api-authentication/) which will be used to authenticate log ingest requests. It should be assigned only the `Log import` permission.
51
+
52
+ ### `ssl_verify_none`
53
+
54
+ - `optional`
55
+ - `default: false`
56
+
57
+ It is recommended to leave this optional configuration set to `false` unless absolutely required. Setting `ssl_verify_none` to `true` causes the output plugin to skip certificate verification when sending log ingest requests to SSL and TLS protected HTTPS endpoints. This option may be required if you are using a self-signed certificate, an expired certificate, or a certificate which was generated for a different domain than the one in use.
58
+
59
+ ## Development
60
+
61
+ `fluent-plugin-dynatrace` supports Ruby versions `>= 2.4.0` but it is recommended that at least `2.7.2` is used for development. Ruby versions can be managed with tools like [chruby](https://github.com/postmodern/chruby) or [rbenv](https://github.com/rbenv/rbenv).
62
+
63
+ ### Install Dependencies
64
+
65
+ ```sh
66
+ bundle install
67
+ ```
68
+
69
+ ### Run All Tests
70
+
71
+ ```sh
72
+ rake test
73
+ ```
74
+
75
+ ### Run Specific Tests
76
+
77
+ ```sh
78
+ # Run one test file
79
+ rake test TEST=test/plugin/out_dynatrace_test.rb
80
+ ```
81
+
82
+ ### Code Style Checks
83
+
84
+ ```sh
85
+ # Check for code style violations
86
+ rake rubocop
87
+
88
+ # Fix auto-fixable style violations
89
+ rake rubocop:auto_correct
90
+ ```
91
+
92
+ ### Run all checks and build
93
+
94
+ ```sh
95
+ # Runs rubocop, tests, and builds the gem
96
+ rake check
97
+ ```
data/Rakefile ADDED
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env rake
2
+ # frozen_string_literal: true
3
+
4
+ # Copyright 2021 Dynatrace LLC
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+
18
+ require 'bundler/gem_tasks'
19
+ require 'rake/testtask'
20
+ require 'rubocop/rake_task'
21
+
22
+ RuboCop::RakeTask.new
23
+
24
+ Rake::TestTask.new :test do |t|
25
+ t.libs << 'test'
26
+ t.libs << 'lib'
27
+ t.test_files = FileList['test/plugin/*_test.rb']
28
+ end
29
+
30
+ Rake::TestTask.new 'test:integration' do |t|
31
+ t.test_files = FileList['test/integration/*_test.rb']
32
+ end
33
+
34
+ desc 'check for style violations and test failures and build the gem'
35
+ task check: %i[rubocop test build]
36
+
37
+ task default: :build
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require './lib/fluent/plugin/dynatrace_constants'
4
+
5
+ Gem::Specification.new do |gem|
6
+ gem.name = 'fluent-plugin-dynatrace'
7
+ gem.version = Fluent::Plugin::DynatraceOutputConstants.version
8
+ gem.authors = ['Dynatrace Open Source Engineering']
9
+ gem.email = ['opensource@dynatrace.com']
10
+ gem.summary = 'A fluentd output plugin for sending logs to the Dynatrace Generic log ingest API v2'
11
+ gem.homepage = 'https://www.dynatrace.com/'
12
+ gem.licenses = ['Apache-2.0']
13
+
14
+ gem.metadata = {
15
+ 'bug_tracker_uri' => 'https://github.com/dynatrace-oss/fluent-plugin-dynatrace/issues',
16
+ 'documentation_uri' => 'https://github.com/dynatrace-oss/fluent-plugin-dynatrace',
17
+ 'source_code_uri' => 'https://github.com/dynatrace-oss/fluent-plugin-dynatrace'
18
+ }
19
+
20
+ gem.files = `git ls-files`.split($OUTPUT_RECORD_SEPARATOR)
21
+ gem.require_paths = ['lib']
22
+
23
+ gem.required_ruby_version = '>= 2.4.0'
24
+
25
+ gem.add_runtime_dependency 'fluentd', ['>= 0.14.22', '< 2']
26
+ gem.add_development_dependency 'bundler', ['>= 2', '<3']
27
+ gem.add_development_dependency 'rake', '13.0.3'
28
+ gem.add_development_dependency 'rubocop', '1.9.1'
29
+ gem.add_development_dependency 'rubocop-rake', '0.5.1'
30
+ end
@@ -0,0 +1,27 @@
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
+ module Fluent
18
+ module Plugin
19
+ # Constants for use in Dynatrace output plugin
20
+ class DynatraceOutputConstants
21
+ # The version of the Dynatrace output plugin
22
+ def self.version
23
+ '0.1.0'
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,139 @@
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/plugin/output'
18
+ require 'net/http'
19
+ require_relative 'dynatrace_constants'
20
+
21
+ module Fluent
22
+ module Plugin
23
+ # Fluentd output plugin for Dynatrace
24
+ class DynatraceOutput < Output
25
+ Fluent::Plugin.register_output('dynatrace', self)
26
+
27
+ helpers :compat_parameters # add :inject if need be
28
+
29
+ # Configurations
30
+ desc 'The full URL of the Dynatrace log ingestion endpoint, e.g. https://my-active-gate.example.com/api/logs/ingest'
31
+ config_param :active_gate_url, :string
32
+ desc 'The API token to use to authenticate requests to the log ingestion endpoint. Must have TODO scope'
33
+ config_param :api_token, :string, secret: true
34
+
35
+ desc 'Disable SSL validation by setting :verify_mode OpenSSL::SSL::VERIFY_NONE'
36
+ config_param :ssl_verify_none, :bool, default: false
37
+
38
+ #############################################
39
+
40
+ config_section :buffer do
41
+ config_set_default :flush_at_shutdown, true
42
+ config_set_default :chunk_limit_size, 10 * 1024
43
+ end
44
+
45
+ # Default injection parameters.
46
+ # Requires the :inject helper to be added to the helpers above and the
47
+ # inject lines to be uncommented in the #write and #process methods
48
+ # config_section :inject do
49
+ # config_set_default :time_type, :string
50
+ # config_set_default :localtime, false
51
+ # end
52
+ #############################################
53
+
54
+ attr_accessor :uri, :agent
55
+
56
+ def configure(conf)
57
+ compat_parameters_convert(conf, :inject)
58
+ super
59
+
60
+ @uri = URI.parse(@active_gate_url)
61
+ @agent = Net::HTTP.new(@uri.host, @uri.port)
62
+
63
+ return unless uri.scheme == 'https'
64
+
65
+ @agent.use_ssl = true
66
+ @agent.verify_mode = OpenSSL::SSL::VERIFY_NONE if @ssl_verify_none
67
+ end
68
+
69
+ def shutdown
70
+ @agent.finish if @agent.started?
71
+ super
72
+ end
73
+
74
+ #############################################
75
+
76
+ def process(_tag, es)
77
+ # es = inject_values_to_event_stream(tag, es)
78
+ es.each do |_time, record|
79
+ send_to_dynatrace("#{record.to_json.chomp}\n")
80
+ end
81
+ end
82
+
83
+ def write(chunk)
84
+ body = []
85
+ chunk.each do |_time, record|
86
+ # body.push(inject_values_to_record(chunk.metadata.tag, time, record))
87
+ body.push(record)
88
+ end
89
+
90
+ send_to_dynatrace("#{body.to_json.chomp}\n")
91
+ end
92
+
93
+ #############################################
94
+
95
+ def prefer_buffered_processing
96
+ true
97
+ end
98
+
99
+ def multi_workers_ready?
100
+ false
101
+ end
102
+
103
+ #############################################
104
+
105
+ def user_agent
106
+ "fluent-plugin-dynatrace v#{DynatraceOutputConstants.version}"
107
+ end
108
+
109
+ def prepare_request(uri)
110
+ req = Net::HTTP::Post.new(uri, { 'User-Agent' => user_agent })
111
+ req['Content-Type'] = 'application/json; charset=utf-8'
112
+ req['Authorization'] = "Api-Token #{@api_token}"
113
+
114
+ req
115
+ end
116
+
117
+ def send_to_dynatrace(body)
118
+ agent.start unless agent.started?
119
+
120
+ req = prepare_request(@uri)
121
+ res = @agent.request(req, body)
122
+
123
+ return if res.is_a?(Net::HTTPSuccess)
124
+
125
+ raise failure_message res
126
+ end
127
+
128
+ def failure_message(res)
129
+ res_summary = if res
130
+ "#{res.code} #{res.message}"
131
+ else
132
+ 'res=nil'
133
+ end
134
+
135
+ "failed to #{req.method} #{uri} (#{res_summary})"
136
+ end
137
+ end
138
+ end
139
+ end
data/test/.rubocop.yml ADDED
@@ -0,0 +1,5 @@
1
+ inherit_from: ../.rubocop.yml
2
+
3
+ Metrics:
4
+ Enabled: false
5
+
@@ -0,0 +1,27 @@
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
+ services:
16
+ fluent:
17
+ build:
18
+ context: ../../../
19
+ dockerfile: test/integration/fixtures/fluent/Dockerfile
20
+ ports:
21
+ - 8080:8080
22
+ links:
23
+ - logsink
24
+ logsink:
25
+ build: logsink
26
+ expose:
27
+ - 8080
@@ -0,0 +1,30 @@
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 fluent/fluentd:edge
16
+
17
+ LABEL maintainer="Daniel Dyla <Daniel.Dyla@dynatrace.com>"
18
+ USER root
19
+
20
+ # the build context is the root of the repo to allow access to the plugin rb
21
+ COPY test/integration/fixtures/fluent/entrypoint.sh /fluentd/entrypoint.sh
22
+ RUN chmod +x /fluentd/entrypoint.sh
23
+
24
+ COPY test/integration/fixtures/fluent/fluent.conf /fluentd/etc/fluent.conf
25
+ COPY lib/fluent/plugin/out_dynatrace.rb /fluentd/plugins/
26
+ COPY lib/fluent/plugin/dynatrace_constants.rb /fluentd/plugins/
27
+
28
+ ENTRYPOINT ["tini", "--", "/fluentd/entrypoint.sh"]
29
+
30
+ USER fluent
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env sh
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
+ exec fluentd -c /fluentd/etc/fluent.conf -p /fluentd/plugins
@@ -0,0 +1,30 @@
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
+ <source>
16
+ @type http
17
+ port 8080
18
+ </source>
19
+
20
+ <match dt.*>
21
+ @type dynatrace
22
+
23
+ active_gate_url http://logsink:8080/api/v2/logs/ingest
24
+ api_token my_token
25
+
26
+ <buffer>
27
+ chunk_limit_records 5
28
+ flush_interval 5s
29
+ </buffer>
30
+ </match>