From 2c736ba3b927da144dffc08f7ba2c1f74ca6c8c0 Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Tue, 14 Oct 2025 11:32:38 -0400 Subject: [PATCH 1/2] NH-121272: add log feature --- CONFIGURATION.md | 1 + lib/solarwinds_apm/opentelemetry.rb | 2 ++ .../opentelemetry/solarwinds_response_propagator.rb | 1 + lib/solarwinds_apm/otel_config.rb | 3 +++ lib/solarwinds_apm/version.rb | 4 ++-- solarwinds_apm.gemspec | 2 ++ 6 files changed, 11 insertions(+), 2 deletions(-) diff --git a/CONFIGURATION.md b/CONFIGURATION.md index dc1448f7..01ff1910 100644 --- a/CONFIGURATION.md +++ b/CONFIGURATION.md @@ -318,6 +318,7 @@ export SW_APM_TRANSACTION_NAME=my-lambda-function | `SW_APM_TRIGGER_TRACING_MODE` | `:trigger_tracing_mode` | Enable/disable trigger tracing for the service. Setting to `disabled` may impact DEM visibility into the service. | `enabled` | | `SW_APM_LAMBDA_PRELOAD_DEPS` | N/A | This option only takes effect in the AWS Lambda runtime. Set to `false` to disable the attempt to preload function dependencies and install instrumentations. | `true` | | `SW_APM_TRANSACTION_NAME` | N/A | Customize the transaction name for all traces, typically used to target specific instrumented lambda functions. _Precedence order_: custom SDK > `SW_APM_TRANSACTION_NAME` > automatic naming | None | +| `SW_APM_LOG_BRIDGE` | N/A | set to `true` to allow the log message send to swo backend | `false` | | N/A | `:log_traceId` | Configure the insertion of trace context into application logs, setting `:traced` would include the available context fields such as trace_id, span_id into log messages. | `:never` | | N/A | `:tracing_mode` | Enable/disable the tracing mode for this service, setting `:disabled` would suppress all trace spans and metrics. | `:enabled` | | N/A | `:transaction_settings` | Configure tracing mode per transaction, aka transaction filtering. See [Transaction Filtering](#transaction-filtering) for details.| None | diff --git a/lib/solarwinds_apm/opentelemetry.rb b/lib/solarwinds_apm/opentelemetry.rb index 165a2c6c..5e48d980 100644 --- a/lib/solarwinds_apm/opentelemetry.rb +++ b/lib/solarwinds_apm/opentelemetry.rb @@ -11,6 +11,8 @@ require 'opentelemetry-exporter-otlp' require 'opentelemetry-exporter-otlp-metrics' require 'opentelemetry-instrumentation-all' +require 'opentelemetry-logs-sdk' +require 'opentelemetry-exporter-otlp-logs' require_relative 'opentelemetry/solarwinds_propagator' require_relative 'opentelemetry/solarwinds_response_propagator' diff --git a/lib/solarwinds_apm/opentelemetry/solarwinds_response_propagator.rb b/lib/solarwinds_apm/opentelemetry/solarwinds_response_propagator.rb index e9ab90a5..4eeff61f 100644 --- a/lib/solarwinds_apm/opentelemetry/solarwinds_response_propagator.rb +++ b/lib/solarwinds_apm/opentelemetry/solarwinds_response_propagator.rb @@ -61,6 +61,7 @@ def inject(carrier, context: ::OpenTelemetry::Context.current, end private + # SW_XTRACEOPTIONS_RESPONSE_KEY -> xtrace_options_response def recover_response_from_tracestate(span_context) sanitized = span_context.tracestate.value(SW_XTRACEOPTIONS_RESPONSE_KEY) diff --git a/lib/solarwinds_apm/otel_config.rb b/lib/solarwinds_apm/otel_config.rb index 2c15e285..9d8636b2 100644 --- a/lib/solarwinds_apm/otel_config.rb +++ b/lib/solarwinds_apm/otel_config.rb @@ -77,6 +77,9 @@ def self.initialize c.use_all(@@config_map) end + # only enable logger bridge if required and exist + SolarWindsAPM.logger.skip_otel_emit = ENV['SW_APM_LOG_BRIDGE'].to_s == 'true' if SolarWindsAPM.logger.respond_to?(:skip_otel_emit) + # append our propagators ::OpenTelemetry.propagation.instance_variable_get(:@propagators).append(SolarWindsAPM::OpenTelemetry::SolarWindsPropagator::TextMapPropagator.new) diff --git a/lib/solarwinds_apm/version.rb b/lib/solarwinds_apm/version.rb index a6f7f6d7..943b0c5e 100644 --- a/lib/solarwinds_apm/version.rb +++ b/lib/solarwinds_apm/version.rb @@ -12,8 +12,8 @@ module SolarWindsAPM # solarwinds_apm.gemspec during gem build process module Version MAJOR = 7 # breaking, - MINOR = 0 # feature, - PATCH = 2 # fix => BFF + MINOR = 1 # feature, + PATCH = 0 # fix => BFF PRE = 'prev1' STRING = [MAJOR, MINOR, PATCH, PRE].compact.join('.') diff --git a/solarwinds_apm.gemspec b/solarwinds_apm.gemspec index 2ef34e66..d5340c3b 100644 --- a/solarwinds_apm.gemspec +++ b/solarwinds_apm.gemspec @@ -27,8 +27,10 @@ Gem::Specification.new do |s| s.files -= ['Rakefile'] s.add_dependency('opentelemetry-exporter-otlp', '>= 0.29.1') + s.add_dependency('opentelemetry-exporter-otlp-logs', '>= 0.2.1') s.add_dependency('opentelemetry-exporter-otlp-metrics', '>= 0.3.0') s.add_dependency('opentelemetry-instrumentation-all', '>= 0.31.0') + s.add_dependency('opentelemetry-logs-sdk', '>= 0.4.0') s.add_dependency('opentelemetry-metrics-sdk', '>= 0.2.0') s.add_dependency('opentelemetry-resource-detector-aws', '>= 0.1.0') s.add_dependency('opentelemetry-resource-detector-azure', '>= 0.2.0') From 4c11e700c62a3c27e3334a98a8986ba821e7476a Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Tue, 14 Oct 2025 20:04:22 -0400 Subject: [PATCH 2/2] add test case and use upstream env --- CONFIGURATION.md | 1 - lib/solarwinds_apm/opentelemetry.rb | 1 + lib/solarwinds_apm/otel_config.rb | 6 +-- solarwinds_apm.gemspec | 1 + .../otel_config_log_bridge_test.rb | 47 +++++++++++++++++++ 5 files changed, 52 insertions(+), 4 deletions(-) create mode 100644 test/solarwinds_apm/otel_config_log_bridge_test.rb diff --git a/CONFIGURATION.md b/CONFIGURATION.md index 01ff1910..dc1448f7 100644 --- a/CONFIGURATION.md +++ b/CONFIGURATION.md @@ -318,7 +318,6 @@ export SW_APM_TRANSACTION_NAME=my-lambda-function | `SW_APM_TRIGGER_TRACING_MODE` | `:trigger_tracing_mode` | Enable/disable trigger tracing for the service. Setting to `disabled` may impact DEM visibility into the service. | `enabled` | | `SW_APM_LAMBDA_PRELOAD_DEPS` | N/A | This option only takes effect in the AWS Lambda runtime. Set to `false` to disable the attempt to preload function dependencies and install instrumentations. | `true` | | `SW_APM_TRANSACTION_NAME` | N/A | Customize the transaction name for all traces, typically used to target specific instrumented lambda functions. _Precedence order_: custom SDK > `SW_APM_TRANSACTION_NAME` > automatic naming | None | -| `SW_APM_LOG_BRIDGE` | N/A | set to `true` to allow the log message send to swo backend | `false` | | N/A | `:log_traceId` | Configure the insertion of trace context into application logs, setting `:traced` would include the available context fields such as trace_id, span_id into log messages. | `:never` | | N/A | `:tracing_mode` | Enable/disable the tracing mode for this service, setting `:disabled` would suppress all trace spans and metrics. | `:enabled` | | N/A | `:transaction_settings` | Configure tracing mode per transaction, aka transaction filtering. See [Transaction Filtering](#transaction-filtering) for details.| None | diff --git a/lib/solarwinds_apm/opentelemetry.rb b/lib/solarwinds_apm/opentelemetry.rb index 5e48d980..cd0b1f7a 100644 --- a/lib/solarwinds_apm/opentelemetry.rb +++ b/lib/solarwinds_apm/opentelemetry.rb @@ -13,6 +13,7 @@ require 'opentelemetry-instrumentation-all' require 'opentelemetry-logs-sdk' require 'opentelemetry-exporter-otlp-logs' +require 'opentelemetry-instrumentation-logger' require_relative 'opentelemetry/solarwinds_propagator' require_relative 'opentelemetry/solarwinds_response_propagator' diff --git a/lib/solarwinds_apm/otel_config.rb b/lib/solarwinds_apm/otel_config.rb index 9d8636b2..388897a1 100644 --- a/lib/solarwinds_apm/otel_config.rb +++ b/lib/solarwinds_apm/otel_config.rb @@ -72,14 +72,14 @@ def self.initialize ENV['OTEL_LOG_LEVEL'] = SolarWindsAPM::Config::SW_LOG_LEVEL_MAPPING.dig(log_level, :otel) end + # disable log bridge by default + ENV['OTEL_RUBY_INSTRUMENTATION_LOGGER_ENABLED'] = 'false' unless %w[true false].include?(ENV['OTEL_RUBY_INSTRUMENTATION_LOGGER_ENABLED'].to_s) + ::OpenTelemetry::SDK.configure do |c| c.resource = final_attributes c.use_all(@@config_map) end - # only enable logger bridge if required and exist - SolarWindsAPM.logger.skip_otel_emit = ENV['SW_APM_LOG_BRIDGE'].to_s == 'true' if SolarWindsAPM.logger.respond_to?(:skip_otel_emit) - # append our propagators ::OpenTelemetry.propagation.instance_variable_get(:@propagators).append(SolarWindsAPM::OpenTelemetry::SolarWindsPropagator::TextMapPropagator.new) diff --git a/solarwinds_apm.gemspec b/solarwinds_apm.gemspec index d5340c3b..c4e3312b 100644 --- a/solarwinds_apm.gemspec +++ b/solarwinds_apm.gemspec @@ -30,6 +30,7 @@ Gem::Specification.new do |s| s.add_dependency('opentelemetry-exporter-otlp-logs', '>= 0.2.1') s.add_dependency('opentelemetry-exporter-otlp-metrics', '>= 0.3.0') s.add_dependency('opentelemetry-instrumentation-all', '>= 0.31.0') + s.add_dependency('opentelemetry-instrumentation-logger', '>= 0.1.0') s.add_dependency('opentelemetry-logs-sdk', '>= 0.4.0') s.add_dependency('opentelemetry-metrics-sdk', '>= 0.2.0') s.add_dependency('opentelemetry-resource-detector-aws', '>= 0.1.0') diff --git a/test/solarwinds_apm/otel_config_log_bridge_test.rb b/test/solarwinds_apm/otel_config_log_bridge_test.rb new file mode 100644 index 00000000..fb9ed5c2 --- /dev/null +++ b/test/solarwinds_apm/otel_config_log_bridge_test.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +# Copyright (c) 2019 SolarWinds, LLC. +# All rights reserved. + +require 'minitest_helper' +require './lib/solarwinds_apm/config' +require './lib/solarwinds_apm/opentelemetry' +require './lib/solarwinds_apm/support/txn_name_manager' +require './lib/solarwinds_apm/otel_config' + +describe 'Log Bridge Initialization Test' do + describe 'check if log bridge is enabled' do + after do + ENV.delete('OTEL_RUBY_INSTRUMENTATION_LOGGER_ENABLED') + end + + it 'OTEL_RUBY_INSTRUMENTATION_LOGGER_ENABLED=true -> enabled' do + ENV['OTEL_RUBY_INSTRUMENTATION_LOGGER_ENABLED'] = 'true' + SolarWindsAPM::OTelConfig.initialize + _(ENV.fetch('OTEL_RUBY_INSTRUMENTATION_LOGGER_ENABLED', nil)).must_equal 'true' + end + + it 'OTEL_RUBY_INSTRUMENTATION_LOGGER_ENABLED=false -> enabled' do + ENV['OTEL_RUBY_INSTRUMENTATION_LOGGER_ENABLED'] = 'false' + SolarWindsAPM::OTelConfig.initialize + _(ENV.fetch('OTEL_RUBY_INSTRUMENTATION_LOGGER_ENABLED', nil)).must_equal 'false' + end + + it 'OTEL_RUBY_INSTRUMENTATION_LOGGER_ENABLED=empty -> disabled' do + ENV['OTEL_RUBY_INSTRUMENTATION_LOGGER_ENABLED'] = '' + SolarWindsAPM::OTelConfig.initialize + _(ENV.fetch('OTEL_RUBY_INSTRUMENTATION_LOGGER_ENABLED', nil)).must_equal 'false' + end + + it 'OTEL_RUBY_INSTRUMENTATION_LOGGER_ENABLED=nil -> disabled' do + ENV['OTEL_RUBY_INSTRUMENTATION_LOGGER_ENABLED'] = nil + SolarWindsAPM::OTelConfig.initialize + _(ENV.fetch('OTEL_RUBY_INSTRUMENTATION_LOGGER_ENABLED', nil)).must_equal 'false' + end + it 'OTEL_RUBY_INSTRUMENTATION_LOGGER_ENABLED=djisdfes -> disabled' do + ENV['OTEL_RUBY_INSTRUMENTATION_LOGGER_ENABLED'] = 'djisdfes' + SolarWindsAPM::OTelConfig.initialize + _(ENV.fetch('OTEL_RUBY_INSTRUMENTATION_LOGGER_ENABLED', nil)).must_equal 'false' + end + end +end