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.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +17 -2
- data/.rubocop.yml +1 -1
- data/CHANGELOG.md +6 -0
- data/README.md +7 -2
- data/lib/scout_apm/logging/config.rb +1 -1
- data/lib/scout_apm/logging/loggers/formatter.rb +1 -1
- data/lib/scout_apm/logging/loggers/opentelemetry/log_record_patch.rb +38 -0
- data/lib/scout_apm/logging/loggers/opentelemetry/opentelemetry.rb +8 -31
- data/lib/scout_apm/logging/version.rb +1 -1
- data/scout_apm_logging.gemspec +4 -2
- data/spec/integration/rails/lifecycle_spec.rb +1 -1
- metadata +36 -31
- data/lib/scout_apm/logging/loggers/opentelemetry/LICENSE +0 -201
- data/lib/scout_apm/logging/loggers/opentelemetry/api/logs/log_record.rb +0 -18
- data/lib/scout_apm/logging/loggers/opentelemetry/api/logs/logger.rb +0 -64
- data/lib/scout_apm/logging/loggers/opentelemetry/api/logs/logger_provider.rb +0 -31
- data/lib/scout_apm/logging/loggers/opentelemetry/api/logs/severity_number.rb +0 -43
- data/lib/scout_apm/logging/loggers/opentelemetry/api/logs/version.rb +0 -18
- data/lib/scout_apm/logging/loggers/opentelemetry/api/logs.rb +0 -28
- data/lib/scout_apm/logging/loggers/opentelemetry/exporter/exporter/otlp/logs_exporter.rb +0 -398
- data/lib/scout_apm/logging/loggers/opentelemetry/exporter/exporter/otlp/version.rb +0 -20
- data/lib/scout_apm/logging/loggers/opentelemetry/exporter/proto/collector/logs/v1/logs_service_pb.rb +0 -43
- data/lib/scout_apm/logging/loggers/opentelemetry/exporter/proto/common/v1/common_pb.rb +0 -58
- data/lib/scout_apm/logging/loggers/opentelemetry/exporter/proto/logs/v1/logs_pb.rb +0 -91
- data/lib/scout_apm/logging/loggers/opentelemetry/exporter/proto/resource/v1/resource_pb.rb +0 -33
- data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/export/batch_log_record_processor.rb +0 -223
- data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/export/log_record_exporter.rb +0 -64
- data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/export.rb +0 -34
- data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/log_record.rb +0 -170
- data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/log_record_data.rb +0 -31
- data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/log_record_limits.rb +0 -49
- data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/log_record_processor.rb +0 -52
- data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/logger.rb +0 -98
- data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/logger_provider.rb +0 -170
- data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/version.rb +0 -20
- 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
|
data/lib/scout_apm/logging/loggers/opentelemetry/exporter/proto/collector/logs/v1/logs_service_pb.rb
DELETED
@@ -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
|