From 0f5cbfc6f607bb877e2cc463041ecfc57494df9d Mon Sep 17 00:00:00 2001 From: Kayla Reopelle <87386821+kaylareopelle@users.noreply.github.com> Date: Wed, 4 Sep 2024 11:40:22 -0700 Subject: [PATCH 1/2] fix: Remove Metrics OTLP exporter `Util#measure_request_duration` and duplicate files (#1717) * fix: Remove measure_request_duration The OTLP metrics exporter does not use the metrics reporter present in the traces OTLP exporter. The measure_request_duration method is used in the traces exporter to provide a value for the metrics reporter. Since the metrics OTLP exporter does not use this metrics reporter, the method is not needed. Also, with the current code, the duration was being calculated in a void context. The value of the response variable has been and should be the result of @http.request(request). * fix: Remove old files outside nesting structure There were some duplicate files at the path exporter/otlp/* that were no longer used, now that the files are nested under exporter/otlp/metrics/* The test file location was updated to reflect the new location. * fix: Remove measure_request_duration from Util * style: Rubocop * style: Rubocop --- .../exporter/otlp/metrics/metrics_exporter.rb | 2 +- .../exporter/otlp/metrics/util.rb | 12 +- .../exporter/otlp/metrics_exporter.rb | 309 ------------------ .../lib/opentelemetry/exporter/otlp/util.rb | 139 -------- .../{ => metrics}/metrics_exporter_test.rb | 0 5 files changed, 2 insertions(+), 460 deletions(-) delete mode 100644 exporter/otlp-metrics/lib/opentelemetry/exporter/otlp/metrics_exporter.rb delete mode 100644 exporter/otlp-metrics/lib/opentelemetry/exporter/otlp/util.rb rename exporter/otlp-metrics/test/opentelemetry/exporter/otlp/{ => metrics}/metrics_exporter_test.rb (100%) diff --git a/exporter/otlp-metrics/lib/opentelemetry/exporter/otlp/metrics/metrics_exporter.rb b/exporter/otlp-metrics/lib/opentelemetry/exporter/otlp/metrics/metrics_exporter.rb index a1b0bf415..44302e0e9 100644 --- a/exporter/otlp-metrics/lib/opentelemetry/exporter/otlp/metrics/metrics_exporter.rb +++ b/exporter/otlp-metrics/lib/opentelemetry/exporter/otlp/metrics/metrics_exporter.rb @@ -115,7 +115,7 @@ def send_bytes(bytes, timeout:) @http.read_timeout = remaining_timeout @http.write_timeout = remaining_timeout @http.start unless @http.started? - response = measure_request_duration { @http.request(request) } + response = @http.request(request) case response when Net::HTTPOK response.body # Read and discard body diff --git a/exporter/otlp-metrics/lib/opentelemetry/exporter/otlp/metrics/util.rb b/exporter/otlp-metrics/lib/opentelemetry/exporter/otlp/metrics/util.rb index 264b1e19b..37f1896da 100644 --- a/exporter/otlp-metrics/lib/opentelemetry/exporter/otlp/metrics/util.rb +++ b/exporter/otlp-metrics/lib/opentelemetry/exporter/otlp/metrics/util.rb @@ -9,7 +9,7 @@ module Exporter module OTLP module Metrics # Util module provide essential functionality for exporter - module Util # rubocop:disable Metrics/ModuleLength + module Util KEEP_ALIVE_TIMEOUT = 30 RETRY_COUNT = 5 ERROR_MESSAGE_INVALID_HEADERS = 'headers must be a String with comma-separated URL Encoded UTF-8 k=v pairs or a Hash' @@ -67,16 +67,6 @@ def prepare_headers(config_headers) headers end - def measure_request_duration - start = Process.clock_gettime(Process::CLOCK_MONOTONIC) - begin - yield - ensure - stop = Process.clock_gettime(Process::CLOCK_MONOTONIC) - 1000.0 * (stop - start) - end - end - def parse_headers(raw) entries = raw.split(',') raise ArgumentError, ERROR_MESSAGE_INVALID_HEADERS if entries.empty? diff --git a/exporter/otlp-metrics/lib/opentelemetry/exporter/otlp/metrics_exporter.rb b/exporter/otlp-metrics/lib/opentelemetry/exporter/otlp/metrics_exporter.rb deleted file mode 100644 index 3d86f9e97..000000000 --- a/exporter/otlp-metrics/lib/opentelemetry/exporter/otlp/metrics_exporter.rb +++ /dev/null @@ -1,309 +0,0 @@ -# frozen_string_literal: true - -# Copyright The OpenTelemetry Authors -# -# SPDX-License-Identifier: Apache-2.0 - -require 'opentelemetry/common' -require 'opentelemetry/sdk' -require 'net/http' -require 'csv' -require 'zlib' - -require 'google/rpc/status_pb' - -require 'opentelemetry/proto/common/v1/common_pb' -require 'opentelemetry/proto/resource/v1/resource_pb' -require 'opentelemetry/proto/metrics/v1/metrics_pb' -require 'opentelemetry/proto/collector/metrics/v1/metrics_service_pb' - -require 'opentelemetry/metrics' -require 'opentelemetry/sdk/metrics' - -require_relative './util' - -module OpenTelemetry - module Exporter - module OTLP - # An OpenTelemetry metrics exporter that sends metrics over HTTP as Protobuf encoded OTLP ExportMetricsServiceRequest. - class MetricsExporter < ::OpenTelemetry::SDK::Metrics::Export::MetricReader - include Util - - attr_reader :metric_snapshots - - SUCCESS = OpenTelemetry::SDK::Metrics::Export::SUCCESS - FAILURE = OpenTelemetry::SDK::Metrics::Export::FAILURE - private_constant(:SUCCESS, :FAILURE) - - WRITE_TIMEOUT_SUPPORTED = Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.6') - private_constant(:WRITE_TIMEOUT_SUPPORTED) - - def self.ssl_verify_mode - if ENV.key?('OTEL_RUBY_EXPORTER_OTLP_SSL_VERIFY_PEER') - OpenSSL::SSL::VERIFY_PEER - elsif ENV.key?('OTEL_RUBY_EXPORTER_OTLP_SSL_VERIFY_NONE') - OpenSSL::SSL::VERIFY_NONE - else - OpenSSL::SSL::VERIFY_PEER - end - end - - def initialize(endpoint: OpenTelemetry::Common::Utilities.config_opt('OTEL_EXPORTER_OTLP_METRICS_ENDPOINT', 'OTEL_EXPORTER_OTLP_ENDPOINT', default: 'http://localhost:4318/v1/metrics'), - certificate_file: OpenTelemetry::Common::Utilities.config_opt('OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE', 'OTEL_EXPORTER_OTLP_CERTIFICATE'), - ssl_verify_mode: MetricsExporter.ssl_verify_mode, - headers: OpenTelemetry::Common::Utilities.config_opt('OTEL_EXPORTER_OTLP_METRICS_HEADERS', 'OTEL_EXPORTER_OTLP_HEADERS', default: {}), - compression: OpenTelemetry::Common::Utilities.config_opt('OTEL_EXPORTER_OTLP_METRICS_COMPRESSION', 'OTEL_EXPORTER_OTLP_COMPRESSION', default: 'gzip'), - timeout: OpenTelemetry::Common::Utilities.config_opt('OTEL_EXPORTER_OTLP_METRICS_TIMEOUT', 'OTEL_EXPORTER_OTLP_TIMEOUT', default: 10)) - raise ArgumentError, "invalid url for OTLP::MetricsExporter #{endpoint}" unless OpenTelemetry::Common::Utilities.valid_url?(endpoint) - raise ArgumentError, "unsupported compression key #{compression}" unless compression.nil? || %w[gzip none].include?(compression) - - # create the MetricStore object - super() - - @uri = if endpoint == ENV['OTEL_EXPORTER_OTLP_ENDPOINT'] - URI.join(endpoint, 'v1/metrics') - else - URI(endpoint) - end - - @http = http_connection(@uri, ssl_verify_mode, certificate_file) - - @path = @uri.path - @headers = prepare_headers(headers) - @timeout = timeout.to_f - @compression = compression - @mutex = Mutex.new - @shutdown = false - end - - # consolidate the metrics data into the form of MetricData - # - # return MetricData - def pull - export(collect) - end - - # metrics Array[MetricData] - def export(metrics, timeout: nil) - @mutex.synchronize do - send_bytes(encode(metrics), timeout: timeout) - end - end - - def send_bytes(bytes, timeout:) - return FAILURE if bytes.nil? - - request = Net::HTTP::Post.new(@path) - - if @compression == 'gzip' - request.add_field('Content-Encoding', 'gzip') - body = Zlib.gzip(bytes) - else - body = bytes - end - - request.body = body - request.add_field('Content-Type', 'application/x-protobuf') - @headers.each { |key, value| request.add_field(key, value) } - - retry_count = 0 - timeout ||= @timeout - start_time = OpenTelemetry::Common::Utilities.timeout_timestamp - - around_request do - remaining_timeout = OpenTelemetry::Common::Utilities.maybe_timeout(timeout, start_time) - return FAILURE if remaining_timeout.zero? - - @http.open_timeout = remaining_timeout - @http.read_timeout = remaining_timeout - @http.write_timeout = remaining_timeout if WRITE_TIMEOUT_SUPPORTED - @http.start unless @http.started? - response = measure_request_duration { @http.request(request) } - case response - when Net::HTTPOK - response.body # Read and discard body - SUCCESS - when Net::HTTPServiceUnavailable, Net::HTTPTooManyRequests - response.body # Read and discard body - redo if backoff?(retry_after: response['Retry-After'], retry_count: retry_count += 1, reason: response.code) - OpenTelemetry.logger.warn('Net::HTTPServiceUnavailable/Net::HTTPTooManyRequests in MetricsExporter#send_bytes') - FAILURE - when Net::HTTPRequestTimeOut, Net::HTTPGatewayTimeOut, Net::HTTPBadGateway - response.body # Read and discard body - redo if backoff?(retry_count: retry_count += 1, reason: response.code) - OpenTelemetry.logger.warn('Net::HTTPRequestTimeOut/Net::HTTPGatewayTimeOut/Net::HTTPBadGateway in MetricsExporter#send_bytes') - FAILURE - when Net::HTTPNotFound - OpenTelemetry.handle_error(message: "OTLP metrics_exporter received http.code=404 for uri: '#{@path}'") - FAILURE - when Net::HTTPBadRequest, Net::HTTPClientError, Net::HTTPServerError - log_status(response.body) - OpenTelemetry.logger.warn('Net::HTTPBadRequest/Net::HTTPClientError/Net::HTTPServerError in MetricsExporter#send_bytes') - FAILURE - when Net::HTTPRedirection - @http.finish - handle_redirect(response['location']) - redo if backoff?(retry_after: 0, retry_count: retry_count += 1, reason: response.code) - else - @http.finish - OpenTelemetry.logger.warn("Unexpected error in OTLP::MetricsExporter#send_bytes - #{response.message}") - FAILURE - end - rescue Net::OpenTimeout, Net::ReadTimeout - retry if backoff?(retry_count: retry_count += 1, reason: 'timeout') - OpenTelemetry.logger.warn('Net::OpenTimeout/Net::ReadTimeout in MetricsExporter#send_bytes') - return FAILURE - rescue OpenSSL::SSL::SSLError - retry if backoff?(retry_count: retry_count += 1, reason: 'openssl_error') - OpenTelemetry.logger.warn('OpenSSL::SSL::SSLError in MetricsExporter#send_bytes') - return FAILURE - rescue SocketError - retry if backoff?(retry_count: retry_count += 1, reason: 'socket_error') - OpenTelemetry.logger.warn('SocketError in MetricsExporter#send_bytes') - return FAILURE - rescue SystemCallError => e - retry if backoff?(retry_count: retry_count += 1, reason: e.class.name) - OpenTelemetry.logger.warn('SystemCallError in MetricsExporter#send_bytes') - return FAILURE - rescue EOFError - retry if backoff?(retry_count: retry_count += 1, reason: 'eof_error') - OpenTelemetry.logger.warn('EOFError in MetricsExporter#send_bytes') - return FAILURE - rescue Zlib::DataError - retry if backoff?(retry_count: retry_count += 1, reason: 'zlib_error') - OpenTelemetry.logger.warn('Zlib::DataError in MetricsExporter#send_bytes') - return FAILURE - rescue StandardError => e - OpenTelemetry.handle_error(exception: e, message: 'unexpected error in OTLP::MetricsExporter#send_bytes') - return FAILURE - end - ensure - # Reset timeouts to defaults for the next call. - @http.open_timeout = @timeout - @http.read_timeout = @timeout - @http.write_timeout = @timeout if WRITE_TIMEOUT_SUPPORTED - end - - def encode(metrics_data) - Opentelemetry::Proto::Collector::Metrics::V1::ExportMetricsServiceRequest.encode( - Opentelemetry::Proto::Collector::Metrics::V1::ExportMetricsServiceRequest.new( - resource_metrics: metrics_data - .group_by(&:resource) - .map do |resource, scope_metrics| - Opentelemetry::Proto::Metrics::V1::ResourceMetrics.new( - resource: Opentelemetry::Proto::Resource::V1::Resource.new( - attributes: resource.attribute_enumerator.map { |key, value| as_otlp_key_value(key, value) } - ), - scope_metrics: scope_metrics - .group_by(&:instrumentation_scope) - .map do |instrumentation_scope, metrics| - Opentelemetry::Proto::Metrics::V1::ScopeMetrics.new( - scope: Opentelemetry::Proto::Common::V1::InstrumentationScope.new( - name: instrumentation_scope.name, - version: instrumentation_scope.version - ), - metrics: metrics.map { |sd| as_otlp_metrics(sd) } - ) - end - ) - end - ) - ) - rescue StandardError => e - OpenTelemetry.handle_error(exception: e, message: 'unexpected error in OTLP::MetricsExporter#encode') - nil - end - - # metrics_pb has following type of data: :gauge, :sum, :histogram, :exponential_histogram, :summary - # current metric sdk only implements instrument: :counter -> :sum, :histogram -> :histogram - # - # metrics [MetricData] - def as_otlp_metrics(metrics) - case metrics.instrument_kind - when :observable_gauge - Opentelemetry::Proto::Metrics::V1::Metric.new( - name: metrics.name, - description: metrics.description, - unit: metrics.unit, - gauge: Opentelemetry::Proto::Metrics::V1::Gauge.new( - aggregation_temporality: as_otlp_aggregation_temporality(metrics.aggregation_temporality), - data_points: metrics.data_points.map do |ndp| - number_data_point(ndp) - end - ) - ) - - when :counter, :up_down_counter - Opentelemetry::Proto::Metrics::V1::Metric.new( - name: metrics.name, - description: metrics.description, - unit: metrics.unit, - sum: Opentelemetry::Proto::Metrics::V1::Sum.new( - aggregation_temporality: as_otlp_aggregation_temporality(metrics.aggregation_temporality), - data_points: metrics.data_points.map do |ndp| - number_data_point(ndp) - end - ) - ) - - when :histogram - Opentelemetry::Proto::Metrics::V1::Metric.new( - name: metrics.name, - description: metrics.description, - unit: metrics.unit, - histogram: Opentelemetry::Proto::Metrics::V1::Histogram.new( - aggregation_temporality: as_otlp_aggregation_temporality(metrics.aggregation_temporality), - data_points: metrics.data_points.map do |hdp| - histogram_data_point(hdp) - end - ) - ) - end - end - - def as_otlp_aggregation_temporality(type) - case type - when :delta then Opentelemetry::Proto::Metrics::V1::AggregationTemporality::AGGREGATION_TEMPORALITY_DELTA - when :cumulative then Opentelemetry::Proto::Metrics::V1::AggregationTemporality::AGGREGATION_TEMPORALITY_CUMULATIVE - else Opentelemetry::Proto::Metrics::V1::AggregationTemporality::AGGREGATION_TEMPORALITY_UNSPECIFIED - end - end - - def histogram_data_point(hdp) - Opentelemetry::Proto::Metrics::V1::HistogramDataPoint.new( - attributes: hdp.attributes.map { |k, v| as_otlp_key_value(k, v) }, - start_time_unix_nano: hdp.start_time_unix_nano, - time_unix_nano: hdp.time_unix_nano, - count: hdp.count, - sum: hdp.sum, - bucket_counts: hdp.bucket_counts, - explicit_bounds: hdp.explicit_bounds, - exemplars: hdp.exemplars, - min: hdp.min, - max: hdp.max - ) - end - - def number_data_point(ndp) - Opentelemetry::Proto::Metrics::V1::NumberDataPoint.new( - attributes: ndp.attributes.map { |k, v| as_otlp_key_value(k, v) }, - as_int: ndp.value, - start_time_unix_nano: ndp.start_time_unix_nano, - time_unix_nano: ndp.time_unix_nano, - exemplars: ndp.exemplars # exemplars not implemented yet from metrics sdk - ) - end - - # may not need this - def reset - SUCCESS - end - - def shutdown(timeout: nil) - @shutdown = true - SUCCESS - end - end - end - end -end diff --git a/exporter/otlp-metrics/lib/opentelemetry/exporter/otlp/util.rb b/exporter/otlp-metrics/lib/opentelemetry/exporter/otlp/util.rb deleted file mode 100644 index 85070a6f4..000000000 --- a/exporter/otlp-metrics/lib/opentelemetry/exporter/otlp/util.rb +++ /dev/null @@ -1,139 +0,0 @@ -# frozen_string_literal: true - -# Copyright The OpenTelemetry Authors -# -# SPDX-License-Identifier: Apache-2.0 - -module OpenTelemetry - module Exporter - module OTLP - # Util module provide essential functionality for exporter - module Util # rubocop:disable Metrics/ModuleLength - KEEP_ALIVE_TIMEOUT = 30 - RETRY_COUNT = 5 - ERROR_MESSAGE_INVALID_HEADERS = 'headers must be a String with comma-separated URL Encoded UTF-8 k=v pairs or a Hash' - DEFAULT_USER_AGENT = "OTel-OTLP-MetricsExporter-Ruby/#{OpenTelemetry::Exporter::OTLP::VERSION} Ruby/#{RUBY_VERSION} (#{RUBY_PLATFORM}; #{RUBY_ENGINE}/#{RUBY_ENGINE_VERSION})".freeze - - def http_connection(uri, ssl_verify_mode, certificate_file) - http = Net::HTTP.new(uri.host, uri.port) - http.use_ssl = uri.scheme == 'https' - http.verify_mode = ssl_verify_mode - http.ca_file = certificate_file unless certificate_file.nil? - http.keep_alive_timeout = KEEP_ALIVE_TIMEOUT - http - end - - def around_request - OpenTelemetry::Common::Utilities.untraced { yield } # rubocop:disable Style/ExplicitBlockArgument - end - - def as_otlp_key_value(key, value) - Opentelemetry::Proto::Common::V1::KeyValue.new(key: key, value: as_otlp_any_value(value)) - rescue Encoding::UndefinedConversionError => e - encoded_value = value.encode('UTF-8', invalid: :replace, undef: :replace, replace: '�') - OpenTelemetry.handle_error(exception: e, message: "encoding error for key #{key} and value #{encoded_value}") - Opentelemetry::Proto::Common::V1::KeyValue.new(key: key, value: as_otlp_any_value('Encoding Error')) - end - - def as_otlp_any_value(value) - result = Opentelemetry::Proto::Common::V1::AnyValue.new - case value - when String - result.string_value = value - when Integer - result.int_value = value - when Float - result.double_value = value - when true, false - result.bool_value = value - when Array - values = value.map { |element| as_otlp_any_value(element) } - result.array_value = Opentelemetry::Proto::Common::V1::ArrayValue.new(values: values) - end - result - end - - def prepare_headers(config_headers) - headers = case config_headers - when String then parse_headers(config_headers) - when Hash then config_headers.dup - else - raise ArgumentError, ERROR_MESSAGE_INVALID_HEADERS - end - - headers['User-Agent'] = "#{headers.fetch('User-Agent', '')} #{DEFAULT_USER_AGENT}".strip - - headers - end - - def measure_request_duration - start = Process.clock_gettime(Process::CLOCK_MONOTONIC) - begin - yield - ensure - stop = Process.clock_gettime(Process::CLOCK_MONOTONIC) - 1000.0 * (stop - start) - end - end - - def parse_headers(raw) - entries = raw.split(',') - raise ArgumentError, ERROR_MESSAGE_INVALID_HEADERS if entries.empty? - - entries.each_with_object({}) do |entry, headers| - k, v = entry.split('=', 2).map(&CGI.method(:unescape)) - begin - k = k.to_s.strip - v = v.to_s.strip - rescue Encoding::CompatibilityError - raise ArgumentError, ERROR_MESSAGE_INVALID_HEADERS - rescue ArgumentError => e - raise e, ERROR_MESSAGE_INVALID_HEADERS - end - raise ArgumentError, ERROR_MESSAGE_INVALID_HEADERS if k.empty? || v.empty? - - headers[k] = v - end - end - - def backoff?(retry_count:, reason:, retry_after: nil) - return false if retry_count > RETRY_COUNT - - sleep_interval = nil - unless retry_after.nil? - sleep_interval = - begin - Integer(retry_after) - rescue ArgumentError - nil - end - sleep_interval ||= - begin - Time.httpdate(retry_after) - Time.now - rescue # rubocop:disable Style/RescueStandardError - nil - end - sleep_interval = nil unless sleep_interval&.positive? - end - sleep_interval ||= rand(2**retry_count) - - sleep(sleep_interval) - true - end - - def log_status(body) - status = Google::Rpc::Status.decode(body) - details = status.details.map do |detail| - klass_or_nil = ::Google::Protobuf::DescriptorPool.generated_pool.lookup(detail.type_name).msgclass - detail.unpack(klass_or_nil) if klass_or_nil - end.compact - OpenTelemetry.handle_error(message: "OTLP metrics_exporter received rpc.Status{message=#{status.message}, details=#{details}}") - rescue StandardError => e - OpenTelemetry.handle_error(exception: e, message: 'unexpected error decoding rpc.Status in OTLP::MetricsExporter#log_status') - end - - def handle_redirect(location); end - end - end - end -end diff --git a/exporter/otlp-metrics/test/opentelemetry/exporter/otlp/metrics_exporter_test.rb b/exporter/otlp-metrics/test/opentelemetry/exporter/otlp/metrics/metrics_exporter_test.rb similarity index 100% rename from exporter/otlp-metrics/test/opentelemetry/exporter/otlp/metrics_exporter_test.rb rename to exporter/otlp-metrics/test/opentelemetry/exporter/otlp/metrics/metrics_exporter_test.rb From 3ff81bdbc3112a69c41275f68153619b98e32209 Mon Sep 17 00:00:00 2001 From: Kayla Reopelle <87386821+kaylareopelle@users.noreply.github.com> Date: Wed, 4 Sep 2024 11:51:58 -0700 Subject: [PATCH 2/2] test: Misc logs fixes (#1697) * test: Add LogRecordProcessor tests * test: Update observed_timestamp LogRecord test Tests for timestamp were updated to use Time objects, but observed_timestamp was not. Now, they both evaluate Time. They are turned into floats when converted to LogRecordData. * test: Exclude test directory from SimpleCov * style: Misc docs/spacing updates * test: Skip flaky JRuby test with link to fix issue --------- Co-authored-by: Matthew Wear --- .../test/opentelemetry/logs/logger_test.rb | 2 +- logs_api/test/test_helper.rb | 7 +++- .../opentelemetry/sdk/logs/log_record_data.rb | 2 +- .../sdk/logs/log_record_processor.rb | 4 +-- logs_sdk/lib/opentelemetry/sdk/logs/logger.rb | 2 ++ .../export/batch_log_record_processor_test.rb | 4 +++ .../sdk/logs/log_record_processor_test.rb | 33 +++++++++++++++++++ .../opentelemetry/sdk/logs/log_record_test.rb | 10 ++---- logs_sdk/test/test_helper.rb | 7 +++- 9 files changed, 58 insertions(+), 13 deletions(-) create mode 100644 logs_sdk/test/opentelemetry/sdk/logs/log_record_processor_test.rb diff --git a/logs_api/test/opentelemetry/logs/logger_test.rb b/logs_api/test/opentelemetry/logs/logger_test.rb index 9fd35a651..faf549f3d 100644 --- a/logs_api/test/opentelemetry/logs/logger_test.rb +++ b/logs_api/test/opentelemetry/logs/logger_test.rb @@ -9,7 +9,7 @@ describe OpenTelemetry::Logs::Logger do let(:logger) { OpenTelemetry::Logs::Logger.new } - describe '#emit' do + describe '#on_emit' do it 'returns nil, as it is a no-op method' do assert_nil(logger.on_emit) end diff --git a/logs_api/test/test_helper.rb b/logs_api/test/test_helper.rb index 151c9213e..a141bff9a 100644 --- a/logs_api/test/test_helper.rb +++ b/logs_api/test/test_helper.rb @@ -5,7 +5,12 @@ # SPDX-License-Identifier: Apache-2.0 require 'simplecov' -SimpleCov.start { enable_coverage :branch } + +SimpleCov.start do + enable_coverage :branch + add_filter '/test/' +end + SimpleCov.minimum_coverage 85 require 'opentelemetry-logs-api' diff --git a/logs_sdk/lib/opentelemetry/sdk/logs/log_record_data.rb b/logs_sdk/lib/opentelemetry/sdk/logs/log_record_data.rb index 17d8b263f..5a7e456d5 100644 --- a/logs_sdk/lib/opentelemetry/sdk/logs/log_record_data.rb +++ b/logs_sdk/lib/opentelemetry/sdk/logs/log_record_data.rb @@ -13,7 +13,7 @@ module Logs :severity_text, # optional String :severity_number, # optional Integer :body, # optional String, Numeric, Boolean, Array, Hash{String => String, Numeric, Boolean, Array} - :attributes, # optional Hash{String => String, Numeric, Boolean, Array} + :attributes, # optional Hash{String => String, Numeric, Boolean, Array} :trace_id, # optional String (16-byte binary) :span_id, # optional String (8-byte binary) :trace_flags, # optional Integer (8-bit byte of bit flags) diff --git a/logs_sdk/lib/opentelemetry/sdk/logs/log_record_processor.rb b/logs_sdk/lib/opentelemetry/sdk/logs/log_record_processor.rb index 6b51b1691..6cca12ea1 100644 --- a/logs_sdk/lib/opentelemetry/sdk/logs/log_record_processor.rb +++ b/logs_sdk/lib/opentelemetry/sdk/logs/log_record_processor.rb @@ -26,7 +26,7 @@ def on_emit(log_record, context); end # the process after an invocation, but before the `Processor` exports # the completed spans. # - # @param [Numeric] timeout An optional timeout in seconds. + # @param [optional Numeric] timeout An optional timeout in seconds. # @return [Integer] Export::SUCCESS if no error occurred, Export::FAILURE if # a non-specific failure occurred, Export::TIMEOUT if a timeout occurred. def force_flush(timeout: nil) @@ -35,7 +35,7 @@ def force_flush(timeout: nil) # Called when {LoggerProvider#shutdown} is called. # - # @param [Numeric] timeout An optional timeout in seconds. + # @param [optional Numeric] timeout An optional timeout in seconds. # @return [Integer] Export::SUCCESS if no error occurred, Export::FAILURE if # a non-specific failure occurred, Export::TIMEOUT if a timeout occurred. def shutdown(timeout: nil) diff --git a/logs_sdk/lib/opentelemetry/sdk/logs/logger.rb b/logs_sdk/lib/opentelemetry/sdk/logs/logger.rb index 51f096c14..231999a33 100644 --- a/logs_sdk/lib/opentelemetry/sdk/logs/logger.rb +++ b/logs_sdk/lib/opentelemetry/sdk/logs/logger.rb @@ -34,6 +34,8 @@ def initialize(name, version, logger_provider) # @param [optional OpenTelemetry::Trace::SpanContext] span_context The # OpenTelemetry::Trace::SpanContext to associate with the # {LogRecord}. + # @param [optional String] severity_text Original string representation of + # the severity as it is known at the source. Also known as log level. # @param severity_number [optional Integer] Numerical value of the # severity. Smaller numerical values correspond to less severe events # (such as debug events), larger numerical values correspond to more diff --git a/logs_sdk/test/opentelemetry/sdk/logs/export/batch_log_record_processor_test.rb b/logs_sdk/test/opentelemetry/sdk/logs/export/batch_log_record_processor_test.rb index 08aee76e8..64e81477a 100644 --- a/logs_sdk/test/opentelemetry/sdk/logs/export/batch_log_record_processor_test.rb +++ b/logs_sdk/test/opentelemetry/sdk/logs/export/batch_log_record_processor_test.rb @@ -204,6 +204,10 @@ def to_log_record_data end it 'logs a warning if a log record was emitted after the buffer is full' do + # This will be fixed as part of Issue #1701 + # https://github.com/open-telemetry/opentelemetry-ruby/issues/1701 + skip if RUBY_ENGINE == 'jruby' + mock_otel_logger = Minitest::Mock.new mock_otel_logger.expect(:warn, nil, ['1 log record(s) dropped. Reason: buffer-full']) diff --git a/logs_sdk/test/opentelemetry/sdk/logs/log_record_processor_test.rb b/logs_sdk/test/opentelemetry/sdk/logs/log_record_processor_test.rb new file mode 100644 index 000000000..9986b1915 --- /dev/null +++ b/logs_sdk/test/opentelemetry/sdk/logs/log_record_processor_test.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +require 'test_helper' + +describe OpenTelemetry::SDK::Logs::LogRecordProcessor do + let(:processor) { OpenTelemetry::SDK::Logs::LogRecordProcessor.new } + let(:log_record) { nil } + let(:context) { nil } + + it 'implements #on_emit' do + processor.on_emit(log_record, context) + end + + it 'implements #force_flush' do + processor.force_flush + end + + it 'returns a success code when #force_flush is called' do + assert(OpenTelemetry::SDK::Logs::Export::SUCCESS, processor.force_flush) + end + + it 'implements #shutdown' do + processor.shutdown + end + + it 'returns a success code when #shutdown is called' do + assert(OpenTelemetry::SDK::Logs::Export::SUCCESS, processor.shutdown) + end +end diff --git a/logs_sdk/test/opentelemetry/sdk/logs/log_record_test.rb b/logs_sdk/test/opentelemetry/sdk/logs/log_record_test.rb index 7ba19048f..ca38350e1 100644 --- a/logs_sdk/test/opentelemetry/sdk/logs/log_record_test.rb +++ b/logs_sdk/test/opentelemetry/sdk/logs/log_record_test.rb @@ -15,7 +15,8 @@ describe '#initialize' do describe 'observed_timestamp' do describe 'when observed_timestamp is present' do - let(:observed_timestamp) { '1692661486.2841358' } + let(:current_time) { Time.now } + let(:observed_timestamp) { current_time + 1 } let(:args) { { observed_timestamp: observed_timestamp } } it 'is equal to observed_timestamp' do @@ -26,13 +27,8 @@ refute_equal(log_record.timestamp, log_record.observed_timestamp) end - # Process.clock_gettime is used to set the current time - # That method returns a Float. Since the stubbed value of - # observed_timestamp is a String, we can know the the - # observed_timestamp was not set to the value of Process.clock_gettime - # by making sure its value is not a Float. it 'is not equal to the current time' do - refute_instance_of(Float, log_record.observed_timestamp) + refute_equal(current_time, log_record.observed_timestamp) end end diff --git a/logs_sdk/test/test_helper.rb b/logs_sdk/test/test_helper.rb index 59d743987..7f11ee950 100644 --- a/logs_sdk/test/test_helper.rb +++ b/logs_sdk/test/test_helper.rb @@ -5,7 +5,12 @@ # SPDX-License-Identifier: Apache-2.0 require 'simplecov' -SimpleCov.start { enable_coverage :branch } + +SimpleCov.start do + enable_coverage :branch + add_filter '/test/' +end + SimpleCov.minimum_coverage 85 require 'opentelemetry-logs-api'