scout_apm_logging 1.1.0 → 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 (37) 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 +6 -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 +1 -1
  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 +4 -2
  12. data/spec/integration/rails/lifecycle_spec.rb +1 -1
  13. metadata +36 -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 -398
  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 -223
  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 -170
  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_limits.rb +0 -49
  33. data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/log_record_processor.rb +0 -52
  34. data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/logger.rb +0 -98
  35. data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/logger_provider.rb +0 -170
  36. data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/version.rb +0 -20
  37. data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs.rb +0 -29
@@ -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,398 +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
- private_constant(:KEEP_ALIVE_TIMEOUT, :RETRY_COUNT)
35
-
36
- ERROR_MESSAGE_INVALID_HEADERS = 'headers must be a String with comma-separated URL Encoded UTF-8 k=v pairs or a Hash'
37
- private_constant(:ERROR_MESSAGE_INVALID_HEADERS)
38
-
39
- DEFAULT_USER_AGENT = "OTel-OTLP-Exporter-Ruby/#{OpenTelemetry::Exporter::OTLP::VERSION} Ruby/#{RUBY_VERSION} (#{RUBY_PLATFORM}; #{RUBY_ENGINE}/#{RUBY_ENGINE_VERSION})".freeze
40
-
41
- def self.ssl_verify_mode
42
- if ENV['OTEL_RUBY_EXPORTER_OTLP_SSL_VERIFY_PEER'] == 'true'
43
- OpenSSL::SSL::VERIFY_PEER
44
- elsif ENV['OTEL_RUBY_EXPORTER_OTLP_SSL_VERIFY_NONE'] == 'true'
45
- OpenSSL::SSL::VERIFY_NONE
46
- else
47
- OpenSSL::SSL::VERIFY_PEER
48
- end
49
- end
50
-
51
- def initialize(endpoint: ::OpenTelemetry::Common::Utilities.config_opt('OTEL_EXPORTER_OTLP_LOGS_ENDPOINT', 'OTEL_EXPORTER_OTLP_ENDPOINT', default: 'http://localhost:4318/v1/logs'),
52
- certificate_file: ::OpenTelemetry::Common::Utilities.config_opt('OTEL_EXPORTER_OTLP_LOGS_CERTIFICATE', 'OTEL_EXPORTER_OTLP_CERTIFICATE'),
53
- client_certificate_file: ::OpenTelemetry::Common::Utilities.config_opt('OTEL_EXPORTER_OTLP_LOGS_CLIENT_CERTIFICATE', 'OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE'),
54
- client_key_file: ::OpenTelemetry::Common::Utilities.config_opt('OTEL_EXPORTER_OTLP_LOGS_CLIENT_KEY', 'OTEL_EXPORTER_OTLP_CLIENT_KEY'),
55
- ssl_verify_mode: LogsExporter.ssl_verify_mode,
56
- headers: ::OpenTelemetry::Common::Utilities.config_opt('OTEL_EXPORTER_OTLP_LOGS_HEADERS', 'OTEL_EXPORTER_OTLP_HEADERS', default: {}),
57
- compression: ::OpenTelemetry::Common::Utilities.config_opt('OTEL_EXPORTER_OTLP_LOGS_COMPRESSION', 'OTEL_EXPORTER_OTLP_COMPRESSION', default: 'gzip'),
58
- timeout: ::OpenTelemetry::Common::Utilities.config_opt('OTEL_EXPORTER_OTLP_LOGS_TIMEOUT', 'OTEL_EXPORTER_OTLP_TIMEOUT', default: 10))
59
- raise ArgumentError, "invalid url for OTLP::Logs::LogsExporter #{endpoint}" unless ::OpenTelemetry::Common::Utilities.valid_url?(endpoint)
60
- raise ArgumentError, "unsupported compression key #{compression}" unless compression.nil? || %w[gzip none].include?(compression)
61
-
62
- @uri = if endpoint == ENV['OTEL_EXPORTER_OTLP_ENDPOINT']
63
- URI.join(endpoint, 'v1/logs')
64
- else
65
- URI(endpoint)
66
- end
67
-
68
- @http = http_connection(@uri, ssl_verify_mode, certificate_file, client_certificate_file, client_key_file)
69
-
70
- @path = @uri.path
71
- @headers = prepare_headers(headers)
72
- @timeout = timeout.to_f
73
- @compression = compression
74
- @shutdown = false
75
- end
76
-
77
- # Called to export sampled {OpenTelemetry::SDK::Logs::LogRecordData} structs.
78
- #
79
- # @param [Enumerable<OpenTelemetry::SDK::Logs::LogRecordData>] log_record_data the
80
- # list of recorded {OpenTelemetry::SDK::Logs::LogRecordData} structs to be
81
- # exported.
82
- # @param [optional Numeric] timeout An optional timeout in seconds.
83
- # @return [Integer] the result of the export.
84
- def export(log_record_data, timeout: nil)
85
- OpenTelemetry.logger.error('Logs Exporter tried to export, but it has already shut down') if @shutdown
86
- return FAILURE if @shutdown
87
-
88
- send_bytes(encode(log_record_data), timeout: timeout)
89
- end
90
-
91
- # Called when {OpenTelemetry::SDK::Logs::LoggerProvider#force_flush} is called, if
92
- # this exporter is registered to a {OpenTelemetry::SDK::Logs::LoggerProvider}
93
- # object.
94
- #
95
- # @param [optional Numeric] timeout An optional timeout in seconds.
96
- def force_flush(timeout: nil)
97
- SUCCESS
98
- end
99
-
100
- # Called when {OpenTelemetry::SDK::Logs::LoggerProvider#shutdown} is called, if
101
- # this exporter is registered to a {OpenTelemetry::SDK::Logs::LoggerProvider}
102
- # object.
103
- #
104
- # @param [optional Numeric] timeout An optional timeout in seconds.
105
- def shutdown(timeout: nil)
106
- @shutdown = true
107
- @http.finish if @http.started?
108
- SUCCESS
109
- end
110
-
111
- private
112
-
113
- def handle_http_error(response)
114
- OpenTelemetry.handle_error(message: "OTLP logs exporter received #{response.class.name}, http.code=#{response.code}, for uri: '#{@path}'")
115
- end
116
-
117
- def http_connection(uri, ssl_verify_mode, certificate_file, client_certificate_file, client_key_file)
118
- http = Net::HTTP.new(uri.host, uri.port)
119
- http.use_ssl = uri.scheme == 'https'
120
- http.verify_mode = ssl_verify_mode
121
- http.ca_file = certificate_file unless certificate_file.nil?
122
- http.cert = OpenSSL::X509::Certificate.new(File.read(client_certificate_file)) unless client_certificate_file.nil?
123
- http.key = OpenSSL::PKey::RSA.new(File.read(client_key_file)) unless client_key_file.nil?
124
- http.keep_alive_timeout = KEEP_ALIVE_TIMEOUT
125
- http
126
- end
127
-
128
- # The around_request is a private method that provides an extension
129
- # point for the exporters network calls. The default behaviour
130
- # is to not record these operations.
131
- #
132
- # An example use case would be to prepend a patch, or extend this class
133
- # and override this method's behaviour to explicitly record the HTTP request.
134
- # This would allow you to create log records for your export pipeline.
135
- def around_request
136
- ::OpenTelemetry::Common::Utilities.untraced { yield } # rubocop:disable Style/ExplicitBlockArgument
137
- end
138
-
139
- def send_bytes(bytes, timeout:) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
140
- return FAILURE if bytes.nil?
141
-
142
- request = Net::HTTP::Post.new(@path)
143
- if @compression == 'gzip'
144
- request.add_field('Content-Encoding', 'gzip')
145
- body = Zlib.gzip(bytes)
146
- else
147
- body = bytes
148
- end
149
-
150
- request.body = body
151
- request.add_field('Content-Type', 'application/x-protobuf')
152
- @headers.each { |key, value| request.add_field(key, value) }
153
-
154
- retry_count = 0
155
- timeout ||= @timeout
156
- start_time = ::OpenTelemetry::Common::Utilities.timeout_timestamp
157
-
158
- around_request do
159
- remaining_timeout = ::OpenTelemetry::Common::Utilities.maybe_timeout(timeout, start_time)
160
- return FAILURE if remaining_timeout.zero?
161
-
162
- @http.open_timeout = remaining_timeout
163
- @http.read_timeout = remaining_timeout
164
- @http.write_timeout = remaining_timeout
165
- @http.start unless @http.started?
166
- response = @http.request(request)
167
-
168
- case response
169
- when Net::HTTPOK
170
- response.body # Read and discard body
171
- SUCCESS
172
- when Net::HTTPServiceUnavailable, Net::HTTPTooManyRequests
173
- response.body # Read and discard body
174
- handle_http_error(response)
175
- redo if backoff?(retry_after: response['Retry-After'], retry_count: retry_count += 1)
176
- FAILURE
177
- when Net::HTTPRequestTimeOut, Net::HTTPGatewayTimeOut, Net::HTTPBadGateway
178
- response.body # Read and discard body
179
- handle_http_error(response)
180
- redo if backoff?(retry_count: retry_count += 1)
181
- FAILURE
182
- when Net::HTTPNotFound
183
- handle_http_error(response)
184
- FAILURE
185
- when Net::HTTPBadRequest, Net::HTTPClientError, Net::HTTPServerError
186
- log_status(response.body)
187
- FAILURE
188
- when Net::HTTPRedirection
189
- @http.finish
190
- handle_redirect(response['location'])
191
- redo if backoff?(retry_after: 0, retry_count: retry_count += 1)
192
- else
193
- @http.finish
194
- handle_http_error(response)
195
- FAILURE
196
- end
197
- rescue Net::OpenTimeout, Net::ReadTimeout => e
198
- OpenTelemetry.handle_error(exception: e)
199
- retry if backoff?(retry_count: retry_count += 1)
200
- return FAILURE
201
- rescue OpenSSL::SSL::SSLError => e
202
- OpenTelemetry.handle_error(exception: e)
203
- retry if backoff?(retry_count: retry_count += 1)
204
- return FAILURE
205
- rescue SocketError => e
206
- OpenTelemetry.handle_error(exception: e)
207
- retry if backoff?(retry_count: retry_count += 1)
208
- return FAILURE
209
- rescue SystemCallError => e
210
- retry if backoff?(retry_count: retry_count += 1)
211
- OpenTelemetry.handle_error(exception: e)
212
- return FAILURE
213
- rescue EOFError => e
214
- OpenTelemetry.handle_error(exception: e)
215
- retry if backoff?(retry_count: retry_count += 1)
216
- return FAILURE
217
- rescue Zlib::DataError => e
218
- OpenTelemetry.handle_error(exception: e)
219
- retry if backoff?(retry_count: retry_count += 1)
220
- return FAILURE
221
- rescue StandardError => e
222
- OpenTelemetry.handle_error(exception: e, message: 'unexpected error in OTLP::Exporter#send_bytes')
223
- return FAILURE
224
- end
225
- ensure
226
- # Reset timeouts to defaults for the next call.
227
- @http.open_timeout = @timeout
228
- @http.read_timeout = @timeout
229
- @http.write_timeout = @timeout
230
- end
231
-
232
- def handle_redirect(location)
233
- # TODO: figure out destination and reinitialize @http and @path
234
- end
235
-
236
- def log_status(body)
237
- status = Google::Rpc::Status.decode(body)
238
- details = status.details.map do |detail|
239
- klass_or_nil = ::Google::Protobuf::DescriptorPool.generated_pool.lookup(detail.type_name).msgclass
240
- detail.unpack(klass_or_nil) if klass_or_nil
241
- end.compact
242
- OpenTelemetry.handle_error(message: "OTLP logs exporter received rpc.Status{message=#{status.message}, details=#{details}}")
243
- rescue StandardError => e
244
- OpenTelemetry.handle_error(exception: e, message: 'unexpected error decoding rpc.Status in OTLP::Exporter#log_status')
245
- end
246
-
247
- def backoff?(retry_count:, retry_after: nil) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
248
- return false if retry_count > RETRY_COUNT
249
-
250
- sleep_interval = nil
251
- unless retry_after.nil?
252
- sleep_interval =
253
- begin
254
- Integer(retry_after)
255
- rescue ArgumentError
256
- nil
257
- end
258
- sleep_interval ||=
259
- begin
260
- Time.httpdate(retry_after) - Time.now
261
- rescue # rubocop:disable Style/RescueStandardError
262
- nil
263
- end
264
- sleep_interval = nil unless sleep_interval&.positive?
265
- end
266
- sleep_interval ||= rand(2**retry_count)
267
-
268
- sleep(sleep_interval)
269
- true
270
- end
271
-
272
- def encode(log_record_data) # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity
273
- Opentelemetry::Proto::Collector::Logs::V1::ExportLogsServiceRequest.encode(
274
- Opentelemetry::Proto::Collector::Logs::V1::ExportLogsServiceRequest.new(
275
- resource_logs: log_record_data
276
- .group_by(&:resource)
277
- .map do |resource, log_record_datas|
278
- Opentelemetry::Proto::Logs::V1::ResourceLogs.new(
279
- resource: Opentelemetry::Proto::Resource::V1::Resource.new(
280
- attributes: resource.attribute_enumerator.map { |key, value| as_otlp_key_value(key, value) }
281
- ),
282
- scope_logs: log_record_datas
283
- .group_by(&:instrumentation_scope)
284
- .map do |il, lrd|
285
- Opentelemetry::Proto::Logs::V1::ScopeLogs.new(
286
- scope: Opentelemetry::Proto::Common::V1::InstrumentationScope.new(
287
- name: il.name,
288
- version: il.version
289
- ),
290
- log_records: lrd.map { |lr| as_otlp_log_record(lr) }
291
- )
292
- end
293
- )
294
- end
295
- )
296
- )
297
- rescue StandardError => e
298
- OpenTelemetry.handle_error(exception: e, message: 'unexpected error in OTLP::Exporter#encode')
299
- nil
300
- end
301
-
302
- def as_otlp_log_record(log_record_data)
303
- Opentelemetry::Proto::Logs::V1::LogRecord.new(
304
- time_unix_nano: log_record_data.timestamp,
305
- observed_time_unix_nano: log_record_data.observed_timestamp,
306
- severity_number: as_otlp_severity_number(log_record_data.severity_number),
307
- severity_text: log_record_data.severity_text,
308
- body: as_otlp_any_value(log_record_data.body),
309
- attributes: log_record_data.attributes&.map { |k, v| as_otlp_key_value(k, v) },
310
- dropped_attributes_count: log_record_data.total_recorded_attributes - log_record_data.attributes&.size.to_i,
311
- flags: log_record_data.trace_flags.instance_variable_get(:@flags),
312
- trace_id: log_record_data.trace_id,
313
- span_id: log_record_data.span_id
314
- )
315
- end
316
-
317
- def as_otlp_key_value(key, value)
318
- Opentelemetry::Proto::Common::V1::KeyValue.new(key: key, value: as_otlp_any_value(value))
319
- rescue Encoding::UndefinedConversionError => e
320
- encoded_value = value.encode('UTF-8', invalid: :replace, undef: :replace, replace: '�')
321
- OpenTelemetry.handle_error(exception: e, message: "encoding error for key #{key} and value #{encoded_value}")
322
- Opentelemetry::Proto::Common::V1::KeyValue.new(key: key, value: as_otlp_any_value('Encoding Error'))
323
- end
324
-
325
- def as_otlp_any_value(value)
326
- result = Opentelemetry::Proto::Common::V1::AnyValue.new
327
- case value
328
- when String
329
- result.string_value = value
330
- when Integer
331
- result.int_value = value
332
- when Float
333
- result.double_value = value
334
- when true, false
335
- result.bool_value = value
336
- when Array
337
- values = value.map { |element| as_otlp_any_value(element) }
338
- result.array_value = Opentelemetry::Proto::Common::V1::ArrayValue.new(values: values)
339
- end
340
- result
341
- end
342
-
343
- def prepare_headers(config_headers)
344
- headers = case config_headers
345
- when String then parse_headers(config_headers)
346
- when Hash then config_headers.dup
347
- else
348
- raise ArgumentError, ERROR_MESSAGE_INVALID_HEADERS
349
- end
350
-
351
- headers['User-Agent'] = "#{headers.fetch('User-Agent', '')} #{DEFAULT_USER_AGENT}".strip
352
-
353
- headers
354
- end
355
-
356
- # NOTE: This has been removed in newer versions of the OpenTelemetry Ruby Logs SDK,
357
- # but we need it for backward compatibility with the protobuf definitions.
358
-
359
- # TODO: maybe don't translate the severity number, but translate the severity text into
360
- # the number if the number is nil? Poss. change to allow for adding your own
361
- # otel values?
362
- def as_otlp_severity_number(severity_number)
363
- case severity_number
364
- when 0 then Opentelemetry::Proto::Logs::V1::SeverityNumber::SEVERITY_NUMBER_DEBUG
365
- when 1 then Opentelemetry::Proto::Logs::V1::SeverityNumber::SEVERITY_NUMBER_INFO
366
- when 2 then Opentelemetry::Proto::Logs::V1::SeverityNumber::SEVERITY_NUMBER_WARN
367
- when 3 then Opentelemetry::Proto::Logs::V1::SeverityNumber::SEVERITY_NUMBER_ERROR
368
- when 4 then Opentelemetry::Proto::Logs::V1::SeverityNumber::SEVERITY_NUMBER_FATAL
369
- when 5 then Opentelemetry::Proto::Logs::V1::SeverityNumber::SEVERITY_NUMBER_UNSPECIFIED
370
- end
371
- end
372
-
373
- def parse_headers(raw)
374
- entries = raw.split(',')
375
- raise ArgumentError, ERROR_MESSAGE_INVALID_HEADERS if entries.empty?
376
-
377
- entries.each_with_object({}) do |entry, headers|
378
- k, v = entry.split('=', 2).map(&CGI.method(:unescape))
379
- begin
380
- k = k.to_s.strip
381
- v = v.to_s.strip
382
- rescue Encoding::CompatibilityError
383
- raise ArgumentError, ERROR_MESSAGE_INVALID_HEADERS
384
- rescue ArgumentError => e
385
- raise e, ERROR_MESSAGE_INVALID_HEADERS
386
- end
387
- raise ArgumentError, ERROR_MESSAGE_INVALID_HEADERS if k.empty? || v.empty?
388
-
389
- headers[k] = v
390
- end
391
- end
392
- end
393
- end
394
- end
395
- end
396
- end
397
- end
398
- 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