-
Notifications
You must be signed in to change notification settings - Fork 277
feat: OpenTelemetry.logger_provider API, ProxyLoggers, Configuration, and Instrument Registry #1725
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
mwear
merged 17 commits into
open-telemetry:main
from
kaylareopelle:logs-configuration-patch
Nov 18, 2024
Merged
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
f70094d
WIP: Log SDK configuration
kaylareopelle f6fb046
feat: Add configuration patch for logs SDK
kaylareopelle 679c085
style: Update spacing
kaylareopelle a6d7079
test: Add tests for logs api
kaylareopelle c9554df
feat: Update inheritance to get tests to pass
kaylareopelle 0e1ad90
feat: Add Instrument Registry to LoggerProvider
kaylareopelle 6a624e6
feat: Rescue NameError for OTLP logs exporter
kaylareopelle dfe8f44
Remove skip instrumenting stuff
kaylareopelle 234cc95
Merge branch 'main' into logs-configuration-patch
kaylareopelle b53e6a3
style: Rubocop
kaylareopelle 34c8f44
Merge branch 'logs-configuration-patch' of github.com:kaylareopelle/o…
kaylareopelle 654385d
test: Add skip for intermittent failure
kaylareopelle acf5cdb
Merge branch 'main' into logs-configuration-patch
kaylareopelle 9e2b8ee
refactor: Remove delegate, mutex from ProxyLogger
kaylareopelle 06e4b05
fix: Do not emit logs if stopped
kaylareopelle 936e149
Merge branch 'main' into logs-configuration-patch
kaylareopelle a3434c8
Merge branch 'main' into logs-configuration-patch
kaylareopelle File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| # Copyright The OpenTelemetry Authors | ||
| # | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| module OpenTelemetry | ||
| module Internal | ||
| # @api private | ||
| # | ||
| # {ProxyLogger} is an implementation of {OpenTelemetry::Logs::Logger}. It is returned from | ||
| # the ProxyLoggerProvider until a delegate logger provider is installed. After the delegate | ||
| # logger provider is installed, the ProxyLogger will delegate to the corresponding "real" | ||
| # logger. | ||
| class ProxyLogger < Logs::Logger | ||
| attr_writer :delegate | ||
|
|
||
| # Returns a new {ProxyLogger} instance. | ||
| # | ||
| # @return [ProxyLogger] | ||
| def initialize | ||
| @delegate = nil | ||
| end | ||
|
|
||
| def on_emit( | ||
| timestamp: nil, | ||
| observed_timestamp: nil, | ||
| severity_number: nil, | ||
| severity_text: nil, | ||
| body: nil, | ||
| trace_id: nil, | ||
| span_id: nil, | ||
| trace_flags: nil, | ||
| attributes: nil, | ||
| context: nil | ||
| ) | ||
| unless @delegate.nil? | ||
| return @delegate.on_emit( | ||
| timestamp: nil, | ||
| observed_timestamp: nil, | ||
| severity_number: nil, | ||
| severity_text: nil, | ||
| body: nil, | ||
| trace_id: nil, | ||
| span_id: nil, | ||
| trace_flags: nil, | ||
| attributes: nil, | ||
| context: nil | ||
| ) | ||
| end | ||
|
|
||
| super | ||
| end | ||
| end | ||
| end | ||
| end |
60 changes: 60 additions & 0 deletions
60
logs_api/lib/opentelemetry/internal/proxy_logger_provider.rb
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| # Copyright The OpenTelemetry Authors | ||
| # | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| module OpenTelemetry | ||
| module Internal | ||
| # @api private | ||
| # | ||
| # {ProxyLoggerProvider} is an implementation of {OpenTelemetry::Logs::LoggerProvider}. | ||
| # It is the default global logger provider returned by OpenTelemetry.logger_provider. | ||
| # It delegates to a "real" LoggerProvider after the global logger provider is registered. | ||
| # It returns {ProxyLogger} instances until the delegate is installed. | ||
| class ProxyLoggerProvider < Logs::LoggerProvider | ||
| Key = Struct.new(:name, :version) | ||
| private_constant(:Key) | ||
| # Returns a new {ProxyLoggerProvider} instance. | ||
| # | ||
| # @return [ProxyLoggerProvider] | ||
| def initialize | ||
| super | ||
|
|
||
| @mutex = Mutex.new | ||
| @registry = {} | ||
| @delegate = nil | ||
| end | ||
|
|
||
| # Set the delegate logger provider. If this is called more than once, a warning will | ||
| # be logged and superfluous calls will be ignored. | ||
| # | ||
| # @param [LoggerProvider] provider The logger provider to delegate to | ||
| def delegate=(provider) | ||
| unless @delegate.nil? | ||
| OpenTelemetry.logger.warn 'Attempt to reset delegate in ProxyLoggerProvider ignored.' | ||
| return | ||
| end | ||
|
|
||
| @mutex.synchronize do | ||
| @delegate = provider | ||
| @registry.each { |key, logger| logger.delegate = provider.logger(key.name, key.version) } | ||
| end | ||
| end | ||
|
|
||
| # Returns a {Logger} instance. | ||
| # | ||
| # @param [optional String] name Instrumentation package name | ||
| # @param [optional String] version Instrumentation package version | ||
| # | ||
| # @return [Logger] | ||
| def logger(name = nil, version = nil) | ||
| @mutex.synchronize do | ||
| return @delegate.logger(name, version) unless @delegate.nil? | ||
|
|
||
| @registry[Key.new(name, version)] ||= ProxyLogger.new | ||
| end | ||
| end | ||
| end | ||
| end | ||
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| # Copyright The OpenTelemetry Authors | ||
| # | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| require 'test_helper' | ||
|
|
||
| describe OpenTelemetry do | ||
| class CustomLogRecord < OpenTelemetry::Logs::LogRecord | ||
| end | ||
|
|
||
| class CustomLogger < OpenTelemetry::Logs::Logger | ||
| def on_emit(*) | ||
| CustomLogRecord.new | ||
| end | ||
| end | ||
|
|
||
| class CustomLoggerProvider < OpenTelemetry::Logs::LoggerProvider | ||
| def logger(name = nil, version = nil) | ||
| CustomLogger.new | ||
| end | ||
| end | ||
|
|
||
| describe '.logger_provider' do | ||
| after do | ||
| # Ensure we don't leak custom logger factories and loggers to other tests | ||
| OpenTelemetry.logger_provider = OpenTelemetry::Internal::ProxyLoggerProvider.new | ||
| end | ||
|
|
||
| it 'returns a Logs::LoggerProvider by default' do | ||
| logger_provider = OpenTelemetry.logger_provider | ||
| _(logger_provider).must_be_kind_of(OpenTelemetry::Logs::LoggerProvider) | ||
| end | ||
|
|
||
| it 'returns the same instance when accessed multiple times' do | ||
| _(OpenTelemetry.logger_provider).must_equal(OpenTelemetry.logger_provider) | ||
| end | ||
|
|
||
| it 'returns user-specified logger provider' do | ||
| custom_logger_provider = CustomLoggerProvider.new | ||
| OpenTelemetry.logger_provider = custom_logger_provider | ||
| _(OpenTelemetry.logger_provider).must_equal(custom_logger_provider) | ||
| end | ||
| end | ||
|
|
||
| describe '.logger_provider=' do | ||
| after do | ||
| # Ensure we don't leak custom logger factories and loggers to other tests | ||
| OpenTelemetry.logger_provider = OpenTelemetry::Internal::ProxyLoggerProvider.new | ||
| end | ||
|
|
||
| it 'has a default proxy logger' do | ||
| refute_nil OpenTelemetry.logger_provider.logger | ||
| end | ||
|
|
||
| it 'upgrades default loggers to *real* loggers' do | ||
| # proxy loggers do not emit any log records, nor does the API logger | ||
| # the on_emit method is empty | ||
| default_logger = OpenTelemetry.logger_provider.logger | ||
| _(default_logger.on_emit(body: 'test')).must_be_instance_of(NilClass) | ||
| OpenTelemetry.logger_provider = CustomLoggerProvider.new | ||
| _(default_logger.on_emit(body: 'test')).must_be_instance_of(CustomLogRecord) | ||
| end | ||
|
|
||
| it 'upgrades the default logger provider to a *real* logger provider' do | ||
| default_logger_provider = OpenTelemetry.logger_provider | ||
| OpenTelemetry.logger_provider = CustomLoggerProvider.new | ||
| _(default_logger_provider.logger).must_be_instance_of(CustomLogger) | ||
| end | ||
| end | ||
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
71 changes: 71 additions & 0 deletions
71
logs_sdk/lib/opentelemetry/sdk/logs/configuration_patch.rb
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| # Copyright The OpenTelemetry Authors | ||
| # | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| require 'opentelemetry/sdk/configurator' | ||
|
|
||
| module OpenTelemetry | ||
| module SDK | ||
| module Logs | ||
| # The ConfiguratorPatch implements a hook to configure the logs portion | ||
| # of the SDK. | ||
| module ConfiguratorPatch | ||
| def add_log_record_processor(log_record_processor) | ||
| @log_record_processors << log_record_processor | ||
| end | ||
|
|
||
| private | ||
|
|
||
| def initialize | ||
| super | ||
| @log_record_processors = [] | ||
| end | ||
|
|
||
| # The logs_configuration_hook method is where we define the setup | ||
| # process for logs SDK. | ||
| def logs_configuration_hook | ||
| OpenTelemetry.logger_provider = Logs::LoggerProvider.new(resource: @resource) | ||
| configure_log_record_processors | ||
| end | ||
|
|
||
| def configure_log_record_processors | ||
| processors = @log_record_processors.empty? ? wrapped_log_exporters_from_env.compact : @log_record_processors | ||
| processors.each { |p| OpenTelemetry.logger_provider.add_log_record_processor(p) } | ||
| end | ||
|
|
||
| def wrapped_log_exporters_from_env | ||
| # TODO: set default to OTLP to match traces, default is console until other exporters merged | ||
| exporters = ENV.fetch('OTEL_LOGS_EXPORTER', 'console') | ||
|
|
||
| exporters.split(',').map do |exporter| | ||
| case exporter.strip | ||
| when 'none' then nil | ||
| when 'console' then Logs::Export::SimpleLogRecordProcessor.new(Logs::Export::ConsoleLogRecordExporter.new) | ||
| when 'otlp' | ||
| otlp_protocol = ENV['OTEL_EXPORTER_OTLP_LOGS_PROTOCOL'] || ENV['OTEL_EXPORTER_OTLP_PROTOCOL'] || 'http/protobuf' | ||
|
|
||
| if otlp_protocol != 'http/protobuf' | ||
| OpenTelemetry.logger.warn "The #{otlp_protocol} transport protocol is not supported by the OTLP exporter, log_records will not be exported." | ||
| nil | ||
| else | ||
| begin | ||
| Logs::Export::BatchLogRecordProcessor.new(OpenTelemetry::Exporter::OTLP::LogsExporter.new) | ||
| rescue NameError | ||
| OpenTelemetry.logger.warn 'The otlp logs exporter cannot be configured - please add opentelemetry-exporter-otlp-logs to your Gemfile. Logs will not be exported' | ||
| nil | ||
| end | ||
| end | ||
| else | ||
| OpenTelemetry.logger.warn "The #{exporter} exporter is unknown and cannot be configured, log records will not be exported" | ||
| nil | ||
| end | ||
| end | ||
| end | ||
| end | ||
| end | ||
| end | ||
| end | ||
|
|
||
| OpenTelemetry::SDK::Configurator.prepend(OpenTelemetry::SDK::Logs::ConfiguratorPatch) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am curious, is it intentional the the module name is ConfiguratorPatch (with an r) but the filename is configuration_patch.rb (with an n) ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Excellent catch. I think that's a mistake. I have a branch with some tests for the ConfiguratorPatch I need to push up, I'll make that fix at the same time. Thanks!