opentelemetry-exporter-otlp-logs 0.5.1 → 0.6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 74262bb2c634c1f01be8043bf31ec59f7201b52d05da1fdbc39f60e52462db57
4
- data.tar.gz: 34f20455c4ca994351b4f3ced9a7f71700b0488fb17cfb89059e76e57872041f
3
+ metadata.gz: f011e5745cf3ae355aae983a0389fbced4e43e6d7a1fb36e678cd0be280a209c
4
+ data.tar.gz: 5d9ef08d0f8028447ecf27df0a13c4073df5a68e19c1c132c0cdfdc5c2f54281
5
5
  SHA512:
6
- metadata.gz: 75a68db1d24cf285e51e9c5b022aa6f08fee794d7bd6e8a4f5f743ced4493e6734f55cfbb0a49d7aa5266fe7c943af6e39218edeb3db68d12deda20655ef58b0
7
- data.tar.gz: 806b6af7206deddef8ab2b796d00543c1a3985886593e0024bd275689c5ee6c163c0ca9c4a5425dcde2734a7f9e9c4705ee0de724c38a57d2f7328cda61de3a2
6
+ metadata.gz: 34630f630284a80938a60aad37e942c766f76447fb683262912365233906fbfbd523cabe9f5a3809f87b68dc7dba8abe9b0df3922696e6c8dd3e628c532a91cb
7
+ data.tar.gz: fdef69bf2f53941f457de68cad325c3b4ec1ed95edfd6e6e7392368bd742a5576f41ae6d8cfd827646a53290a97e041b35fb4bb76c195ef49b560cd32b468a58
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Release History: opentelemetry-exporter-otlp-logs
2
2
 
3
+ ### v0.6.0 / 2026-09-29
4
+
5
+ * ADDED: Move otlp exporter uri builder to common (#2240)
6
+ * FIXED: Update total_recorded_attributes when LogRecord#attributes= is called (#2241)
7
+ * FIXED: Normalize UTF-8 attribute strings (#2259)
8
+ * FIXED: Handle partial success responses (#2396)
9
+
3
10
  ### v0.5.1 / 2026-06-02
4
11
 
5
12
  * FIXED: `URI.join` dropping path prefix in logs and metrics exporters (#2158)
@@ -5,6 +5,7 @@
5
5
  # SPDX-License-Identifier: Apache-2.0
6
6
 
7
7
  require 'opentelemetry/common'
8
+ require 'opentelemetry/exporter/otlp/common'
8
9
  require 'opentelemetry/sdk'
9
10
  require 'opentelemetry-logs-api' # the sdk isn't loading the api, but not sure why
10
11
  require 'opentelemetry/sdk/logs'
@@ -38,6 +39,7 @@ module OpenTelemetry
38
39
 
39
40
  DEFAULT_USER_AGENT = "OTel-OTLP-Exporter-Ruby/#{OpenTelemetry::Exporter::OTLP::Logs::VERSION} Ruby/#{RUBY_VERSION} (#{RUBY_PLATFORM}; #{RUBY_ENGINE}/#{RUBY_ENGINE_VERSION})".freeze
40
41
 
42
+ # rubocop:disable-next Lint/DuplicateBranch
41
43
  def self.ssl_verify_mode
42
44
  if ENV['OTEL_RUBY_EXPORTER_OTLP_SSL_VERIFY_PEER'] == 'true'
43
45
  OpenSSL::SSL::VERIFY_PEER
@@ -48,7 +50,7 @@ module OpenTelemetry
48
50
  end
49
51
  end
50
52
 
51
- def initialize(endpoint: OpenTelemetry::Common::Utilities.config_opt('OTEL_EXPORTER_OTLP_LOGS_ENDPOINT', 'OTEL_EXPORTER_OTLP_ENDPOINT', default: 'http://localhost:4318/v1/logs'),
53
+ def initialize(endpoint: nil,
52
54
  certificate_file: OpenTelemetry::Common::Utilities.config_opt('OTEL_EXPORTER_OTLP_LOGS_CERTIFICATE', 'OTEL_EXPORTER_OTLP_CERTIFICATE'),
53
55
  client_certificate_file: OpenTelemetry::Common::Utilities.config_opt('OTEL_EXPORTER_OTLP_LOGS_CLIENT_CERTIFICATE', 'OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE'),
54
56
  client_key_file: OpenTelemetry::Common::Utilities.config_opt('OTEL_EXPORTER_OTLP_LOGS_CLIENT_KEY', 'OTEL_EXPORTER_OTLP_CLIENT_KEY'),
@@ -56,16 +58,9 @@ module OpenTelemetry
56
58
  headers: OpenTelemetry::Common::Utilities.config_opt('OTEL_EXPORTER_OTLP_LOGS_HEADERS', 'OTEL_EXPORTER_OTLP_HEADERS', default: {}),
57
59
  compression: OpenTelemetry::Common::Utilities.config_opt('OTEL_EXPORTER_OTLP_LOGS_COMPRESSION', 'OTEL_EXPORTER_OTLP_COMPRESSION', default: 'gzip'),
58
60
  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
61
  raise ArgumentError, "unsupported compression key #{compression}" unless compression.nil? || %w[gzip none].include?(compression)
61
62
 
62
- @uri = if endpoint == ENV['OTEL_EXPORTER_OTLP_ENDPOINT']
63
- endpoint += '/' unless endpoint.end_with?('/')
64
- URI.join(endpoint, 'v1/logs')
65
- else
66
- URI(endpoint)
67
- end
68
-
63
+ @uri = OpenTelemetry::Exporter::OTLP::Common::Utilities.build_uri(endpoint, 'v1/logs', 'OTEL_EXPORTER_OTLP_LOGS_ENDPOINT', 'OTEL_EXPORTER_OTLP_ENDPOINT', 'http://localhost:4318/')
69
64
  @http = http_connection(@uri, ssl_verify_mode, certificate_file, client_certificate_file, client_key_file)
70
65
 
71
66
  @path = @uri.path
@@ -156,6 +151,7 @@ module OpenTelemetry
156
151
  timeout ||= @timeout
157
152
  start_time = OpenTelemetry::Common::Utilities.timeout_timestamp
158
153
 
154
+ # rubocop:disable-next Lint/DuplicateBranch
159
155
  around_request do
160
156
  remaining_timeout = OpenTelemetry::Common::Utilities.maybe_timeout(timeout, start_time)
161
157
  return FAILURE if remaining_timeout.zero?
@@ -168,7 +164,7 @@ module OpenTelemetry
168
164
 
169
165
  case response
170
166
  when Net::HTTPSuccess
171
- response.body # Read and discard body
167
+ log_partial_success(response.body)
172
168
  SUCCESS
173
169
  when Net::HTTPServiceUnavailable, Net::HTTPTooManyRequests
174
170
  response.body # Read and discard body
@@ -236,26 +232,35 @@ module OpenTelemetry
236
232
 
237
233
  def log_status(body)
238
234
  status = Google::Rpc::Status.decode(body)
239
- details = status.details.map do |detail|
240
- klass_or_nil = ::Google::Protobuf::DescriptorPool.generated_pool.lookup(detail.type_name).msgclass
241
- detail.unpack(klass_or_nil) if klass_or_nil
242
- end.compact
235
+ pool = ::Google::Protobuf::DescriptorPool.generated_pool
236
+ details = status.details.filter_map do |detail|
237
+ klass = pool.lookup(detail.type_name).msgclass
238
+ detail.unpack(klass) if klass
239
+ end
243
240
  OpenTelemetry.handle_error(message: "OTLP logs exporter received rpc.Status{message=#{status.message}, details=#{details}}")
244
241
  rescue StandardError => e
245
242
  OpenTelemetry.handle_error(exception: e, message: 'unexpected error decoding rpc.Status in OTLP::Exporter#log_status')
246
243
  end
247
244
 
248
- def backoff?(retry_count:, retry_after: nil) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
245
+ def log_partial_success(body)
246
+ response = Opentelemetry::Proto::Collector::Logs::V1::ExportLogsServiceResponse.decode(body)
247
+ partial_success = response.partial_success
248
+ return if partial_success.nil? || partial_success.rejected_log_records <= 0
249
+
250
+ OpenTelemetry.handle_error(
251
+ message: "OTLP logs exporter received partial success: rejected_log_records=#{partial_success.rejected_log_records}, error_message=#{partial_success.error_message}"
252
+ )
253
+ rescue StandardError => e
254
+ OpenTelemetry.handle_error(exception: e, message: 'unexpected error decoding ExportLogsServiceResponse in OTLP::Exporter#log_partial_success')
255
+ end
256
+
257
+ def backoff?(retry_count:, retry_after: nil) # rubocop:disable Metrics/CyclomaticComplexity
249
258
  return false if retry_count > RETRY_COUNT
250
259
 
251
260
  sleep_interval = nil
252
261
  unless retry_after.nil?
253
262
  sleep_interval =
254
- begin
255
- Integer(retry_after)
256
- rescue ArgumentError
257
- nil
258
- end
263
+ Integer(retry_after, exception: false)
259
264
  sleep_interval ||=
260
265
  begin
261
266
  Time.httpdate(retry_after) - Time.now
@@ -308,7 +313,7 @@ module OpenTelemetry
308
313
  severity_text: log_record_data.severity_text,
309
314
  body: as_otlp_any_value(log_record_data.body),
310
315
  attributes: log_record_data.attributes&.map { |k, v| as_otlp_key_value(k, v) },
311
- dropped_attributes_count: log_record_data.total_recorded_attributes - log_record_data.attributes&.size.to_i,
316
+ dropped_attributes_count: log_record_data.dropped_attributes_count,
312
317
  event_name: log_record_data.event_name,
313
318
  flags: log_record_data.trace_flags.instance_variable_get(:@flags),
314
319
  trace_id: log_record_data.trace_id,
@@ -317,9 +322,10 @@ module OpenTelemetry
317
322
  end
318
323
 
319
324
  def as_otlp_key_value(key, value)
325
+ key = OpenTelemetry::Common::Utilities.utf8_encode(key, placeholder: 'Encoding Error')
320
326
  Opentelemetry::Proto::Common::V1::KeyValue.new(key: key, value: as_otlp_any_value(value))
321
327
  rescue Encoding::UndefinedConversionError => e
322
- encoded_value = value.encode('UTF-8', invalid: :replace, undef: :replace, replace: '�')
328
+ encoded_value = value.to_s.encode('UTF-8', invalid: :replace, undef: :replace, replace: '�')
323
329
  OpenTelemetry.handle_error(exception: e, message: "encoding error for key #{key} and value #{encoded_value}")
324
330
  Opentelemetry::Proto::Common::V1::KeyValue.new(key: key, value: as_otlp_any_value('Encoding Error'))
325
331
  end
@@ -328,7 +334,7 @@ module OpenTelemetry
328
334
  result = Opentelemetry::Proto::Common::V1::AnyValue.new
329
335
  case value
330
336
  when String
331
- result.string_value = value
337
+ result.string_value = OpenTelemetry::Common::Utilities.utf8_encode(value, placeholder: value)
332
338
  when Integer
333
339
  result.int_value = value
334
340
  when Float
@@ -363,7 +369,7 @@ module OpenTelemetry
363
369
  raise ArgumentError, ERROR_MESSAGE_INVALID_HEADERS if entries.empty?
364
370
 
365
371
  entries.each_with_object({}) do |entry, headers|
366
- k, v = entry.split('=', 2).map(&URI.method(:decode_uri_component))
372
+ k, v = entry.split('=', 2).map { |part| URI.decode_uri_component part }
367
373
  begin
368
374
  k = k.to_s.strip
369
375
  v = v.to_s.strip
@@ -9,7 +9,7 @@ module OpenTelemetry
9
9
  module OTLP
10
10
  module Logs
11
11
  ## Current OpenTelemetry OTLP logs exporter version
12
- VERSION = '0.5.1'
12
+ VERSION = '0.6.0'
13
13
  end
14
14
  end
15
15
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: opentelemetry-exporter-otlp-logs
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - OpenTelemetry Authors
@@ -65,6 +65,20 @@ dependencies:
65
65
  - - "~>"
66
66
  - !ruby/object:Gem::Version
67
67
  version: '0.20'
68
+ - !ruby/object:Gem::Dependency
69
+ name: opentelemetry-exporter-otlp-common
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '0.2'
75
+ type: :runtime
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '0.2'
68
82
  - !ruby/object:Gem::Dependency
69
83
  name: opentelemetry-logs-api
70
84
  requirement: !ruby/object:Gem::Requirement
@@ -150,10 +164,10 @@ homepage: https://github.com/open-telemetry/opentelemetry-ruby
150
164
  licenses:
151
165
  - Apache-2.0
152
166
  metadata:
153
- changelog_uri: https://rubydoc.info/gems/opentelemetry-exporter-otlp-logs/0.5.1/file/CHANGELOG.md
154
- source_code_uri: https://github.com/open-telemetry/opentelemetry-ruby/tree/opentelemetry-exporter-otlp-logs/v0.5.1/exporter/otlp-logs
167
+ changelog_uri: https://rubydoc.info/gems/opentelemetry-exporter-otlp-logs/0.6.0/file/CHANGELOG.md
168
+ source_code_uri: https://github.com/open-telemetry/opentelemetry-ruby/tree/opentelemetry-exporter-otlp-logs/v0.6.0/exporter/otlp-logs
155
169
  bug_tracker_uri: https://github.com/open-telemetry/opentelemetry-ruby/issues
156
- documentation_uri: https://rubydoc.info/gems/opentelemetry-exporter-otlp-logs/0.5.1
170
+ documentation_uri: https://rubydoc.info/gems/opentelemetry-exporter-otlp-logs/0.6.0
157
171
  rdoc_options: []
158
172
  require_paths:
159
173
  - lib
@@ -168,7 +182,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
168
182
  - !ruby/object:Gem::Version
169
183
  version: '0'
170
184
  requirements: []
171
- rubygems_version: 4.0.10
185
+ rubygems_version: 4.0.20
172
186
  specification_version: 4
173
187
  summary: Experimental OTLP Logs exporter for the OpenTelemetry framework
174
188
  test_files: []