fluent-plugin-dynatrace 0.1.3 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 11015b23549401ef5812fbc636a3da5a2dc1ff200fad51a1c972f9d9cf54d2e1
4
- data.tar.gz: 87a353d50119fe09e3d11a9ce23f6c20c282b31c4a930dba5336a3c05e95e5f4
3
+ metadata.gz: b25942088d9fc1e97ab3e9c5ee2cfec5baca12f39744bb09012e5f5238522dd9
4
+ data.tar.gz: d942be9cfa1215746fcf513a629d09986d5996ba8a0401622b6d0cf5cdf93cf2
5
5
  SHA512:
6
- metadata.gz: 9d8ea643ef564a15584364fcdb28aabf2118cf145f6d4c82301b7441e7986a9f3c7e7e4f4beb93ccdcc7164f60621b96ad238f56531274f72cf5df84dbd74a19
7
- data.tar.gz: cd0ac68b36280801f40da7de3363bb5e0051ff697870fc6cb4390f7100f22dfadf417c0cb6c5be6641fa79f01a8ba5434e01bae21fb43e78bd8d2fb6a81cbd89
6
+ metadata.gz: 63ca8a3ab6b1e22d7d6e4c29bdcba35e33b145b494f6e736b5cd117feb5af22e647262d0477d9eb72ab316550af2a1469cc7459f0730f3a36fceee79d4834cf0
7
+ data.tar.gz: 9c9532efc4215183ee632ea51a30c27b630b5a239b9fc548e499446fb2dd819ec6c00753e0b3756d435b8625148b59fa1e2c05ad3579d3de5b909fe1c92aa4f7
@@ -20,7 +20,7 @@ module Fluent
20
20
  class DynatraceOutputConstants
21
21
  # The version of the Dynatrace output plugin
22
22
  def self.version
23
- '0.1.3'
23
+ '0.2.0'
24
24
  end
25
25
  end
26
26
  end
@@ -24,17 +24,24 @@ module Fluent
24
24
  class DynatraceOutput < Output
25
25
  Fluent::Plugin.register_output('dynatrace', self)
26
26
 
27
+ HTTP_REQUEST_LOCK = Mutex.new
28
+
27
29
  helpers :compat_parameters # add :inject if need be
28
30
 
29
31
  # Configurations
30
32
  desc 'The full URL of the Dynatrace log ingestion endpoint, e.g. https://my-active-gate.example.com/api/logs/ingest'
31
33
  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'
34
+ desc 'The API token to use to authenticate requests to the log ingestion endpoint. '\
35
+ 'Must have logs.ingest (Ingest Logs) scope. '\
36
+ 'It is recommended to limit scope to only this one.'
33
37
  config_param :api_token, :string, secret: true
34
38
 
35
39
  desc 'Disable SSL validation by setting :verify_mode OpenSSL::SSL::VERIFY_NONE'
36
40
  config_param :ssl_verify_none, :bool, default: false
37
41
 
42
+ desc 'Inject timestamp into each log message'
43
+ config_param :inject_timestamp, :bool, default: false
44
+
38
45
  #############################################
39
46
 
40
47
  config_section :buffer do
@@ -57,7 +64,10 @@ module Fluent
57
64
  compat_parameters_convert(conf, :inject)
58
65
  super
59
66
 
60
- @uri = URI.parse(@active_gate_url)
67
+ raise Fluent::ConfigError, 'api_token is empty' if @api_token.empty?
68
+
69
+ @uri = parse_and_validate_uri(@active_gate_url)
70
+
61
71
  @agent = Net::HTTP.new(@uri.host, @uri.port)
62
72
 
63
73
  return unless uri.scheme == 'https'
@@ -74,20 +84,29 @@ module Fluent
74
84
  #############################################
75
85
 
76
86
  def process(_tag, es)
87
+ log.on_trace { log.trace('#process') }
88
+ records = 0
77
89
  # es = inject_values_to_event_stream(tag, es)
78
- es.each do |_time, record|
79
- send_to_dynatrace("#{record.to_json.chomp}\n")
90
+ es.each do |time, record|
91
+ records += 1
92
+ log.on_trace { log.trace("#process Processing record #{records}") }
93
+ record['@timestamp'] = time * 1000 if @inject_timestamp
94
+ synchronized_send_records(record)
80
95
  end
96
+ log.on_trace { log.trace("#process Processed #{records} records") }
81
97
  end
82
98
 
83
99
  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)
100
+ log.on_trace { log.trace('#write') }
101
+ records = []
102
+ chunk.each do |time, record|
103
+ # records.push(inject_values_to_record(chunk.metadata.tag, time, record))
104
+ record['@timestamp'] = time * 1000 if @inject_timestamp
105
+ records.push(record)
88
106
  end
89
107
 
90
- send_to_dynatrace("#{body.to_json.chomp}\n")
108
+ log.on_trace { log.trace("#write sent #{records.length} records") }
109
+ synchronized_send_records(records) unless records.empty?
91
110
  end
92
111
 
93
112
  #############################################
@@ -106,7 +125,8 @@ module Fluent
106
125
  "fluent-plugin-dynatrace v#{DynatraceOutputConstants.version}"
107
126
  end
108
127
 
109
- def prepare_request(uri)
128
+ def prepare_request
129
+ log.on_trace { log.trace('#prepare_request') }
110
130
  req = Net::HTTP::Post.new(uri, { 'User-Agent' => user_agent })
111
131
  req['Content-Type'] = 'application/json; charset=utf-8'
112
132
  req['Authorization'] = "Api-Token #{@api_token}"
@@ -114,15 +134,37 @@ module Fluent
114
134
  req
115
135
  end
116
136
 
117
- def send_to_dynatrace(body)
137
+ def synchronized_send_records(records)
138
+ log.on_trace { log.trace('#synchronized_send_records') }
139
+ HTTP_REQUEST_LOCK.synchronize do
140
+ send_records(records)
141
+ end
142
+ end
143
+
144
+ def send_records(records)
145
+ log.on_trace { log.trace('#send_records') }
146
+
118
147
  agent.start unless agent.started?
119
148
 
120
- req = prepare_request(@uri)
121
- res = @agent.request(req, body)
149
+ response = send_request(serialize(records))
150
+
151
+ return if response.is_a?(Net::HTTPSuccess)
152
+
153
+ raise failure_message response
154
+ end
122
155
 
123
- return if res.is_a?(Net::HTTPSuccess)
156
+ def serialize(records)
157
+ log.on_trace { log.trace('#serialize') }
158
+ body = "#{records.to_json.chomp}\n"
159
+ log.on_trace { log.trace("#serialize body length #{body.length}") }
160
+ body
161
+ end
124
162
 
125
- raise failure_message res
163
+ def send_request(body)
164
+ log.on_trace { log.trace('#send_request') }
165
+ response = @agent.request(prepare_request, body)
166
+ log.on_trace { log.trace("#send_request response #{response}") }
167
+ response
126
168
  end
127
169
 
128
170
  def failure_message(res)
@@ -134,6 +176,22 @@ module Fluent
134
176
 
135
177
  "failed to request #{uri} (#{res_summary})"
136
178
  end
179
+
180
+ #############################################
181
+
182
+ private
183
+
184
+ def parse_and_validate_uri(uri_string)
185
+ raise Fluent::ConfigError, 'active_gate_url is empty' if uri_string.empty?
186
+
187
+ uri = URI.parse(uri_string)
188
+ raise Fluent::ConfigError, 'active_gate_url scheme must be http or https' unless
189
+ %w[http https].include?(uri.scheme)
190
+
191
+ raise Fluent::ConfigError, 'active_gate_url must include an authority' if uri.host.nil?
192
+
193
+ uri
194
+ end
137
195
  end
138
196
  end
139
197
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-dynatrace
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dynatrace Open Source Engineering
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-04-08 00:00:00.000000000 Z
11
+ date: 2022-02-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fluentd
@@ -124,7 +124,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
124
124
  - !ruby/object:Gem::Version
125
125
  version: '0'
126
126
  requirements: []
127
- rubygems_version: 3.1.4
127
+ rubygems_version: 3.1.6
128
128
  signing_key:
129
129
  specification_version: 4
130
130
  summary: A fluentd output plugin for sending logs to the Dynatrace Generic log ingest