scout_apm_logging 0.0.13 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -4
  3. data/.rubocop.yml +1 -1
  4. data/CHANGELOG.md +6 -0
  5. data/NOTICE +4 -0
  6. data/lib/scout_apm/logging/config.rb +5 -131
  7. data/lib/scout_apm/logging/loggers/capture.rb +3 -2
  8. data/lib/scout_apm/logging/loggers/formatter.rb +21 -2
  9. data/lib/scout_apm/logging/loggers/opentelemetry/LICENSE +201 -0
  10. data/lib/scout_apm/logging/loggers/opentelemetry/NOTICE +9 -0
  11. data/lib/scout_apm/logging/loggers/opentelemetry/api/logs/log_record.rb +18 -0
  12. data/lib/scout_apm/logging/loggers/opentelemetry/api/logs/logger.rb +64 -0
  13. data/lib/scout_apm/logging/loggers/opentelemetry/api/logs/logger_provider.rb +31 -0
  14. data/lib/scout_apm/logging/loggers/opentelemetry/api/logs/severity_number.rb +43 -0
  15. data/lib/scout_apm/logging/loggers/opentelemetry/api/logs/version.rb +18 -0
  16. data/lib/scout_apm/logging/loggers/opentelemetry/api/logs.rb +28 -0
  17. data/lib/scout_apm/logging/loggers/opentelemetry/exporter/exporter/otlp/logs_exporter.rb +389 -0
  18. data/lib/scout_apm/logging/loggers/opentelemetry/exporter/exporter/otlp/version.rb +20 -0
  19. data/lib/scout_apm/logging/loggers/opentelemetry/exporter/proto/collector/logs/v1/logs_service_pb.rb +43 -0
  20. data/lib/scout_apm/logging/loggers/opentelemetry/exporter/proto/common/v1/common_pb.rb +58 -0
  21. data/lib/scout_apm/logging/loggers/opentelemetry/exporter/proto/logs/v1/logs_pb.rb +91 -0
  22. data/lib/scout_apm/logging/loggers/opentelemetry/exporter/proto/resource/v1/resource_pb.rb +33 -0
  23. data/lib/scout_apm/logging/loggers/opentelemetry/opentelemetry.rb +62 -0
  24. data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/export/batch_log_record_processor.rb +225 -0
  25. data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/export/log_record_exporter.rb +64 -0
  26. data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/export.rb +34 -0
  27. data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/log_record.rb +115 -0
  28. data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/log_record_data.rb +31 -0
  29. data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/log_record_processor.rb +53 -0
  30. data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/logger.rb +94 -0
  31. data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/logger_provider.rb +158 -0
  32. data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/version.rb +20 -0
  33. data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs.rb +28 -0
  34. data/lib/scout_apm/logging/utils.rb +0 -69
  35. data/lib/scout_apm/logging/version.rb +1 -1
  36. data/lib/scout_apm_logging.rb +2 -11
  37. data/scout_apm_logging.gemspec +7 -0
  38. data/spec/data/config_test_1.yml +0 -1
  39. data/spec/data/mock_config.yml +0 -3
  40. data/spec/integration/rails/lifecycle_spec.rb +57 -23
  41. data/spec/spec_helper.rb +0 -12
  42. data/spec/unit/config_spec.rb +0 -12
  43. data/spec/unit/loggers/capture_spec.rb +0 -6
  44. metadata +126 -39
  45. data/bin/scout_apm_logging_monitor +0 -6
  46. data/lib/scout_apm/logging/monitor/_rails.rb +0 -22
  47. data/lib/scout_apm/logging/monitor/collector/checksum.rb +0 -51
  48. data/lib/scout_apm/logging/monitor/collector/configuration.rb +0 -150
  49. data/lib/scout_apm/logging/monitor/collector/downloader.rb +0 -78
  50. data/lib/scout_apm/logging/monitor/collector/extractor.rb +0 -37
  51. data/lib/scout_apm/logging/monitor/collector/manager.rb +0 -57
  52. data/lib/scout_apm/logging/monitor/monitor.rb +0 -216
  53. data/lib/scout_apm/logging/monitor_manager/manager.rb +0 -162
  54. data/lib/scout_apm/logging/state.rb +0 -69
  55. data/spec/data/empty_logs_config.yml +0 -0
  56. data/spec/data/logs_config.yml +0 -3
  57. data/spec/data/state_file.json +0 -3
  58. data/spec/integration/loggers/capture_spec.rb +0 -68
  59. data/spec/integration/monitor/collector/downloader/will_verify_checksum.rb +0 -49
  60. data/spec/integration/monitor/collector_healthcheck_spec.rb +0 -29
  61. data/spec/integration/monitor/continuous_state_collector_spec.rb +0 -31
  62. data/spec/integration/monitor/previous_collector_setup_spec.rb +0 -45
  63. data/spec/integration/monitor_manager/disable_agent_spec.rb +0 -30
  64. data/spec/integration/monitor_manager/monitor_pid_file_spec.rb +0 -38
  65. data/spec/integration/monitor_manager/single_monitor_spec.rb +0 -53
  66. data/spec/unit/monitor/collector/configuration_spec.rb +0 -64
  67. data/spec/unit/state_spec.rb +0 -20
  68. data/tooling/checksums.rb +0 -106
@@ -0,0 +1,18 @@
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
@@ -0,0 +1,28 @@
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
@@ -0,0 +1,389 @@
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
@@ -0,0 +1,20 @@
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
@@ -0,0 +1,43 @@
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
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
4
+ # source: opentelemetry/proto/common/v1/common.proto
5
+
6
+ require 'google/protobuf'
7
+
8
+ Google::Protobuf::DescriptorPool.generated_pool.build do
9
+ add_file("scout/opentelemetry/proto/common/v1/common.proto", :syntax => :proto3) do
10
+ add_message "scout_apm.logging.loggers.opentelemetry.proto.common.v1.AnyValue" do
11
+ oneof :value do
12
+ optional :string_value, :string, 1
13
+ optional :bool_value, :bool, 2
14
+ optional :int_value, :int64, 3
15
+ optional :double_value, :double, 4
16
+ optional :array_value, :message, 5, "scout_apm.logging.loggers.opentelemetry.proto.common.v1.ArrayValue"
17
+ optional :kvlist_value, :message, 6, "scout_apm.logging.loggers.opentelemetry.proto.common.v1.KeyValueList"
18
+ optional :bytes_value, :bytes, 7
19
+ end
20
+ end
21
+ add_message "scout_apm.logging.loggers.opentelemetry.proto.common.v1.ArrayValue" do
22
+ repeated :values, :message, 1, "scout_apm.logging.loggers.opentelemetry.proto.common.v1.AnyValue"
23
+ end
24
+ add_message "scout_apm.logging.loggers.opentelemetry.proto.common.v1.KeyValueList" do
25
+ repeated :values, :message, 1, "scout_apm.logging.loggers.opentelemetry.proto.common.v1.KeyValue"
26
+ end
27
+ add_message "scout_apm.logging.loggers.opentelemetry.proto.common.v1.KeyValue" do
28
+ optional :key, :string, 1
29
+ optional :value, :message, 2, "scout_apm.logging.loggers.opentelemetry.proto.common.v1.AnyValue"
30
+ end
31
+ add_message "scout_apm.logging.loggers.opentelemetry.proto.common.v1.InstrumentationScope" do
32
+ optional :name, :string, 1
33
+ optional :version, :string, 2
34
+ repeated :attributes, :message, 3, "scout_apm.logging.loggers.opentelemetry.proto.common.v1.KeyValue"
35
+ optional :dropped_attributes_count, :uint32, 4
36
+ end
37
+ end
38
+ end
39
+
40
+ module ScoutApm
41
+ module Logging
42
+ module Loggers
43
+ module Opentelemetry
44
+ module Proto
45
+ module Common
46
+ module V1
47
+ AnyValue = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("scout_apm.logging.loggers.opentelemetry.proto.common.v1.AnyValue").msgclass
48
+ ArrayValue = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("scout_apm.logging.loggers.opentelemetry.proto.common.v1.ArrayValue").msgclass
49
+ KeyValueList = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("scout_apm.logging.loggers.opentelemetry.proto.common.v1.KeyValueList").msgclass
50
+ KeyValue = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("scout_apm.logging.loggers.opentelemetry.proto.common.v1.KeyValue").msgclass
51
+ InstrumentationScope = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("scout_apm.logging.loggers.opentelemetry.proto.common.v1.InstrumentationScope").msgclass
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
4
+ # source: opentelemetry/proto/logs/v1/logs.proto
5
+
6
+ require 'google/protobuf'
7
+
8
+ require_relative '../../common/v1/common_pb'
9
+ require_relative '../../resource/v1/resource_pb'
10
+
11
+ Google::Protobuf::DescriptorPool.generated_pool.build do
12
+ add_file("scout/opentelemetry/proto/logs/v1/logs.proto", :syntax => :proto3) do
13
+ add_message "scout_apm.logging.loggers.opentelemetry.proto.logs.v1.LogsData" do
14
+ repeated :resource_logs, :message, 1, "scout_apm.logging.loggers.opentelemetry.proto.logs.v1.ResourceLogs"
15
+ end
16
+ add_message "scout_apm.logging.loggers.opentelemetry.proto.logs.v1.ResourceLogs" do
17
+ optional :resource, :message, 1, "scout_apm.logging.loggers.opentelemetry.proto.resource.v1.Resource"
18
+ repeated :scope_logs, :message, 2, "scout_apm.logging.loggers.opentelemetry.proto.logs.v1.ScopeLogs"
19
+ optional :schema_url, :string, 3
20
+ end
21
+ add_message "scout_apm.logging.loggers.opentelemetry.proto.logs.v1.ScopeLogs" do
22
+ optional :scope, :message, 1, "scout_apm.logging.loggers.opentelemetry.proto.common.v1.InstrumentationScope"
23
+ repeated :log_records, :message, 2, "scout_apm.logging.loggers.opentelemetry.proto.logs.v1.LogRecord"
24
+ optional :schema_url, :string, 3
25
+ end
26
+ add_message "scout_apm.logging.loggers.opentelemetry.proto.logs.v1.LogRecord" do
27
+ optional :time_unix_nano, :fixed64, 1
28
+ optional :observed_time_unix_nano, :fixed64, 11
29
+ optional :severity_number, :enum, 2, "scout_apm.logging.loggers.opentelemetry.proto.logs.v1.SeverityNumber"
30
+ optional :severity_text, :string, 3
31
+ optional :body, :message, 5, "scout_apm.logging.loggers.opentelemetry.proto.common.v1.AnyValue"
32
+ repeated :attributes, :message, 6, "scout_apm.logging.loggers.opentelemetry.proto.common.v1.KeyValue"
33
+ optional :dropped_attributes_count, :uint32, 7
34
+ optional :flags, :fixed32, 8
35
+ optional :trace_id, :bytes, 9
36
+ optional :span_id, :bytes, 10
37
+ end
38
+ add_enum "scout_apm.logging.loggers.opentelemetry.proto.logs.v1.SeverityNumber" do
39
+ value :SEVERITY_NUMBER_UNSPECIFIED, 0
40
+ value :SEVERITY_NUMBER_TRACE, 1
41
+ value :SEVERITY_NUMBER_TRACE2, 2
42
+ value :SEVERITY_NUMBER_TRACE3, 3
43
+ value :SEVERITY_NUMBER_TRACE4, 4
44
+ value :SEVERITY_NUMBER_DEBUG, 5
45
+ value :SEVERITY_NUMBER_DEBUG2, 6
46
+ value :SEVERITY_NUMBER_DEBUG3, 7
47
+ value :SEVERITY_NUMBER_DEBUG4, 8
48
+ value :SEVERITY_NUMBER_INFO, 9
49
+ value :SEVERITY_NUMBER_INFO2, 10
50
+ value :SEVERITY_NUMBER_INFO3, 11
51
+ value :SEVERITY_NUMBER_INFO4, 12
52
+ value :SEVERITY_NUMBER_WARN, 13
53
+ value :SEVERITY_NUMBER_WARN2, 14
54
+ value :SEVERITY_NUMBER_WARN3, 15
55
+ value :SEVERITY_NUMBER_WARN4, 16
56
+ value :SEVERITY_NUMBER_ERROR, 17
57
+ value :SEVERITY_NUMBER_ERROR2, 18
58
+ value :SEVERITY_NUMBER_ERROR3, 19
59
+ value :SEVERITY_NUMBER_ERROR4, 20
60
+ value :SEVERITY_NUMBER_FATAL, 21
61
+ value :SEVERITY_NUMBER_FATAL2, 22
62
+ value :SEVERITY_NUMBER_FATAL3, 23
63
+ value :SEVERITY_NUMBER_FATAL4, 24
64
+ end
65
+ add_enum "scout_apm.logging.loggers.opentelemetry.proto.logs.v1.LogRecordFlags" do
66
+ value :LOG_RECORD_FLAGS_DO_NOT_USE, 0
67
+ value :LOG_RECORD_FLAGS_TRACE_FLAGS_MASK, 255
68
+ end
69
+ end
70
+ end
71
+
72
+ module ScoutApm
73
+ module Logging
74
+ module Loggers
75
+ module Opentelemetry
76
+ module Proto
77
+ module Logs
78
+ module V1
79
+ LogsData = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("scout_apm.logging.loggers.opentelemetry.proto.logs.v1.LogsData").msgclass
80
+ ResourceLogs = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("scout_apm.logging.loggers.opentelemetry.proto.logs.v1.ResourceLogs").msgclass
81
+ ScopeLogs = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("scout_apm.logging.loggers.opentelemetry.proto.logs.v1.ScopeLogs").msgclass
82
+ LogRecord = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("scout_apm.logging.loggers.opentelemetry.proto.logs.v1.LogRecord").msgclass
83
+ SeverityNumber = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("scout_apm.logging.loggers.opentelemetry.proto.logs.v1.SeverityNumber").enummodule
84
+ LogRecordFlags = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("scout_apm.logging.loggers.opentelemetry.proto.logs.v1.LogRecordFlags").enummodule
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end