diff --git a/CONFIGURATION.md b/CONFIGURATION.md index bec0b17..132242d 100644 --- a/CONFIGURATION.md +++ b/CONFIGURATION.md @@ -126,9 +126,10 @@ Environment Variable | Config File Key | Description | Default `SW_APM_LOG_FILEPATH` | N/A | Configure the log file path for the C extension, e.g. `export SW_APM_LOG_FILEPATH=/path/file_path.log`. If set, messages from the C extension are written to the specified file instead of stderr. | None `SW_APM_PROXY` | `:http_proxy` | Configure an HTTP proxy through which the library connects to the collector. | None `SW_APM_SERVICE_KEY` | `:service_key` | API token and service name in the form of `token:service_name`, **required**. | None -`SW_APM_TAG_SQL` | `:tag_sql` | Enable/disable injecting trace context into supported SQL statements. Set to boolean true or (or string `true` in env var) to enable, see [Tag Query with Trace Context](#tag-query-with-trace-context) for details.| false +`SW_APM_TAG_SQL` | `:tag_sql` | Enable/disable injecting trace context into supported SQL statements. Set to boolean true or (or string `true` in env var) to enable, see [Tag Query with Trace Context](#tag-query-with-trace-context) for details.| `false` `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_TRUSTEDPATH` | N/A | The library uses the host system's default trusted CA certificates to verify the TLS connection to the collector. To override the default, define the trusted certificate path configuration option with an absolute path to a specific trusted certificate file in PEM format. | None +`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 N/A | `:log_args` | Enable/disable the collection of URL query parameters, set to boolean false to disable. | true 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` diff --git a/lambda/otel/layer/Gemfile b/lambda/otel/layer/Gemfile index 8b4223f..d06ec32 100644 --- a/lambda/otel/layer/Gemfile +++ b/lambda/otel/layer/Gemfile @@ -4,8 +4,8 @@ source 'https://rubygems.org' source 'https://rubygems.pkg.github.com/solarwinds' do gem 'opentelemetry-exporter-otlp', '0.26.1' - gem 'opentelemetry-metrics-api', '0.0.1' - gem 'opentelemetry-metrics-sdk', '0.0.1' end +gem 'opentelemetry-metrics-api', '0.1.0' +gem 'opentelemetry-metrics-sdk', '0.1.0' gem 'solarwinds_apm', '6.0.2' diff --git a/lambda/otel/layer/otel_wrapper.rb b/lambda/otel/layer/otel_wrapper.rb index 97936a2..3016133 100644 --- a/lambda/otel/layer/otel_wrapper.rb +++ b/lambda/otel/layer/otel_wrapper.rb @@ -3,6 +3,42 @@ require 'opentelemetry-metrics-api' require 'opentelemetry-metrics-sdk' require 'opentelemetry-exporter-otlp' + +# We need to load the function code's dependencies, and _before_ any dependencies might +# be initialized outside of the function handler, bootstrap instrumentation. This allows +# instrumentation targets to be present, and accommodates instrumentations like AWS SDK +# that add plugins on client initialization (vs. prepending methods). +def preload_function_dependencies + default_task_location = '/var/task' + + handler_file = ENV.values_at('ORIG_HANDLER', '_HANDLER').compact.first&.split('.')&.first + + unless handler_file && File.exist?("#{default_task_location}/#{handler_file}.rb") + OpenTelemetry.logger.warn { 'Could not find the original handler file to preload libraries.' } + return + end + + libraries = File.read("#{default_task_location}/#{handler_file}.rb") + .scan(/^\s*require\s+['"]([^'"]+)['"]/) + .flatten + + libraries.each do |lib| + require lib + rescue StandardError => e + OpenTelemetry.logger.warn { "Could not load library #{lib}: #{e.message}" } + end +end + +unless ENV['SW_APM_LAMBDA_PRELOAD_DEPS'].to_s.downcase == 'false' + OpenTelemetry.logger.warn { "SW_APM_LAMBDA_PRELOAD_DEPS set to #{ENV.fetch('SW_APM_LAMBDA_PRELOAD_DEPS', nil)}. No libraries will be preloaded." } + preload_function_dependencies + + require 'opentelemetry-registry' + require 'opentelemetry-instrumentation-all' + + OpenTelemetry::Instrumentation.registry.install_all +end + require 'solarwinds_apm' def otel_wrapper(event:, context:) diff --git a/lib/solarwinds_apm/opentelemetry/otlp_processor.rb b/lib/solarwinds_apm/opentelemetry/otlp_processor.rb index 951c265..17286ea 100644 --- a/lib/solarwinds_apm/opentelemetry/otlp_processor.rb +++ b/lib/solarwinds_apm/opentelemetry/otlp_processor.rb @@ -22,7 +22,7 @@ def initialize # @param [Context] parent_context the # started span. def on_start(span, parent_context) - SolarWindsAPM.logger.debug { "[#{self.class}/#{__method__}] processor on_start span: #{span.inspect}" } + SolarWindsAPM.logger.debug { "[#{self.class}/#{__method__}] processor on_start span: #{span.to_span_data.inspect}" } return if non_entry_span(parent_context: parent_context)