scout_apm_logging 1.0.3 → 2.0.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.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +17 -2
  3. data/.rubocop.yml +1 -1
  4. data/CHANGELOG.md +9 -0
  5. data/README.md +7 -2
  6. data/lib/scout_apm/logging/config.rb +1 -1
  7. data/lib/scout_apm/logging/loggers/formatter.rb +2 -2
  8. data/lib/scout_apm/logging/loggers/opentelemetry/log_record_patch.rb +38 -0
  9. data/lib/scout_apm/logging/loggers/opentelemetry/opentelemetry.rb +8 -31
  10. data/lib/scout_apm/logging/version.rb +1 -1
  11. data/scout_apm_logging.gemspec +5 -3
  12. data/spec/integration/rails/lifecycle_spec.rb +1 -1
  13. metadata +37 -31
  14. data/lib/scout_apm/logging/loggers/opentelemetry/LICENSE +0 -201
  15. data/lib/scout_apm/logging/loggers/opentelemetry/api/logs/log_record.rb +0 -18
  16. data/lib/scout_apm/logging/loggers/opentelemetry/api/logs/logger.rb +0 -64
  17. data/lib/scout_apm/logging/loggers/opentelemetry/api/logs/logger_provider.rb +0 -31
  18. data/lib/scout_apm/logging/loggers/opentelemetry/api/logs/severity_number.rb +0 -43
  19. data/lib/scout_apm/logging/loggers/opentelemetry/api/logs/version.rb +0 -18
  20. data/lib/scout_apm/logging/loggers/opentelemetry/api/logs.rb +0 -28
  21. data/lib/scout_apm/logging/loggers/opentelemetry/exporter/exporter/otlp/logs_exporter.rb +0 -389
  22. data/lib/scout_apm/logging/loggers/opentelemetry/exporter/exporter/otlp/version.rb +0 -20
  23. data/lib/scout_apm/logging/loggers/opentelemetry/exporter/proto/collector/logs/v1/logs_service_pb.rb +0 -43
  24. data/lib/scout_apm/logging/loggers/opentelemetry/exporter/proto/common/v1/common_pb.rb +0 -58
  25. data/lib/scout_apm/logging/loggers/opentelemetry/exporter/proto/logs/v1/logs_pb.rb +0 -91
  26. data/lib/scout_apm/logging/loggers/opentelemetry/exporter/proto/resource/v1/resource_pb.rb +0 -33
  27. data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/export/batch_log_record_processor.rb +0 -225
  28. data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/export/log_record_exporter.rb +0 -64
  29. data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/export.rb +0 -34
  30. data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/log_record.rb +0 -115
  31. data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/log_record_data.rb +0 -31
  32. data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/log_record_processor.rb +0 -53
  33. data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/logger.rb +0 -94
  34. data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/logger_provider.rb +0 -158
  35. data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/version.rb +0 -20
  36. data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs.rb +0 -28
@@ -1,64 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Copyright The OpenTelemetry Authors
4
- #
5
- # SPDX-License-Identifier: Apache-2.0
6
-
7
- module ScoutApm
8
- module Logging
9
- module Loggers
10
- module OpenTelemetry
11
- module Logs
12
- # No-op implementation of logger.
13
- class Logger
14
- # rubocop:disable Style/EmptyMethod
15
-
16
- # Emit a {LogRecord} to the processing pipeline.
17
- #
18
- # @param timestamp [optional Time] Time when the event occurred.
19
- # @param observed_timestamp [optional Time] Time when the event was
20
- # observed by the collection system.
21
- # @param context [optional Context] The Context to associate with the
22
- # LogRecord. Intended default: OpenTelemetry::Context.current
23
- # @param severity_number [optional Integer] Numerical value of the
24
- # severity. Smaller numerical values correspond to less severe events
25
- # (such as debug events), larger numerical values correspond to more
26
- # severe events (such as errors and critical events).
27
- # @param [optional String] severity_text Original string representation of
28
- # the severity as it is known at the source. Also known as log level.
29
- # @param [optional String, Numeric, Boolean, Array<String, Numeric,
30
- # Boolean>, Hash{String => String, Numeric, Boolean, Array<String,
31
- # Numeric, Boolean>}] body A value containing the body of the log record.
32
- # @param [optional String] trace_id The trace ID associated with the
33
- # current context.
34
- # @param [optional String] span_id The span ID associated with the
35
- # current context.
36
- # @param [optional TraceFlags] trace_flags The trace flags associated
37
- # with the current context.
38
- # @param [optional Hash{String => String, Numeric, Boolean,
39
- # Array<String, Numeric, Boolean>}] attributes Additional information
40
- # about the event.
41
- # @param [optional Context] context The Context to associate with the
42
- # LogRecord. Intended default: OpenTelemetry::Context.current
43
- #
44
- # @api public
45
- def on_emit(
46
- timestamp: nil,
47
- observed_timestamp: nil,
48
- severity_number: nil,
49
- severity_text: nil,
50
- body: nil,
51
- trace_id: nil,
52
- span_id: nil,
53
- trace_flags: nil,
54
- attributes: nil,
55
- context: nil
56
- )
57
- end
58
- # rubocop:enable Style/EmptyMethod
59
- end
60
- end
61
- end
62
- end
63
- end
64
- end
@@ -1,31 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Copyright The OpenTelemetry Authors
4
- #
5
- # SPDX-License-Identifier: Apache-2.0
6
-
7
- module ScoutApm
8
- module Logging
9
- module Loggers
10
- module OpenTelemetry
11
- module Logs
12
- # No-op implementation of a logger provider.
13
- class LoggerProvider
14
- NOOP_LOGGER = OpenTelemetry::Logs::Logger.new
15
- private_constant :NOOP_LOGGER
16
-
17
- # Returns an {OpenTelemetry::Logs::Logger} instance.
18
- #
19
- # @param [optional String] name Instrumentation package name
20
- # @param [optional String] version Instrumentation package version
21
- #
22
- # @return [OpenTelemetry::Logs::Logger]
23
- def logger(name = nil, version = nil)
24
- @logger ||= NOOP_LOGGER
25
- end
26
- end
27
- end
28
- end
29
- end
30
- end
31
- end
@@ -1,43 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Copyright The OpenTelemetry Authors
4
- #
5
- # SPDX-License-Identifier: Apache-2.0
6
-
7
- module ScoutApm
8
- module Logging
9
- module Loggers
10
- module OpenTelemetry
11
- module Logs
12
- class SeverityNumber
13
- SEVERITY_NUMBER_UNSPECIFIED = 0
14
- SEVERITY_NUMBER_TRACE = 1
15
- SEVERITY_NUMBER_TRACE2 = 2
16
- SEVERITY_NUMBER_TRACE3 = 3
17
- SEVERITY_NUMBER_TRACE4 = 4
18
- SEVERITY_NUMBER_DEBUG = 5
19
- SEVERITY_NUMBER_DEBUG2 = 7
20
- SEVERITY_NUMBER_DEBUG3 = 6
21
- SEVERITY_NUMBER_DEBUG4 = 8
22
- SEVERITY_NUMBER_INFO = 9
23
- SEVERITY_NUMBER_INFO2 = 10
24
- SEVERITY_NUMBER_INFO3 = 11
25
- SEVERITY_NUMBER_INFO4 = 12
26
- SEVERITY_NUMBER_WARN = 13
27
- SEVERITY_NUMBER_WARN2 = 14
28
- SEVERITY_NUMBER_WARN3 = 15
29
- SEVERITY_NUMBER_WARN4 = 16
30
- SEVERITY_NUMBER_ERROR = 17
31
- SEVERITY_NUMBER_ERROR2 = 18
32
- SEVERITY_NUMBER_ERROR3 = 19
33
- SEVERITY_NUMBER_ERROR4 = 20
34
- SEVERITY_NUMBER_FATAL = 21
35
- SEVERITY_NUMBER_FATAL2 = 22
36
- SEVERITY_NUMBER_FATAL3 = 23
37
- SEVERITY_NUMBER_FATAL4 = 24
38
- end
39
- end
40
- end
41
- end
42
- end
43
- end
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Copyright The OpenTelemetry Authors
4
- #
5
- # SPDX-License-Identifier: Apache-2.0
6
-
7
- module ScoutApm
8
- module Logging
9
- module Loggers
10
- module OpenTelemetry
11
- module Logs
12
- ## Current OpenTelemetry logs version
13
- VERSION = '0.1.0'
14
- end
15
- end
16
- end
17
- end
18
- end
@@ -1,28 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Copyright The OpenTelemetry Authors
4
- #
5
- # SPDX-License-Identifier: Apache-2.0
6
-
7
- require_relative 'logs/log_record'
8
- require_relative 'logs/logger'
9
- require_relative 'logs/logger_provider'
10
- require_relative 'logs/severity_number'
11
-
12
- module ScoutApm
13
- module Logging
14
- module Loggers
15
- module OpenTelemetry
16
- # The Logs API records a timestamped record with metadata.
17
- # In OpenTelemetry, any data that is not part of a distributed trace or a
18
- # metric is a log. For example, events are a specific type of log.
19
- #
20
- # This API is provided for logging library authors to build log
21
- # appenders/bridges. It should NOT be used directly by application
22
- # developers.
23
- module Logs
24
- end
25
- end
26
- end
27
- end
28
- end
@@ -1,389 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Copyright The OpenTelemetry Authors
4
- #
5
- # SPDX-License-Identifier: Apache-2.0
6
-
7
- require 'opentelemetry/common'
8
- require 'opentelemetry/sdk'
9
- require 'net/http'
10
- require 'zlib'
11
-
12
- require 'google/rpc/status_pb'
13
-
14
- require_relative '../../proto/common/v1/common_pb'
15
- require_relative '../../proto/resource/v1/resource_pb'
16
- require_relative '../../proto/logs/v1/logs_pb'
17
- require_relative '../../proto/collector/logs/v1/logs_service_pb'
18
-
19
- module ScoutApm
20
- module Logging
21
- module Loggers
22
- module OpenTelemetry
23
- module Exporter
24
- module OTLP
25
- # An OpenTelemetry log exporter that sends log records over HTTP as Protobuf encoded OTLP ExportLogsServiceRequests.
26
- class LogsExporter # rubocop:disable Metrics/ClassLength
27
- SUCCESS = OpenTelemetry::SDK::Logs::Export::SUCCESS
28
- FAILURE = OpenTelemetry::SDK::Logs::Export::FAILURE
29
- private_constant(:SUCCESS, :FAILURE)
30
-
31
- # Default timeouts in seconds.
32
- KEEP_ALIVE_TIMEOUT = 30
33
- RETRY_COUNT = 5
34
- WRITE_TIMEOUT_SUPPORTED = Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.6')
35
- private_constant(:KEEP_ALIVE_TIMEOUT, :RETRY_COUNT, :WRITE_TIMEOUT_SUPPORTED)
36
-
37
- ERROR_MESSAGE_INVALID_HEADERS = 'headers must be a String with comma-separated URL Encoded UTF-8 k=v pairs or a Hash'
38
- private_constant(:ERROR_MESSAGE_INVALID_HEADERS)
39
-
40
- DEFAULT_USER_AGENT = "OTel-OTLP-Exporter-Ruby/#{OpenTelemetry::Exporter::OTLP::VERSION} Ruby/#{RUBY_VERSION} (#{RUBY_PLATFORM}; #{RUBY_ENGINE}/#{RUBY_ENGINE_VERSION})".freeze
41
-
42
- def self.ssl_verify_mode
43
- if ENV.key?('OTEL_RUBY_EXPORTER_OTLP_SSL_VERIFY_PEER')
44
- OpenSSL::SSL::VERIFY_PEER
45
- elsif ENV.key?('OTEL_RUBY_EXPORTER_OTLP_SSL_VERIFY_NONE')
46
- OpenSSL::SSL::VERIFY_NONE
47
- else
48
- OpenSSL::SSL::VERIFY_PEER
49
- end
50
- end
51
-
52
- def initialize(endpoint: ::OpenTelemetry::Common::Utilities.config_opt('OTEL_EXPORTER_OTLP_LOGS_ENDPOINT', 'OTEL_EXPORTER_OTLP_ENDPOINT', default: 'http://localhost:4318/v1/logs'),
53
- certificate_file: ::OpenTelemetry::Common::Utilities.config_opt('OTEL_EXPORTER_OTLP_LOGS_CERTIFICATE', 'OTEL_EXPORTER_OTLP_CERTIFICATE'),
54
- ssl_verify_mode: LogsExporter.ssl_verify_mode,
55
- headers: ::OpenTelemetry::Common::Utilities.config_opt('OTEL_EXPORTER_OTLP_LOGS_HEADERS', 'OTEL_EXPORTER_OTLP_HEADERS', default: {}),
56
- compression: ::OpenTelemetry::Common::Utilities.config_opt('OTEL_EXPORTER_OTLP_LOGS_COMPRESSION', 'OTEL_EXPORTER_OTLP_COMPRESSION', default: 'gzip'),
57
- timeout: ::OpenTelemetry::Common::Utilities.config_opt('OTEL_EXPORTER_OTLP_LOGS_TIMEOUT', 'OTEL_EXPORTER_OTLP_TIMEOUT', default: 10))
58
- raise ArgumentError, "invalid url for OTLP::Exporter #{endpoint}" unless ::OpenTelemetry::Common::Utilities.valid_url?(endpoint)
59
- raise ArgumentError, "unsupported compression key #{compression}" unless compression.nil? || %w[gzip none].include?(compression)
60
-
61
- @uri = if endpoint == ENV['OTEL_EXPORTER_OTLP_ENDPOINT']
62
- URI.join(endpoint, 'v1/logs')
63
- else
64
- URI(endpoint)
65
- end
66
-
67
- @http = http_connection(@uri, ssl_verify_mode, certificate_file)
68
-
69
- @path = @uri.path
70
- @headers = prepare_headers(headers)
71
- @timeout = timeout.to_f
72
- @compression = compression
73
- @shutdown = false
74
- end
75
-
76
- # Called to export sampled {OpenTelemetry::SDK::Logs::LogRecordData} structs.
77
- #
78
- # @param [Enumerable<OpenTelemetry::SDK::Logs::LogRecordData>] log_record_data the
79
- # list of recorded {OpenTelemetry::SDK::Logs::LogRecordData} structs to be
80
- # exported.
81
- # @param [optional Numeric] timeout An optional timeout in seconds.
82
- # @return [Integer] the result of the export.
83
- def export(log_record_data, timeout: nil)
84
- OpenTelemetry.logger.error('Logs Exporter tried to export, but it has already shut down') if @shutdown
85
- return FAILURE if @shutdown
86
-
87
- send_bytes(encode(log_record_data), timeout: timeout)
88
- end
89
-
90
- # Called when {OpenTelemetry::SDK::Logs::LoggerProvider#force_flush} is called, if
91
- # this exporter is registered to a {OpenTelemetry::SDK::Logs::LoggerProvider}
92
- # object.
93
- #
94
- # @param [optional Numeric] timeout An optional timeout in seconds.
95
- def force_flush(timeout: nil)
96
- SUCCESS
97
- end
98
-
99
- # Called when {OpenTelemetry::SDK::Logs::LoggerProvider#shutdown} is called, if
100
- # this exporter is registered to a {OpenTelemetry::SDK::Logs::LoggerProvider}
101
- # object.
102
- #
103
- # @param [optional Numeric] timeout An optional timeout in seconds.
104
- def shutdown(timeout: nil)
105
- @shutdown = true
106
- @http.finish if @http.started?
107
- SUCCESS
108
- end
109
-
110
- private
111
-
112
- def http_connection(uri, ssl_verify_mode, certificate_file)
113
- http = Net::HTTP.new(uri.host, uri.port)
114
- http.use_ssl = uri.scheme == 'https'
115
- http.verify_mode = ssl_verify_mode
116
- http.ca_file = certificate_file unless certificate_file.nil?
117
- http.keep_alive_timeout = KEEP_ALIVE_TIMEOUT
118
- http
119
- end
120
-
121
- # The around_request is a private method that provides an extension
122
- # point for the exporters network calls. The default behaviour
123
- # is to not record these operations.
124
- #
125
- # An example use case would be to prepend a patch, or extend this class
126
- # and override this method's behaviour to explicitly record the HTTP request.
127
- # This would allow you to create log records for your export pipeline.
128
- def around_request
129
- ::OpenTelemetry::Common::Utilities.untraced { yield } # rubocop:disable Style/ExplicitBlockArgument
130
- end
131
-
132
- def send_bytes(bytes, timeout:) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
133
- return FAILURE if bytes.nil?
134
-
135
- request = Net::HTTP::Post.new(@path)
136
- if @compression == 'gzip'
137
- request.add_field('Content-Encoding', 'gzip')
138
- body = Zlib.gzip(bytes)
139
- else
140
- body = bytes
141
- end
142
-
143
- request.body = body
144
- request.add_field('Content-Type', 'application/x-protobuf')
145
- @headers.each { |key, value| request.add_field(key, value) }
146
-
147
- retry_count = 0
148
- timeout ||= @timeout
149
- start_time = ::OpenTelemetry::Common::Utilities.timeout_timestamp
150
-
151
- around_request do
152
- remaining_timeout = ::OpenTelemetry::Common::Utilities.maybe_timeout(timeout, start_time)
153
- return FAILURE if remaining_timeout.zero?
154
-
155
- @http.open_timeout = remaining_timeout
156
- @http.read_timeout = remaining_timeout
157
- @http.write_timeout = remaining_timeout if WRITE_TIMEOUT_SUPPORTED
158
- @http.start unless @http.started?
159
- response = measure_request_duration { @http.request(request) }
160
-
161
- case response
162
- when Net::HTTPOK
163
- response.body # Read and discard body
164
- SUCCESS
165
- when Net::HTTPServiceUnavailable, Net::HTTPTooManyRequests
166
- response.body # Read and discard body
167
- redo if backoff?(retry_after: response['Retry-After'], retry_count: retry_count += 1, reason: response.code)
168
- FAILURE
169
- when Net::HTTPRequestTimeOut, Net::HTTPGatewayTimeOut, Net::HTTPBadGateway
170
- response.body # Read and discard body
171
- redo if backoff?(retry_count: retry_count += 1, reason: response.code)
172
- FAILURE
173
- when Net::HTTPNotFound
174
- OpenTelemetry.handle_error(message: "OTLP exporter received http.code=404 for uri: '#{@path}'")
175
- FAILURE
176
- when Net::HTTPBadRequest, Net::HTTPClientError, Net::HTTPServerError
177
- log_status(response.body)
178
- FAILURE
179
- when Net::HTTPRedirection
180
- @http.finish
181
- handle_redirect(response['location'])
182
- redo if backoff?(retry_after: 0, retry_count: retry_count += 1, reason: response.code)
183
- else
184
- @http.finish
185
- FAILURE
186
- end
187
- rescue Net::OpenTimeout, Net::ReadTimeout
188
- retry if backoff?(retry_count: retry_count += 1, reason: 'timeout')
189
- return FAILURE
190
- rescue OpenSSL::SSL::SSLError
191
- retry if backoff?(retry_count: retry_count += 1, reason: 'openssl_error')
192
- return FAILURE
193
- rescue SocketError
194
- retry if backoff?(retry_count: retry_count += 1, reason: 'socket_error')
195
- return FAILURE
196
- rescue SystemCallError => e
197
- retry if backoff?(retry_count: retry_count += 1, reason: e.class.name)
198
- return FAILURE
199
- rescue EOFError
200
- retry if backoff?(retry_count: retry_count += 1, reason: 'eof_error')
201
- return FAILURE
202
- rescue Zlib::DataError
203
- retry if backoff?(retry_count: retry_count += 1, reason: 'zlib_error')
204
- return FAILURE
205
- rescue StandardError => e
206
- OpenTelemetry.handle_error(exception: e, message: 'unexpected error in OTLP::Exporter#send_bytes')
207
- return FAILURE
208
- end
209
- ensure
210
- # Reset timeouts to defaults for the next call.
211
- @http.open_timeout = @timeout
212
- @http.read_timeout = @timeout
213
- @http.write_timeout = @timeout if WRITE_TIMEOUT_SUPPORTED
214
- end
215
-
216
- def handle_redirect(location)
217
- # TODO: figure out destination and reinitialize @http and @path
218
- end
219
-
220
- def log_status(body)
221
- status = Google::Rpc::Status.decode(body)
222
- details = status.details.map do |detail|
223
- klass_or_nil = ::Google::Protobuf::DescriptorPool.generated_pool.lookup(detail.type_name).msgclass
224
- detail.unpack(klass_or_nil) if klass_or_nil
225
- end.compact
226
- OpenTelemetry.handle_error(message: "OTLP exporter received rpc.Status{message=#{status.message}, details=#{details}}")
227
- rescue StandardError => e
228
- OpenTelemetry.handle_error(exception: e, message: 'unexpected error decoding rpc.Status in OTLP::Exporter#log_status')
229
- end
230
-
231
- def measure_request_duration
232
- start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
233
- begin
234
- yield
235
- ensure
236
- stop = Process.clock_gettime(Process::CLOCK_MONOTONIC)
237
- 1000.0 * (stop - start)
238
- end
239
- end
240
-
241
- def backoff?(retry_count:, reason:, retry_after: nil) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
242
- return false if retry_count > RETRY_COUNT
243
-
244
- sleep_interval = nil
245
- unless retry_after.nil?
246
- sleep_interval =
247
- begin
248
- Integer(retry_after)
249
- rescue ArgumentError
250
- nil
251
- end
252
- sleep_interval ||=
253
- begin
254
- Time.httpdate(retry_after) - Time.now
255
- rescue # rubocop:disable Style/RescueStandardError
256
- nil
257
- end
258
- sleep_interval = nil unless sleep_interval&.positive?
259
- end
260
- sleep_interval ||= rand(2**retry_count)
261
-
262
- sleep(sleep_interval)
263
- true
264
- end
265
-
266
- def encode(log_record_data) # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity
267
- Opentelemetry::Proto::Collector::Logs::V1::ExportLogsServiceRequest.encode(
268
- Opentelemetry::Proto::Collector::Logs::V1::ExportLogsServiceRequest.new(
269
- resource_logs: log_record_data
270
- .group_by(&:resource)
271
- .map do |resource, log_record_datas|
272
- Opentelemetry::Proto::Logs::V1::ResourceLogs.new(
273
- resource: Opentelemetry::Proto::Resource::V1::Resource.new(
274
- attributes: resource.attribute_enumerator.map { |key, value| as_otlp_key_value(key, value) }
275
- ),
276
- scope_logs: log_record_datas
277
- .group_by(&:instrumentation_scope)
278
- .map do |il, lrd|
279
- Opentelemetry::Proto::Logs::V1::ScopeLogs.new(
280
- scope: Opentelemetry::Proto::Common::V1::InstrumentationScope.new(
281
- name: il.name,
282
- version: il.version
283
- ),
284
- log_records: lrd.map { |lr| as_otlp_log_record(lr) }
285
- )
286
- end
287
- )
288
- end
289
- )
290
- )
291
- rescue StandardError => e
292
- OpenTelemetry.handle_error(exception: e, message: 'unexpected error in OTLP::Exporter#encode')
293
- nil
294
- end
295
-
296
- def as_otlp_log_record(log_record_data)
297
- Opentelemetry::Proto::Logs::V1::LogRecord.new(
298
- time_unix_nano: log_record_data.timestamp,
299
- observed_time_unix_nano: log_record_data.observed_timestamp,
300
- severity_number: as_otlp_severity_number(log_record_data.severity_number),
301
- severity_text: log_record_data.severity_text,
302
- body: as_otlp_any_value(log_record_data.body),
303
- attributes: log_record_data.attributes&.map { |k, v| as_otlp_key_value(k, v) },
304
- dropped_attributes_count: log_record_data.total_recorded_attributes - log_record_data.attributes&.size.to_i,
305
- flags: log_record_data.trace_flags.instance_variable_get(:@flags),
306
- trace_id: log_record_data.trace_id,
307
- span_id: log_record_data.span_id
308
- )
309
- end
310
-
311
- def as_otlp_key_value(key, value)
312
- Opentelemetry::Proto::Common::V1::KeyValue.new(key: key, value: as_otlp_any_value(value))
313
- rescue Encoding::UndefinedConversionError => e
314
- encoded_value = value.encode('UTF-8', invalid: :replace, undef: :replace, replace: '�')
315
- OpenTelemetry.handle_error(exception: e, message: "encoding error for key #{key} and value #{encoded_value}")
316
- Opentelemetry::Proto::Common::V1::KeyValue.new(key: key, value: as_otlp_any_value('Encoding Error'))
317
- end
318
-
319
- def as_otlp_any_value(value)
320
- result = Opentelemetry::Proto::Common::V1::AnyValue.new
321
- case value
322
- when String
323
- result.string_value = value
324
- when Integer
325
- result.int_value = value
326
- when Float
327
- result.double_value = value
328
- when true, false
329
- result.bool_value = value
330
- when Array
331
- values = value.map { |element| as_otlp_any_value(element) }
332
- result.array_value = Opentelemetry::Proto::Common::V1::ArrayValue.new(values: values)
333
- end
334
- result
335
- end
336
-
337
- # TODO: maybe don't translate the severity number, but translate the severity text into
338
- # the number if the number is nil? Poss. change to allow for adding your own
339
- # otel values?
340
- def as_otlp_severity_number(severity_number)
341
- case severity_number
342
- when 0 then Opentelemetry::Proto::Logs::V1::SeverityNumber::SEVERITY_NUMBER_DEBUG
343
- when 1 then Opentelemetry::Proto::Logs::V1::SeverityNumber::SEVERITY_NUMBER_INFO
344
- when 2 then Opentelemetry::Proto::Logs::V1::SeverityNumber::SEVERITY_NUMBER_WARN
345
- when 3 then Opentelemetry::Proto::Logs::V1::SeverityNumber::SEVERITY_NUMBER_ERROR
346
- when 4 then Opentelemetry::Proto::Logs::V1::SeverityNumber::SEVERITY_NUMBER_FATAL
347
- when 5 then Opentelemetry::Proto::Logs::V1::SeverityNumber::SEVERITY_NUMBER_UNSPECIFIED
348
- end
349
- end
350
-
351
- def prepare_headers(config_headers)
352
- headers = case config_headers
353
- when String then parse_headers(config_headers)
354
- when Hash then config_headers.dup
355
- else
356
- raise ArgumentError, ERROR_MESSAGE_INVALID_HEADERS
357
- end
358
-
359
- headers['User-Agent'] = "#{headers.fetch('User-Agent', '')} #{DEFAULT_USER_AGENT}".strip
360
-
361
- headers
362
- end
363
-
364
- def parse_headers(raw)
365
- entries = raw.split(',')
366
- raise ArgumentError, ERROR_MESSAGE_INVALID_HEADERS if entries.empty?
367
-
368
- entries.each_with_object({}) do |entry, headers|
369
- k, v = entry.split('=', 2).map(&CGI.method(:unescape))
370
- begin
371
- k = k.to_s.strip
372
- v = v.to_s.strip
373
- rescue Encoding::CompatibilityError
374
- raise ArgumentError, ERROR_MESSAGE_INVALID_HEADERS
375
- rescue ArgumentError => e
376
- raise e, ERROR_MESSAGE_INVALID_HEADERS
377
- end
378
- raise ArgumentError, ERROR_MESSAGE_INVALID_HEADERS if k.empty? || v.empty?
379
-
380
- headers[k] = v
381
- end
382
- end
383
- end
384
- end
385
- end
386
- end
387
- end
388
- end
389
- end
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Copyright The OpenTelemetry Authors
4
- #
5
- # SPDX-License-Identifier: Apache-2.0
6
-
7
- module ScoutApm
8
- module Logging
9
- module Loggers
10
- module OpenTelemetry
11
- module Exporter
12
- module OTLP
13
- ## Current OpenTelemetry OTLP logs exporter version
14
- VERSION = '0.26.3'
15
- end
16
- end
17
- end
18
- end
19
- end
20
- end
@@ -1,43 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Generated by the protocol buffer compiler. DO NOT EDIT!
4
- # source: opentelemetry/proto/collector/logs/v1/logs_service.proto
5
-
6
- require 'google/protobuf'
7
-
8
- require_relative '../../../logs/v1/logs_pb'
9
-
10
- Google::Protobuf::DescriptorPool.generated_pool.build do
11
- add_file("scout/opentelemetry/proto/collector/logs/v1/logs_service.proto", :syntax => :proto3) do
12
- add_message "scout_apm.logging.loggers.opentelemetry.proto.collector.logs.v1.ExportLogsServiceRequest" do
13
- repeated :resource_logs, :message, 1, "scout_apm.logging.loggers.opentelemetry.proto.logs.v1.ResourceLogs"
14
- end
15
- add_message "scout_apm.logging.loggers.opentelemetry.proto.collector.logs.v1.ExportLogsServiceResponse" do
16
- optional :partial_success, :message, 1, "scout_apm.logging.loggers.opentelemetry.proto.collector.logs.v1.ExportLogsPartialSuccess"
17
- end
18
- add_message "scout_apm.logging.loggers.opentelemetry.proto.collector.logs.v1.ExportLogsPartialSuccess" do
19
- optional :rejected_log_records, :int64, 1
20
- optional :error_message, :string, 2
21
- end
22
- end
23
- end
24
-
25
- module ScoutApm
26
- module Logging
27
- module Loggers
28
- module Opentelemetry
29
- module Proto
30
- module Collector
31
- module Logs
32
- module V1
33
- ExportLogsServiceRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("scout_apm.logging.loggers.opentelemetry.proto.collector.logs.v1.ExportLogsServiceRequest").msgclass
34
- ExportLogsServiceResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("scout_apm.logging.loggers.opentelemetry.proto.collector.logs.v1.ExportLogsServiceResponse").msgclass
35
- ExportLogsPartialSuccess = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("scout_apm.logging.loggers.opentelemetry.proto.collector.logs.v1.ExportLogsPartialSuccess").msgclass
36
- end
37
- end
38
- end
39
- end
40
- end
41
- end
42
- end
43
- end