fluent-plugin-opentelemetry 0.3.0 → 0.4.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 +4 -4
- data/.editorconfig +14 -0
- data/.rubocop.yml +3 -0
- data/CHANGELOG.md +4 -0
- data/README.md +35 -2
- data/lib/fluent/plugin/in_opentelemetry_metrics.rb +285 -0
- data/lib/fluent/plugin/opentelemetry/request.rb +6 -6
- data/lib/fluent/plugin/opentelemetry/version.rb +9 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1fce288ab5297db7255a6f89bd709731863d5a8952a08a40276f2f06381bfdf6
|
4
|
+
data.tar.gz: df4713f998552481517d0af45085b99551751e89600d9c6f46e541349173aaf3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8e1d534c9ed6045031b9a40e58751c9c4a1c77e519d37a06dffa9d9d9e97eacccb8e0f90b3931ef925b20268dd97163423aaf05d4013f4b73192fbd46f322f82
|
7
|
+
data.tar.gz: e11de5fbc7b9282a205a653b05f7ed6e6554ac5760ef02b3e9f143875cc771720609095012f343ea5bc0a02daeba6e85baafb7e2a1ffe5fdcb0a7756f40e12a0
|
data/.editorconfig
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# EditorConfig helps developers define and maintain consistent coding styles between different editors and IDEs
|
2
|
+
# @see http://editorconfig.org
|
3
|
+
root = true
|
4
|
+
|
5
|
+
[*]
|
6
|
+
end_of_line = lf
|
7
|
+
charset = utf-8
|
8
|
+
trim_trailing_whitespace = true
|
9
|
+
insert_final_newline = true
|
10
|
+
indent_style = space
|
11
|
+
tab_width = 4
|
12
|
+
|
13
|
+
[*.{rb,yml,yaml,md,conf}]
|
14
|
+
indent_size = 2
|
data/.rubocop.yml
CHANGED
@@ -12,9 +12,12 @@ AllCops:
|
|
12
12
|
|
13
13
|
# rubocop-fluentd
|
14
14
|
Lint/FluentdPluginLogScope:
|
15
|
+
AssumeConfigLogLevel: 'info'
|
15
16
|
Enabled: true
|
16
17
|
Lint/FluentdPluginConfigParamDefaultTime:
|
17
18
|
Enabled: true
|
19
|
+
Lint/FluentdPluginIgnoreStandardError:
|
20
|
+
Enabled: true
|
18
21
|
Performance/FluentdPluginLogStringInterpolation:
|
19
22
|
Enabled: true
|
20
23
|
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -24,7 +24,7 @@ $ bundle
|
|
24
24
|
|
25
25
|
## Configuration
|
26
26
|
|
27
|
-
### Input plugin
|
27
|
+
### Input `opentelemetry` plugin
|
28
28
|
|
29
29
|
To receive data, this plugin requires `<http>` or `<grpc>` section, or both.
|
30
30
|
|
@@ -106,7 +106,40 @@ Refer [Config: Transport Section](https://docs.fluentd.org/configuration/transpo
|
|
106
106
|
</source>
|
107
107
|
```
|
108
108
|
|
109
|
-
###
|
109
|
+
### Input `opentelemetry_metrics` plugin
|
110
|
+
|
111
|
+
This plugin emits Fluentd's metric data that conforms to the OpenTelemetry Protocol.
|
112
|
+
To output the data, it requires to use output `opentelemetry` plugin.
|
113
|
+
|
114
|
+
#### Root section
|
115
|
+
|
116
|
+
| parameter | type | description | default |
|
117
|
+
|--------------------|--------|-------------------------------------------------------|-------------|
|
118
|
+
| tag | string | The tag of the event | required |
|
119
|
+
| emit_interval | time | Determine the rate to emit internal metrics as events | `60` |
|
120
|
+
| metric_name_prefix | string | The prefix of metric name | `fluentd_` |
|
121
|
+
|
122
|
+
#### Example
|
123
|
+
|
124
|
+
```
|
125
|
+
# Emit Fluentd metrics
|
126
|
+
<source>
|
127
|
+
@type opentelemetry_metrics
|
128
|
+
tag opentelemetry.fluentd.metrics
|
129
|
+
emit_interval 300s
|
130
|
+
</source>
|
131
|
+
|
132
|
+
# Send Fluentd metrics to OpenTelemetry Collector
|
133
|
+
<match opentelemetry.fluentd.metrics>
|
134
|
+
@type opentelemetry
|
135
|
+
|
136
|
+
<http>
|
137
|
+
endpoint "https://127.0.0.1:4318"
|
138
|
+
</http>
|
139
|
+
</match>
|
140
|
+
```
|
141
|
+
|
142
|
+
### Output `opentelemetry` plugin
|
110
143
|
|
111
144
|
To send data, this plugin requires `<http>` or `<grpc>` section.
|
112
145
|
|
@@ -0,0 +1,285 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "fluent/plugin/input"
|
4
|
+
require "fluent/plugin/opentelemetry/constant"
|
5
|
+
require "fluent/plugin/opentelemetry/version"
|
6
|
+
require "fluent/plugin_helper/timer"
|
7
|
+
require "fluent/version"
|
8
|
+
|
9
|
+
require "json"
|
10
|
+
require "socket"
|
11
|
+
|
12
|
+
module Fluent::Plugin
|
13
|
+
class OpentelemetryMetricsInput < Input
|
14
|
+
Fluent::Plugin.register_input("opentelemetry_metrics", self)
|
15
|
+
|
16
|
+
helpers :timer
|
17
|
+
|
18
|
+
desc "Determine the rate to emit internal metrics as events."
|
19
|
+
config_param :emit_interval, :time, default: 60
|
20
|
+
|
21
|
+
desc "The tag of the event."
|
22
|
+
config_param :tag, :string
|
23
|
+
|
24
|
+
desc "The prefix of metric name."
|
25
|
+
config_param :metric_name_prefix, :string, default: "fluentd_"
|
26
|
+
|
27
|
+
def start
|
28
|
+
super
|
29
|
+
|
30
|
+
@metrics = Metrics.new(metric_name_prefix: @metric_name_prefix)
|
31
|
+
timer_execute(:in_opentelemetry_metrics, @emit_interval) do
|
32
|
+
router.emit(@tag, Fluent::EventTime.now, { "type" => Opentelemetry::RECORD_TYPE_METRICS, "message" => @metrics.record })
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
module Extension
|
37
|
+
refine Time do
|
38
|
+
def to_nano_sec
|
39
|
+
(to_i * 1_000_000_000) + nsec
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class Metrics
|
45
|
+
using Extension
|
46
|
+
|
47
|
+
def initialize(metric_name_prefix:)
|
48
|
+
@start_time_unix_nano = Time.now.to_nano_sec
|
49
|
+
@metric_name_prefix = metric_name_prefix.to_s
|
50
|
+
@hostname = Socket.gethostname
|
51
|
+
@monitor_info = MonitorInfo.new
|
52
|
+
end
|
53
|
+
|
54
|
+
def record
|
55
|
+
values.to_json
|
56
|
+
end
|
57
|
+
|
58
|
+
def values
|
59
|
+
metrics_data
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def metrics_data
|
65
|
+
{
|
66
|
+
"resourceMetrics" => [
|
67
|
+
{
|
68
|
+
"resource" => {
|
69
|
+
"attributes" => [
|
70
|
+
string_value_attribute("service.name", "fluentd"),
|
71
|
+
string_value_attribute("service.version", Fluent::VERSION),
|
72
|
+
string_value_attribute("host.name", @hostname),
|
73
|
+
string_value_attribute("process.runtime.name", "ruby"),
|
74
|
+
string_value_attribute("process.runtime.version", RUBY_VERSION),
|
75
|
+
int_value_attribute("process.pid", Process.pid)
|
76
|
+
]
|
77
|
+
},
|
78
|
+
"scopeMetrics" => scope_metrics
|
79
|
+
}
|
80
|
+
]
|
81
|
+
}
|
82
|
+
end
|
83
|
+
|
84
|
+
def scope_metrics
|
85
|
+
[
|
86
|
+
{
|
87
|
+
"scope" => {
|
88
|
+
"name" => "fluent-plugin-opentelemetry",
|
89
|
+
"version" => Fluent::Plugin::Opentelemetry::VERSION
|
90
|
+
},
|
91
|
+
"metrics" => metrics
|
92
|
+
}
|
93
|
+
]
|
94
|
+
end
|
95
|
+
|
96
|
+
def metrics
|
97
|
+
time_nano_sec = Time.now.to_nano_sec
|
98
|
+
metrics = []
|
99
|
+
|
100
|
+
@monitor_info.plugins_info_all.each do |record|
|
101
|
+
attributes = {
|
102
|
+
plugin_id: record["plugin_id"],
|
103
|
+
plugin: plugin_name(record["plugin_category"], record["type"]),
|
104
|
+
plugin_category: record["plugin_category"],
|
105
|
+
plugin_type: record["type"]
|
106
|
+
}.map { |k, v| string_value_attribute(k, v) }
|
107
|
+
|
108
|
+
record.each do |key, value|
|
109
|
+
next unless value.is_a?(Numeric)
|
110
|
+
|
111
|
+
metrics << {
|
112
|
+
"name" => @metric_name_prefix + key.to_s,
|
113
|
+
"unit" => "1",
|
114
|
+
# TODO: "description"
|
115
|
+
"gauge" => {
|
116
|
+
"dataPoints" => [
|
117
|
+
{
|
118
|
+
"startTimeUnixNano" => @start_time_unix_nano,
|
119
|
+
"timeUnixNano" => time_nano_sec,
|
120
|
+
"asDouble" => value,
|
121
|
+
"attributes" => attributes
|
122
|
+
}
|
123
|
+
]
|
124
|
+
}
|
125
|
+
}
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
metrics
|
130
|
+
end
|
131
|
+
|
132
|
+
def plugin_name(category, type)
|
133
|
+
prefix =
|
134
|
+
case category
|
135
|
+
when "input"
|
136
|
+
"in"
|
137
|
+
when "output"
|
138
|
+
"out"
|
139
|
+
else
|
140
|
+
category
|
141
|
+
end
|
142
|
+
|
143
|
+
"#{prefix}_#{type}"
|
144
|
+
end
|
145
|
+
|
146
|
+
def string_value_attribute(key, value)
|
147
|
+
{
|
148
|
+
"key" => key.to_s,
|
149
|
+
"value" => {
|
150
|
+
"stringValue" => value.to_s
|
151
|
+
}
|
152
|
+
}
|
153
|
+
end
|
154
|
+
|
155
|
+
def int_value_attribute(key, value)
|
156
|
+
{
|
157
|
+
"key" => key.to_s,
|
158
|
+
"value" => {
|
159
|
+
"intValue" => value
|
160
|
+
}
|
161
|
+
}
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
# Imported from Fluent::Plugin::MonitorAgentInput
|
166
|
+
class MonitorInfo
|
167
|
+
# They are deprecated but remain for compatibiscripts/pluginslity
|
168
|
+
MONITOR_INFO = {
|
169
|
+
"output_plugin" => -> { is_a?(::Fluent::Plugin::Output) },
|
170
|
+
"buffer_queue_length" => lambda {
|
171
|
+
throw(:skip) unless instance_variable_defined?(:@buffer) && !@buffer.nil? && @buffer.is_a?(::Fluent::Plugin::Buffer)
|
172
|
+
@buffer.queue.size
|
173
|
+
},
|
174
|
+
"buffer_timekeys" => lambda {
|
175
|
+
throw(:skip) unless instance_variable_defined?(:@buffer) && !@buffer.nil? && @buffer.is_a?(::Fluent::Plugin::Buffer)
|
176
|
+
@buffer.timekeys
|
177
|
+
},
|
178
|
+
"buffer_total_queued_size" => lambda {
|
179
|
+
throw(:skip) unless instance_variable_defined?(:@buffer) && !@buffer.nil? && @buffer.is_a?(::Fluent::Plugin::Buffer)
|
180
|
+
@buffer.stage_size + @buffer.queue_size
|
181
|
+
},
|
182
|
+
"retry_count" => -> { respond_to?(:num_errors) ? num_errors : nil }
|
183
|
+
}.freeze
|
184
|
+
|
185
|
+
def all_plugins
|
186
|
+
array = []
|
187
|
+
|
188
|
+
# get all input plugins
|
189
|
+
array.concat Fluent::Engine.root_agent.inputs
|
190
|
+
|
191
|
+
# get all output plugins
|
192
|
+
array.concat Fluent::Engine.root_agent.outputs
|
193
|
+
|
194
|
+
# get all filter plugins
|
195
|
+
array.concat Fluent::Engine.root_agent.filters
|
196
|
+
|
197
|
+
Fluent::Engine.root_agent.labels.each_value do |l|
|
198
|
+
# TODO: Add label name to outputs / filters for identifying plugins
|
199
|
+
array.concat l.outputs
|
200
|
+
array.concat l.filters
|
201
|
+
end
|
202
|
+
|
203
|
+
array
|
204
|
+
end
|
205
|
+
|
206
|
+
def plugin_category(pe)
|
207
|
+
case pe
|
208
|
+
when Fluent::Plugin::Input
|
209
|
+
"input"
|
210
|
+
when Fluent::Plugin::Output, Fluent::Plugin::MultiOutput, Fluent::Plugin::BareOutput
|
211
|
+
"output"
|
212
|
+
when Fluent::Plugin::Filter
|
213
|
+
"filter"
|
214
|
+
else
|
215
|
+
"unknown"
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
def plugins_info_all(opts = {})
|
220
|
+
all_plugins.map do |pe|
|
221
|
+
get_monitor_info(pe, opts)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
IGNORE_ATTRIBUTES = %i(@config_root_section @config @masked_config).freeze
|
226
|
+
|
227
|
+
# get monitor info from the plugin `pe` and return a hash object
|
228
|
+
def get_monitor_info(pe, opts = {})
|
229
|
+
obj = {}
|
230
|
+
|
231
|
+
# Common plugin information
|
232
|
+
obj["plugin_id"] = pe.plugin_id
|
233
|
+
obj["plugin_category"] = plugin_category(pe)
|
234
|
+
obj["type"] = pe.config["@type"]
|
235
|
+
obj["config"] = pe.config if opts[:with_config]
|
236
|
+
|
237
|
+
# run MONITOR_INFO in plugins' instance context and store the info to obj
|
238
|
+
MONITOR_INFO.each_pair do |key, code|
|
239
|
+
catch(:skip) do
|
240
|
+
obj[key] = pe.instance_exec(&code)
|
241
|
+
end
|
242
|
+
rescue NoMethodError => e
|
243
|
+
unless @first_warn
|
244
|
+
log.error "NoMethodError in monitoring plugins", key: key, plugin: pe.class, error: e
|
245
|
+
log.error_backtrace
|
246
|
+
@first_warn = true
|
247
|
+
end
|
248
|
+
rescue StandardError => e
|
249
|
+
log.warn "unexpected error in monitoring plugins", key: key, plugin: pe.class, error: e
|
250
|
+
end
|
251
|
+
|
252
|
+
if pe.respond_to?(:statistics)
|
253
|
+
obj.merge!(pe.statistics["output"] || {})
|
254
|
+
obj.merge!(pe.statistics["filter"] || {})
|
255
|
+
obj.merge!(pe.statistics["input"] || {})
|
256
|
+
end
|
257
|
+
|
258
|
+
obj["retry"] = get_retry_info(pe.retry) if opts[:with_retry] && pe.instance_variable_defined?(:@retry)
|
259
|
+
|
260
|
+
# include all instance variables if :with_debug_info is set
|
261
|
+
if opts[:with_debug_info]
|
262
|
+
iv = {}
|
263
|
+
pe.instance_eval do
|
264
|
+
instance_variables.each do |sym|
|
265
|
+
next if IGNORE_ATTRIBUTES.include?(sym)
|
266
|
+
|
267
|
+
key = sym.to_s[1..] # removes first '@'
|
268
|
+
iv[key] = instance_variable_get(sym)
|
269
|
+
end
|
270
|
+
end
|
271
|
+
obj["instance_variables"] = iv
|
272
|
+
elsif (ivars = opts[:ivars])
|
273
|
+
iv = {}
|
274
|
+
ivars.each do |name|
|
275
|
+
iname = "@#{name}"
|
276
|
+
iv[name] = pe.instance_variable_get(iname) if pe.instance_variable_defined?(iname)
|
277
|
+
end
|
278
|
+
obj["instance_variables"] = iv
|
279
|
+
end
|
280
|
+
|
281
|
+
obj
|
282
|
+
end
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
@@ -9,10 +9,10 @@ require "google/protobuf"
|
|
9
9
|
|
10
10
|
class Fluent::Plugin::Opentelemetry::Request
|
11
11
|
class Logs
|
12
|
-
def initialize(body)
|
12
|
+
def initialize(body, ignore_unknown_fields: true)
|
13
13
|
@request =
|
14
14
|
if body.start_with?("{")
|
15
|
-
Opentelemetry::Proto::Collector::Logs::V1::ExportLogsServiceRequest.decode_json(body, ignore_unknown_fields:
|
15
|
+
Opentelemetry::Proto::Collector::Logs::V1::ExportLogsServiceRequest.decode_json(body, ignore_unknown_fields: ignore_unknown_fields)
|
16
16
|
else
|
17
17
|
Opentelemetry::Proto::Collector::Logs::V1::ExportLogsServiceRequest.decode(body)
|
18
18
|
end
|
@@ -28,10 +28,10 @@ class Fluent::Plugin::Opentelemetry::Request
|
|
28
28
|
end
|
29
29
|
|
30
30
|
class Metrics
|
31
|
-
def initialize(body)
|
31
|
+
def initialize(body, ignore_unknown_fields: true)
|
32
32
|
@request =
|
33
33
|
if body.start_with?("{")
|
34
|
-
Opentelemetry::Proto::Collector::Metrics::V1::ExportMetricsServiceRequest.decode_json(body, ignore_unknown_fields:
|
34
|
+
Opentelemetry::Proto::Collector::Metrics::V1::ExportMetricsServiceRequest.decode_json(body, ignore_unknown_fields: ignore_unknown_fields)
|
35
35
|
else
|
36
36
|
Opentelemetry::Proto::Collector::Metrics::V1::ExportMetricsServiceRequest.decode(body)
|
37
37
|
end
|
@@ -47,10 +47,10 @@ class Fluent::Plugin::Opentelemetry::Request
|
|
47
47
|
end
|
48
48
|
|
49
49
|
class Traces
|
50
|
-
def initialize(body)
|
50
|
+
def initialize(body, ignore_unknown_fields: true)
|
51
51
|
@request =
|
52
52
|
if body.start_with?("{")
|
53
|
-
Opentelemetry::Proto::Collector::Trace::V1::ExportTraceServiceRequest.decode_json(body, ignore_unknown_fields:
|
53
|
+
Opentelemetry::Proto::Collector::Trace::V1::ExportTraceServiceRequest.decode_json(body, ignore_unknown_fields: ignore_unknown_fields)
|
54
54
|
else
|
55
55
|
Opentelemetry::Proto::Collector::Trace::V1::ExportTraceServiceRequest.decode(body)
|
56
56
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluent-plugin-opentelemetry
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shizuo Fujita
|
@@ -72,6 +72,7 @@ executables: []
|
|
72
72
|
extensions: []
|
73
73
|
extra_rdoc_files: []
|
74
74
|
files:
|
75
|
+
- ".editorconfig"
|
75
76
|
- ".rubocop.yml"
|
76
77
|
- CHANGELOG.md
|
77
78
|
- LICENSE
|
@@ -79,6 +80,7 @@ files:
|
|
79
80
|
- Rakefile
|
80
81
|
- TODO.md
|
81
82
|
- lib/fluent/plugin/in_opentelemetry.rb
|
83
|
+
- lib/fluent/plugin/in_opentelemetry_metrics.rb
|
82
84
|
- lib/fluent/plugin/opentelemetry/constant.rb
|
83
85
|
- lib/fluent/plugin/opentelemetry/grpc_input_handler.rb
|
84
86
|
- lib/fluent/plugin/opentelemetry/grpc_output_handler.rb
|
@@ -86,6 +88,7 @@ files:
|
|
86
88
|
- lib/fluent/plugin/opentelemetry/http_output_handler.rb
|
87
89
|
- lib/fluent/plugin/opentelemetry/request.rb
|
88
90
|
- lib/fluent/plugin/opentelemetry/response.rb
|
91
|
+
- lib/fluent/plugin/opentelemetry/version.rb
|
89
92
|
- lib/fluent/plugin/out_opentelemetry.rb
|
90
93
|
- lib/opentelemetry/proto/collector/logs/v1/logs_service_pb.rb
|
91
94
|
- lib/opentelemetry/proto/collector/logs/v1/logs_service_services_pb.rb
|
@@ -122,7 +125,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
122
125
|
- !ruby/object:Gem::Version
|
123
126
|
version: '0'
|
124
127
|
requirements: []
|
125
|
-
rubygems_version: 3.7.
|
128
|
+
rubygems_version: 3.7.2
|
126
129
|
specification_version: 4
|
127
130
|
summary: Fluentd input/output plugin to forward OpenTelemetry Protocol data.
|
128
131
|
test_files: []
|