From 62fb9496eedce2db8f0d9e8ba133ea97ca1e8ff9 Mon Sep 17 00:00:00 2001 From: Kayla Reopelle Date: Tue, 15 Aug 2023 18:22:36 -0700 Subject: [PATCH 1/2] feat: Create SDK LogRecord LogRecord implements the read-write log record as described in the Logs SDK spec. --- logs_api/lib/opentelemetry/logs.rb | 1 + .../lib/opentelemetry/logs/severity_number.rb | 51 ++++++++++ logs_sdk/lib/opentelemetry/sdk/logs.rb | 1 + .../lib/opentelemetry/sdk/logs/log_record.rb | 75 +++++++++++++++ logs_sdk/lib/opentelemetry/sdk/logs/logger.rb | 4 + .../opentelemetry/sdk/logs/log_record_test.rb | 94 +++++++++++++++++++ .../opentelemetry/sdk/logs/logger_test.rb | 18 ++++ 7 files changed, 244 insertions(+) create mode 100644 logs_api/lib/opentelemetry/logs/severity_number.rb create mode 100644 logs_sdk/lib/opentelemetry/sdk/logs/log_record.rb create mode 100644 logs_sdk/test/opentelemetry/sdk/logs/log_record_test.rb create mode 100644 logs_sdk/test/opentelemetry/sdk/logs/logger_test.rb diff --git a/logs_api/lib/opentelemetry/logs.rb b/logs_api/lib/opentelemetry/logs.rb index bab3adede3..0669bb21d3 100644 --- a/logs_api/lib/opentelemetry/logs.rb +++ b/logs_api/lib/opentelemetry/logs.rb @@ -7,6 +7,7 @@ require_relative 'logs/log_record' require_relative 'logs/logger' require_relative 'logs/logger_provider' +require_relative 'logs/severity_number' module OpenTelemetry # The Logs API records a timestamped record with metadata. diff --git a/logs_api/lib/opentelemetry/logs/severity_number.rb b/logs_api/lib/opentelemetry/logs/severity_number.rb new file mode 100644 index 0000000000..10f01da391 --- /dev/null +++ b/logs_api/lib/opentelemetry/logs/severity_number.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +module OpenTelemetry + module Logs + # Class with constants representing the numerical value of the log severity + # as defined in the OpenTelemetry specification. + class SeverityNumber + # TRACE: A fine-grained debugging event. Typically disabled in + # default configurations. + TRACE = 1 + TRACE2 = 2 + TRACE3 = 3 + TRACE4 = 4 + + # DEBUG: Used for debugging events. + DEBUG = 5 + DEBUG2 = 6 + DEBUG3 = 7 + DEBUG4 = 8 + + # INFO: An informational event. Indicates that an event happened. + INFO = 9 + INFO2 = 10 + INFO3 = 11 + INFO4 = 12 + + # WARN: A warning event. Not an error but is likely more important than an + # informational event. + WARN = 13 + WARN2 = 14 + WARN3 = 15 + WARN4 = 16 + + # ERROR: An error event. Something went wrong. + ERROR = 17 + ERROR2 = 18 + ERROR3 = 19 + ERROR4 = 20 + + # FATAL: A fatal error such as application or system crash. + FATAL = 21 + FATAL2 = 22 + FATAL3 = 23 + FATAL4 = 24 + end + end +end diff --git a/logs_sdk/lib/opentelemetry/sdk/logs.rb b/logs_sdk/lib/opentelemetry/sdk/logs.rb index 4331257d39..5edc0871b6 100644 --- a/logs_sdk/lib/opentelemetry/sdk/logs.rb +++ b/logs_sdk/lib/opentelemetry/sdk/logs.rb @@ -9,6 +9,7 @@ require_relative 'logs/logger_provider' require_relative 'logs/log_record_processor' require_relative 'logs/export' +require_relative 'logs/log_record' module OpenTelemetry module SDK diff --git a/logs_sdk/lib/opentelemetry/sdk/logs/log_record.rb b/logs_sdk/lib/opentelemetry/sdk/logs/log_record.rb new file mode 100644 index 0000000000..0842da5f08 --- /dev/null +++ b/logs_sdk/lib/opentelemetry/sdk/logs/log_record.rb @@ -0,0 +1,75 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +module OpenTelemetry + module SDK + module Logs + # Implementation of {OpenTelemetry::Logs::LogRecord} that records log events. + # + # This implementation includes reader methods intended to allow access to + # internal state by {LogRecordProcessor}s. + # TODO: There's a note about instrumentation use in Span, do we need that here too? + class LogRecord < OpenTelemetry::Logs::LogRecord + attr_accessor :timestamp, + :observed_timestamp, + :span_context, + :severity_text, + :severity_number, + :body, + :resource, + :instrumentation_scope, + :attributes + + # Creates a new {LogRecord}. + # + # @param [optional Float, Time] timestamp Time when the event occurred. + # @param [optional Float, Time] observed_timestamp Time when the event + # was observed by the collection system. If nil, will first attempt + # to set to `timestamp`. If `timestamp` is nil, will set to + # `Process.clock_gettime(Process::CLOCK_REALTIME)`. + # @param [optional OpenTelemetry::Trace::SpanContext] span_context The + # OpenTelemetry::Trace::SpanContext to associate with the + # {LogRecord}. + # @param [optional String] severity_text The log severity, also known as + # log level. + # @param [optional Integer] severity_number The numerical value of the + # log severity. See OpenTelemetry::Logs::SeverityNumber. + # @param [optional String, Numeric, Boolean, Array, Hash{String => String, Numeric, Boolean, Array}] body The body of the {LogRecord}. + # @param [optional Hash{String => String, Numeric, Boolean, + # Array}] attributes Attributes to associate + # with the {LogRecord}. + # @param [OpenTelemetry::SDK::Logs::Logger] logger The logger that + # created the {LogRecord}. Used to set `resource` and + # `instrumentation_scope`. + # + # @return [LogRecord] + def initialize( + timestamp: nil, + observed_timestamp: nil, + span_context: nil, + severity_text: nil, + severity_number: nil, + body: nil, + attributes: nil, + logger: nil + ) + @timestamp = timestamp + @observed_timestamp = observed_timestamp || timestamp || Process.clock_gettime(Process::CLOCK_REALTIME) + @span_context = span_context + @severity_text = severity_text + @severity_number = severity_number + @body = body + @resource = logger&.resource + @instrumentation_scope = logger&.instrumentation_scope + # TODO: Give attributes more love when working on limits, Issue #1516 + @attributes = attributes + end + end + end + end +end diff --git a/logs_sdk/lib/opentelemetry/sdk/logs/logger.rb b/logs_sdk/lib/opentelemetry/sdk/logs/logger.rb index 5d3707c4d4..f8c6014ece 100644 --- a/logs_sdk/lib/opentelemetry/sdk/logs/logger.rb +++ b/logs_sdk/lib/opentelemetry/sdk/logs/logger.rb @@ -27,6 +27,10 @@ def initialize(name, version, logger_provider) @instrumentation_scope = InstrumentationScope.new(name, version) @logger_provider = logger_provider end + + def resource + logger_provider.resource + end end 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 new file mode 100644 index 0000000000..70612148f2 --- /dev/null +++ b/logs_sdk/test/opentelemetry/sdk/logs/log_record_test.rb @@ -0,0 +1,94 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +require 'test_helper' + +describe OpenTelemetry::SDK::Logs::LogRecord do + let(:log_record) { OpenTelemetry::SDK::Logs::LogRecord.new(**args) } + let(:args) { {} } + + describe '#initialize' do + describe 'observed_timestamp' do + describe 'when observed_timestamp is present' do + let(:observed_timestamp) { '1692661486.2841358' } + let(:args) { { observed_timestamp: observed_timestamp } } + + it 'is equal to observed_timestamp' do + assert_equal(observed_timestamp, log_record.observed_timestamp) + end + + it 'is not equal to timestamp' do + 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) + end + end + + describe 'when timestamp is present' do + let(:timestamp) { Process.clock_gettime(Process::CLOCK_REALTIME) } + let(:args) { { timestamp: timestamp } } + + it 'is equal to timestamp' do + assert_equal(timestamp, log_record.observed_timestamp) + end + end + + describe 'when observed_timestamp and timestamp are nil' do + let(:args) { { timestamp: nil, observed_timestamp: nil } } + + it 'is not nil' do + refute_nil(log_record.observed_timestamp) + end + + it 'is equal to the current time' do + # Since I can't get the current time when the test was run + # I'm going to assert it's a Float, which is the Process.clock_gettime + # return value class. + assert_instance_of(Float, log_record.observed_timestamp) + end + end + end + + describe 'attributes set through logger' do + let(:logger_provider) { OpenTelemetry::SDK::Logs::LoggerProvider.new } + let(:resource) { OpenTelemetry::SDK::Resources::Resource.create } + let(:instrumentation_scope) { OpenTelemetry::SDK::InstrumentationScope.new('name', 'version') } + let(:logger) { OpenTelemetry::SDK::Logs::Logger.new(resource, instrumentation_scope, logger_provider) } + let(:args) { { logger: logger } } + + describe 'resource' do + it 'is set to the resource of the logger given on initialization' do + assert_equal(logger.resource, log_record.resource) + end + end + + describe 'instrumentation_scope' do + it 'is set to the instrumentation_scope of the logger given on initialization' do + assert_equal(logger.instrumentation_scope, log_record.instrumentation_scope) + end + end + + describe 'when logger is nil' do + let(:logger) { nil } + + it 'sets the resource to nil' do + assert_nil(log_record.resource) + end + + it 'sets the instrumentation_scope to nil' do + assert_nil(log_record.instrumentation_scope) + end + end + end + end +end diff --git a/logs_sdk/test/opentelemetry/sdk/logs/logger_test.rb b/logs_sdk/test/opentelemetry/sdk/logs/logger_test.rb new file mode 100644 index 0000000000..39868700db --- /dev/null +++ b/logs_sdk/test/opentelemetry/sdk/logs/logger_test.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +require 'test_helper' + +describe OpenTelemetry::SDK::Logs::Logger do + let(:logger_provider) { OpenTelemetry::SDK::Logs::LoggerProvider.new } + let(:logger) { logger_provider.logger } + + describe '#resource' do + it 'returns the resource associated with the logger_provider' do + assert_equal(logger.resource, logger_provider.resource) + end + end +end From 4b0ff26dcf058b4b0a95486743ea22adb750b3a3 Mon Sep 17 00:00:00 2001 From: Kayla Reopelle Date: Fri, 25 Aug 2023 16:23:33 -0700 Subject: [PATCH 2/2] Update documentation --- logs_sdk/lib/opentelemetry/sdk/logs/log_record.rb | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/logs_sdk/lib/opentelemetry/sdk/logs/log_record.rb b/logs_sdk/lib/opentelemetry/sdk/logs/log_record.rb index 0842da5f08..0bcff365aa 100644 --- a/logs_sdk/lib/opentelemetry/sdk/logs/log_record.rb +++ b/logs_sdk/lib/opentelemetry/sdk/logs/log_record.rb @@ -7,11 +7,7 @@ module OpenTelemetry module SDK module Logs - # Implementation of {OpenTelemetry::Logs::LogRecord} that records log events. - # - # This implementation includes reader methods intended to allow access to - # internal state by {LogRecordProcessor}s. - # TODO: There's a note about instrumentation use in Span, do we need that here too? + # Implementation of OpenTelemetry::Logs::LogRecord that records log events. class LogRecord < OpenTelemetry::Logs::LogRecord attr_accessor :timestamp, :observed_timestamp, @@ -43,7 +39,7 @@ class LogRecord < OpenTelemetry::Logs::LogRecord # @param [optional Hash{String => String, Numeric, Boolean, # Array}] attributes Attributes to associate # with the {LogRecord}. - # @param [OpenTelemetry::SDK::Logs::Logger] logger The logger that + # @param [optional OpenTelemetry::SDK::Logs::Logger] logger The logger that # created the {LogRecord}. Used to set `resource` and # `instrumentation_scope`. #